/** * Handles CORS pre-flight request. * * @param request The {@link HttpServletRequest} object. * @param response The {@link HttpServletResponse} object. * @param filterChain The {@link FilterChain} object. * @throws IOException * @throws ServletException */ public void handlePreflightCORS( final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws IOException, ServletException { CORSRequestType requestType = checkRequestType(request); if (requestType != CORSRequestType.PRE_FLIGHT) { throw new IllegalArgumentException( "Expects a HttpServletRequest object of type " + CORSRequestType.PRE_FLIGHT.name().toLowerCase()); } final String origin = request.getHeader(CORSFilter.REQUEST_HEADER_ORIGIN); // Section 6.2.2 if (!isOriginAllowed(origin)) { handleInvalidCORS(request, response, filterChain); return; } // Section 6.2.3 String accessControlRequestMethod = request.getHeader(CORSFilter.REQUEST_HEADER_ACCESS_CONTROL_REQUEST_METHOD); if (accessControlRequestMethod == null || (!HTTP_METHODS.contains(accessControlRequestMethod.trim()))) { handleInvalidCORS(request, response, filterChain); return; } else { accessControlRequestMethod = accessControlRequestMethod.trim(); } // Section 6.2.4 String accessControlRequestHeadersHeader = request.getHeader(CORSFilter.REQUEST_HEADER_ACCESS_CONTROL_REQUEST_HEADERS); List<String> accessControlRequestHeaders = new LinkedList<String>(); if (accessControlRequestHeadersHeader != null && !accessControlRequestHeadersHeader.trim().isEmpty()) { String[] headers = accessControlRequestHeadersHeader.trim().split(","); for (String header : headers) { accessControlRequestHeaders.add(header.trim().toLowerCase()); } } // Section 6.2.5 if (!allowedHttpMethods.contains(accessControlRequestMethod)) { handleInvalidCORS(request, response, filterChain); return; } // Section 6.2.6 if (!accessControlRequestHeaders.isEmpty()) { for (String header : accessControlRequestHeaders) { if (!allowedHttpHeaders.contains(header)) { handleInvalidCORS(request, response, filterChain); return; } } } // Section 6.2.7 if (supportsCredentials) { response.addHeader(CORSFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, origin); response.addHeader(CORSFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); } else { if (anyOriginAllowed) { response.addHeader(CORSFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*"); } else { response.addHeader(CORSFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, origin); } } // Section 6.2.8 if (preflightMaxAge > 0) { response.addHeader( CORSFilter.RESPONSE_HEADER_ACCESS_CONTROL_MAX_AGE, String.valueOf(preflightMaxAge)); } // Section 6.2.9 response.addHeader( CORSFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_METHODS, accessControlRequestMethod); // Section 6.2.10 if ((allowedHttpHeaders != null) && (!allowedHttpHeaders.isEmpty())) { response.addHeader( CORSFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_HEADERS, join(allowedHttpHeaders, ",")); } // Do not forward the request down the filter chain. }
/** * Handles a CORS request of type {@link CORSRequestType}.SIMPLE. * * @param request The {@link HttpServletRequest} object. * @param response The {@link HttpServletResponse} object. * @param filterChain The {@link FilterChain} object. * @throws IOException * @throws ServletException * @see <a href="http://www.w3.org/TR/cors/#resource-requests">Simple Cross-Origin Request, Actual * Request, and Redirects</a> */ public void handleSimpleCORS( final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws IOException, ServletException { CORSFilter.CORSRequestType requestType = checkRequestType(request); if (!(requestType == CORSFilter.CORSRequestType.SIMPLE || requestType == CORSFilter.CORSRequestType.ACTUAL)) { String message = "Expects a HttpServletRequest object of type " + CORSFilter.CORSRequestType.SIMPLE + " or " + CORSFilter.CORSRequestType.ACTUAL; throw new IllegalArgumentException(message); } final String origin = request.getHeader(CORSFilter.REQUEST_HEADER_ORIGIN); final String method = request.getMethod(); // Section 6.1.2 if (!isOriginAllowed(origin)) { handleInvalidCORS(request, response, filterChain); return; } if (!allowedHttpMethods.contains(method)) { handleInvalidCORS(request, response, filterChain); return; } // Section 6.1.3 // Add a single Access-Control-Allow-Origin header. if (anyOriginAllowed && !supportsCredentials) { // If resource doesn't support credentials and if any origin is // allowed // to make CORS request, return header with '*'. response.addHeader(CORSFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*"); } else { // If the resource supports credentials add a single // Access-Control-Allow-Origin header, with the value of the Origin // header as value. response.addHeader(CORSFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, origin); } // Section 6.1.3 // If the resource supports credentials, add a single // Access-Control-Allow-Credentials header with the case-sensitive // string "true" as value. if (supportsCredentials) { response.addHeader(CORSFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); } // Section 6.1.4 // If the list of exposed headers is not empty add one or more // Access-Control-Expose-Headers headers, with as values the header // field names given in the list of exposed headers. if ((exposedHeaders != null) && (exposedHeaders.size() > 0)) { String exposedHeadersString = join(exposedHeaders, ","); response.addHeader( CORSFilter.RESPONSE_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS, exposedHeadersString); } // Forward the request down the filter chain. filterChain.doFilter(request, response); }