gpt4 book ai didi

rest - 嵌入式 Jetty : In secure https server, ContextHandler 重定向到 http URI

转载 作者:太空宇宙 更新时间:2023-11-03 12:52:00 27 4
gpt4 key购买 nike

我正在使用嵌入式 Jetty 构建沙盒 RESTful API。我的概念验证设计:一个简单的嵌入式 jetty 服务器,它 (1) 接受 SSL 端口上的连接,并且 (2) 使用 ContextHandlerCollection 根据 URI 前缀调用适当的处理程序。

我最初的测试,使用一个简单的非 SSL 连接,似乎工作完美(注意,附录中的导入代码和帮助程序 HelloHandler 类)。

public static void main(String[] args) throws Exception {
Server server = new Server(12000);

ContextHandler test1Context = new ContextHandler();
test1Context.setContextPath("/test1");
test1Context.setHandler(new HelloHandler("Hello1"));

ContextHandler test2Context = new ContextHandler();
test2Context.setContextPath("/test2");
test2Context.setHandler(new HelloHandler("Hello2"));

ContextHandlerCollection contextHandlers = new ContextHandlerCollection();
contextHandlers.setHandlers(new Handler[] { test1Context, test2Context });

server.setHandler(contextHandlers);
server.start();
server.join();
}

然而,在测试这个时,我没有注意到当我省略尾部正斜杠时浏览器重定向正在发生,所以 http://localhost:12000/test1被重定向到 http://localhost:12000/test1/ . (FWIW,该站点稍后会转化为 4 个多小时的故障排除)。

当我切换到 HTTPS SSL 连接时,一切都出错了。代码如下:

public static void main(String[] args) throws Exception {
Server server = new Server();

// Setups
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("C:/keystore.jks");
sslContextFactory.setKeyStorePassword("password");
sslContextFactory.setKeyManagerPassword("password");

ContextHandler test1Context = new ContextHandler();
test1Context.setContextPath("/test1");
test1Context.setHandler(new HelloHandler("Hello1"));

ContextHandler test2Context = new ContextHandler();
test2Context.setContextPath("/test2");
test2Context.setHandler(new HelloHandler("Hello2"));

ContextHandlerCollection contextHandlers = new ContextHandlerCollection();
contextHandlers.setHandlers(new Handler[] { test1Context, test2Context });

ServerConnector serverConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, "http/1.1"),
new HttpConnectionFactory());

serverConnector.setPort(12000);
server.setConnectors(new Connector[] { serverConnector });
server.setHandler(contextHandlers);

server.start();
server.join();
}

症状:

正在尝试使用 https://localhost:12000/test1 (没有尾部斜杠)会导致浏览器报告服务器已重置连接。此外,我最初没有发现的是,URI 被重定向到 http://localhost:12000/test1/ (不是 https!)。有趣的是(以一种虐待狂的幽默感),有几次,我会更改代码中一些无关紧要的东西,然后无意中用 https://localhost:12000/test1/ 进行测试。它会起作用的。此类误报造成的挫败感无法用语言来表达。

除了浏览器重定向和报告连接重置错误外,我的服务器日志中还会出现以下异常:

2013-11-23 13:57:48 DEBUG org.eclipse.jetty.server.HttpConnection:282 - 
org.eclipse.jetty.io.EofException
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:653)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:240)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.run(AbstractConnection.java:358)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:601)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:532)
at java.lang.Thread.run(Thread.java:722)
Caused by: javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
at sun.security.ssl.EngineInputRecord.bytesInCompletePacket(EngineInputRecord.java:171)
at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:845)
at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:758)
at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:518)
... 5 more

不幸的是,当关键线索在浏览器重定向的 URL 中时,我将所有时间都花在了尝试直接解决此异常上。事实证明,ContextHandler 代码有一个默认行为,当不存在尾随正斜杠时,它会导致它仅重定向到具有尾随斜杠的 URI。不幸的是,这个重定向是到一个 HTTP URI - 所以 HTTPS 方案被丢弃,这导致服务器提示纯文本。

解决方法:

一旦我清楚了这种重定向行为,通过 Google 快速搜索那个实际问题,我找到了 ContextHandler.setAllowNullPathInfo(true) 方法 - 它关闭了这种重定向行为。在我上面的代码中,这是用两行代码完成的:

test1Context.setAllowNullPathInfo(true);
test2Context.setAllowNullPathInfo(true);

这篇文章的要点:

我花了 3 到 4 个小时尝试解决“javax.net.ssl.SSLException:无法识别的 SSL 消息,纯文本连接?”异常,我在网络上的任何地方都没有找到与上述解决方案/解决方法相关的异常。如果我能从我所经历的挫败感中拯救一位其他开发人员,那么任务就完成了。

挥之不去的问题(发布此问题的其他原因):好的,所以我让这段代码工作了,但不得不承认:我非常不安的事实是,我非常简单的概念验证测试,做了一些我认为很常见的事情,遇到了这种似乎完全前所未有的情况.这告诉我,我可能正在做超出“最佳实践”范围的事情;或者,更糟的是,我在设计它时做了一些完全错误的事情。所以,问题:

1) 我做错了吗?

2) 为什么 ContextHandler 的默认行为是重定向缺少尾随空格的 URI?使用 setAllowNullPathInfo(true) 覆盖该默认行为会招致哪些风险?

附录(辅助类和导入代码)进口: 导入 java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.util.ssl.SslContextFactory;

辅助类:

static class HelloHandler extends AbstractHandler {
final String _greeting;

public HelloHandler(String greeting) {
_greeting = greeting;
}

public void handle(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
baseRequest.setHandled(true);
response.getWriter().println("<h1>" + _greeting + "</h1>");
}
}

最佳答案

您缺少 HttpConfiguration 设置。

这里...

package jetty.examples;

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.util.ssl.SslContextFactory;

public class SecureContexts
{
public static void main(String[] args) throws Exception
{
Server server = new Server();
int port = 12000;

// Setup SSL
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath(System.getProperty("jetty.keystore.path","C:/keystore.jks"));
sslContextFactory.setKeyStorePassword(System.getProperty("jetty.keystore.password","password"));
sslContextFactory.setKeyManagerPassword(System.getProperty("jetty.keymanager.password","password"));

// Setup HTTP Configuration
HttpConfiguration httpConf = new HttpConfiguration();
httpConf.setSecurePort(port);
httpConf.setSecureScheme("https");
httpConf.addCustomizer(new SecureRequestCustomizer());

ContextHandler test1Context = new ContextHandler();
test1Context.setContextPath("/test1");
test1Context.setHandler(new HelloHandler("Hello1"));

ContextHandler test2Context = new ContextHandler();
test2Context.setContextPath("/test2");
test2Context.setHandler(new HelloHandler("Hello2"));

ContextHandlerCollection contextHandlers = new ContextHandlerCollection();
contextHandlers.setHandlers(new Handler[]
{ test1Context, test2Context });

ServerConnector serverConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,"http/1.1"),
new HttpConnectionFactory(httpConf)); // <-- use it!
serverConnector.setPort(port);

server.setConnectors(new Connector[]
{ serverConnector });
server.setHandler(contextHandlers);

server.start();
server.join();
}
}

关于rest - 嵌入式 Jetty : In secure https server, ContextHandler 重定向到 http URI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20175924/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com