001/* 002 * Copyright 2002-2015 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.socket.sockjs.support; 018 019import java.io.IOException; 020import javax.servlet.ServletContext; 021import javax.servlet.ServletException; 022import javax.servlet.http.HttpServletRequest; 023import javax.servlet.http.HttpServletResponse; 024 025import org.springframework.context.Lifecycle; 026import org.springframework.http.server.ServerHttpRequest; 027import org.springframework.http.server.ServerHttpResponse; 028import org.springframework.http.server.ServletServerHttpRequest; 029import org.springframework.http.server.ServletServerHttpResponse; 030import org.springframework.util.Assert; 031import org.springframework.web.HttpRequestHandler; 032import org.springframework.web.context.ServletContextAware; 033import org.springframework.web.cors.CorsConfiguration; 034import org.springframework.web.cors.CorsConfigurationSource; 035import org.springframework.web.servlet.HandlerMapping; 036import org.springframework.web.socket.WebSocketHandler; 037import org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator; 038import org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator; 039import org.springframework.web.socket.sockjs.SockJsException; 040import org.springframework.web.socket.sockjs.SockJsService; 041 042/** 043 * An {@link HttpRequestHandler} that allows mapping a {@link SockJsService} to requests 044 * in a Servlet container. 045 * 046 * @author Rossen Stoyanchev 047 * @author Sebastien Deleuze 048 * @since 4.0 049 */ 050public class SockJsHttpRequestHandler 051 implements HttpRequestHandler, CorsConfigurationSource, Lifecycle, ServletContextAware { 052 053 // No logging: HTTP transports too verbose and we don't know enough to log anything of value 054 055 private final SockJsService sockJsService; 056 057 private final WebSocketHandler webSocketHandler; 058 059 private volatile boolean running = false; 060 061 062 /** 063 * Create a new SockJsHttpRequestHandler. 064 * @param sockJsService the SockJS service 065 * @param webSocketHandler the websocket handler 066 */ 067 public SockJsHttpRequestHandler(SockJsService sockJsService, WebSocketHandler webSocketHandler) { 068 Assert.notNull(sockJsService, "SockJsService must not be null"); 069 Assert.notNull(webSocketHandler, "WebSocketHandler must not be null"); 070 this.sockJsService = sockJsService; 071 this.webSocketHandler = 072 new ExceptionWebSocketHandlerDecorator(new LoggingWebSocketHandlerDecorator(webSocketHandler)); 073 } 074 075 076 /** 077 * Return the {@link SockJsService}. 078 */ 079 public SockJsService getSockJsService() { 080 return this.sockJsService; 081 } 082 083 /** 084 * Return the {@link WebSocketHandler}. 085 */ 086 public WebSocketHandler getWebSocketHandler() { 087 return this.webSocketHandler; 088 } 089 090 @Override 091 public void setServletContext(ServletContext servletContext) { 092 if (this.sockJsService instanceof ServletContextAware) { 093 ((ServletContextAware) this.sockJsService).setServletContext(servletContext); 094 } 095 } 096 097 098 @Override 099 public void start() { 100 if (!isRunning()) { 101 this.running = true; 102 if (this.sockJsService instanceof Lifecycle) { 103 ((Lifecycle) this.sockJsService).start(); 104 } 105 } 106 } 107 108 @Override 109 public void stop() { 110 if (isRunning()) { 111 this.running = false; 112 if (this.sockJsService instanceof Lifecycle) { 113 ((Lifecycle) this.sockJsService).stop(); 114 } 115 } 116 } 117 118 @Override 119 public boolean isRunning() { 120 return this.running; 121 } 122 123 124 @Override 125 public void handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) 126 throws ServletException, IOException { 127 128 ServerHttpRequest request = new ServletServerHttpRequest(servletRequest); 129 ServerHttpResponse response = new ServletServerHttpResponse(servletResponse); 130 131 try { 132 this.sockJsService.handleRequest(request, response, getSockJsPath(servletRequest), this.webSocketHandler); 133 } 134 catch (Throwable ex) { 135 throw new SockJsException("Uncaught failure in SockJS request, uri=" + request.getURI(), ex); 136 } 137 } 138 139 private String getSockJsPath(HttpServletRequest servletRequest) { 140 String attribute = HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE; 141 String path = (String) servletRequest.getAttribute(attribute); 142 return (path.length() > 0 && path.charAt(0) != '/' ? "/" + path : path); 143 } 144 145 @Override 146 public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { 147 if (this.sockJsService instanceof CorsConfigurationSource) { 148 return ((CorsConfigurationSource) this.sockJsService).getCorsConfiguration(request); 149 } 150 return null; 151 } 152 153}