Jetty BadMessage 嵌入式 WebSocket Servlet
Jetty BadMessage Embedded WebSocket Servlet
我使用 jetty 9.2.5 创建了一个简单的嵌入式 WebSocket 服务器。使用不安全的连接时,服务器可以完美运行。当我添加 SSL 连接器时,客户端无法使用 https 方案进行连接,"wss" vs "ws",并且我看到一条 badMessage 警告:
31710 [qtp6566818-16] WARN org.eclipse.jetty.http.HttpParser - badMessage: 400 Illegal character 0x16 in state=START in '\x16<<<\x03\x01\x00\xAb\x01\x00\x00\xA7\x03\x037%\x03d\xFf\xBd\xE8...\x01\x05\x01\x02\x01\x04\x03\x05\x03\x02\x03\x04\x02\x02\x02>>>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' for HttpChannelOverHttp@f59306{r=0,c=false,a=IDLE,uri=-}
当我将 URI 恢复为不安全的 WebSocket 方案时,客户端没有问题:
40559 [qtp6566818-17] INFO com.datafascia.emerge.websocketEchoService.EchoService - Connected ...
40562 [qtp6566818-17] INFO com.datafascia.emerge.websocketEchoService.EchoService - Session: WebSocketSession[websocket=JettyAnnotatedEventDriver[com.datafascia.emerge.websocketEchoService.EchoService@18c45017],behavior=SERVER,connection=WebSocketServerConnection@77882dcc{IDLE}{f=Flusher[queueSize=0,aggregateSize=0,failure=null],g=Generator[SERVER,validating],p=Parser@61ed4bc3[ExtensionStack,s=START,c=0,len=0,f=null,p=WebSocketPolicy@379e5d9e[behavior=SERVER,maxTextMessageSize=65536,maxTextMessageBufferSize=32768,maxBinaryMessageSize=65536,maxBinaryMessageBufferSize=32768,asyncWriteTimeout=60000,idleTimeout=300000,inputBufferSize=4096]]},remote=WebSocketRemoteEndpoint@2e93a9a8[batching=true],incoming=JettyAnnotatedEventDriver[com.datafascia.emerge.websocketEchoService.EchoService@18c45017],outgoing=ExtensionStack[queueSize=0,extensions=[],incoming=org.eclipse.jetty.websocket.common.WebSocketSession,outgoing=org.eclipse.jetty.websocket.server.WebSocketServerConnection]]
40571 [qtp6566818-16] INFO com.datafascia.emerge.websocketEchoService.EchoService - incomingMessage= 05501140317063844 123CYC EMERGE-123C015083
40578 [qtp6566818-17] INFO com.datafascia.emerge.websocketEchoService.EchoService - Connection closed with statusCode: 1005, reason: null
服务器代码大部分取自我在码头站点和 Internet 上遇到的示例。下面是设置 WebSocket servlet 的代码:
// Setup the websocket server
Server server = new Server(websocketPort);
if (wssEnabled) {
// Add http/s connectors
//connector = new ServerConnector(server);
//connector.setPort(websocketPort);
// HTTP Configuration
HttpConfiguration http_config = new HttpConfiguration();
http_config.setSecureScheme("https");
http_config.setSecurePort(8443);
http_config.setOutputBufferSize(32768);
http_config.setRequestHeaderSize(8192);
http_config.setResponseHeaderSize(8192);
http_config.setSendServerVersion(true);
http_config.setSendDateHeader(false);
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("/home/jedwards/keystore");
logger.info("keystore path: {}", sslContextFactory.getKeyStorePath());
sslContextFactory.setKeyStorePassword("1deadparrot");
sslContextFactory.setKeyManagerPassword("1deadparrot");
sslContextFactory.setExcludeCipherSuites(
"SSL_RSA_WITH_DES_CBC_SHA","SSL_DHE_RSA_WITH_DES_CBC_SHA","SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5","SSL_RSA_EXPORT_WITH_DES40_CBC_SHA","SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
// SSL HTTP Configuration
HttpConfiguration https_config = new HttpConfiguration(http_config);
https_config.addCustomizer(new SecureRequestCustomizer());
// SSL Connector
connector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
connector.setPort(8443);
connector.setIdleTimeout(500000);
} else {
// Basic HTTP connector
connector = new ServerConnector(server);
connector.setPort(websocketPort);
}
ServletContextHandler ctx = new ServletContextHandler();
ctx.setContextPath("/");
ctx.addServlet(EmergeEchoServiceSocketServlet.class, websocketServicePoint);
server.setHandler(ctx);
server.addConnector(connector);
// Start the websocket server
server.start();
logger.info("server status: {}", server.dump());
server.join();
我使用推荐的命令创建了一个自签名证书和密钥对:
keytool -keystore keystore -alias jetty -genkey -keyalg RSA
此时我不知所措,因为我相信我已经正确设置了嵌入式 WebSocket servlet。所以我认为这是显而易见的事情,但我就是想不出问题所在。
我稍微简化了代码并且能够让 SSL WebSockets 服务器正常工作。我仍在使用自签名证书,因此它只是本地的。我可以使用 IP 地址但不能使用 "localhost" 例如"wss://192.168.2.115:8443/servicePoint".
这是新代码:
// Setup the websocket server
Server server = new Server();
if (wssEnabled) {
// HTTP Configuration
HttpConfiguration https_config = new HttpConfiguration();
https_config.setSecureScheme("https");
https_config.setSecurePort(8443);
https_config.setSendServerVersion(true);
https_config.setSendDateHeader(false);
https_config.addCustomizer(new SecureRequestCustomizer());
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("/pathTo//keystore");
sslContextFactory.setTrustStorePath("/pathTo/keystore");
logger.info("keystore path: {}", sslContextFactory.getKeyStorePath());
sslContextFactory.setKeyStorePassword("myPassword");
sslContextFactory.setKeyManagerPassword("myPassword");
sslContextFactory.setTrustStorePassword("myPassword");
sslContextFactory.setExcludeCipherSuites(
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
// SSL Connector
connector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
connector.setPort(8443);
} else {
// Basic HTTP connector
connector = new ServerConnector(server);
connector.setPort(websocketPort);
}
ServletContextHandler ctx = new ServletContextHandler();
ctx.setContextPath("/");
ctx.addServlet(EmergeEchoServiceSocketServlet.class, "/dF" + websocketServicePoint);
server.setHandler(ctx);
server.addConnector(connector);
// Start the websocket server
server.start();
logger.info("server status: {}", server.dump());
server.join();
}
我使用 jetty 9.2.5 创建了一个简单的嵌入式 WebSocket 服务器。使用不安全的连接时,服务器可以完美运行。当我添加 SSL 连接器时,客户端无法使用 https 方案进行连接,"wss" vs "ws",并且我看到一条 badMessage 警告:
31710 [qtp6566818-16] WARN org.eclipse.jetty.http.HttpParser - badMessage: 400 Illegal character 0x16 in state=START in '\x16<<<\x03\x01\x00\xAb\x01\x00\x00\xA7\x03\x037%\x03d\xFf\xBd\xE8...\x01\x05\x01\x02\x01\x04\x03\x05\x03\x02\x03\x04\x02\x02\x02>>>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' for HttpChannelOverHttp@f59306{r=0,c=false,a=IDLE,uri=-}
当我将 URI 恢复为不安全的 WebSocket 方案时,客户端没有问题:
40559 [qtp6566818-17] INFO com.datafascia.emerge.websocketEchoService.EchoService - Connected ...
40562 [qtp6566818-17] INFO com.datafascia.emerge.websocketEchoService.EchoService - Session: WebSocketSession[websocket=JettyAnnotatedEventDriver[com.datafascia.emerge.websocketEchoService.EchoService@18c45017],behavior=SERVER,connection=WebSocketServerConnection@77882dcc{IDLE}{f=Flusher[queueSize=0,aggregateSize=0,failure=null],g=Generator[SERVER,validating],p=Parser@61ed4bc3[ExtensionStack,s=START,c=0,len=0,f=null,p=WebSocketPolicy@379e5d9e[behavior=SERVER,maxTextMessageSize=65536,maxTextMessageBufferSize=32768,maxBinaryMessageSize=65536,maxBinaryMessageBufferSize=32768,asyncWriteTimeout=60000,idleTimeout=300000,inputBufferSize=4096]]},remote=WebSocketRemoteEndpoint@2e93a9a8[batching=true],incoming=JettyAnnotatedEventDriver[com.datafascia.emerge.websocketEchoService.EchoService@18c45017],outgoing=ExtensionStack[queueSize=0,extensions=[],incoming=org.eclipse.jetty.websocket.common.WebSocketSession,outgoing=org.eclipse.jetty.websocket.server.WebSocketServerConnection]]
40571 [qtp6566818-16] INFO com.datafascia.emerge.websocketEchoService.EchoService - incomingMessage= 05501140317063844 123CYC EMERGE-123C015083
40578 [qtp6566818-17] INFO com.datafascia.emerge.websocketEchoService.EchoService - Connection closed with statusCode: 1005, reason: null
服务器代码大部分取自我在码头站点和 Internet 上遇到的示例。下面是设置 WebSocket servlet 的代码:
// Setup the websocket server
Server server = new Server(websocketPort);
if (wssEnabled) {
// Add http/s connectors
//connector = new ServerConnector(server);
//connector.setPort(websocketPort);
// HTTP Configuration
HttpConfiguration http_config = new HttpConfiguration();
http_config.setSecureScheme("https");
http_config.setSecurePort(8443);
http_config.setOutputBufferSize(32768);
http_config.setRequestHeaderSize(8192);
http_config.setResponseHeaderSize(8192);
http_config.setSendServerVersion(true);
http_config.setSendDateHeader(false);
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("/home/jedwards/keystore");
logger.info("keystore path: {}", sslContextFactory.getKeyStorePath());
sslContextFactory.setKeyStorePassword("1deadparrot");
sslContextFactory.setKeyManagerPassword("1deadparrot");
sslContextFactory.setExcludeCipherSuites(
"SSL_RSA_WITH_DES_CBC_SHA","SSL_DHE_RSA_WITH_DES_CBC_SHA","SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5","SSL_RSA_EXPORT_WITH_DES40_CBC_SHA","SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
// SSL HTTP Configuration
HttpConfiguration https_config = new HttpConfiguration(http_config);
https_config.addCustomizer(new SecureRequestCustomizer());
// SSL Connector
connector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
connector.setPort(8443);
connector.setIdleTimeout(500000);
} else {
// Basic HTTP connector
connector = new ServerConnector(server);
connector.setPort(websocketPort);
}
ServletContextHandler ctx = new ServletContextHandler();
ctx.setContextPath("/");
ctx.addServlet(EmergeEchoServiceSocketServlet.class, websocketServicePoint);
server.setHandler(ctx);
server.addConnector(connector);
// Start the websocket server
server.start();
logger.info("server status: {}", server.dump());
server.join();
我使用推荐的命令创建了一个自签名证书和密钥对:
keytool -keystore keystore -alias jetty -genkey -keyalg RSA
此时我不知所措,因为我相信我已经正确设置了嵌入式 WebSocket servlet。所以我认为这是显而易见的事情,但我就是想不出问题所在。
我稍微简化了代码并且能够让 SSL WebSockets 服务器正常工作。我仍在使用自签名证书,因此它只是本地的。我可以使用 IP 地址但不能使用 "localhost" 例如"wss://192.168.2.115:8443/servicePoint".
这是新代码:
// Setup the websocket server
Server server = new Server();
if (wssEnabled) {
// HTTP Configuration
HttpConfiguration https_config = new HttpConfiguration();
https_config.setSecureScheme("https");
https_config.setSecurePort(8443);
https_config.setSendServerVersion(true);
https_config.setSendDateHeader(false);
https_config.addCustomizer(new SecureRequestCustomizer());
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("/pathTo//keystore");
sslContextFactory.setTrustStorePath("/pathTo/keystore");
logger.info("keystore path: {}", sslContextFactory.getKeyStorePath());
sslContextFactory.setKeyStorePassword("myPassword");
sslContextFactory.setKeyManagerPassword("myPassword");
sslContextFactory.setTrustStorePassword("myPassword");
sslContextFactory.setExcludeCipherSuites(
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
// SSL Connector
connector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
connector.setPort(8443);
} else {
// Basic HTTP connector
connector = new ServerConnector(server);
connector.setPort(websocketPort);
}
ServletContextHandler ctx = new ServletContextHandler();
ctx.setContextPath("/");
ctx.addServlet(EmergeEchoServiceSocketServlet.class, "/dF" + websocketServicePoint);
server.setHandler(ctx);
server.addConnector(connector);
// Start the websocket server
server.start();
logger.info("server status: {}", server.dump());
server.join();
}