diff --git a/game/src/main/kotlin/org/openrs2/game/net/crossdomain/CrossDomainChannelHandler.kt b/game/src/main/kotlin/org/openrs2/game/net/crossdomain/CrossDomainChannelHandler.kt index f8b47ddf..ecc137c4 100644 --- a/game/src/main/kotlin/org/openrs2/game/net/crossdomain/CrossDomainChannelHandler.kt +++ b/game/src/main/kotlin/org/openrs2/game/net/crossdomain/CrossDomainChannelHandler.kt @@ -1,14 +1,13 @@ package org.openrs2.game.net.crossdomain import io.netty.buffer.Unpooled -import io.netty.channel.ChannelFutureListener import io.netty.channel.ChannelHandler import io.netty.channel.ChannelHandlerContext import io.netty.channel.SimpleChannelInboundHandler -import io.netty.handler.codec.http.HttpHeaderNames import io.netty.handler.codec.http.HttpMethod import io.netty.handler.codec.http.HttpRequest import io.netty.handler.codec.http.HttpResponseStatus +import org.openrs2.buffer.use import org.openrs2.game.net.http.Http @ChannelHandler.Sharable @@ -29,15 +28,13 @@ public object CrossDomainChannelHandler : SimpleChannelInboundHandler + Http.writeResponse(ctx, msg, buf, Http.TEXT_X_CROSS_DOMAIN_POLICY) + } } override fun channelReadComplete(ctx: ChannelHandlerContext) { diff --git a/game/src/main/kotlin/org/openrs2/game/net/http/Http.kt b/game/src/main/kotlin/org/openrs2/game/net/http/Http.kt index 9b836bcd..5c2828c3 100644 --- a/game/src/main/kotlin/org/openrs2/game/net/http/Http.kt +++ b/game/src/main/kotlin/org/openrs2/game/net/http/Http.kt @@ -1,20 +1,91 @@ package org.openrs2.game.net.http +import io.netty.buffer.ByteBuf +import io.netty.channel.ChannelFutureListener +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.FileRegion import io.netty.handler.codec.http.DefaultHttpResponse import io.netty.handler.codec.http.HttpHeaderNames import io.netty.handler.codec.http.HttpHeaderValues -import io.netty.handler.codec.http.HttpResponse +import io.netty.handler.codec.http.HttpMethod +import io.netty.handler.codec.http.HttpRequest import io.netty.handler.codec.http.HttpResponseStatus import io.netty.handler.codec.http.HttpVersion +import io.netty.util.ReferenceCounted +import org.openrs2.buffer.copiedBuffer +import org.openrs2.buffer.use public object Http { public const val MAX_CONTENT_LENGTH: Int = 65536 public const val TEXT_X_CROSS_DOMAIN_POLICY: String = "text/x-cross-domain-policy" + private const val BANNER = "OpenRS2" - public fun createResponse(status: HttpResponseStatus): HttpResponse { - val response = DefaultHttpResponse(HttpVersion.HTTP_1_1, status) + private fun writeResponse( + ctx: ChannelHandlerContext, + request: HttpRequest, + status: HttpResponseStatus, + content: ReferenceCounted, + contentType: CharSequence, + contentLength: Long + ) { + val version = if (request.protocolVersion() == HttpVersion.HTTP_1_0) { + HttpVersion.HTTP_1_0 + } else { + HttpVersion.HTTP_1_1 + } + + val response = DefaultHttpResponse(version, status) response.headers().add(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE) - response.headers().add(HttpHeaderNames.SERVER, "OpenRS2") - return response + response.headers().add(HttpHeaderNames.SERVER, BANNER) + response.headers().add(HttpHeaderNames.CONTENT_TYPE, contentType) + response.headers().add(HttpHeaderNames.CONTENT_LENGTH, contentLength) + + if (request.method() == HttpMethod.HEAD) { + ctx.write(response).addListener(ChannelFutureListener.CLOSE) + } else { + ctx.write(response, ctx.voidPromise()) + ctx.write(content.retain()).addListener(ChannelFutureListener.CLOSE) + } + } + + public fun writeResponse( + ctx: ChannelHandlerContext, + request: HttpRequest, + content: ByteBuf, + contentType: CharSequence + ) { + writeResponse(ctx, request, HttpResponseStatus.OK, content, contentType, content.readableBytes().toLong()) + } + + public fun writeResponse( + ctx: ChannelHandlerContext, + request: HttpRequest, + content: FileRegion, + contentType: CharSequence + ) { + writeResponse(ctx, request, HttpResponseStatus.OK, content, contentType, content.count()) + } + + public fun writeResponse(ctx: ChannelHandlerContext, request: HttpRequest, status: HttpResponseStatus) { + copiedBuffer( + """ + + + + + $status + + +
+

$status

+
+
+
$BANNER
+ + + """.trimIndent().plus("\n"), Charsets.UTF_8 + ).use { buf -> + writeResponse(ctx, request, status, buf, HttpHeaderValues.TEXT_HTML, buf.readableBytes().toLong()) + } } } diff --git a/game/src/main/kotlin/org/openrs2/game/net/http/HttpChannelHandler.kt b/game/src/main/kotlin/org/openrs2/game/net/http/HttpChannelHandler.kt index 63116b82..ab6eff8a 100644 --- a/game/src/main/kotlin/org/openrs2/game/net/http/HttpChannelHandler.kt +++ b/game/src/main/kotlin/org/openrs2/game/net/http/HttpChannelHandler.kt @@ -1,13 +1,12 @@ package org.openrs2.game.net.http -import io.netty.channel.ChannelFutureListener import io.netty.channel.ChannelHandler import io.netty.channel.ChannelHandlerContext import io.netty.channel.SimpleChannelInboundHandler -import io.netty.handler.codec.http.HttpHeaderNames import io.netty.handler.codec.http.HttpHeaderValues import io.netty.handler.codec.http.HttpRequest import io.netty.handler.codec.http.HttpResponseStatus +import org.openrs2.buffer.use import org.openrs2.game.net.FileProvider import javax.inject.Inject import javax.inject.Singleton @@ -24,22 +23,18 @@ public class HttpChannelHandler @Inject constructor( override fun channelRead0(ctx: ChannelHandlerContext, msg: HttpRequest) { val uri = msg.uri() if (!uri.startsWith("/")) { - ctx.write(Http.createResponse(HttpResponseStatus.BAD_REQUEST)).addListener(ChannelFutureListener.CLOSE) + Http.writeResponse(ctx, msg, HttpResponseStatus.BAD_REQUEST) return } - val file = fileProvider.get(uri.substring(1)) - if (file == null) { - ctx.write(Http.createResponse(HttpResponseStatus.NOT_FOUND)).addListener(ChannelFutureListener.CLOSE) - return - } + fileProvider.get(uri.substring(1)).use { file -> + if (file == null) { + Http.writeResponse(ctx, msg, HttpResponseStatus.NOT_FOUND) + return + } - val response = Http.createResponse(HttpResponseStatus.OK) - response.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_OCTET_STREAM) - response.headers().add(HttpHeaderNames.CONTENT_LENGTH, file.count()) - - ctx.write(response, ctx.voidPromise()) - ctx.write(file).addListener(ChannelFutureListener.CLOSE) + Http.writeResponse(ctx, msg, file, HttpHeaderValues.APPLICATION_OCTET_STREAM) + } } override fun channelReadComplete(ctx: ChannelHandlerContext) {