@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; }
@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 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 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)); } }
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 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 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); }
@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; } } }
@Override public void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException { response.setStatusCode(this.status); }
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)); }
/** * 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(); } }
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 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")); }