Skip to content

Commit 0fd150d

Browse files
author
Ali Beyad
committed
Single comma-delimited response header for multiple values
Despite the RFC permitting multi-value response headers to appear as individual header fields instead of a single header field with a comma delimitted value, Internet Explorer does not deal well with this and hence, this commit ensures that multi-value CORS response headers are serialized as a single header field with a comma delimitted value. This also brings the implementation in conformity with how Netty4 handles multi-value headers, which is the default transport implementation for 5.x. Backports #19872
1 parent 1f11ac1 commit 0fd150d

File tree

2 files changed

+81
-4
lines changed

2 files changed

+81
-4
lines changed

core/src/main/java/org/elasticsearch/http/netty/cors/CorsHandler.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,16 +228,18 @@ private static boolean isPreflightRequest(final HttpRequest request) {
228228
headers.contains(HttpHeaders.Names.ACCESS_CONTROL_REQUEST_METHOD);
229229
}
230230

231-
private void setAllowMethods(final HttpResponse response) {
231+
// package private for testing
232+
void setAllowMethods(final HttpResponse response) {
232233
Set<String> strMethods = new HashSet<>();
233234
for (HttpMethod method : config.allowedRequestMethods()) {
234235
strMethods.add(method.getName().trim());
235236
}
236-
response.headers().set(ACCESS_CONTROL_ALLOW_METHODS, strMethods);
237+
response.headers().set(ACCESS_CONTROL_ALLOW_METHODS, Strings.collectionToCommaDelimitedString(strMethods));
237238
}
238239

239-
private void setAllowHeaders(final HttpResponse response) {
240-
response.headers().set(ACCESS_CONTROL_ALLOW_HEADERS, config.allowedRequestHeaders());
240+
// package private for testing
241+
void setAllowHeaders(final HttpResponse response) {
242+
response.headers().set(ACCESS_CONTROL_ALLOW_HEADERS, Strings.collectionToCommaDelimitedString(config.allowedRequestHeaders()));
241243
}
242244

243245
private void setMaxAge(final HttpResponse response) {
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.http.netty.cors;
21+
22+
import org.elasticsearch.common.Strings;
23+
import org.elasticsearch.test.ESTestCase;
24+
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
25+
import org.jboss.netty.handler.codec.http.HttpMethod;
26+
import org.jboss.netty.handler.codec.http.HttpResponse;
27+
import org.jboss.netty.handler.codec.http.HttpVersion;
28+
import org.junit.Test;
29+
30+
import java.util.Set;
31+
32+
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_ALLOW_HEADERS;
33+
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_ALLOW_METHODS;
34+
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK;
35+
36+
/**
37+
* Tests for {@link CorsHandler}
38+
*/
39+
public class CorsHandlerTests extends ESTestCase {
40+
41+
@Test
42+
public void testSingleValueResponseHeaders() {
43+
CorsConfig corsConfig = new CorsConfigBuilder()
44+
.allowedRequestHeaders("content-type")
45+
.allowedRequestMethods(HttpMethod.GET)
46+
.build();
47+
CorsHandler corsHandler = new CorsHandler(corsConfig);
48+
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, OK);
49+
corsHandler.setAllowMethods(response);
50+
corsHandler.setAllowHeaders(response);
51+
assertEquals("content-type", response.headers().get(ACCESS_CONTROL_ALLOW_HEADERS));
52+
assertEquals("GET", response.headers().get(ACCESS_CONTROL_ALLOW_METHODS));
53+
}
54+
55+
@Test
56+
public void testMultiValueResponseHeaders() {
57+
CorsConfig corsConfig = new CorsConfigBuilder()
58+
.allowedRequestHeaders("content-type,x-requested-with,accept")
59+
.allowedRequestMethods(HttpMethod.GET, HttpMethod.POST)
60+
.build();
61+
CorsHandler corsHandler = new CorsHandler(corsConfig);
62+
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, OK);
63+
corsHandler.setAllowMethods(response);
64+
corsHandler.setAllowHeaders(response);
65+
Set<String> responseHeadersSet = Strings.commaDelimitedListToSet(response.headers().get(ACCESS_CONTROL_ALLOW_HEADERS));
66+
assertEquals(3, responseHeadersSet.size());
67+
assertTrue(responseHeadersSet.contains("content-type"));
68+
assertTrue(responseHeadersSet.contains("x-requested-with"));
69+
assertTrue(responseHeadersSet.contains("accept"));
70+
Set<String> responseMethodsSet = Strings.commaDelimitedListToSet(response.headers().get(ACCESS_CONTROL_ALLOW_METHODS));
71+
assertEquals(2, responseMethodsSet.size());
72+
assertTrue(responseMethodsSet.contains("GET"));
73+
assertTrue(responseMethodsSet.contains("POST"));
74+
}
75+
}

0 commit comments

Comments
 (0)