381639 - CrossOriginFilter does not support Access-Control-Expose-Headers.
This commit is contained in:
parent
5b3999a7f4
commit
28c3c3e917
|
@ -54,15 +54,18 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
* and any 3 letter top-level domain (.com, .net, .org, etc.).</li>
|
* and any 3 letter top-level domain (.com, .net, .org, etc.).</li>
|
||||||
* <li><b>allowedMethods</b>, a comma separated list of HTTP methods that
|
* <li><b>allowedMethods</b>, a comma separated list of HTTP methods that
|
||||||
* are allowed to be used when accessing the resources. Default value is
|
* are allowed to be used when accessing the resources. Default value is
|
||||||
* <b>GET,POST</b></li>
|
* <b>GET,POST,HEAD</b></li>
|
||||||
* <li><b>allowedHeaders</b>, a comma separated list of HTTP headers that
|
* <li><b>allowedHeaders</b>, a comma separated list of HTTP headers that
|
||||||
* are allowed to be specified when accessing the resources. Default value
|
* are allowed to be specified when accessing the resources. Default value
|
||||||
* is <b>X-Requested-With</b></li>
|
* is <b>X-Requested-With,Content-Type,Accept,Origin</b></li>
|
||||||
* <li><b>preflightMaxAge</b>, the number of seconds that preflight requests
|
* <li><b>preflightMaxAge</b>, the number of seconds that preflight requests
|
||||||
* can be cached by the client. Default value is <b>1800</b> seconds, or 30
|
* can be cached by the client. Default value is <b>1800</b> seconds, or 30
|
||||||
* minutes</li>
|
* minutes</li>
|
||||||
* <li><b>allowCredentials</b>, a boolean indicating if the resource allows
|
* <li><b>allowCredentials</b>, a boolean indicating if the resource allows
|
||||||
* requests with credentials. Default value is <b>false</b></li>
|
* requests with credentials. Default value is <b>false</b></li>
|
||||||
|
* <li><b>exposeHeaders</b>, a comma separated list of HTTP headers that
|
||||||
|
* are allowed to be exposed on the client. Default value is the
|
||||||
|
* <b>empty list</b></li>
|
||||||
* </ul></p>
|
* </ul></p>
|
||||||
* <p>A typical configuration could be:
|
* <p>A typical configuration could be:
|
||||||
* <pre>
|
* <pre>
|
||||||
|
@ -79,8 +82,6 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
* ...
|
* ...
|
||||||
* </web-app>
|
* </web-app>
|
||||||
* </pre></p>
|
* </pre></p>
|
||||||
*
|
|
||||||
* @version $Revision$ $Date$
|
|
||||||
*/
|
*/
|
||||||
public class CrossOriginFilter implements Filter
|
public class CrossOriginFilter implements Filter
|
||||||
{
|
{
|
||||||
|
@ -96,12 +97,14 @@ public class CrossOriginFilter implements Filter
|
||||||
public static final String ACCESS_CONTROL_ALLOW_HEADERS_HEADER = "Access-Control-Allow-Headers";
|
public static final String ACCESS_CONTROL_ALLOW_HEADERS_HEADER = "Access-Control-Allow-Headers";
|
||||||
public static final String ACCESS_CONTROL_MAX_AGE_HEADER = "Access-Control-Max-Age";
|
public static final String ACCESS_CONTROL_MAX_AGE_HEADER = "Access-Control-Max-Age";
|
||||||
public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER = "Access-Control-Allow-Credentials";
|
public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER = "Access-Control-Allow-Credentials";
|
||||||
|
public static final String ACCESS_CONTROL_EXPOSE_HEADERS_HEADER = "Access-Control-Expose-Headers";
|
||||||
// Implementation constants
|
// Implementation constants
|
||||||
public static final String ALLOWED_ORIGINS_PARAM = "allowedOrigins";
|
public static final String ALLOWED_ORIGINS_PARAM = "allowedOrigins";
|
||||||
public static final String ALLOWED_METHODS_PARAM = "allowedMethods";
|
public static final String ALLOWED_METHODS_PARAM = "allowedMethods";
|
||||||
public static final String ALLOWED_HEADERS_PARAM = "allowedHeaders";
|
public static final String ALLOWED_HEADERS_PARAM = "allowedHeaders";
|
||||||
public static final String PREFLIGHT_MAX_AGE_PARAM = "preflightMaxAge";
|
public static final String PREFLIGHT_MAX_AGE_PARAM = "preflightMaxAge";
|
||||||
public static final String ALLOW_CREDENTIALS_PARAM = "allowCredentials";
|
public static final String ALLOW_CREDENTIALS_PARAM = "allowCredentials";
|
||||||
|
public static final String EXPOSED_HEADERS_PARAM = "exposedHeaders";
|
||||||
private static final String ANY_ORIGIN = "*";
|
private static final String ANY_ORIGIN = "*";
|
||||||
private static final List<String> SIMPLE_HTTP_METHODS = Arrays.asList("GET", "POST", "HEAD");
|
private static final List<String> SIMPLE_HTTP_METHODS = Arrays.asList("GET", "POST", "HEAD");
|
||||||
|
|
||||||
|
@ -109,6 +112,7 @@ public class CrossOriginFilter implements Filter
|
||||||
private List<String> allowedOrigins = new ArrayList<String>();
|
private List<String> allowedOrigins = new ArrayList<String>();
|
||||||
private List<String> allowedMethods = new ArrayList<String>();
|
private List<String> allowedMethods = new ArrayList<String>();
|
||||||
private List<String> allowedHeaders = new ArrayList<String>();
|
private List<String> allowedHeaders = new ArrayList<String>();
|
||||||
|
private List<String> exposedHeaders = new ArrayList<String>();
|
||||||
private int preflightMaxAge = 0;
|
private int preflightMaxAge = 0;
|
||||||
private boolean allowCredentials;
|
private boolean allowCredentials;
|
||||||
|
|
||||||
|
@ -163,6 +167,11 @@ public class CrossOriginFilter implements Filter
|
||||||
allowedCredentialsConfig = "true";
|
allowedCredentialsConfig = "true";
|
||||||
allowCredentials = Boolean.parseBoolean(allowedCredentialsConfig);
|
allowCredentials = Boolean.parseBoolean(allowedCredentialsConfig);
|
||||||
|
|
||||||
|
String exposedHeadersConfig = config.getInitParameter(EXPOSED_HEADERS_PARAM);
|
||||||
|
if (exposedHeadersConfig == null)
|
||||||
|
exposedHeadersConfig = "";
|
||||||
|
exposedHeaders.addAll(Arrays.asList(exposedHeadersConfig.split(",")));
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
{
|
{
|
||||||
LOG.debug("Cross-origin filter configuration: " +
|
LOG.debug("Cross-origin filter configuration: " +
|
||||||
|
@ -170,7 +179,9 @@ public class CrossOriginFilter implements Filter
|
||||||
ALLOWED_METHODS_PARAM + " = " + allowedMethodsConfig + ", " +
|
ALLOWED_METHODS_PARAM + " = " + allowedMethodsConfig + ", " +
|
||||||
ALLOWED_HEADERS_PARAM + " = " + allowedHeadersConfig + ", " +
|
ALLOWED_HEADERS_PARAM + " = " + allowedHeadersConfig + ", " +
|
||||||
PREFLIGHT_MAX_AGE_PARAM + " = " + preflightMaxAgeConfig + ", " +
|
PREFLIGHT_MAX_AGE_PARAM + " = " + preflightMaxAgeConfig + ", " +
|
||||||
ALLOW_CREDENTIALS_PARAM + " = " + allowedCredentialsConfig);
|
ALLOW_CREDENTIALS_PARAM + " = " + allowedCredentialsConfig + "," +
|
||||||
|
EXPOSED_HEADERS_PARAM + " = " + exposedHeadersConfig
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,6 +316,8 @@ public class CrossOriginFilter implements Filter
|
||||||
response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, origin);
|
response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, origin);
|
||||||
if (allowCredentials)
|
if (allowCredentials)
|
||||||
response.setHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true");
|
response.setHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true");
|
||||||
|
if (!exposedHeaders.isEmpty())
|
||||||
|
response.setHeader(ACCESS_CONTROL_EXPOSE_HEADERS_HEADER, commify(exposedHeaders));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handlePreflightResponse(HttpServletRequest request, HttpServletResponse response, String origin)
|
private void handlePreflightResponse(HttpServletRequest request, HttpServletResponse response, String origin)
|
||||||
|
|
|
@ -371,6 +371,27 @@ public class CrossOriginFilterTest
|
||||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleRequestWithExposedHeaders() throws Exception
|
||||||
|
{
|
||||||
|
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||||
|
filterHolder.setInitParameter("exposedHeaders", "Content-Length");
|
||||||
|
tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
|
||||||
|
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||||
|
|
||||||
|
String request = "" +
|
||||||
|
"GET / HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Origin: http://localhost\r\n" +
|
||||||
|
"\r\n";
|
||||||
|
String response = tester.getResponses(request);
|
||||||
|
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||||
|
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_EXPOSE_HEADERS_HEADER));
|
||||||
|
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
public static class ResourceServlet extends HttpServlet
|
public static class ResourceServlet extends HttpServlet
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
Loading…
Reference in New Issue