@Override public void failed(IOException ex) { throw new SockJsTransportFailureException("Failed to execute request to " + url, ex);
/**
* For internal use within a TransportHandler and the (TransportHandler-specific)
* session class.
protected void writeFrame(SockJsFrame frame) throws SockJsTransportFailureException {
if (logger.isTraceEnabled()) {
logger.trace("Preparing to write " + frame);
try {
writeFrameInternal(frame);
catch (Throwable ex) {
logWriteFrameFailure(ex);
try {
// Force disconnect (so we won't try to send close frame)
disconnect(CloseStatus.SERVER_ERROR);
catch (Throwable disconnectFailure) {
// Ignore
try {
close(CloseStatus.SERVER_ERROR);
catch (Throwable closeFailure) {
// Nothing of consequence, already forced disconnect
throw new SockJsTransportFailureException("Failed to write " + frame, getId(), ex);
@Override public void handleRequest(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, SockJsSession wsSession) throws SockJsException { WebSocketServerSockJsSession sockJsSession = (WebSocketServerSockJsSession) wsSession; try { wsHandler = new SockJsWebSocketHandler(getServiceConfig(), wsHandler, sockJsSession); this.handshakeHandler.doHandshake(request, response, wsHandler, sockJsSession.getAttributes()); catch (Throwable ex) { sockJsSession.tryCloseWithSockJsTransportError(ex, CloseStatus.SERVER_ERROR); throw new SockJsTransportFailureException("WebSocket handshake failure", wsSession.getId(), ex);
if (sockJsSession.isNew()) {
if (logger.isDebugEnabled()) {
logger.debug(request.getMethod() + " " + request.getURI());
sockJsSession.handleInitialRequest(request, response, getFrameFormat(request));
else if (sockJsSession.isClosed()) {
if (logger.isDebugEnabled()) {
logger.debug("Connection already closed (but not removed yet) for " + sockJsSession);
SockJsFrame frame = SockJsFrame.closeFrameGoAway();
try {
response.getBody().write(frame.getContentBytes());
throw new SockJsException("Failed to send " + frame, sockJsSession.getId(), ex);
else if (!sockJsSession.isActive()) {
if (logger.isTraceEnabled()) {
logger.trace("Starting " + getTransportType() + " async request.");
sockJsSession.handleSuccessiveRequest(request, response, getFrameFormat(request));
logger.debug("Another " + getTransportType() + " connection still open for " + sockJsSession);
String formattedFrame = getFrameFormat(request).format(SockJsFrame.closeFrameAnotherConnectionOpen());
try {
response.getBody().write(formattedFrame.getBytes(SockJsFrame.CHARSET));
throw new SockJsException("Failed to send " + formattedFrame, sockJsSession.getId(), ex);
TransportType transportType = TransportType.fromValue(transport);
if (transportType == null) {
if (logger.isWarnEnabled()) {
HttpMethod supportedMethod = transportType.getHttpMethod();
if (supportedMethod != request.getMethod()) {
if (request.getMethod() == HttpMethod.OPTIONS && transportType.supportsCors()) {
if (checkOrigin(request, response, HttpMethod.OPTIONS, supportedMethod)) {
response.setStatusCode(HttpStatus.NO_CONTENT);
addCacheHeaders(response);
else if (transportType.supportsCors()) {
sendMethodNotAllowed(response, supportedMethod, HttpMethod.OPTIONS);
sendMethodNotAllowed(response, supportedMethod);
session = createSockJsSession(sessionId, sessionFactory, handler, attributes);
Principal principal = session.getPrincipal();
if (principal != null && !principal.equals(request.getPrincipal())) {
logger.debug("The user for the session does not match the user for the request.");
if (!transportHandler.checkSessionType(session)) {
logger.debug("Session type does not match the transport type for the request.");
response.setStatusCode(HttpStatus.NOT_FOUND);
if (transportType.sendsNoCacheInstruction()) {
addNoCacheHeaders(response);
if (isClosed()) {
response.getBody().write(SockJsFrame.closeFrameGoAway().getContentBytes());
return;
this.asyncRequestControl = control;
control.start(-1);
disableShallowEtagHeaderFilter(request);
handleRequestInternal(request, response, false);
this.readyToSend = isActive();
tryCloseWithSockJsTransportError(ex, CloseStatus.SERVER_ERROR);
throw new SockJsTransportFailureException("Failed to handle SockJS receive request", getId(), ex);
this.asyncRequestControl = control;
control.start(-1);
disableShallowEtagHeaderFilter(request);
delegateConnectionEstablished();
handleRequestInternal(request, response, true);
this.readyToSend = isActive();
tryCloseWithSockJsTransportError(ex, CloseStatus.SERVER_ERROR);
throw new SockJsTransportFailureException("Failed to open session", getId(), ex);
logger.debug("Processing transport request: " + requestInfo);
this.infoHandler.handle(request, response);
logger.debug("Processing transport request: " + requestInfo);
this.iframeHandler.handle(request, response);
if (isWebSocketEnabled()) {
if (requestInfo != null) {
logger.debug("Processing transport request: " + requestInfo);
handleRawWebSocketRequest(request, response, wsHandler);
String transport = pathSegments[2];
if (!isWebSocketEnabled() && transport.equals("websocket")) {
if (requestInfo != null) {
logger.debug("WebSocket disabled. Ignoring transport request: " + requestInfo);
else if (!validateRequest(serverId, sessionId, transport) || !validatePath(request)) {
if (requestInfo != null) {
logger.debug("Ignoring transport request: " + requestInfo);
handleTransportRequest(request, response, wsHandler, sessionId, transport);
throw new SockJsException("Failed to write to the response", null, ex);
@Override public void handleEvent(StreamSourceChannel channel) { if (this.session.isDisconnected()) { if (logger.isDebugEnabled()) { logger.debug("SockJS sockJsSession closed, closing response."); throw new SockJsException("Session closed.", this.session.getId(), null); onSuccess(); int b = buffer.get(); if (b == '\n') { handleFrame(); onFailure(exc);
@Override public void handleRequestInternal(ServerHttpRequest request, ServerHttpResponse response, AbstractHttpSockJsSession sockJsSession) throws SockJsException { String callback = getCallbackParam(request); if (!StringUtils.hasText(callback)) { response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); try { response.getBody().write("\"callback\" parameter required".getBytes(StandardCharsets.UTF_8)); catch (IOException ex) { sockJsSession.tryCloseWithSockJsTransportError(ex, CloseStatus.SERVER_ERROR); throw new SockJsTransportFailureException("Failed to write to response", sockJsSession.getId(), ex); return; super.handleRequestInternal(request, response, sockJsSession);
String message = "Connect timed out for " + DefaultTransportRequest.this;
logger.error(message);
ex = new SockJsTransportFailureException(message, getSockJsUrlInfo().getSessionId(), ex);
fallbackRequest.connect(this.handler, this.future);
@Override public void onContent(Response response, ByteBuffer buffer) { while (true) { if (this.sockJsSession.isDisconnected()) { if (logger.isDebugEnabled()) { logger.debug("SockJS sockJsSession closed, closing response."); response.abort(new SockJsException("Session closed.", this.sockJsSession.getId(), null)); return; if (buffer.remaining() == 0) { break; int b = buffer.get(); if (b == '\n') { handleFrame(); else { this.outputStream.write(b);
@Override public void handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException { ServerHttpRequest request = new ServletServerHttpRequest(servletRequest); ServerHttpResponse response = new ServletServerHttpResponse(servletResponse); try { this.sockJsService.handleRequest(request, response, getSockJsPath(servletRequest), this.webSocketHandler); catch (Throwable ex) { throw new SockJsException("Uncaught failure in SockJS request, uri=" + request.getURI(), ex);
protected ResponseEntity<String> executeRequest(URI url, HttpMethod method,
HttpHeaders headers, @Nullable String body) {
Request httpRequest = this.httpClient.newRequest(url).method(method);
addHttpHeaders(httpRequest, headers);
if (body != null) {
httpRequest.content(new StringContentProvider(body));
ContentResponse response;
try {
response = httpRequest.send();
catch (Exception ex) {
throw new SockJsTransportFailureException("Failed to execute request to " + url, ex);
HttpStatus status = HttpStatus.valueOf(response.getStatus());
HttpHeaders responseHeaders = toHttpHeaders(response.getHeaders());
return (response.getContent() != null ?
new ResponseEntity<>(response.getContentAsString(), responseHeaders, status) :
new ResponseEntity<>(responseHeaders, status));
public void delegateMessages(String... messages) throws SockJsMessageDeliveryException {
List<String> undelivered = new ArrayList<>(Arrays.asList(messages));
for (String message : messages) {
try {
if (isClosed()) {
throw new SockJsMessageDeliveryException(this.id, undelivered, "Session closed");
else {
this.handler.handleMessage(this, new TextMessage(message));
undelivered.remove(0);
catch (Throwable ex) {
throw new SockJsMessageDeliveryException(this.id, undelivered, ex);
@Override public void stop() { try { if (this.httpClient.isRunning()) { this.httpClient.stop(); catch (Exception ex) { throw new SockJsException("Failed to stop JettyXhrTransport", ex);
@Test public void delegateMessagesWithErrorAndConnectionClosing() throws Exception { WebSocketHandler wsHandler = new ExceptionWebSocketHandlerDecorator(this.webSocketHandler); TestSockJsSession sockJsSession = new TestSockJsSession( "1", this.sockJsConfig, wsHandler, Collections.<String, Object>emptyMap()); String msg1 = "message 1"; String msg2 = "message 2"; String msg3 = "message 3"; willThrow(new IOException()).given(this.webSocketHandler).handleMessage(sockJsSession, new TextMessage(msg2)); sockJsSession.delegateConnectionEstablished(); try { sockJsSession.delegateMessages(msg1, msg2, msg3); fail("expected exception"); catch (SockJsMessageDeliveryException ex) { assertEquals(Collections.singletonList(msg3), ex.