protected void addCorsHeaders( ServerHttpRequest request, ServerHttpResponse response, HttpMethod... httpMethods) { String origin = request.getHeaders().getFirst("origin"); origin = ((origin == null) || origin.equals("null")) ? "*" : origin; response.getHeaders().add("Access-Control-Allow-Origin", origin); response.getHeaders().add("Access-Control-Allow-Credentials", "true"); List<String> accessControllerHeaders = request.getHeaders().get("Access-Control-Request-Headers"); if (accessControllerHeaders != null) { for (String header : accessControllerHeaders) { response.getHeaders().add("Access-Control-Allow-Headers", header); } } if (!ObjectUtils.isEmpty(httpMethods)) { response .getHeaders() .add( "Access-Control-Allow-Methods", StringUtils.arrayToDelimitedString(httpMethods, ", ")); response.getHeaders().add("Access-Control-Max-Age", String.valueOf(ONE_YEAR)); } }
@Override public void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException { if (HttpMethod.GET.equals(request.getMethod())) { response .getHeaders() .setContentType(new MediaType("application", "json", Charset.forName("UTF-8"))); addCorsHeaders(request, response); addNoCacheHeaders(response); String content = String.format( INFO_CONTENT, random.nextInt(), isJsessionIdCookieRequired(), isWebSocketEnabled()); response.getBody().write(content.getBytes()); } else if (HttpMethod.OPTIONS.equals(request.getMethod())) { response.setStatusCode(HttpStatus.NO_CONTENT); addCorsHeaders(request, response, HttpMethod.OPTIONS, HttpMethod.GET); addCacheHeaders(response); } else { sendMethodNotAllowed(response, Arrays.asList(HttpMethod.OPTIONS, HttpMethod.GET)); } }
@Override public void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException { if (!HttpMethod.GET.equals(request.getMethod())) { sendMethodNotAllowed(response, Arrays.asList(HttpMethod.GET)); return; } String content = String.format(IFRAME_CONTENT, getSockJsClientLibraryUrl()); byte[] contentBytes = content.getBytes(Charset.forName("UTF-8")); StringBuilder builder = new StringBuilder("\"0"); DigestUtils.appendMd5DigestAsHex(contentBytes, builder); builder.append('"'); String etagValue = builder.toString(); List<String> ifNoneMatch = request.getHeaders().getIfNoneMatch(); if (!CollectionUtils.isEmpty(ifNoneMatch) && ifNoneMatch.get(0).equals(etagValue)) { response.setStatusCode(HttpStatus.NOT_MODIFIED); return; } response .getHeaders() .setContentType(new MediaType("text", "html", Charset.forName("UTF-8"))); response.getHeaders().setContentLength(contentBytes.length); addCacheHeaders(response); response.getHeaders().setETag(etagValue); response.getBody().write(contentBytes); }
@Override public final boolean doHandshake( ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws HandshakeFailureException { if (logger.isDebugEnabled()) { logger.debug( "Initiating handshake for " + request.getURI() + ", headers=" + request.getHeaders()); } try { if (!HttpMethod.GET.equals(request.getMethod())) { response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED); response.getHeaders().setAllow(Collections.singleton(HttpMethod.GET)); logger.debug("Only HTTP GET is allowed, current method is " + request.getMethod()); return false; } if (!"WebSocket".equalsIgnoreCase(request.getHeaders().getUpgrade())) { handleInvalidUpgradeHeader(request, response); return false; } if (!request.getHeaders().getConnection().contains("Upgrade") && !request.getHeaders().getConnection().contains("upgrade")) { handleInvalidConnectHeader(request, response); return false; } if (!isWebSocketVersionSupported(request)) { handleWebSocketVersionNotSupported(request, response); return false; } if (!isValidOrigin(request)) { response.setStatusCode(HttpStatus.FORBIDDEN); return false; } String wsKey = request.getHeaders().getSecWebSocketKey(); if (wsKey == null) { logger.debug("Missing \"Sec-WebSocket-Key\" header"); response.setStatusCode(HttpStatus.BAD_REQUEST); return false; } } catch (IOException ex) { throw new HandshakeFailureException( "Response update failed during upgrade to WebSocket, uri=" + request.getURI(), ex); } String subProtocol = selectProtocol(request.getHeaders().getSecWebSocketProtocol()); if (logger.isDebugEnabled()) { logger.debug("Upgrading request, sub-protocol=" + subProtocol); } this.requestUpgradeStrategy.upgrade(request, response, subProtocol, wsHandler, attributes); return true; }
protected void handleWebSocketVersionNotSupported( ServerHttpRequest request, ServerHttpResponse response) { logger.debug( "WebSocket version not supported " + request.getHeaders().get("Sec-WebSocket-Version")); response.setStatusCode(HttpStatus.UPGRADE_REQUIRED); response .getHeaders() .setSecWebSocketVersion(StringUtils.arrayToCommaDelimitedString(getSupportedVerions())); }
@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(); }
@Override protected void handleRawWebSocketRequest( ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler) throws IOException { TransportHandler transportHandler = this.handlers.get(TransportType.WEBSOCKET); if (!(transportHandler instanceof HandshakeHandler)) { logger.error("No handler configured for raw WebSocket messages"); response.setStatusCode(HttpStatus.NOT_FOUND); return; } HandshakeInterceptorChain chain = new HandshakeInterceptorChain(this.interceptors, handler); HandshakeFailureException failure = null; try { Map<String, Object> attributes = new HashMap<String, Object>(); if (!chain.applyBeforeHandshake(request, response, attributes)) { return; } ((HandshakeHandler) transportHandler).doHandshake(request, response, handler, attributes); chain.applyAfterHandshake(request, response, null); } catch (HandshakeFailureException ex) { failure = ex; } catch (Throwable ex) { failure = new HandshakeFailureException("Uncaught failure for request " + request.getURI(), ex); } finally { if (failure != null) { chain.applyAfterHandshake(request, response, failure); throw failure; } } }
@RequestMapping(method = RequestMethod.POST) public ModelAndView update( @Valid SearchElementEntity elementDefinition, BindingResult bindingResult, HttpServletRequest httpServletRequest, ServerHttpResponse response) { LOGGER.info( "Creating an filed element: " + elementDefinition.getClazz().getSimpleName() + " for preset: " + elementDefinition.getPreset().getSlug()); ModelAndView model = new ModelAndView("admin/SearchElementDefinition/updateForm"); if (bindingResult.hasErrors()) { LOGGER.error("Bindding has error..."); for (ObjectError error : bindingResult.getAllErrors()) { LOGGER.error("Error: " + error.getDefaultMessage()); } response.setStatusCode(HttpStatus.PRECONDITION_FAILED); return model; } try { elementDefinition = repository.save(elementDefinition); } catch (Exception e) { LOGGER.error("Could not save elementDefinition", e); } model.addObject("searchElementDefinition", elementDefinition); return model; }
@Override public void handleReturnValue( Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue == null) { mavContainer.setRequestHandled(true); return; } HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); ServerHttpResponse outputMessage = new ServletServerHttpResponse(response); if (ResponseEntity.class.isAssignableFrom(returnValue.getClass())) { ResponseEntity<?> responseEntity = (ResponseEntity<?>) returnValue; outputMessage.setStatusCode(responseEntity.getStatusCode()); outputMessage.getHeaders().putAll(responseEntity.getHeaders()); returnValue = responseEntity.getBody(); if (returnValue == null) { mavContainer.setRequestHandled(true); return; } } ServletRequest request = webRequest.getNativeRequest(ServletRequest.class); ShallowEtagHeaderFilter.disableContentCaching(request); Assert.isInstanceOf(ResponseBodyEmitter.class, returnValue); ResponseBodyEmitter emitter = (ResponseBodyEmitter) returnValue; emitter.extendResponse(outputMessage); // Commit the response and wrap to ignore further header changes outputMessage.getBody(); outputMessage = new StreamingServletServerHttpResponse(outputMessage); DeferredResult<?> deferredResult = new DeferredResult<Object>(emitter.getTimeout()); WebAsyncUtils.getAsyncManager(webRequest) .startDeferredResultProcessing(deferredResult, mavContainer); HttpMessageConvertingHandler handler = new HttpMessageConvertingHandler(outputMessage, deferredResult); emitter.initialize(handler); }
@Override protected void extendResponse(ServerHttpResponse outputMessage) { super.extendResponse(outputMessage); HttpHeaders headers = outputMessage.getHeaders(); if (headers.getContentType() == null) { headers.setContentType(new MediaType("text", "event-stream")); } }
@Override public void handleRequestInternal( ServerHttpRequest request, ServerHttpResponse response, AbstractHttpSockJsSession sockJsSession) throws SockJsException { try { String callback = request.getQueryParams().getFirst("c"); if (!StringUtils.hasText(callback)) { response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); response.getBody().write("\"callback\" parameter required".getBytes("UTF-8")); return; } } catch (Throwable t) { sockJsSession.tryCloseWithSockJsTransportError(t, CloseStatus.SERVER_ERROR); throw new SockJsTransportFailureException("Failed to send error", sockJsSession.getId(), t); } super.handleRequestInternal(request, response, sockJsSession); }
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 public final void handleRequest( ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, SockJsSession wsSession) throws SockJsException { AbstractHttpSockJsSession sockJsSession = (AbstractHttpSockJsSession) wsSession; String protocol = null; // https://github.com/sockjs/sockjs-client/issues/130 sockJsSession.setAcceptedProtocol(protocol); // Set content type before writing response.getHeaders().setContentType(getContentType()); handleRequestInternal(request, response, sockJsSession); }
@Override protected void beforeBodyWriteInternal( MappingJacksonValue bodyContainer, MediaType contentType, MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) { HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest(); for (String name : this.jsonpQueryParamNames) { String value = servletRequest.getParameter(name); if (value != null) { MediaType contentTypeToUse = getContentType(contentType, request, response); response.getHeaders().setContentType(contentTypeToUse); bodyContainer.setJsonpFunction(value); return; } } }
/** * 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); } } }
public StreamingServletServerHttpResponse(ServerHttpResponse delegate) { this.delegate = delegate; this.mutableHeaders.putAll(delegate.getHeaders()); }
@Override public void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException { response.setStatusCode(this.status); }
protected void handleInvalidUpgradeHeader(ServerHttpRequest request, ServerHttpResponse response) throws IOException { logger.debug("Invalid Upgrade header " + request.getHeaders().getUpgrade()); response.setStatusCode(HttpStatus.BAD_REQUEST); response.getBody().write("Can \"Upgrade\" only to \"WebSocket\".".getBytes("UTF-8")); }
protected void handleInvalidConnectHeader(ServerHttpRequest request, ServerHttpResponse response) throws IOException { logger.debug("Invalid Connection header " + request.getHeaders().getConnection()); response.setStatusCode(HttpStatus.BAD_REQUEST); response.getBody().write("\"Connection\" must be \"upgrade\".".getBytes("UTF-8")); }
protected void addCacheHeaders(ServerHttpResponse response) { response.getHeaders().setCacheControl("public, max-age=" + ONE_YEAR); response.getHeaders().setExpires(new Date().getTime() + ONE_YEAR * 1000); }
protected void sendMethodNotAllowed(ServerHttpResponse response, List<HttpMethod> httpMethods) throws IOException { logger.debug("Sending Method Not Allowed (405)"); response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED); response.getHeaders().setAllow(new HashSet<HttpMethod>(httpMethods)); }
protected void addNoCacheHeaders(ServerHttpResponse response) { response.getHeaders().setCacheControl("no-store, no-cache, must-revalidate, max-age=0"); }
@Override protected void handleTransportRequest( ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler, String sessionId, String transport) throws SockJsException { TransportType transportType = TransportType.fromValue(transport); if (transportType == null) { logger.error("Unknown transport type for " + request.getURI()); response.setStatusCode(HttpStatus.NOT_FOUND); return; } TransportHandler transportHandler = this.handlers.get(transportType); if (transportHandler == null) { logger.error("No TransportHandler for " + request.getURI()); response.setStatusCode(HttpStatus.NOT_FOUND); return; } HttpMethod supportedMethod = transportType.getHttpMethod(); if (!supportedMethod.equals(request.getMethod())) { if (HttpMethod.OPTIONS.equals(request.getMethod()) && transportType.supportsCors()) { if (checkAndAddCorsHeaders(request, response, HttpMethod.OPTIONS, supportedMethod)) { response.setStatusCode(HttpStatus.NO_CONTENT); addCacheHeaders(response); } } else if (transportType.supportsCors()) { sendMethodNotAllowed(response, supportedMethod, HttpMethod.OPTIONS); } else { sendMethodNotAllowed(response, supportedMethod); } return; } HandshakeInterceptorChain chain = new HandshakeInterceptorChain(this.interceptors, handler); SockJsException failure = null; try { SockJsSession session = this.sessions.get(sessionId); if (session == null) { if (transportHandler instanceof SockJsSessionFactory) { Map<String, Object> attributes = new HashMap<String, Object>(); if (!chain.applyBeforeHandshake(request, response, attributes)) { return; } SockJsSessionFactory sessionFactory = (SockJsSessionFactory) transportHandler; session = createSockJsSession(sessionId, sessionFactory, handler, attributes); } else { response.setStatusCode(HttpStatus.NOT_FOUND); if (logger.isDebugEnabled()) { logger.debug( "Session not found, sessionId=" + sessionId + ". The session may have been closed " + "(e.g. missed heart-beat) while a message was coming in."); } return; } } if (transportType.sendsNoCacheInstruction()) { addNoCacheHeaders(response); } if (transportType.supportsCors()) { if (!checkAndAddCorsHeaders(request, response)) { return; } } transportHandler.handleRequest(request, response, handler, session); chain.applyAfterHandshake(request, response, null); } catch (SockJsException ex) { failure = ex; } catch (Throwable ex) { failure = new SockJsException("Uncaught failure for request " + request.getURI(), sessionId, ex); } finally { if (failure != null) { chain.applyAfterHandshake(request, response, failure); throw failure; } } }
/** * TODO * * @param request * @param response * @param sockJsPath * @throws Exception */ @Override public final void handleRequest( ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler) throws IOException, TransportErrorException { String sockJsPath = getSockJsPath(request); if (sockJsPath == null) { logger.warn( "Could not determine SockJS path for URL \"" + request.getURI().getPath() + ". Consider setting validSockJsPrefixes."); response.setStatusCode(HttpStatus.NOT_FOUND); return; } logger.debug(request.getMethod() + " with SockJS path [" + sockJsPath + "]"); try { request.getHeaders(); } catch (IllegalArgumentException ex) { // Ignore invalid Content-Type (TODO) } try { if (sockJsPath.equals("") || sockJsPath.equals("/")) { response .getHeaders() .setContentType(new MediaType("text", "plain", Charset.forName("UTF-8"))); response.getBody().write("Welcome to SockJS!\n".getBytes("UTF-8")); return; } else if (sockJsPath.equals("/info")) { this.infoHandler.handle(request, response); return; } else if (sockJsPath.matches("/iframe[0-9-.a-z_]*.html")) { this.iframeHandler.handle(request, response); return; } else if (sockJsPath.equals("/websocket")) { handleRawWebSocketRequest(request, response, handler); return; } String[] pathSegments = StringUtils.tokenizeToStringArray(sockJsPath.substring(1), "/"); if (pathSegments.length != 3) { logger.warn("Expected \"/{server}/{session}/{transport}\" but got \"" + sockJsPath + "\""); response.setStatusCode(HttpStatus.NOT_FOUND); return; } String serverId = pathSegments[0]; String sessionId = pathSegments[1]; String transport = pathSegments[2]; if (!validateRequest(serverId, sessionId, transport)) { response.setStatusCode(HttpStatus.NOT_FOUND); return; } handleTransportRequest( request, response, sessionId, TransportType.fromValue(transport), handler); } finally { response.flush(); } }