@Override protected void flushCache() throws SockJsTransportFailureException { while (!getMessageCache().isEmpty()) { String message = getMessageCache().poll(); SockJsMessageCodec messageCodec = getSockJsServiceConfig().getMessageCodec(); SockJsFrame frame = SockJsFrame.messageFrame(messageCodec, message); writeFrame(frame); this.byteCount += frame.getContentBytes().length + 1; if (logger.isTraceEnabled()) { logger.trace( this.byteCount + " bytes written so far, " + getMessageCache().size() + " more messages not flushed"); } if (this.byteCount >= getSockJsServiceConfig().getStreamBytesLimit()) { if (logger.isTraceEnabled()) { logger.trace("Streamed bytes limit reached. Recycling current request"); } resetRequest(); this.byteCount = 0; break; } } scheduleHeartbeat(); }
/** * Handle the first request for receiving messages on a SockJS HTTP transport based session. * * <p>Long polling-based transports (e.g. "xhr", "jsonp") complete the request after writing the * open frame. Streaming-based transports ("xhr_streaming", "eventsource", and "htmlfile") leave * the response open longer for further streaming of message frames but will also close it * eventually after some amount of data has been sent. * * @param request the current request * @param response the current response * @param frameFormat the transport-specific SocksJS frame format to use */ public void handleInitialRequest( ServerHttpRequest request, ServerHttpResponse response, SockJsFrameFormat frameFormat) throws SockJsException { this.uri = request.getURI(); this.handshakeHeaders = request.getHeaders(); this.principal = request.getPrincipal(); this.localAddress = request.getLocalAddress(); this.remoteAddress = request.getRemoteAddress(); this.response = response; this.frameFormat = frameFormat; this.asyncRequestControl = request.getAsyncRequestControl(response); synchronized (this.responseLock) { try { // Let "our" handler know before sending the open frame to the remote handler delegateConnectionEstablished(); writePrelude(request, response); writeFrame(SockJsFrame.openFrame()); if (isStreaming() && !isClosed()) { startAsyncRequest(); } } catch (Throwable ex) { tryCloseWithSockJsTransportError(ex, CloseStatus.SERVER_ERROR); throw new SockJsTransportFailureException("Failed to open session", getId(), ex); } } }
protected void handleRequestInternal( ServerHttpRequest request, ServerHttpResponse response, AbstractHttpSockJsSession sockJsSession) throws SockJsException { 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()); } catch (IOException ex) { 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)); } else { if (logger.isDebugEnabled()) { logger.debug( "Another " + getTransportType() + " connection still open for " + sockJsSession); } String formattedFrame = getFrameFormat(request).format(SockJsFrame.closeFrameAnotherConnectionOpen()); try { response.getBody().write(formattedFrame.getBytes(SockJsFrame.CHARSET)); } catch (IOException ex) { throw new SockJsException("Failed to send " + formattedFrame, sockJsSession.getId(), ex); } } }
@Override protected void handleRequestInternal( ServerHttpRequest request, ServerHttpResponse response, boolean initialRequest) throws IOException { byte[] prelude = getPrelude(request); Assert.notNull(prelude); response.getBody().write(prelude); response.flush(); if (initialRequest) { writeFrame(SockJsFrame.openFrame()); } flushCache(); }
/** * Handle all requests, except the first one, to receive messages on a SockJS HTTP transport based * session. * * <p>Long polling-based transports (e.g. "xhr", "jsonp") complete the request after writing any * buffered message frames (or the next one). Streaming-based transports ("xhr_streaming", * "eventsource", and "htmlfile") leave the response open longer for further streaming of message * frames but will also close it eventually after some amount of data has been sent. * * @param request the current request * @param response the current response * @param frameFormat the transport-specific SocksJS frame format to use */ public void handleSuccessiveRequest( ServerHttpRequest request, ServerHttpResponse response, SockJsFrameFormat frameFormat) throws SockJsException { synchronized (this.responseLock) { try { if (isClosed()) { response.getBody().write(SockJsFrame.closeFrameGoAway().getContentBytes()); } this.response = response; this.frameFormat = frameFormat; this.asyncRequestControl = request.getAsyncRequestControl(response); writePrelude(request, response); startAsyncRequest(); } catch (Throwable ex) { tryCloseWithSockJsTransportError(ex, CloseStatus.SERVER_ERROR); throw new SockJsTransportFailureException( "Failed to handle SockJS receive request", getId(), ex); } } }