This commit is contained in:
tursom 2020-06-19 00:23:00 +08:00
parent 444e784e70
commit d92160c768
9 changed files with 213 additions and 75 deletions

View File

@ -0,0 +1,14 @@
package cn.tursom.log
import org.slf4j.Logger
val Logger?.traceEnabled
get() = this?.isTraceEnabled ?: false
val Logger?.debugEnabled
get() = this?.isDebugEnabled ?: false
val Logger?.infoEnabled
get() = this?.isInfoEnabled ?: false
val Logger?.warnEnabled
get() = this?.isWarnEnabled ?: false
val Logger?.errorEnabled
get() = this?.isErrorEnabled ?: false

View File

@ -1,6 +1,7 @@
package cn.tursom.web.netty
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.log.traceEnabled
import cn.tursom.utils.bytebuffer.NettyByteBuffer
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufAllocator
@ -28,7 +29,9 @@ class NettyChunkedByteBuffer(
override fun readChunk(allocator: ByteBufAllocator?): ByteBuf = readChunk()
private fun readChunk(): ByteBuf {
log?.trace("readChunk")
if (log.traceEnabled) {
log?.trace("readChunk")
}
this.next?.close()
val next = iterator.next()()
this.next = next
@ -38,7 +41,9 @@ class NettyChunkedByteBuffer(
}
override fun close() {
log?.trace("close")
if (log.traceEnabled) {
log?.trace("close")
}
}
companion object {

View File

@ -1,5 +1,6 @@
package cn.tursom.web.netty
import cn.tursom.log.traceEnabled
import cn.tursom.utils.bytebuffer.NettyByteBuffer
import cn.tursom.web.utils.Chunked
import io.netty.buffer.ByteBuf
@ -16,16 +17,21 @@ class NettyChunkedInput(private val chunked: Chunked) : ChunkedInput<ByteBuf> {
override fun readChunk(ctx: ChannelHandlerContext?): ByteBuf = readChunk()
override fun readChunk(allocator: ByteBufAllocator?): ByteBuf = readChunk()
@Suppress("MemberVisibilityCanBePrivate")
fun readChunk(): ByteBuf {
val buf = chunked.readChunk()
log?.trace("readChunk {}", buf)
if (log.traceEnabled) {
log?.trace("readChunk {}", buf)
}
return if (buf is NettyByteBuffer) buf.byteBuf
else Unpooled.wrappedBuffer(buf.readBuffer())
}
override fun close() {
log?.trace("close")
if (log.traceEnabled) {
log?.trace("close")
}
chunked.close()
}

View File

@ -1,6 +1,7 @@
package cn.tursom.web.netty
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.log.traceEnabled
import cn.tursom.utils.bytebuffer.NettyByteBuffer
import cn.tursom.web.ExceptionContent
import io.netty.buffer.ByteBuf
@ -8,6 +9,7 @@ import io.netty.buffer.CompositeByteBuf
import io.netty.buffer.Unpooled
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.http.*
import org.slf4j.LoggerFactory
@Suppress("MemberVisibilityCanBePrivate")
class NettyExceptionContent(
@ -24,14 +26,23 @@ class NettyExceptionContent(
}
override fun write(message: String) {
if (log.traceEnabled) {
log?.trace("write message: {}", message)
}
responseBodyBuf.addComponent(Unpooled.wrappedBuffer(message.toByteArray()))
}
override fun write(bytes: ByteArray, offset: Int, length: Int) {
if (log.traceEnabled) {
log?.trace("write bytes: {}", String(bytes, offset, length, Charsets.UTF_8))
}
responseBodyBuf.addComponent(Unpooled.wrappedBuffer(bytes, offset, length))
}
override fun write(buffer: ByteBuffer) {
if (log.traceEnabled) {
log?.trace("write buffer: {}", buffer.toString(buffer.readable))
}
when (buffer) {
is NettyByteBuffer -> responseBodyBuf.addComponent(buffer.byteBuf)
else -> write(buffer.getBytes())
@ -44,21 +55,31 @@ class NettyExceptionContent(
fun finish(buf: ByteBuf) = finish(buf, responseStatus)
fun finish(buf: ByteBuf, responseCode: HttpResponseStatus) {
if (log.traceEnabled) {
log?.trace("finish buf: {}, responseCode: {}", buf.toString(Charsets.UTF_8), responseCode)
}
val response = DefaultFullHttpResponse(HttpVersion.HTTP_1_1, responseCode, buf)
finish(response)
}
fun finish(response: FullHttpResponse) {
if (log.traceEnabled) {
log?.trace("finish")
}
finished = true
val heads = response.headers()
addHeaders(
heads,
mapOf(
HttpHeaderNames.CONTENT_TYPE to "${HttpHeaderValues.TEXT_PLAIN}; charset=UTF-8",
HttpHeaderNames.CONTENT_LENGTH to response.content().readableBytes(),
HttpHeaderNames.CONNECTION to HttpHeaderValues.KEEP_ALIVE
)
response.headers().addHeaders(
HttpHeaderNames.CONTENT_TYPE to "${HttpHeaderValues.TEXT_PLAIN}; charset=UTF-8",
HttpHeaderNames.CONTENT_LENGTH to response.content().readableBytes(),
HttpHeaderNames.CONNECTION to HttpHeaderValues.KEEP_ALIVE
)
ctx.writeAndFlush(response)
}
companion object {
private val log = try {
LoggerFactory.getLogger(NettyExceptionContent::class.java)
} catch (e: Throwable) {
null
}
}
}

View File

@ -1,6 +1,7 @@
package cn.tursom.web.netty
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.log.traceEnabled
import cn.tursom.utils.bytebuffer.NettyByteBuffer
import cn.tursom.web.MutableHttpContent
import cn.tursom.web.utils.Chunked
@ -101,32 +102,44 @@ open class NettyHttpContent(
}
override fun getHeader(header: String): String? {
log?.trace("getHeader {}", header)
if (log.traceEnabled) {
log?.trace("getHeader {}", header)
}
return headers[header]
}
override fun getHeaders(header: String): List<String> {
log?.trace("getHeaders {}", header)
if (log.traceEnabled) {
log?.trace("getHeaders {}", header)
}
return headers.getAll(header)
}
override fun getHeaders(): Iterable<Map.Entry<String, String>> {
log?.trace("getHeaders")
if (log.traceEnabled) {
log?.trace("getHeaders")
}
return headers
}
override fun getParams(): Map<String, List<String>> {
log?.trace("getParams")
if (log.traceEnabled) {
log?.trace("getParams")
}
return paramMap
}
override fun getParams(param: String): List<String>? {
log?.trace("getParams {}", param)
if (log.traceEnabled) {
log?.trace("getParams {}", param)
}
return paramMap[param]
}
override fun addParam(key: String, value: String) {
log?.trace("addParam {}: {}", key, value)
if (log.traceEnabled) {
log?.trace("addParam {}: {}", key, value)
}
if (!paramMap.containsKey(key)) {
paramMap[key] = ArrayList()
}
@ -134,27 +147,35 @@ open class NettyHttpContent(
}
override fun write(message: String) {
log?.trace("write {}", message)
if (log.traceEnabled) {
log?.trace("write {}", message)
}
getResponseBodyBuf().addComponent(Unpooled.wrappedBuffer(message.toByteArray()))
//responseBody.write(message.toByteArray())
}
override fun write(byte: Byte) {
log?.trace("write {}", byte)
if (log.traceEnabled) {
log?.trace("write {}", byte)
}
val buffer = ctx.alloc().buffer(1).writeByte(byte.toInt())
getResponseBodyBuf().addComponent(buffer)
//responseBody.write(byte.toInt())
}
override fun write(bytes: ByteArray, offset: Int, size: Int) {
log?.trace("write {}({}:{})", bytes, offset, size)
if (log.traceEnabled) {
log?.trace("write {}({}:{})", bytes, offset, size)
}
getResponseBodyBuf().addComponent(Unpooled.wrappedBuffer(bytes, offset, size))
//responseBody.write(bytes, offset, size)
}
override fun write(buffer: ByteBuffer) {
//buffer.writeTo(responseBody)
log?.trace("write {}", buffer)
if (log.traceEnabled) {
log?.trace("write {}", buffer)
}
getResponseBodyBuf().addComponent(
if (buffer is NettyByteBuffer) {
buffer.byteBuf
@ -167,22 +188,30 @@ open class NettyHttpContent(
}
override fun reset() {
log?.trace("reset")
if (log.traceEnabled) {
log?.trace("reset")
}
getResponseBodyBuf().clear()
}
override fun finish() {
log?.trace("finish")
if (log.traceEnabled) {
log?.trace("finish")
}
finish(getResponseBodyBuf())
}
override fun finish(buffer: ByteArray, offset: Int, size: Int) {
log?.trace("finish ByteArray[{}]({}:{})", buffer.size, offset, size)
if (log.traceEnabled) {
log?.trace("finish ByteArray[{}]({}:{})", buffer.size, offset, size)
}
finish(Unpooled.wrappedBuffer(buffer, offset, size))
}
override fun finish(buffer: ByteBuffer) {
log?.trace("finish {}", buffer)
if (log.traceEnabled) {
log?.trace("finish {}", buffer)
}
if (buffer is NettyByteBuffer) {
finish(buffer.byteBuf)
} else {
@ -192,57 +221,52 @@ open class NettyHttpContent(
fun finish(buf: ByteBuf) = finish(buf, responseStatus)
fun finish(buf: ByteBuf, responseCode: HttpResponseStatus): ChannelFuture {
log?.trace("finish {}: {}", responseCode, buf)
if (log.traceEnabled) {
log?.trace("finish {}: {}", responseCode, buf)
}
val response = DefaultFullHttpResponse(HttpVersion.HTTP_1_1, responseCode, buf)
return finish(response)
}
fun finish(response: FullHttpResponse): ChannelFuture {
log?.trace("finish {}", response)
finished = true
val heads = response.headers()
addHeaders(
heads,
mapOf(
HttpHeaderNames.CONTENT_TYPE to "${HttpHeaderValues.TEXT_PLAIN}; charset=UTF-8",
HttpHeaderNames.CONTENT_LENGTH to response.content().readableBytes(),
HttpHeaderNames.CONNECTION to HttpHeaderValues.KEEP_ALIVE
)
)
val write = ctx.writeAndFlush(response)
write.addListener {
if (it.isDone) {
val bodyBuf = responseBodyBuf ?: return@addListener
bodyBuf.release(bodyBuf.refCnt())
}
if (log.traceEnabled) {
log?.trace("finish {}", response)
}
return write
finished = true
response.headers().addHeaders(
HttpHeaderNames.CONTENT_TYPE to "${HttpHeaderValues.TEXT_PLAIN}; charset=UTF-8",
HttpHeaderNames.CONTENT_LENGTH to response.content().readableBytes(),
HttpHeaderNames.CONNECTION to HttpHeaderValues.KEEP_ALIVE
)
return ctx.writeAndFlush(response)
}
override fun writeChunkedHeader() {
log?.trace("writeChunkedHeader")
if (log.traceEnabled) {
log?.trace("writeChunkedHeader")
}
val response = DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
response.status = if (responseMessage != null) HttpResponseStatus(responseCode, responseMessage)
else responseStatus
val heads = response.headers()
addHeaders(
heads,
mapOf(
HttpHeaderNames.CONTENT_TYPE to "${HttpHeaderValues.TEXT_PLAIN}; charset=UTF-8",
HttpHeaderNames.CONNECTION to HttpHeaderValues.KEEP_ALIVE,
HttpHeaderNames.TRANSFER_ENCODING to "chunked"
)
response.headers().addHeaders(
HttpHeaderNames.CONTENT_TYPE to "${HttpHeaderValues.TEXT_PLAIN}; charset=UTF-8",
HttpHeaderNames.CONNECTION to HttpHeaderValues.KEEP_ALIVE,
HttpHeaderNames.TRANSFER_ENCODING to "chunked"
)
ctx.write(response)
}
override fun addChunked(buffer: () -> ByteBuffer) {
log?.trace("addChunked {}", buffer)
if (log.traceEnabled) {
log?.trace("addChunked {}", buffer)
}
chunkedList.add(buffer)
}
override fun finishChunked() {
log?.trace("finishChunked {}", chunkedList)
if (log.traceEnabled) {
log?.trace("finishChunked {}", chunkedList)
}
finished = true
responseBodyBuf?.release()
writeChunkedHeader()
@ -251,7 +275,9 @@ open class NettyHttpContent(
}
override fun finishChunked(chunked: Chunked) {
log?.trace("finishChunked {}", chunked)
if (log.traceEnabled) {
log?.trace("finishChunked {}", chunked)
}
finished = true
responseBodyBuf?.release()
writeChunkedHeader()
@ -260,7 +286,9 @@ open class NettyHttpContent(
}
override fun finishFile(file: File, chunkSize: Int) {
log?.trace("finishFile {} chunkSize {}", file, chunkSize)
if (log.traceEnabled) {
log?.trace("finishFile {} chunkSize {}", file, chunkSize)
}
finished = true
responseBodyBuf?.release()
writeChunkedHeader()
@ -268,7 +296,9 @@ open class NettyHttpContent(
}
override fun finishFile(file: RandomAccessFile, offset: Long, length: Long, chunkSize: Int) {
log?.trace("finishFile {}({}:{}) chunkSize {}", file, offset, length, chunkSize)
if (log.traceEnabled) {
log?.trace("finishFile {}({}:{}) chunkSize {}", file, offset, length, chunkSize)
}
finished = true
responseBodyBuf?.release()
writeChunkedHeader()

View File

@ -1,5 +1,6 @@
package cn.tursom.web.netty
import cn.tursom.log.debugEnabled
import cn.tursom.web.HttpHandler
import io.netty.channel.ChannelHandler
import io.netty.channel.ChannelHandlerContext
@ -19,7 +20,9 @@ class NettyHttpHandler(
override fun channelRead0(ctx: ChannelHandlerContext, msg: FullHttpRequest) {
val handlerContext = NettyHttpContent(ctx, msg)
log?.debug("{} {} {}", handlerContext.remoteAddress, handlerContext.method, handlerContext.uri)
if (log.debugEnabled) {
log?.debug("{} {} {}", handlerContext.remoteAddress, handlerContext.method, handlerContext.uri)
}
handler.handle(handlerContext)
}

View File

@ -1,6 +1,7 @@
package cn.tursom.web.netty
import cn.tursom.log.lazyPrettyMap
import cn.tursom.log.traceEnabled
import cn.tursom.web.ResponseHeaderAdapter
import io.netty.handler.codec.http.HttpHeaders
import org.slf4j.LoggerFactory
@ -14,13 +15,17 @@ open class NettyResponseHeaderAdapter : ResponseHeaderAdapter {
val responseListMap = HashMap<String, ArrayList<Any>>()
override fun setResponseHeader(name: String, value: Any) {
log?.trace("setResponseHeader {}: {}", name, value)
if (log.traceEnabled) {
log?.trace("setResponseHeader {}: {}", name, value)
}
responseMap[name] = value
responseListMap.remove(name)
}
override fun addResponseHeader(name: String, value: Any) {
log?.trace("addResponseHeader {}: {}", name, value)
if (log.traceEnabled) {
log?.trace("addResponseHeader {}: {}", name, value)
}
val list = responseListMap[name] ?: run {
val newList = ArrayList<Any>()
responseListMap[name] = newList
@ -33,21 +38,44 @@ open class NettyResponseHeaderAdapter : ResponseHeaderAdapter {
list.add(value)
}
protected fun addHeaders(heads: HttpHeaders, defaultHeaders: Map<out CharSequence, Any>) {
log?.trace("addHeader\nheaders {}\ndefault {}", lazyPrettyMap(heads), lazyPrettyMap(defaultHeaders))
protected fun HttpHeaders.addResponseListMap() {
responseListMap.forEach { (t, u) ->
u.forEach {
heads.add(t, it)
add(t, it)
}
}
}
protected fun HttpHeaders.addHeaders(defaultHeaders: Map<out CharSequence, Any>) {
if (log.traceEnabled) {
log?.trace("addHeader\nheaders {}\ndefault {}", lazyPrettyMap(this), lazyPrettyMap(defaultHeaders))
}
addResponseListMap()
responseMap.forEach { (t, u) ->
heads.set(t, u)
set(t, u)
}
defaultHeaders.forEach { (t, u) ->
if (!heads.contains(t)) {
heads.set(t, u)
if (!contains(t)) {
set(t, u)
}
}
}
protected fun HttpHeaders.addHeaders(vararg defaultHeaders: Pair<CharSequence, Any>) {
if (log.traceEnabled) {
log?.trace("addHeader\nheaders {}\ndefault {}", lazyPrettyMap(this), defaultHeaders.asList())
}
addResponseListMap()
responseMap.forEach { (t, u) ->
set(t, u)
}
defaultHeaders.forEach { (t, u) ->
if (!contains(t)) {
set(t, u)
}
}
}

View File

@ -2,12 +2,14 @@ package cn.tursom.web.netty
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.read
import cn.tursom.log.traceEnabled
import cn.tursom.utils.bytebuffer.NettyByteBuffer
import cn.tursom.web.WebSocketContent
import io.netty.buffer.Unpooled
import io.netty.channel.Channel
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame
import org.slf4j.LoggerFactory
import java.net.SocketAddress
class NettyWebSocketContent(
@ -15,6 +17,9 @@ class NettyWebSocketContent(
) : WebSocketContent {
override val remoteAddress: SocketAddress get() = channel.remoteAddress()
override fun writeText(buffer: ByteBuffer) {
if (log.traceEnabled) {
log?.trace("remoteAddress buffer: {}", buffer.toString(buffer.readable))
}
if (buffer is NettyByteBuffer) {
channel.writeAndFlush(TextWebSocketFrame(buffer.byteBuf))
} else {
@ -26,6 +31,9 @@ class NettyWebSocketContent(
}
override fun writeBinary(buffer: ByteBuffer) {
if (log.traceEnabled) {
log?.trace("writeBinary buffer: {}", buffer.toString(buffer.readable))
}
if (buffer is NettyByteBuffer) {
channel.writeAndFlush(BinaryWebSocketFrame(buffer.byteBuf))
} else {
@ -35,4 +43,12 @@ class NettyWebSocketContent(
buffer.close()
}
}
companion object {
private val log = try {
LoggerFactory.getLogger(NettyWebSocketContent::class.java)
} catch (e: Throwable) {
null
}
}
}

View File

@ -3,6 +3,7 @@ package cn.tursom.web
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.urlDecode
import cn.tursom.web.utils.Chunked
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File
import java.io.RandomAccessFile
@ -38,7 +39,7 @@ interface HttpContent : ResponseHeaderAdapter, RequestHeaderAdapter {
fun write(message: String)
fun write(byte: Byte)
fun write(bytes: ByteArray, offset: Int = 0, size: Int = 0)
fun write(bytes: ByteArray, offset: Int = 0, size: Int = bytes.size - offset)
fun write(buffer: ByteBuffer)
fun reset()
@ -100,21 +101,27 @@ interface HttpContent : ResponseHeaderAdapter, RequestHeaderAdapter {
}
fun finishHtml(response: ByteBuffer, code: Int = responseCode) {
log?.trace("finishHtml {}: {}", code, response)
if (log.traceEnabled) {
log?.trace("finishHtml {}: {}", code, response)
}
responseHtml()
responseCode = code
finish(response)
}
fun finishText(response: ByteBuffer, code: Int = responseCode) {
log?.trace("finishText {}: {}", code, response)
if (log.traceEnabled) {
log?.trace("finishText {}: {}", code, response)
}
responseText()
responseCode = code
finish(response)
}
fun finishJson(response: ByteBuffer, code: Int = responseCode) {
log?.trace("finishJson {}: {}", code, response)
if (log.traceEnabled) {
log?.trace("finishJson {}: {}", code, response)
}
responseJson()
responseCode = code
finish(response)
@ -143,20 +150,26 @@ interface HttpContent : ResponseHeaderAdapter, RequestHeaderAdapter {
fun moved(url: String) = permanentlyMoved(url)
fun permanentlyMoved(url: String) {
log?.trace("permanentlyMoved {}", url)
if (log.traceEnabled) {
log?.trace("permanentlyMoved {}", url)
}
setResponseHeader("Location", url)
finish(301)
}
fun temporaryMoved(url: String) {
log?.trace("temporaryMoved {}", url)
if (log.traceEnabled) {
log?.trace("temporaryMoved {}", url)
}
noStore()
setResponseHeader("Location", url)
finish(302)
}
fun finish(msg: String) {
log?.trace("finish {}", msg)
if (log.traceEnabled) {
log?.trace("finish {}", msg)
}
write(msg)
finish()
}
@ -167,5 +180,7 @@ interface HttpContent : ResponseHeaderAdapter, RequestHeaderAdapter {
} catch (e: Throwable) {
null
}
private inline val Logger?.traceEnabled get() = this?.isTraceEnabled ?: false
}
}