Http功能增强

This commit is contained in:
tursom 2019-11-21 13:47:23 +08:00
parent cb61ac0ca7
commit 367b3067c0
2 changed files with 183 additions and 161 deletions

View File

@ -20,181 +20,181 @@ import kotlin.collections.set
@Suppress("MemberVisibilityCanBePrivate", "unused")
open class NettyHttpContent(
val ctx: ChannelHandlerContext,
val msg: FullHttpRequest
val ctx: ChannelHandlerContext,
val msg: FullHttpRequest
) : AdvanceHttpContent {
override val uri: String by lazy {
var uri = msg.uri()
while (uri.contains("//")) {
uri = uri.replace("//", "/")
}
uri
override val uri: String by lazy {
var uri = msg.uri()
while (uri.contains("//")) {
uri = uri.replace("//", "/")
}
override val clientIp get() = ctx.channel().remoteAddress()!!
override val realIp: String = super.realIp
val httpMethod: HttpMethod get() = msg.method()
val protocolVersion: HttpVersion get() = msg.protocolVersion()
val headers: HttpHeaders get() = msg.headers()
protected val paramMap by lazy { RequestParser.parse(msg) }
override val cookieMap by lazy { getHeader("Cookie")?.let { decodeCookie(it) } ?: mapOf() }
override val body = msg.content()?.let { NettyByteBuffer(it) }
uri
}
override val clientIp get() = ctx.channel().remoteAddress()!!
override val realIp: String = super.realIp
val httpMethod: HttpMethod get() = msg.method()
val protocolVersion: HttpVersion get() = msg.protocolVersion()
val headers: HttpHeaders get() = msg.headers()
protected val paramMap by lazy { RequestParser.parse(msg) }
override val cookieMap by lazy { getHeader("Cookie")?.let { decodeCookie(it) } ?: mapOf() }
override val body = msg.content()?.let { NettyByteBuffer(it) }
val responseMap = HashMap<String, Any>()
val responseListMap = HashMap<String, ArrayList<Any>>()
override val responseBody = ByteArrayOutputStream()
override var responseCode: Int = 200
override var responseMessage: String? = null
override val method: String get() = httpMethod.name()
val chunkedList = ArrayList<ByteBuffer>()
val responseMap = HashMap<String, Any>()
val responseListMap = HashMap<String, ArrayList<Any>>()
override val responseBody = ByteArrayOutputStream()
override var responseCode: Int = 200
override var responseMessage: String? = null
override val method: String get() = httpMethod.name()
val chunkedList = ArrayList<ByteBuffer>()
override fun getHeader(header: String): String? {
return headers[header]
override fun getHeader(header: String): String? {
return headers[header]
}
override fun getHeaders(): List<Map.Entry<String, String>> {
return headers.toList()
}
override fun getParam(param: String): String? {
return paramMap[param]?.get(0)
}
override fun getParams(): Map<String, List<String>> {
return paramMap
}
override fun getParams(param: String): List<String>? {
return paramMap[param]
}
override fun addParam(key: String, value: String) {
if (!paramMap.containsKey(key)) {
paramMap[key] = ArrayList()
}
(paramMap[key] as ArrayList).add(value)
}
override fun setResponseHeader(name: String, value: Any) {
responseMap[name] = value
}
override fun addResponseHeader(name: String, value: Any) {
val list = responseListMap[name] ?: run {
val newList = ArrayList<Any>()
responseListMap[name] = newList
newList
}
list.add(value)
}
override fun write(message: String) {
responseBody.write(message.toByteArray())
}
override fun write(byte: Byte) {
responseBody.write(byte.toInt())
}
override fun write(bytes: ByteArray, offset: Int, size: Int) {
responseBody.write(bytes, offset, size)
}
override fun write(buffer: ByteBuffer) {
buffer.writeTo(responseBody)
}
override fun reset() {
responseBody.reset()
}
override fun finish() {
finish(responseBody.buf, 0, responseBody.size())
}
override fun finish(buffer: ByteArray, offset: Int, size: Int) {
finish(Unpooled.wrappedBuffer(buffer, offset, size))
}
override fun finish(buffer: ByteBuffer) {
if (buffer is NettyByteBuffer) {
finish(buffer.byteBuf)
} else {
super.finish(buffer)
}
}
fun finish(buf: ByteBuf) = finish(buf, HttpResponseStatus.valueOf(responseCode))
fun finish(buf: ByteBuf, responseCode: HttpResponseStatus) {
val response = DefaultFullHttpResponse(HttpVersion.HTTP_1_1, responseCode, buf)
finish(response)
}
fun finish(response: FullHttpResponse) {
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
)
)
ctx.writeAndFlush(response)
}
fun addHeaders(heads: HttpHeaders, defaultHeaders: Map<out CharSequence, Any>) {
responseListMap.forEach { (t, u) ->
u.forEach {
heads.add(t, it)
}
}
override fun getHeaders(): List<Map.Entry<String, String>> {
return headers.toList()
defaultHeaders.forEach { (t, u) ->
heads.set(t, u)
}
override fun getParam(param: String): String? {
return paramMap[param]?.get(0)
responseMap.forEach { (t, u) ->
heads.set(t, u)
}
}
override fun getParams(): Map<String, List<String>> {
return paramMap
}
override fun writeChunkedHeader() {
val response = DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
response.status = if (responseMessage != null) HttpResponseStatus(responseCode, responseMessage)
else HttpResponseStatus.valueOf(responseCode)
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"
)
)
ctx.write(response)
}
override fun getParams(param: String): List<String>? {
return paramMap[param]
}
override fun addChunked(buffer: ByteBuffer) {
chunkedList.add(buffer)
}
override fun addParam(key: String, value: String) {
if (!paramMap.containsKey(key)) {
paramMap[key] = ArrayList()
}
(paramMap[key] as ArrayList).add(value)
}
override fun finishChunked() {
val httpChunkWriter = HttpChunkedInput(NettyChunkedByteBuffer(chunkedList))
ctx.writeAndFlush(httpChunkWriter)
}
override fun setResponseHeader(name: String, value: Any) {
responseMap[name] = value
}
override fun finishChunked(chunked: Chunked) {
val httpChunkWriter = HttpChunkedInput(NettyChunkedInput(chunked))
ctx.writeAndFlush(httpChunkWriter)
}
override fun addResponseHeader(name: String, value: Any) {
val list = responseListMap[name] ?: run {
val newList = ArrayList<Any>()
responseListMap[name] = newList
newList
}
list.add(value)
}
override fun finishFile(file: File, chunkSize: Int) {
writeChunkedHeader()
ctx.writeAndFlush(HttpChunkedInput(ChunkedFile(file, chunkSize)))
}
override fun write(message: String) {
responseBody.write(message.toByteArray())
}
override fun write(byte: Byte) {
responseBody.write(byte.toInt())
}
override fun write(bytes: ByteArray, offset: Int, size: Int) {
responseBody.write(bytes, offset, size)
}
override fun write(buffer: ByteBuffer) {
buffer.writeTo(responseBody)
}
override fun reset() {
responseBody.reset()
}
override fun finish() {
finish(responseBody.buf, 0, responseBody.size())
}
override fun finish(buffer: ByteArray, offset: Int, size: Int) {
finish(Unpooled.wrappedBuffer(buffer, offset, size))
}
override fun finish(buffer: ByteBuffer) {
if (buffer is NettyByteBuffer) {
finish(buffer.byteBuf)
} else {
super.finish(buffer)
}
}
fun finish(buf: ByteBuf) = finish(buf, HttpResponseStatus.valueOf(responseCode))
fun finish(buf: ByteBuf, responseCode: HttpResponseStatus) {
val response = DefaultFullHttpResponse(HttpVersion.HTTP_1_1, responseCode, buf)
finish(response)
}
fun finish(response: FullHttpResponse) {
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
)
)
ctx.writeAndFlush(response)
}
fun addHeaders(heads: HttpHeaders, defaultHeaders: Map<out CharSequence, Any>) {
responseListMap.forEach { (t, u) ->
u.forEach {
heads.add(t, it)
}
}
defaultHeaders.forEach { (t, u) ->
heads.set(t, u)
}
responseMap.forEach { (t, u) ->
heads.set(t, u)
}
}
override fun writeChunkedHeader() {
val response = DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
response.status = if (responseMessage != null) HttpResponseStatus(responseCode, responseMessage)
else HttpResponseStatus.valueOf(responseCode)
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"
)
)
ctx.write(response)
}
override fun addChunked(buffer: ByteBuffer) {
chunkedList.add(buffer)
}
override fun finishChunked() {
val httpChunkWriter = HttpChunkedInput(NettyChunkedByteBuffer(chunkedList))
ctx.writeAndFlush(httpChunkWriter)
}
override fun finishChunked(chunked: Chunked) {
val httpChunkWriter = HttpChunkedInput(NettyChunkedInput(chunked))
ctx.writeAndFlush(httpChunkWriter)
}
override fun finishFile(file: File, chunkSize: Int) {
writeChunkedHeader()
ctx.writeAndFlush(HttpChunkedInput(ChunkedFile(file, chunkSize)))
}
override fun finishFile(file: RandomAccessFile, offset: Long, length: Long, chunkSize: Int) {
writeChunkedHeader()
ctx.writeAndFlush(HttpChunkedInput(ChunkedFile(file, offset, length, chunkSize)))
}
override fun finishFile(file: RandomAccessFile, offset: Long, length: Long, chunkSize: Int) {
writeChunkedHeader()
ctx.writeAndFlush(HttpChunkedInput(ChunkedFile(file, offset, length, chunkSize)))
}
}

View File

@ -174,4 +174,26 @@ interface HttpContent {
)
fun setContextType(type: Any) = setResponseHeader("Content-Type", type)
fun jump(url: String) = temporaryMoved(url)
fun moved(url: String) = permanentlyMoved(url)
fun permanentlyMoved(url: String) {
setResponseHeader("Location", url)
finish(301)
}
fun temporaryMoved(url: String) {
noStore()
setResponseHeader("Location", url)
finish(302)
}
fun noCache() {
setResponseHeader("Cache-Control", "no-cache")
}
fun noStore() {
setResponseHeader("Cache-Control", "no-store")
}
}