diff --git a/web/src/main/kotlin/cn/tursom/web/HttpContent.kt b/web/src/main/kotlin/cn/tursom/web/HttpContent.kt index 7d7d60a..c1c02ac 100644 --- a/web/src/main/kotlin/cn/tursom/web/HttpContent.kt +++ b/web/src/main/kotlin/cn/tursom/web/HttpContent.kt @@ -119,8 +119,6 @@ interface HttpContent : ResponseHeaderAdapter, RequestHeaderAdapter { chunkSize: Int = 8192 ) - fun setContextType(type: Any) = setResponseHeader("Content-Type", type) - fun jump(url: String) = temporaryMoved(url) fun moved(url: String) = permanentlyMoved(url) diff --git a/web/src/main/kotlin/cn/tursom/web/ResponseHeaderAdapter.kt b/web/src/main/kotlin/cn/tursom/web/ResponseHeaderAdapter.kt index f22b68b..250f7ac 100644 --- a/web/src/main/kotlin/cn/tursom/web/ResponseHeaderAdapter.kt +++ b/web/src/main/kotlin/cn/tursom/web/ResponseHeaderAdapter.kt @@ -1,6 +1,7 @@ package cn.tursom.web import cn.tursom.web.utils.CacheControl +import cn.tursom.web.utils.ContextTypeMap import cn.tursom.web.utils.Cookie import cn.tursom.web.utils.SameSite @@ -53,7 +54,11 @@ interface ResponseHeaderAdapter { fun range(start: Int, end: Int, resourceSize: Int) = setResponseHeader("Content-Range", "$start-$end/$resourceSize") fun range(resourceSize: Int) = setResponseHeader("Content-Range", "*/$resourceSize") + fun setContextType(type: Any) = setResponseHeader("Content-Type", type) + fun responseHtml() = setResponseHeader("content-type", "text/html; charset=UTF-8") fun responseText() = setResponseHeader("content-type", "text/plain; charset=UTF-8") fun responseJson() = setResponseHeader("content-type", "application/json; charset=UTF-8") + + fun autoContextType(type: String) = setContextType(ContextTypeMap[type] ?: "application/octet-stream") } \ No newline at end of file diff --git a/web/src/main/kotlin/cn/tursom/web/router/mapping/ConnectMapping.kt b/web/src/main/kotlin/cn/tursom/web/mapping/ConnectMapping.kt similarity index 62% rename from web/src/main/kotlin/cn/tursom/web/router/mapping/ConnectMapping.kt rename to web/src/main/kotlin/cn/tursom/web/mapping/ConnectMapping.kt index 3153c15..0bace78 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/mapping/ConnectMapping.kt +++ b/web/src/main/kotlin/cn/tursom/web/mapping/ConnectMapping.kt @@ -1,4 +1,4 @@ -package cn.tursom.web.router.mapping +package cn.tursom.web.mapping annotation class ConnectMapping( vararg val route: String diff --git a/web/src/main/kotlin/cn/tursom/web/router/mapping/DeleteMapping.kt b/web/src/main/kotlin/cn/tursom/web/mapping/DeleteMapping.kt similarity index 62% rename from web/src/main/kotlin/cn/tursom/web/router/mapping/DeleteMapping.kt rename to web/src/main/kotlin/cn/tursom/web/mapping/DeleteMapping.kt index e53447d..44b2695 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/mapping/DeleteMapping.kt +++ b/web/src/main/kotlin/cn/tursom/web/mapping/DeleteMapping.kt @@ -1,4 +1,4 @@ -package cn.tursom.web.router.mapping +package cn.tursom.web.mapping annotation class DeleteMapping( vararg val route: String diff --git a/web/src/main/kotlin/cn/tursom/web/router/mapping/GetMapping.kt b/web/src/main/kotlin/cn/tursom/web/mapping/GetMapping.kt similarity index 61% rename from web/src/main/kotlin/cn/tursom/web/router/mapping/GetMapping.kt rename to web/src/main/kotlin/cn/tursom/web/mapping/GetMapping.kt index 6d33d3e..a75c2be 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/mapping/GetMapping.kt +++ b/web/src/main/kotlin/cn/tursom/web/mapping/GetMapping.kt @@ -1,4 +1,4 @@ -package cn.tursom.web.router.mapping +package cn.tursom.web.mapping annotation class GetMapping( vararg val route: String diff --git a/web/src/main/kotlin/cn/tursom/web/router/mapping/HeadMapping.kt b/web/src/main/kotlin/cn/tursom/web/mapping/HeadMapping.kt similarity index 61% rename from web/src/main/kotlin/cn/tursom/web/router/mapping/HeadMapping.kt rename to web/src/main/kotlin/cn/tursom/web/mapping/HeadMapping.kt index 553a461..6ce01c2 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/mapping/HeadMapping.kt +++ b/web/src/main/kotlin/cn/tursom/web/mapping/HeadMapping.kt @@ -1,4 +1,4 @@ -package cn.tursom.web.router.mapping +package cn.tursom.web.mapping annotation class HeadMapping( vararg val route: String diff --git a/web/src/main/kotlin/cn/tursom/web/router/mapping/Mapping.kt b/web/src/main/kotlin/cn/tursom/web/mapping/Mapping.kt similarity index 68% rename from web/src/main/kotlin/cn/tursom/web/router/mapping/Mapping.kt rename to web/src/main/kotlin/cn/tursom/web/mapping/Mapping.kt index ed062e4..d70711f 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/mapping/Mapping.kt +++ b/web/src/main/kotlin/cn/tursom/web/mapping/Mapping.kt @@ -1,4 +1,4 @@ -package cn.tursom.web.router.mapping +package cn.tursom.web.mapping annotation class Mapping( vararg val route: String, diff --git a/web/src/main/kotlin/cn/tursom/web/router/mapping/OptionsMapping.kt b/web/src/main/kotlin/cn/tursom/web/mapping/OptionsMapping.kt similarity index 62% rename from web/src/main/kotlin/cn/tursom/web/router/mapping/OptionsMapping.kt rename to web/src/main/kotlin/cn/tursom/web/mapping/OptionsMapping.kt index e343b00..1c33822 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/mapping/OptionsMapping.kt +++ b/web/src/main/kotlin/cn/tursom/web/mapping/OptionsMapping.kt @@ -1,4 +1,4 @@ -package cn.tursom.web.router.mapping +package cn.tursom.web.mapping annotation class OptionsMapping( vararg val route: String diff --git a/web/src/main/kotlin/cn/tursom/web/router/mapping/PatchMapping.kt b/web/src/main/kotlin/cn/tursom/web/mapping/PatchMapping.kt similarity index 61% rename from web/src/main/kotlin/cn/tursom/web/router/mapping/PatchMapping.kt rename to web/src/main/kotlin/cn/tursom/web/mapping/PatchMapping.kt index 22d8066..61285e2 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/mapping/PatchMapping.kt +++ b/web/src/main/kotlin/cn/tursom/web/mapping/PatchMapping.kt @@ -1,4 +1,4 @@ -package cn.tursom.web.router.mapping +package cn.tursom.web.mapping annotation class PatchMapping( vararg val route: String diff --git a/web/src/main/kotlin/cn/tursom/web/router/mapping/PostMapping.kt b/web/src/main/kotlin/cn/tursom/web/mapping/PostMapping.kt similarity index 61% rename from web/src/main/kotlin/cn/tursom/web/router/mapping/PostMapping.kt rename to web/src/main/kotlin/cn/tursom/web/mapping/PostMapping.kt index b5f22be..906cf67 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/mapping/PostMapping.kt +++ b/web/src/main/kotlin/cn/tursom/web/mapping/PostMapping.kt @@ -1,4 +1,4 @@ -package cn.tursom.web.router.mapping +package cn.tursom.web.mapping annotation class PostMapping( vararg val route: String diff --git a/web/src/main/kotlin/cn/tursom/web/router/mapping/PutMapping.kt b/web/src/main/kotlin/cn/tursom/web/mapping/PutMapping.kt similarity index 61% rename from web/src/main/kotlin/cn/tursom/web/router/mapping/PutMapping.kt rename to web/src/main/kotlin/cn/tursom/web/mapping/PutMapping.kt index f6e1622..2cfa1b2 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/mapping/PutMapping.kt +++ b/web/src/main/kotlin/cn/tursom/web/mapping/PutMapping.kt @@ -1,4 +1,4 @@ -package cn.tursom.web.router.mapping +package cn.tursom.web.mapping annotation class PutMapping( vararg val route: String diff --git a/web/src/main/kotlin/cn/tursom/web/router/mapping/TraceMapping.kt b/web/src/main/kotlin/cn/tursom/web/mapping/TraceMapping.kt similarity index 61% rename from web/src/main/kotlin/cn/tursom/web/router/mapping/TraceMapping.kt rename to web/src/main/kotlin/cn/tursom/web/mapping/TraceMapping.kt index 0bbe973..f891b1e 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/mapping/TraceMapping.kt +++ b/web/src/main/kotlin/cn/tursom/web/mapping/TraceMapping.kt @@ -1,4 +1,4 @@ -package cn.tursom.web.router.mapping +package cn.tursom.web.mapping annotation class TraceMapping( vararg val route: String diff --git a/web/src/main/kotlin/cn/tursom/web/result/Html.kt b/web/src/main/kotlin/cn/tursom/web/result/Html.kt new file mode 100644 index 0000000..4645d96 --- /dev/null +++ b/web/src/main/kotlin/cn/tursom/web/result/Html.kt @@ -0,0 +1,3 @@ +package cn.tursom.web.result + +annotation class Html \ No newline at end of file diff --git a/web/src/main/kotlin/cn/tursom/web/result/Json.kt b/web/src/main/kotlin/cn/tursom/web/result/Json.kt new file mode 100644 index 0000000..8316d39 --- /dev/null +++ b/web/src/main/kotlin/cn/tursom/web/result/Json.kt @@ -0,0 +1,3 @@ +package cn.tursom.web.result + +annotation class Json \ No newline at end of file diff --git a/web/src/main/kotlin/cn/tursom/web/result/Text.kt b/web/src/main/kotlin/cn/tursom/web/result/Text.kt new file mode 100644 index 0000000..eaa40c7 --- /dev/null +++ b/web/src/main/kotlin/cn/tursom/web/result/Text.kt @@ -0,0 +1,3 @@ +package cn.tursom.web.result + +annotation class Text \ No newline at end of file diff --git a/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt b/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt index f1e52e3..ed5ecfb 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt +++ b/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt @@ -1,11 +1,15 @@ package cn.tursom.web.router +import cn.tursom.core.buffer.ByteBuffer import cn.tursom.json.JsonWorkerImpl import cn.tursom.web.ExceptionContent import cn.tursom.web.HttpContent import cn.tursom.web.HttpHandler import cn.tursom.web.router.impl.SimpleRouter -import cn.tursom.web.router.mapping.* +import cn.tursom.web.mapping.* +import cn.tursom.web.result.Html +import cn.tursom.web.result.Json +import cn.tursom.web.result.Text import cn.tursom.web.utils.Chunked import org.slf4j.LoggerFactory import java.io.File @@ -50,10 +54,9 @@ open class RoutedHttpHandler( @Suppress("LeakingThis") val clazz = handler.javaClass clazz.methods.forEach { method -> + log?.debug("try mapping {}", method) method.parameterTypes.let { - if (it.size != 1 || !HttpContent::class.java.isAssignableFrom(it[0])) { - return@forEach - } else if (it.isNotEmpty()) { + if (!(it.size == 1 && HttpContent::class.java.isAssignableFrom(it[0])) && it.isNotEmpty()) { return@forEach } } @@ -128,15 +131,11 @@ open class RoutedHttpHandler( router[safeRoute(route)] = handler@{ content -> if (method.parameterTypes.isEmpty()) { val result = method(obj) ?: return@handler - when (result) { - is String -> content.finishHtml(result.toByteArray()) - is ByteArray -> content.finishText(result) - is File -> content.finishFile(result) - is RandomAccessFile -> content.finishFile(result) - is Chunked -> content.finishChunked(result) - else -> json?.let { - content.finishJson(json.toJson(result)!!.toByteArray()) - } ?: content.finishText(result.toString().toByteArray()) + when { + method.getAnnotation(Html::class.java) != null -> finishHtml(result, content) + method.getAnnotation(Text::class.java) != null -> finishText(result, content) + method.getAnnotation(Json::class.java) != null -> finishJson(result, content) + else -> autoReturn(result, content) } } else { method(obj, content) @@ -173,5 +172,48 @@ open class RoutedHttpHandler( } private fun safeRoute(route: String) = if (route.first() == '/') route else "/$route" + + private fun autoReturn(result: Any, content: HttpContent) = when (result) { + is String -> content.finishText(result.toByteArray()) + is ByteArray -> content.finishText(result) + is File -> { + content.autoContextType(result.name) + content.finishFile(result) + } + is RandomAccessFile -> content.finishFile(result) + is Chunked -> content.finishChunked(result) + else -> finishJson(result, content) + } + + private fun finishHtml(result: Any, content: HttpContent) = when (result) { + is ByteBuffer -> content.finishHtml(result) + is ByteArray -> content.finishHtml(result) + is String -> content.finishHtml(result.toByteArray()) + else -> content.finishHtml(result.toString().toByteArray()) + } + + private fun finishText(result: Any, content: HttpContent) = when (result) { + is ByteBuffer -> content.finishText(result) + is ByteArray -> content.finishText(result) + is String -> content.finishText(result.toByteArray()) + else -> content.finishText(result.toString().toByteArray()) + } + + private fun finishJson(result: Any, content: HttpContent) { + when (result) { + is ByteBuffer -> content.finishJson(result) + is ByteArray -> content.finishJson(result) + is String -> content.finishJson("\"$result\"".toByteArray()) + is Byte, Short, Int, Long, Float, Double, Boolean -> content.finishJson(result.toString().toByteArray()) + else -> { + val json = json?.toJson(result)?.toByteArray() + if (json != null) { + content.finishJson(json) + } else { + content.finishText(result.toString().toByteArray()) + } + } + } + } } } diff --git a/web/src/main/kotlin/cn/tursom/web/utils/ContextTypeMap.kt b/web/src/main/kotlin/cn/tursom/web/utils/ContextTypeMap.kt new file mode 100644 index 0000000..d2e2ef7 --- /dev/null +++ b/web/src/main/kotlin/cn/tursom/web/utils/ContextTypeMap.kt @@ -0,0 +1,83 @@ +package cn.tursom.web.utils + +import cn.tursom.core.datastruct.StringRadixTree + +object ContextTypeMap { + private val router = StringRadixTree() + operator fun get(type: String) = router[type.substringAfterLast('.')] + + init { + router["aac"] = "audio/aac" + router["abw"] = "application/x-abiword" + router["arc"] = "application/x-freearc" + router["avi"] = "video/x-msvideo" + router["azw"] = "aapplication/vnd.amazon.ebook" + router["bin"] = "application/octet-stream" + router["bmp"] = "image/bmp" + router["bz"] = "application/x-bzip" + router["bz2"] = "application/x-bzip2" + router["csh"] = "application/x-csh" + router["css"] = "itext/css; charset=UTF-8" + router["csv"] = "itext/csv; charset=UTF-8" + router["doc"] = "application/msword" + router["docx"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + router["eot"] = "application/vnd.ms-fontobject" + router["epub"] = "application/epub+zip" + router["gif"] = "image/gif" + router["html"] = "text/html; charset=UTF-8" + router["htm"] = "text/html; charset=UTF-8" + router["ico"] = "image/vnd.microsoft.icon" + router["ics"] = "text/calendar; charset=UTF-8" + router["jar"] = "application/java-archive" + router["jpeg"] = "image/jpeg" + router["jpg"] = "image/jpeg" + router["js"] = "text/javascript; charset=UTF-8" + router["json"] = "application/json; charset=UTF-8" + router["jsonld"] = "application/ld+json" + router["mid"] = "audio/midi" + router["midi"] = "audio/midi" + router["mjs"] = "text/javascript" + router["mp3"] = "audio/mpeg" + router["mp4"] = "audio/mp4" + router["mpeg"] = "video/mpeg" + router["mpkg"] = "application/vnd.apple.installer+xml" + router["odp"] = "application/vnd.oasis.opendocument.presentation" + router["ods"] = "application/vnd.oasis.opendocument.spreadsheet" + router["odt"] = "application/vnd.oasis.opendocument.text" + router["oga"] = "audio/ogg" + router["ogg"] = "application/ogg" + router["ogv"] = "video/ogg" + router["ogx"] = "application/ogg" + router["otf"] = "font/otf" + router["png"] = "image/png" + router["pdf"] = "application/pdf" + router["ppt"] = "application/vnd.ms-powerpoint" + router["pptx"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation" + router["rar"] = "application/x-rar-compressed" + router["rtf"] = "application/rtf" + router["sh"] = "application/x-sh" + router["svg"] = "image/svg+xml" + router["swf"] = "application/x-shockwave-flash" + router["tar"] = "application/x-tar" + router["tif"] = "image/tiff" + router["tiff"] = "image/tiff" + router["ttf"] = "font/ttf" + router["txt"] = "text/plain; charset=UTF-8" + router["vsd"] = "application/vnd.visio" + router["wav"] = "audio/wav" + router["weba"] = "audio/webm" + router["webm"] = "video/webm" + router["webp"] = "image/webp" + router["woff"] = "font/woff" + router["woff2"] = "font/woff2" + router["xhtml"] = "application/xhtml+xml" + router["xls"] = "application/vnd.ms-excel" + router["xlsx"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + router["xml"] = "text/xml; charset=UTF-8" + router["xul"] = "application/vnd.mozilla.xul+xml" + router["zip"] = "application/zip" + router["3gp"] = "video/3gpp" + router["3g2"] = "ivideo/3gpp2" + router["7z"] = "application/x-7z-compressed" + } +} \ No newline at end of file