|
44 | 44 | import org.springframework.web.socket.WebSocketHandler;
|
45 | 45 | import org.springframework.web.socket.sockjs.SockJsException;
|
46 | 46 | import org.springframework.web.socket.sockjs.SockJsService;
|
47 |
| -import org.springframework.web.util.UriComponentsBuilder; |
48 | 47 |
|
49 | 48 | /**
|
50 | 49 | * An abstract base class for {@link SockJsService} implementations that provides SockJS
|
@@ -102,16 +101,20 @@ public String getName() {
|
102 | 101 | }
|
103 | 102 |
|
104 | 103 | /**
|
105 |
| - * Transports which don't support cross-domain communication natively (e.g. |
106 |
| - * "eventsource", "htmlfile") rely on serving a simple page (using the |
107 |
| - * "foreign" domain) from an invisible iframe. Code run from this iframe |
108 |
| - * doesn't need to worry about cross-domain issues since it is running from |
109 |
| - * a domain local to the SockJS server. The iframe does need to load the |
110 |
| - * SockJS javascript client library and this option allows configuring that url. |
111 |
| - * For more details see the reference documentation. |
112 |
| - * |
| 104 | + * Transports with no native cross-domain communication (e.g. "eventsource", |
| 105 | + * "htmlfile") must get a simple page from the "foreign" domain in an invisible |
| 106 | + * iframe so that code in the iframe can run from a domain local to the SockJS |
| 107 | + * server. Since the iframe needs to load the SockJS javascript client library, |
| 108 | + * this property allows specifying where to load it from. |
113 | 109 | * <p>By default this is set to point to
|
114 | 110 | * "https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.4.min.js".
|
| 111 | + * However, it can also be set to point to a URL served by the application. |
| 112 | + * <p>Note that it's possible to specify a relative URL in which case the URL |
| 113 | + * must be relative to the iframe URL. For example assuming a SockJS endpoint |
| 114 | + * mapped to "/sockjs", and resulting iframe URL "/sockjs/iframe.html", then the |
| 115 | + * the relative URL must start with "../../" to traverse up to the location |
| 116 | + * above the SockJS mapping. In case of a prefix-based Servlet mapping one more |
| 117 | + * traversal may be needed. |
115 | 118 | */
|
116 | 119 | public void setSockJsClientLibraryUrl(String clientLibraryUrl) {
|
117 | 120 | this.clientLibraryUrl = clientLibraryUrl;
|
@@ -148,16 +151,13 @@ public int getStreamBytesLimit() {
|
148 | 151 | * clients with a "cookie_needed" boolean property that indicates whether the use of a
|
149 | 152 | * JSESSIONID cookie is required for the application to function correctly, e.g. for
|
150 | 153 | * load balancing or in Java Servlet containers for the use of an HTTP session.
|
151 |
| - * |
152 | 154 | * <p>This is especially important for IE 8,9 that support XDomainRequest -- a modified
|
153 | 155 | * AJAX/XHR -- that can do requests across domains but does not send any cookies. In
|
154 | 156 | * those cases, the SockJS client prefers the "iframe-htmlfile" transport over
|
155 | 157 | * "xdr-streaming" in order to be able to send cookies.
|
156 |
| - * |
157 | 158 | * <p>The SockJS protocol also expects a SockJS service to echo back the JSESSIONID
|
158 | 159 | * cookie when this property is set to true. However, when running in a Servlet
|
159 | 160 | * container this is not necessary since the container takes care of it.
|
160 |
| - * |
161 | 161 | * <p>The default value is "true" to maximize the chance for applications to work
|
162 | 162 | * correctly in IE 8,9 with support for cookies (and the JSESSIONID cookie in
|
163 | 163 | * particular). However, an application can choose to set this to "false" if
|
@@ -358,14 +358,18 @@ protected abstract void handleTransportRequest(ServerHttpRequest request, Server
|
358 | 358 |
|
359 | 359 |
|
360 | 360 | protected void addCorsHeaders(ServerHttpRequest request, ServerHttpResponse response, HttpMethod... httpMethods) {
|
361 |
| - |
362 | 361 | HttpHeaders requestHeaders = request.getHeaders();
|
363 | 362 | HttpHeaders responseHeaders = response.getHeaders();
|
364 | 363 |
|
365 |
| - // Perhaps a CORS Filter has already added this? |
366 |
| - if (!CollectionUtils.isEmpty(responseHeaders.get("Access-Control-Allow-Origin"))) { |
367 |
| - logger.debug("Skip adding CORS headers, response already contains \"Access-Control-Allow-Origin\""); |
368 |
| - return; |
| 364 | + try { |
| 365 | + // Perhaps a CORS Filter has already added this? |
| 366 | + if (!CollectionUtils.isEmpty(responseHeaders.get("Access-Control-Allow-Origin"))) { |
| 367 | + logger.debug("Skip adding CORS headers, response already contains \"Access-Control-Allow-Origin\""); |
| 368 | + return; |
| 369 | + } |
| 370 | + } |
| 371 | + catch (NullPointerException npe) { |
| 372 | + // See SPR-11919 and https://issues.jboss.org/browse/WFLY-3474 |
369 | 373 | }
|
370 | 374 |
|
371 | 375 | String origin = requestHeaders.getFirst("origin");
|
@@ -434,6 +438,7 @@ else if (HttpMethod.OPTIONS.equals(request.getMethod())) {
|
434 | 438 | }
|
435 | 439 | };
|
436 | 440 |
|
| 441 | + |
437 | 442 | private final SockJsRequestHandler iframeHandler = new SockJsRequestHandler() {
|
438 | 443 |
|
439 | 444 | private static final String IFRAME_CONTENT =
|
|
0 commit comments