WebSocket Server with SSL example app
This commit is contained in:
parent
2e3971953b
commit
3b0eb64f1c
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.jboss.netty.example.http.websocketx.sslserver;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.logging.ConsoleHandler;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jboss.netty.bootstrap.ServerBootstrap;
|
||||||
|
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A HTTP server which serves Web Socket requests at:
|
||||||
|
*
|
||||||
|
* https://localhost:8081/websocket
|
||||||
|
*
|
||||||
|
* Open your browser at https://localhost:8081/, then the demo page will be
|
||||||
|
* loaded and a Web Socket connection will be made automatically.
|
||||||
|
*
|
||||||
|
* This server illustrates support for the different web socket specification
|
||||||
|
* versions and will work with:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>Safari 5+ (draft-ietf-hybi-thewebsocketprotocol-00)
|
||||||
|
* <li>
|
||||||
|
* <li>Chrome 6-13 (draft-ietf-hybi-thewebsocketprotocol-00)
|
||||||
|
* <li>
|
||||||
|
* <li>Chrome 14+ (draft-ietf-hybi-thewebsocketprotocol-10)
|
||||||
|
* <li>
|
||||||
|
* <li>Firefox 7+ (draft-ietf-hybi-thewebsocketprotocol-10)
|
||||||
|
* <li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
|
||||||
|
* @author <a href="http://gleamynode.net/">Trustin Lee</a>
|
||||||
|
* @author <a href="http://www.veebsbraindump.com/">Vibul Imtarnasan</a>
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
|
public class WebSocketSslServer {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ConsoleHandler ch = new ConsoleHandler();
|
||||||
|
ch.setLevel(Level.FINE);
|
||||||
|
Logger.getLogger("").addHandler(ch);
|
||||||
|
Logger.getLogger("").setLevel(Level.FINE);
|
||||||
|
|
||||||
|
// Configure the server.
|
||||||
|
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
|
||||||
|
Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
|
||||||
|
|
||||||
|
// Set up the event pipeline factory.
|
||||||
|
bootstrap.setPipelineFactory(new WebSocketSslServerPipelineFactory());
|
||||||
|
|
||||||
|
// Bind and start to accept incoming connections.
|
||||||
|
bootstrap.bind(new InetSocketAddress(8081));
|
||||||
|
|
||||||
|
System.out.println("Web Socket Server started on 8081. Open your browser and navigate to https://localhost:8081/");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.jboss.netty.example.http.websocketx.sslserver;
|
||||||
|
|
||||||
|
import static org.jboss.netty.handler.codec.http.HttpHeaders.*;
|
||||||
|
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*;
|
||||||
|
import static org.jboss.netty.handler.codec.http.HttpMethod.*;
|
||||||
|
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
|
||||||
|
import static org.jboss.netty.handler.codec.http.HttpVersion.*;
|
||||||
|
|
||||||
|
import org.jboss.netty.buffer.ChannelBuffer;
|
||||||
|
import org.jboss.netty.buffer.ChannelBuffers;
|
||||||
|
import org.jboss.netty.channel.ChannelFuture;
|
||||||
|
import org.jboss.netty.channel.ChannelFutureListener;
|
||||||
|
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||||
|
import org.jboss.netty.channel.ExceptionEvent;
|
||||||
|
import org.jboss.netty.channel.MessageEvent;
|
||||||
|
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
|
||||||
|
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
|
||||||
|
import org.jboss.netty.handler.codec.http.HttpHeaders;
|
||||||
|
import org.jboss.netty.handler.codec.http.HttpRequest;
|
||||||
|
import org.jboss.netty.handler.codec.http.HttpResponse;
|
||||||
|
import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
|
||||||
|
import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame;
|
||||||
|
import org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame;
|
||||||
|
import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||||
|
import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame;
|
||||||
|
import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
|
||||||
|
import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
|
||||||
|
import org.jboss.netty.logging.InternalLogger;
|
||||||
|
import org.jboss.netty.logging.InternalLoggerFactory;
|
||||||
|
import org.jboss.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles handshakes and messages
|
||||||
|
*
|
||||||
|
* @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
|
||||||
|
* @author <a href="http://gleamynode.net/">Trustin Lee</a>
|
||||||
|
* @author <a href="http://www.veebsbraindump.com/">Vibul Imtarnasan</a>
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
|
public class WebSocketSslServerHandler extends SimpleChannelUpstreamHandler {
|
||||||
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketSslServerHandler.class);
|
||||||
|
|
||||||
|
private static final String WEBSOCKET_PATH = "/websocket";
|
||||||
|
|
||||||
|
private WebSocketServerHandshaker handshaker = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
|
||||||
|
Object msg = e.getMessage();
|
||||||
|
if (msg instanceof HttpRequest) {
|
||||||
|
handleHttpRequest(ctx, (HttpRequest) msg);
|
||||||
|
} else if (msg instanceof WebSocketFrame) {
|
||||||
|
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
|
||||||
|
// Allow only GET methods.
|
||||||
|
if (req.getMethod() != GET) {
|
||||||
|
sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the demo page and favicon.ico
|
||||||
|
if (req.getUri().equals("/")) {
|
||||||
|
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK);
|
||||||
|
|
||||||
|
ChannelBuffer content = WebSocketSslServerIndexPage.getContent(getWebSocketLocation(req));
|
||||||
|
|
||||||
|
res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||||
|
setContentLength(res, content.readableBytes());
|
||||||
|
|
||||||
|
res.setContent(content);
|
||||||
|
sendHttpResponse(ctx, req, res);
|
||||||
|
return;
|
||||||
|
} else if (req.getUri().equals("/favicon.ico")) {
|
||||||
|
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND);
|
||||||
|
sendHttpResponse(ctx, req, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handshake
|
||||||
|
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
|
||||||
|
this.getWebSocketLocation(req), null, false);
|
||||||
|
this.handshaker = wsFactory.newHandshaker(ctx, req);
|
||||||
|
if (this.handshaker == null) {
|
||||||
|
wsFactory.sendUnsupportedWebSocketVersionResponse(ctx);
|
||||||
|
} else {
|
||||||
|
this.handshaker.executeOpeningHandshake(ctx, req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
|
||||||
|
|
||||||
|
// Check for closing frame
|
||||||
|
if (frame instanceof CloseWebSocketFrame) {
|
||||||
|
this.handshaker.executeClosingHandshake(ctx, (CloseWebSocketFrame) frame);
|
||||||
|
return;
|
||||||
|
} else if (frame instanceof PingWebSocketFrame) {
|
||||||
|
ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData()));
|
||||||
|
return;
|
||||||
|
} else if (!(frame instanceof TextWebSocketFrame)) {
|
||||||
|
throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass()
|
||||||
|
.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the uppercase string back.
|
||||||
|
String request = ((TextWebSocketFrame) frame).getText();
|
||||||
|
logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request));
|
||||||
|
ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
|
||||||
|
// Generate an error page if response status code is not OK (200).
|
||||||
|
if (res.getStatus().getCode() != 200) {
|
||||||
|
res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8));
|
||||||
|
setContentLength(res, res.getContent().readableBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the response and close the connection if necessary.
|
||||||
|
ChannelFuture f = ctx.getChannel().write(res);
|
||||||
|
if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
|
||||||
|
f.addListener(ChannelFutureListener.CLOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
|
||||||
|
e.getCause().printStackTrace();
|
||||||
|
e.getChannel().close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getWebSocketLocation(HttpRequest req) {
|
||||||
|
return "wss://" + req.getHeader(HttpHeaders.Names.HOST) + WEBSOCKET_PATH;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.jboss.netty.example.http.websocketx.sslserver;
|
||||||
|
|
||||||
|
import org.jboss.netty.buffer.ChannelBuffer;
|
||||||
|
import org.jboss.netty.buffer.ChannelBuffers;
|
||||||
|
import org.jboss.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the demo HTML page which is served at http://localhost:8080/
|
||||||
|
*
|
||||||
|
* @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
|
||||||
|
* @author <a href="http://gleamynode.net/">Trustin Lee</a>
|
||||||
|
* @author <a href="http://www.veebsbraindump.com/">Vibul Imtarnasan</a>
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
|
public class WebSocketSslServerIndexPage {
|
||||||
|
|
||||||
|
private static final String NEWLINE = "\r\n";
|
||||||
|
|
||||||
|
public static ChannelBuffer getContent(String webSocketLocation) {
|
||||||
|
return ChannelBuffers.copiedBuffer(
|
||||||
|
"<html><head><title>Web Socket Test</title></head>" + NEWLINE +
|
||||||
|
"<body>" + NEWLINE +
|
||||||
|
"<script type=\"text/javascript\">" + NEWLINE +
|
||||||
|
"var socket;" + NEWLINE +
|
||||||
|
"if (!window.WebSocket) {" + NEWLINE +
|
||||||
|
" window.WebSocket = window.MozWebSocket;" + NEWLINE +
|
||||||
|
"}" + NEWLINE +
|
||||||
|
"if (window.WebSocket) {" + NEWLINE +
|
||||||
|
" socket = new WebSocket(\"" + webSocketLocation + "\");" + NEWLINE +
|
||||||
|
" socket.onmessage = function(event) { var ta = document.getElementById('responseText'); ta.value = ta.value + '\\n' + event.data };" + NEWLINE +
|
||||||
|
" socket.onopen = function(event) { var ta = document.getElementById('responseText'); ta.value = \"Web Socket opened!\"; };" + NEWLINE +
|
||||||
|
" socket.onclose = function(event) { var ta = document.getElementById('responseText'); ta.value = ta.value + \"Web Socket closed\"; };" + NEWLINE +
|
||||||
|
"} else {" + NEWLINE +
|
||||||
|
" alert(\"Your browser does not support Web Socket.\");" + NEWLINE +
|
||||||
|
"}" + NEWLINE +
|
||||||
|
"" + NEWLINE +
|
||||||
|
"function send(message) {" + NEWLINE +
|
||||||
|
" if (!window.WebSocket) { return; }" + NEWLINE +
|
||||||
|
" if (socket.readyState == WebSocket.OPEN) {" + NEWLINE +
|
||||||
|
" socket.send(message);" + NEWLINE +
|
||||||
|
" } else {" + NEWLINE +
|
||||||
|
" alert(\"The socket is not open.\");" + NEWLINE +
|
||||||
|
" }" + NEWLINE +
|
||||||
|
"}" + NEWLINE +
|
||||||
|
"</script>" + NEWLINE +
|
||||||
|
"<form onsubmit=\"return false;\">" + NEWLINE +
|
||||||
|
"<input type=\"text\" name=\"message\" value=\"Hello, World!\"/>" +
|
||||||
|
"<input type=\"button\" value=\"Send Web Socket Data\" onclick=\"send(this.form.message.value)\" />" + NEWLINE +
|
||||||
|
"<h3>Output</h3>" + NEWLINE +
|
||||||
|
"<textarea id=\"responseText\" style=\"width: 500px; height:300px;\"></textarea>" + NEWLINE +
|
||||||
|
"</form>" + NEWLINE +
|
||||||
|
"</body>" + NEWLINE +
|
||||||
|
"</html>" + NEWLINE,
|
||||||
|
CharsetUtil.US_ASCII);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.jboss.netty.example.http.websocketx.sslserver;
|
||||||
|
|
||||||
|
import static org.jboss.netty.channel.Channels.*;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLEngine;
|
||||||
|
|
||||||
|
import org.jboss.netty.channel.ChannelPipeline;
|
||||||
|
import org.jboss.netty.channel.ChannelPipelineFactory;
|
||||||
|
import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
|
||||||
|
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
|
||||||
|
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
|
||||||
|
import org.jboss.netty.handler.ssl.SslHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
|
||||||
|
* @author <a href="http://gleamynode.net/">Trustin Lee</a>
|
||||||
|
* @author <a href="http://www.veebsbraindump.com/">Vibul Imtarnasan</a>
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
|
public class WebSocketSslServerPipelineFactory implements ChannelPipelineFactory {
|
||||||
|
@Override
|
||||||
|
public ChannelPipeline getPipeline() throws Exception {
|
||||||
|
// Create a default pipeline implementation.
|
||||||
|
ChannelPipeline pipeline = pipeline();
|
||||||
|
|
||||||
|
SSLEngine engine = WebSocketSslServerSslContext.getInstance().getServerContext().createSSLEngine();
|
||||||
|
engine.setUseClientMode(false);
|
||||||
|
pipeline.addLast("ssl", new SslHandler(engine));
|
||||||
|
|
||||||
|
pipeline.addLast("decoder", new HttpRequestDecoder());
|
||||||
|
pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
|
||||||
|
pipeline.addLast("encoder", new HttpResponseEncoder());
|
||||||
|
pipeline.addLast("handler", new WebSocketSslServerHandler());
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.jboss.netty.example.http.websocketx.sslserver;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.Security;
|
||||||
|
|
||||||
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
|
import org.jboss.netty.logging.InternalLogger;
|
||||||
|
import org.jboss.netty.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link SSLContext} for just server certificates.
|
||||||
|
*
|
||||||
|
* @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
|
||||||
|
* @author <a href="http://gleamynode.net/">Trustin Lee</a>
|
||||||
|
* @author <a href="http://www.veebsbraindump.com/">Vibul Imtarnasan</a>
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
|
public class WebSocketSslServerSslContext {
|
||||||
|
|
||||||
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketSslServerSslContext.class);
|
||||||
|
private static final String PROTOCOL = "TLS";
|
||||||
|
private SSLContext _serverContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the singleton instance for this class
|
||||||
|
*/
|
||||||
|
public static WebSocketSslServerSslContext getInstance() {
|
||||||
|
return SingletonHolder.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SingletonHolder is loaded on the first execution of
|
||||||
|
* Singleton.getInstance() or the first access to SingletonHolder.INSTANCE,
|
||||||
|
* not before.
|
||||||
|
*
|
||||||
|
* See http://en.wikipedia.org/wiki/Singleton_pattern
|
||||||
|
*/
|
||||||
|
private static class SingletonHolder {
|
||||||
|
|
||||||
|
public static final WebSocketSslServerSslContext INSTANCE = new WebSocketSslServerSslContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for singleton
|
||||||
|
*/
|
||||||
|
private WebSocketSslServerSslContext() {
|
||||||
|
try {
|
||||||
|
// Key store (Server side certificate)
|
||||||
|
String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
|
||||||
|
if (algorithm == null) {
|
||||||
|
algorithm = "SunX509";
|
||||||
|
}
|
||||||
|
|
||||||
|
SSLContext serverContext = null;
|
||||||
|
try {
|
||||||
|
String keyStoreFilePath = System.getProperty("keystore.file.path");
|
||||||
|
String keyStoreFilePassword = System.getProperty("keystore.file.password");
|
||||||
|
|
||||||
|
KeyStore ks = KeyStore.getInstance("JKS");
|
||||||
|
FileInputStream fin = new FileInputStream(keyStoreFilePath);
|
||||||
|
ks.load(fin, keyStoreFilePassword.toCharArray());
|
||||||
|
|
||||||
|
// Set up key manager factory to use our key store
|
||||||
|
// Assume key password is the same as the key store file
|
||||||
|
// password
|
||||||
|
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
|
||||||
|
kmf.init(ks, keyStoreFilePassword.toCharArray());
|
||||||
|
|
||||||
|
// Initialise the SSLContext to work with our key managers.
|
||||||
|
serverContext = SSLContext.getInstance(PROTOCOL);
|
||||||
|
serverContext.init(kmf.getKeyManagers(), null, null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Error("Failed to initialize the server-side SSLContext", e);
|
||||||
|
}
|
||||||
|
_serverContext = serverContext;
|
||||||
|
|
||||||
|
return;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error("Error initializing SslContextManager. " + ex.getMessage(), ex);
|
||||||
|
System.exit(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the server context with server side key store
|
||||||
|
*/
|
||||||
|
public SSLContext getServerContext() {
|
||||||
|
return _serverContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>This package contains an example web socket web server with server SSL.
|
||||||
|
* <p>To run this example, follow the steps below:
|
||||||
|
* <dl>
|
||||||
|
* <dt>Step 1. Generate Your Key</dt>
|
||||||
|
* <dd>
|
||||||
|
* <code>keytool -genkey -keystore mySrvKeystore -keyalg RSA</code>.
|
||||||
|
* Make sure that you set the key password to be the same the key file password.
|
||||||
|
* </dd>
|
||||||
|
* <dt>Step 2. Specify your key store file and password as system properties</dt>
|
||||||
|
* <dd>
|
||||||
|
* <code>-Dkeystore.file.path=<path to mySrvKeystore> -Dkeystore.file.password=<password></code>
|
||||||
|
* </dd>
|
||||||
|
* <dt>Step 3. Run WebSocketSslServer as a Java application</dt>
|
||||||
|
* <dd>
|
||||||
|
* Once started, you can test the web server against your browser by navigating to https://localhost:8081/
|
||||||
|
* </dd>
|
||||||
|
* </dl>
|
||||||
|
* <p>To find out more about setting up key stores, refer to this
|
||||||
|
* <a href="http://download.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html">giude</a>.
|
||||||
|
*/
|
||||||
|
package org.jboss.netty.example.http.websocketx.sslserver;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user