From 47c07d94ad3d60e3740cea60d3fedd846d983ddc Mon Sep 17 00:00:00 2001 From: Looly Date: Wed, 25 Oct 2023 00:21:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DSimpleServer=E5=9C=A8?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=9A=84HttpFilter=E4=B8=AD=E6=9C=89?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E8=AF=B7=E6=B1=82=E5=8F=82=E6=95=B0=E6=97=B6?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/server/HttpExchangeWrapper.java | 158 ++++++++++++++++++ .../hutool/http/server/SimpleServer.java | 3 +- .../http/server/handler/ActionHandler.java | 17 +- .../hutool/http/server/Issue3343Test.java | 46 +++++ 4 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 hutool-http/src/main/java/org/dromara/hutool/http/server/HttpExchangeWrapper.java create mode 100644 hutool-http/src/test/java/org/dromara/hutool/http/server/Issue3343Test.java diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/HttpExchangeWrapper.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/HttpExchangeWrapper.java new file mode 100644 index 000000000..1d5960044 --- /dev/null +++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/HttpExchangeWrapper.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2023. looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * https://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.http.server; + +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpPrincipal; +import org.dromara.hutool.core.func.Wrapper; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.URI; + +/** + * {@link HttpExchange}包装类,提供增强方法和缓存 + * + * @author looly + */ +public class HttpExchangeWrapper extends HttpExchange implements Wrapper { + + private final HttpExchange raw; + private final HttpServerRequest request; + private final HttpServerResponse response; + + /** + * 构造 + * + * @param raw {@link HttpExchange} + */ + public HttpExchangeWrapper(final HttpExchange raw) { + this.raw = raw; + this.request = new HttpServerRequest(this); + this.response = new HttpServerResponse(this); + } + + @Override + public HttpExchange getRaw() { + return this.raw; + } + + /** + * 获取请求 + * + * @return 请求 + */ + public HttpServerRequest getRequest() { + return request; + } + + /** + * 获取响应 + * + * @return 响应 + */ + public HttpServerResponse getResponse() { + return response; + } + + // region ----- HttpExchange methods + @Override + public Headers getRequestHeaders() { + return this.raw.getRequestHeaders(); + } + + @Override + public Headers getResponseHeaders() { + return this.raw.getResponseHeaders(); + } + + @Override + public URI getRequestURI() { + return this.raw.getRequestURI(); + } + + @Override + public String getRequestMethod() { + return this.raw.getRequestMethod(); + } + + @Override + public HttpContext getHttpContext() { + return this.raw.getHttpContext(); + } + + @Override + public void close() { + this.raw.close(); + } + + @Override + public InputStream getRequestBody() { + return this.raw.getRequestBody(); + } + + @Override + public OutputStream getResponseBody() { + return this.raw.getResponseBody(); + } + + @Override + public void sendResponseHeaders(final int rCode, final long responseLength) throws IOException { + this.raw.sendResponseHeaders(rCode, responseLength); + } + + @Override + public InetSocketAddress getRemoteAddress() { + return this.raw.getRemoteAddress(); + } + + @Override + public int getResponseCode() { + return this.raw.getResponseCode(); + } + + @Override + public InetSocketAddress getLocalAddress() { + return this.raw.getLocalAddress(); + } + + @Override + public String getProtocol() { + return this.raw.getProtocol(); + } + + @Override + public Object getAttribute(final String name) { + return this.raw.getAttribute(name); + } + + @Override + public void setAttribute(final String name, final Object value) { + this.raw.setAttribute(name, value); + } + + @Override + public void setStreams(final InputStream i, final OutputStream o) { + this.raw.setStreams(i, o); + } + + @Override + public HttpPrincipal getPrincipal() { + return this.raw.getPrincipal(); + } + // endregion +} diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/SimpleServer.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/SimpleServer.java index 019788b42..b55e8353c 100644 --- a/hutool-http/src/main/java/org/dromara/hutool/http/server/SimpleServer.java +++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/SimpleServer.java @@ -132,7 +132,8 @@ public class SimpleServer { return addFilter(new SimpleFilter() { @Override public void doFilter(final HttpExchange httpExchange, final Chain chain) throws IOException { - filter.doFilter(new HttpServerRequest(httpExchange), new HttpServerResponse(httpExchange), chain); + final HttpExchangeWrapper httpExchangeWrapper = new HttpExchangeWrapper(httpExchange); + filter.doFilter(httpExchangeWrapper.getRequest(), httpExchangeWrapper.getResponse(), chain); } }); } diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/handler/ActionHandler.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/handler/ActionHandler.java index 62a291e2e..d9ab30d13 100644 --- a/hutool-http/src/main/java/org/dromara/hutool/http/server/handler/ActionHandler.java +++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/handler/ActionHandler.java @@ -12,6 +12,7 @@ package org.dromara.hutool.http.server.handler; +import org.dromara.hutool.http.server.HttpExchangeWrapper; import org.dromara.hutool.http.server.HttpServerRequest; import org.dromara.hutool.http.server.HttpServerResponse; import org.dromara.hutool.http.server.action.Action; @@ -41,10 +42,18 @@ public class ActionHandler implements HttpHandler { @Override public void handle(final HttpExchange httpExchange) throws IOException { - action.doAction( - new HttpServerRequest(httpExchange), - new HttpServerResponse(httpExchange) - ); + final HttpServerRequest request; + final HttpServerResponse response; + if (httpExchange instanceof HttpExchangeWrapper) { + // issue#3343 当使用Filter时,可能读取了请求参数,此时使用共享的req和res,可复用缓存 + final HttpExchangeWrapper wrapper = (HttpExchangeWrapper) httpExchange; + request = wrapper.getRequest(); + response = wrapper.getResponse(); + } else { + request = new HttpServerRequest(httpExchange); + response = new HttpServerResponse(httpExchange); + } + action.doAction(request, response); httpExchange.close(); } } diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/server/Issue3343Test.java b/hutool-http/src/test/java/org/dromara/hutool/http/server/Issue3343Test.java new file mode 100644 index 000000000..12233bc3f --- /dev/null +++ b/hutool-http/src/test/java/org/dromara/hutool/http/server/Issue3343Test.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023. looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * https://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.http.server; + +import org.dromara.hutool.core.date.DateUtil; +import org.dromara.hutool.core.lang.Console; +import org.dromara.hutool.core.map.multi.ListValueMap; +import org.dromara.hutool.http.HttpUtil; + +/** + * http://localhost:8888/?name=hutool + */ +public class Issue3343Test { + + public static void main(final String[] args) { + final SimpleServer server = HttpUtil.createServer(8888) + .addFilter((req, res, chain)->{ + Console.log(DateUtil.now() + " got request: " + req.getPath()); + Console.log(" > from : " + req.getClientIP()); + // 过滤器中获取请求参数 + Console.log(" > params : " + req.getParams()); + chain.doFilter(req.getHttpExchange()); + }); + + server.addAction("/", Issue3343Test::index); + + server.start(); + } + + private static void index(HttpServerRequest request, HttpServerResponse response) { + // 具体逻辑中再次获取请求参数 + ListValueMap params = request.getParams(); + Console.log("index params: " + params); + response.getWriter().write("GOT: " + params); + } +}