use of javax.websocket.CloseReason in project atmosphere by Atmosphere.
the class JSR356Endpoint method onOpen.
@Override
public void onOpen(Session session, final EndpointConfig endpointConfig) {
if (framework.isDestroyed())
return;
if (!session.isOpen()) {
logger.trace("Session Closed {}", session);
return;
}
if (maxBinaryBufferSize != -1)
session.setMaxBinaryMessageBufferSize(maxBinaryBufferSize);
if (webSocketWriteTimeout != -1)
session.setMaxIdleTimeout(webSocketWriteTimeout);
if (maxTextBufferSize != -1)
session.setMaxTextMessageBufferSize(maxTextBufferSize);
webSocket = new JSR356WebSocket(session, framework.getAtmosphereConfig());
Map<String, String> headers = new HashMap<String, String>();
// TODO: We don't support multi map header, which cause => https://github.com/Atmosphere/atmosphere/issues/1945
for (Map.Entry<String, List<String>> e : handshakeRequest.getHeaders().entrySet()) {
headers.put(e.getKey(), !e.getValue().isEmpty() ? e.getValue().get(0) : "");
}
// Force WebSocket. Hack for https://github.com/Atmosphere/atmosphere/issues/1944
headers.put("Connection", "Upgrade");
String servletPath = framework.getAtmosphereConfig().getInitParameter(ApplicationConfig.JSR356_MAPPING_PATH);
if (servletPath == null) {
servletPath = IOUtils.guestServletPath(framework.getAtmosphereConfig());
}
boolean recomputeForBackwardCompat = false;
URI uri = session.getRequestURI();
String rawPath = uri.getPath();
String contextPath = framework.getAtmosphereConfig().getServletContext().getContextPath();
int pathInfoStartAt = rawPath.indexOf(servletPath) + servletPath.length();
String pathInfo = null;
if (rawPath.length() >= pathInfoStartAt) {
pathInfo = rawPath.substring(pathInfoStartAt);
} else {
recomputeForBackwardCompat = true;
}
if (recomputeForBackwardCompat) {
// DON"T SCREAM this code is for broken/backward compatible
String[] paths = uri.getPath() != null ? uri.getPath().split("/") : new String[] {};
int pathInfoStartIndex = 3;
if ("".equals(contextPath) || "".equals(servletPath)) {
pathInfoStartIndex = 2;
}
///contextPath / servletPath / pathInfo or / servletPath / pathInfo
StringBuilder b = new StringBuilder("/");
for (int i = 0; i < paths.length; i++) {
if (i >= pathInfoStartIndex) {
b.append(paths[i]).append("/");
}
}
if (b.length() > 1) {
b.deleteCharAt(b.length() - 1);
}
pathInfo = b.toString();
}
if (pathInfo.equals("/")) {
pathInfo = null;
}
try {
String requestURL = uri.toASCIIString();
if (requestURL.contains("?")) {
requestURL = requestURL.substring(0, requestURL.indexOf("?"));
}
// https://java.net/jira/browse/WEBSOCKET_SPEC-228
if ((!requestURL.startsWith("http://")) || (!requestURL.startsWith("https://"))) {
if (requestURL.startsWith("/")) {
List<String> l = handshakeRequest.getHeaders().get("origin");
if (l == null) {
// https://issues.jboss.org/browse/UNDERTOW-252
l = handshakeRequest.getHeaders().get("Origin");
}
String origin;
if (l != null && !l.isEmpty()) {
origin = l.get(0);
} else {
// Broken WebSocket Spec
logger.trace("Unable to retrieve the `origin` header for websocket {}", session);
origin = "http" + (session.isSecure() ? "s" : "") + "://0.0.0.0:80";
}
requestURL = origin + requestURL;
} else if (requestURL.startsWith("ws://")) {
requestURL = requestURL.replace("ws://", "http://");
} else if (requestURL.startsWith("wss://")) {
requestURL = requestURL.replace("wss://", "https://");
}
}
List<String> cookieHeaders = handshakeRequest.getHeaders().get("Cookie");
Set<Cookie> cookies = null;
if (cookieHeaders != null) {
cookies = new HashSet<Cookie>();
for (String cookieHeader : cookieHeaders) cookies.addAll(CookieUtil.ServerCookieDecoder.STRICT.decode(cookieHeader));
}
request = new AtmosphereRequestImpl.Builder().requestURI(uri.getPath()).requestURL(requestURL).headers(headers).cookies(cookies).session((HttpSession) handshakeRequest.getHttpSession()).servletPath(servletPath).contextPath(framework.getServletContext().getContextPath()).pathInfo(pathInfo).destroyable(false).userPrincipal(session.getUserPrincipal()).remoteInetSocketAddress(new Callable<InetSocketAddress>() {
@Override
public InetSocketAddress call() throws Exception {
return (InetSocketAddress) endpointConfig.getUserProperties().get(JAVAX_WEBSOCKET_ENDPOINT_REMOTE_ADDRESS);
}
}).localInetSocketAddress(new Callable<InetSocketAddress>() {
@Override
public InetSocketAddress call() throws Exception {
return (InetSocketAddress) endpointConfig.getUserProperties().get(JAVAX_WEBSOCKET_ENDPOINT_LOCAL_ADDRESS);
}
}).build().queryString(session.getQueryString());
if (!webSocketProcessor.handshake(request)) {
try {
session.close(new CloseReason(CloseReason.CloseCodes.CANNOT_ACCEPT, "Handshake not accepted."));
} catch (IOException e) {
logger.trace("", e);
}
return;
}
// TODO: Fix this crazy code.
framework.addInitParameter(ALLOW_QUERYSTRING_AS_REQUEST, "false");
webSocketProcessor.open(webSocket, request, AtmosphereResponseImpl.newInstance(framework.getAtmosphereConfig(), request, webSocket));
framework.addInitParameter(ALLOW_QUERYSTRING_AS_REQUEST, "true");
if (session.isOpen()) {
session.addMessageHandler(new MessageHandler.Whole<String>() {
@Override
public void onMessage(String s) {
webSocketProcessor.invokeWebSocketProtocol(webSocket, s);
}
});
session.addMessageHandler(new MessageHandler.Whole<ByteBuffer>() {
@Override
public void onMessage(ByteBuffer bb) {
byte[] b = bb.hasArray() ? bb.array() : new byte[bb.limit()];
bb.get(b);
webSocketProcessor.invokeWebSocketProtocol(webSocket, b, 0, b.length);
}
});
} else {
logger.trace("Session closed during onOpen {}", session);
onClose(session, new CloseReason(CloseReason.CloseCodes.GOING_AWAY, "Session closed already"));
}
} catch (Throwable e) {
if (session.isOpen()) {
logger.error("", e);
} else {
logger.trace("Session closed during onOpen", e);
}
try {
session.close(new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, e.getMessage()));
} catch (IOException e1) {
logger.trace("", e);
}
return;
}
}
use of javax.websocket.CloseReason in project undertow by undertow-io.
the class UndertowSession method closeInternal.
public void closeInternal(CloseReason closeReason) throws IOException {
if (closed.compareAndSet(false, true)) {
try {
try {
if (!webSocketChannel.isCloseFrameReceived() && !webSocketChannel.isCloseFrameSent()) {
//will deal with sending back the reason message
if (closeReason == null || closeReason.getCloseCode().getCode() == CloseReason.CloseCodes.NO_STATUS_CODE.getCode()) {
webSocketChannel.sendClose();
} else {
WebSockets.sendClose(new CloseMessage(closeReason.getCloseCode().getCode(), closeReason.getReasonPhrase()).toByteBuffer(), webSocketChannel, null);
}
}
} finally {
try {
String reason = null;
CloseReason.CloseCode code = CloseReason.CloseCodes.NO_STATUS_CODE;
if (webSocketChannel.getCloseCode() != -1) {
reason = webSocketChannel.getCloseReason();
code = CloseReason.CloseCodes.getCloseCode(webSocketChannel.getCloseCode());
} else if (closeReason != null) {
reason = closeReason.getReasonPhrase();
code = closeReason.getCloseCode();
}
//we need to really clean up the close behaviour in the next spec
if (!webSocketChannel.isCloseInitiatedByRemotePeer() && !localClose && code.getCode() != CloseReason.CloseCodes.TOO_BIG.getCode()) {
//2.1.5: we must use 1006 if the close was initiated locally
//however we only do this for normal closure
//if the close was due to another reason such as a message being too long we need to report the real reason
code = CloseReason.CloseCodes.CLOSED_ABNORMALLY;
}
endpoint.getInstance().onClose(this, new CloseReason(code, reason));
} catch (Exception e) {
endpoint.getInstance().onError(this, e);
}
}
} finally {
close0();
if (clientConnectionBuilder != null && !localClose) {
WebSocketReconnectHandler webSocketReconnectHandler = container.getWebSocketReconnectHandler();
if (webSocketReconnectHandler != null) {
JsrWebSocketLogger.REQUEST_LOGGER.debugf("Calling reconnect handler for %s", this);
long reconnect = webSocketReconnectHandler.disconnected(closeReason, requestUri, this, ++disconnectCount);
if (reconnect >= 0) {
handleReconnect(reconnect);
}
}
}
}
}
}
use of javax.websocket.CloseReason in project undertow by undertow-io.
the class UndertowSession method setupWebSocketChannel.
private void setupWebSocketChannel(WebSocketChannel webSocketChannel) {
this.frameHandler = new FrameHandler(this, this.endpoint.getInstance());
webSocketChannel.getReceiveSetter().set(frameHandler);
webSocketChannel.addCloseTask(new ChannelListener<WebSocketChannel>() {
@Override
public void handleEvent(WebSocketChannel channel) {
//so this puts us in an interesting position. We know the underlying
//TCP connection has been torn down, however this may have involved reading
//a close frame, which will be delivered shortly
//to get around this we schedule the code in the IO thread, so if there is a close
//frame awaiting delivery it will be delivered before the close
channel.getIoThread().execute(new Runnable() {
@Override
public void run() {
//we delegate this execution to the IO thread
try {
closeInternal(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, null));
} catch (IOException e) {
//ignore
}
}
});
}
});
}
use of javax.websocket.CloseReason in project undertow by undertow-io.
the class ClientEndpointReconnectTestCase method setup.
@BeforeClass
public static void setup() throws Exception {
final ServletContainer container = ServletContainer.Factory.newInstance();
DeploymentInfo builder = new DeploymentInfo().setClassLoader(ClientEndpointReconnectTestCase.class.getClassLoader()).setContextPath("/ws").setResourceManager(new TestResourceLoader(ClientEndpointReconnectTestCase.class)).setClassIntrospecter(TestClassIntrospector.INSTANCE).addServletContextAttribute(WebSocketDeploymentInfo.ATTRIBUTE_NAME, new WebSocketDeploymentInfo().setBuffers(new DefaultByteBufferPool(true, 8192)).setWorker(DefaultServer.getWorker()).addEndpoint(DisconnectServerEndpoint.class).addEndpoint(AnnotatedClientReconnectEndpoint.class).addListener(new WebSocketDeploymentInfo.ContainerReadyListener() {
@Override
public void ready(ServerWebSocketContainer container) {
deployment = container;
}
}).setReconnectHandler(new WebSocketReconnectHandler() {
@Override
public long disconnected(CloseReason closeReason, URI connectionUri, Session session, int disconnectCount) {
if (disconnectCount < 3) {
return 1;
} else {
return -1;
}
}
@Override
public long reconnectFailed(IOException exception, URI connectionUri, Session session, int failedCount) {
failed = true;
return -1;
}
})).setDeploymentName("servletContext.war");
DeploymentManager manager = container.addDeployment(builder);
manager.deploy();
DefaultServer.setRootHandler(Handlers.path().addPrefixPath("/ws", manager.start()));
}
use of javax.websocket.CloseReason in project undertow by undertow-io.
the class AnnotatedEndpointTest method testCloseReason.
@Test
public void testCloseReason() throws Exception {
MessageEndpoint.reset();
Session session = deployment.connectToServer(AnnotatedClientEndpoint.class, new URI("ws://" + DefaultServer.getHostAddress("default") + ":" + DefaultServer.getHostPort("default") + "/ws/chat/Bob"));
Assert.assertEquals("hi Bob (protocol=foo)", AnnotatedClientEndpoint.message());
session.close(new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "Foo!"));
Assert.assertEquals("CLOSED", AnnotatedClientEndpoint.message());
CloseReason cr = MessageEndpoint.getReason();
Assert.assertEquals(CloseReason.CloseCodes.VIOLATED_POLICY.getCode(), cr.getCloseCode().getCode());
Assert.assertEquals("Foo!", cr.getReasonPhrase());
}
Aggregations