添加对Http Multipart的支持

This commit is contained in:
tursom 2020-05-20 00:23:45 +08:00
parent 8675eccd33
commit 7685ca42f5
11 changed files with 48 additions and 18 deletions

View File

@ -33,7 +33,7 @@ open class NettyHttpContent(
}
uri
}
override val clientIp get() = ctx.channel().remoteAddress()!!
override val remoteAddress get() = ctx.channel().remoteAddress()!!
override val realIp: String = super.realIp
val httpMethod: HttpMethod get() = request.method()
val protocolVersion: HttpVersion get() = request.protocolVersion()
@ -71,6 +71,8 @@ open class NettyHttpContent(
}
}
override fun peekBody(): ByteBuffer? = bodyList.peek()?.content()?.let { NettyByteBuffer(it.slice()) }
override fun waitBody(action: (end: Boolean) -> Unit) {
if (!requestSendFully) {
waitBodyHandler.add(action)

View File

@ -19,7 +19,7 @@ class NettyHttpHandler(
override fun channelRead0(ctx: ChannelHandlerContext, msg: FullHttpRequest) {
val handlerContext = NettyHttpContent(ctx, msg)
log?.debug("{} {} {}", handlerContext.clientIp, handlerContext.method, handlerContext.uri)
log?.debug("{} {} {}", handlerContext.remoteAddress, handlerContext.method, handlerContext.uri)
handler.handle(handlerContext)
}

View File

@ -27,7 +27,7 @@ class NettyHttpServer(
var bodySize: Int = 512 * 1024,
autoRun: Boolean = false,
var webSocketPath: Iterable<Pair<String, WebSocketHandler<NettyWebSocketContent>>> = listOf(),
var readTimeout: Int? = null,
var readTimeout: Int? = 60,
var writeTimeout: Int? = null,
decodeType: NettyHttpDecodeType = NettyHttpDecodeType.MULTI_PART,
backlog: Int = 1024
@ -37,7 +37,7 @@ class NettyHttpServer(
bodySize: Int = 512 * 1024,
autoRun: Boolean = false,
webSocketPath: Iterable<Pair<String, WebSocketHandler<NettyWebSocketContent>>> = listOf(),
readTimeout: Int? = null,
readTimeout: Int? = 60,
writeTimeout: Int? = null,
decodeType: NettyHttpDecodeType = NettyHttpDecodeType.MULTI_PART,
handler: (content: NettyHttpContent) -> Unit
@ -49,7 +49,6 @@ class NettyHttpServer(
bodySize, autoRun, webSocketPath, readTimeout, writeTimeout, decodeType
)
var decodeType: NettyHttpDecodeType = decodeType
set(value) {
if (value != field) {

View File

@ -8,10 +8,12 @@ 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 java.net.SocketAddress
class NettyWebSocketContent(
private val channel: Channel
val channel: Channel
) : WebSocketContent {
override val remoteAddress: SocketAddress get() = channel.remoteAddress()
override fun writeText(buffer: ByteBuffer) {
if (buffer is NettyByteBuffer) {
channel.writeAndFlush(TextWebSocketFrame(buffer.byteBuf))

View File

@ -15,13 +15,14 @@ interface HttpContent : ResponseHeaderAdapter, RequestHeaderAdapter {
var responseCode: Int
var responseMessage: String?
val body: ByteBuffer?
val clientIp: SocketAddress
val remoteAddress: SocketAddress
val method: String
val realIp
get() = getHeader("X-Forwarded-For") ?: clientIp.toString().let { str ->
get() = getHeader("X-Forwarded-For") ?: remoteAddress.toString().let { str ->
str.substring(1, str.indexOf(':').let { if (it < 1) str.length else it - 1 })
}
fun peekBody(): ByteBuffer?
fun waitBody(action: (end: Boolean) -> Unit = { addBodyParam() })
fun addBodyParam(body: ByteBuffer)
fun addBodyParam() {

View File

@ -2,9 +2,11 @@ package cn.tursom.web
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
import java.net.SocketAddress
import java.nio.charset.Charset
interface WebSocketContent {
val remoteAddress: SocketAddress
fun writeText(buffer: ByteBuffer)
fun writeText(bytes: ByteArray) = writeText(HeapByteBuffer(bytes))
fun writeText(str: String, charset: Charset = Charsets.UTF_8) = writeText(str.toByteArray(charset))

View File

@ -1,7 +1,6 @@
package cn.tursom.web.router
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.cast
import cn.tursom.core.lambda
import cn.tursom.core.regex.regex
import cn.tursom.json.JsonWorkerImpl
@ -282,13 +281,13 @@ open class RoutedHttpHandler(
fun autoReturn(method: Method, result: Any?, content: HttpContent, doLog: Boolean? = null) {
method.getAnnotation(ContextType::class.java)?.let {
content.setContextType(it.type.value)
log?.debug("{}: autoReturn context type auto set to {}({})", content.clientIp, it.type.key, it.type.value)
log?.debug("{}: autoReturn context type auto set to {}({})", content.remoteAddress, it.type.key, it.type.value)
}
autoReturn(result, content, doLog ?: method.doLog)
}
fun autoReturn(result: Any?, content: HttpContent, doLog: Boolean = true) {
if (doLog) log?.debug("{}: autoReturn: {}", content.clientIp, result)
if (doLog) log?.debug("{}: autoReturn: {}", content.remoteAddress, result)
result ?: return
when (result) {
null -> content.finish(404)
@ -310,7 +309,7 @@ open class RoutedHttpHandler(
}
fun finishHtml(result: Any?, content: HttpContent, doLog: Boolean = true) {
if (doLog) log?.debug("{} finishHtml {}", content.clientIp, result)
if (doLog) log?.debug("{} finishHtml {}", content.remoteAddress, result)
result ?: return
when (result) {
null -> content.finish(404)
@ -328,7 +327,7 @@ open class RoutedHttpHandler(
}
fun finishText(result: Any?, content: HttpContent, doLog: Boolean = true) {
if (doLog) log?.debug("{} finishText {}", content.clientIp, result)
if (doLog) log?.debug("{} finishText {}", content.remoteAddress, result)
result ?: return
when (result) {
null -> content.finish(404)
@ -346,7 +345,7 @@ open class RoutedHttpHandler(
}
fun finishJson(result: Any?, content: HttpContent, doLog: Boolean = true) {
if (doLog) log?.debug("{} finishJson {}", content.clientIp, result)
if (doLog) log?.debug("{} finishJson {}", content.remoteAddress, result)
result ?: return
when (result) {
null -> content.finish(404)
@ -362,7 +361,7 @@ open class RoutedHttpHandler(
}
else -> {
val json = json?.toJson(result)
if (doLog) log?.debug("{} finishJson: generate json {}", content.clientIp, json)
if (doLog) log?.debug("{} finishJson: generate json {}", content.remoteAddress, json)
if (json != null) {
content.finishJson(json.toByteArray())
} else {

View File

@ -14,7 +14,7 @@ class EmptyHttpContent(
override var responseCode: Int = 200,
override var responseMessage: String? = null,
override val body: ByteBuffer? = null,
override val clientIp: SocketAddress = InetSocketAddress(0),
override val remoteAddress: SocketAddress = InetSocketAddress(0),
override val method: String = "GET",
override val cookieMap: Map<String, String> = mapOf(),
override val requestSendFully: Boolean
@ -46,5 +46,6 @@ class EmptyHttpContent(
override fun finishFile(file: RandomAccessFile, offset: Long, length: Long, chunkSize: Int) {}
override fun addBodyParam(body: ByteBuffer) {}
override fun waitBody(action: (end: Boolean) -> Unit) {}
override fun peekBody(): ByteBuffer? = null
}

View File

@ -2,6 +2,6 @@ dependencies {
implementation project(":web")
api project(":json")
api group: 'org.slf4j', name: 'slf4j-api', version: '1.7.29'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlinVersion
}

View File

@ -0,0 +1,24 @@
package cn.tursom.web
import cn.tursom.core.buffer.ByteBuffer
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
suspend fun HttpContent.getBody(): ByteBuffer {
suspendCoroutine<Boolean> { cont ->
waitBody {
cont.resume(it)
}
}
return body!!
}
suspend fun HttpContent.waitBodyParam(): HttpContent {
suspendCoroutine<Boolean> { cont ->
waitBody {
addBodyParam()
cont.resume(it)
}
}
return this
}

View File

@ -223,7 +223,7 @@ open class AsyncRoutedHttpHandler(
fun autoReturn(method: KCallable<*>, result: Any?, content: HttpContent, doLog: Boolean? = null) {
method.findAnnotation<ContextType>()?.let {
content.setContextType(it.type.value)
log?.debug("{}: autoReturn context type auto set to {}({})", content.clientIp, it.type.key, it.type.value)
log?.debug("{}: autoReturn context type auto set to {}({})", content.remoteAddress, it.type.key, it.type.value)
}
autoReturn(result, content, doLog ?: method.doLog)
}