X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=third-party%2Forg.apache.catalina.filters.CorsFilter%2Fsrc%2Fmain%2Fjava%2Forg%2Fapache%2Fcatalina%2Ffilters%2FCorsFilter.java;fp=third-party%2Forg.apache.catalina.filters.CorsFilter%2Fsrc%2Fmain%2Fjava%2Forg%2Fapache%2Fcatalina%2Ffilters%2FCorsFilter.java;h=0000000000000000000000000000000000000000;hb=e1c04c5af263a9604a765f1ab98be51dfc51d8cb;hp=8069c9939c1971886838394ecff01929649e7937;hpb=a935ffda7f26be29de879a47b426d0db7a28d588;p=controller.git diff --git a/third-party/org.apache.catalina.filters.CorsFilter/src/main/java/org/apache/catalina/filters/CorsFilter.java b/third-party/org.apache.catalina.filters.CorsFilter/src/main/java/org/apache/catalina/filters/CorsFilter.java deleted file mode 100644 index 8069c9939c..0000000000 --- a/third-party/org.apache.catalina.filters.CorsFilter/src/main/java/org/apache/catalina/filters/CorsFilter.java +++ /dev/null @@ -1,1166 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.filters; - -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.filters.Constants; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -import org.apache.tomcat.util.res.StringManager; - -/** - *

- * A {@link Filter} that enable client-side cross-origin requests by - * implementing W3C's CORS (Cross-Origin Resource - * Sharing) specification for resources. Each {@link HttpServletRequest} - * request is inspected as per specification, and appropriate response headers - * are added to {@link HttpServletResponse}. - *

- * - *

- * By default, it also sets following request attributes, that help to - * determine the nature of the request downstream. - *

- *

- * - * @see CORS specification - * - */ -public final class CorsFilter implements Filter { - - private static final Log log = LogFactory.getLog(CorsFilter.class); - - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * A {@link Collection} of origins consisting of zero or more origins that - * are allowed access to the resource. - */ - private final Collection allowedOrigins; - - /** - * Determines if any origin is allowed to make request. - */ - private boolean anyOriginAllowed; - - /** - * A {@link Collection} of methods consisting of zero or more methods that - * are supported by the resource. - */ - private final Collection allowedHttpMethods; - - /** - * A {@link Collection} of headers consisting of zero or more header field - * names that are supported by the resource. - */ - private final Collection allowedHttpHeaders; - - /** - * A {@link Collection} of exposed headers consisting of zero or more header - * field names of headers other than the simple response headers that the - * resource might use and can be exposed. - */ - private final Collection exposedHeaders; - - /** - * A supports credentials flag that indicates whether the resource supports - * user credentials in the request. It is true when the resource does and - * false otherwise. - */ - private boolean supportsCredentials; - - /** - * Indicates (in seconds) how long the results of a pre-flight request can - * be cached in a pre-flight result cache. - */ - private long preflightMaxAge; - - /** - * Determines if the request should be decorated or not. - */ - private boolean decorateRequest; - - - public CorsFilter() { - this.allowedOrigins = new HashSet(); - this.allowedHttpMethods = new HashSet(); - this.allowedHttpHeaders = new HashSet(); - this.exposedHeaders = new HashSet(); - } - - - @Override - public void doFilter(final ServletRequest servletRequest, - final ServletResponse servletResponse, final FilterChain filterChain) - throws IOException, ServletException { - if (!(servletRequest instanceof HttpServletRequest) || - !(servletResponse instanceof HttpServletResponse)) { - throw new ServletException(sm.getString("corsFilter.onlyHttp")); - } - - // Safe to downcast at this point. - HttpServletRequest request = (HttpServletRequest) servletRequest; - HttpServletResponse response = (HttpServletResponse) servletResponse; - - // Determines the CORS request type. - CorsFilter.CORSRequestType requestType = checkRequestType(request); - - // Adds CORS specific attributes to request. - if (decorateRequest) { - CorsFilter.decorateCORSProperties(request, requestType); - } - switch (requestType) { - case SIMPLE: - // Handles a Simple CORS request. - this.handleSimpleCORS(request, response, filterChain); - break; - case ACTUAL: - // Handles an Actual CORS request. - this.handleSimpleCORS(request, response, filterChain); - break; - case PRE_FLIGHT: - // Handles a Pre-flight CORS request. - this.handlePreflightCORS(request, response, filterChain); - break; - case NOT_CORS: - // Handles a Normal request that is not a cross-origin request. - this.handleNonCORS(request, response, filterChain); - break; - default: - // Handles a CORS request that violates specification. - this.handleInvalidCORS(request, response, filterChain); - break; - } - } - - - @Override - public void init(final FilterConfig filterConfig) throws ServletException { - // Initialize defaults - parseAndStore(DEFAULT_ALLOWED_ORIGINS, DEFAULT_ALLOWED_HTTP_METHODS, - DEFAULT_ALLOWED_HTTP_HEADERS, DEFAULT_EXPOSED_HEADERS, - DEFAULT_SUPPORTS_CREDENTIALS, DEFAULT_PREFLIGHT_MAXAGE, - DEFAULT_DECORATE_REQUEST); - - if (filterConfig != null) { - String configAllowedOrigins = filterConfig - .getInitParameter(PARAM_CORS_ALLOWED_ORIGINS); - String configAllowedHttpMethods = filterConfig - .getInitParameter(PARAM_CORS_ALLOWED_METHODS); - String configAllowedHttpHeaders = filterConfig - .getInitParameter(PARAM_CORS_ALLOWED_HEADERS); - String configExposedHeaders = filterConfig - .getInitParameter(PARAM_CORS_EXPOSED_HEADERS); - String configSupportsCredentials = filterConfig - .getInitParameter(PARAM_CORS_SUPPORT_CREDENTIALS); - String configPreflightMaxAge = filterConfig - .getInitParameter(PARAM_CORS_PREFLIGHT_MAXAGE); - String configDecorateRequest = filterConfig - .getInitParameter(PARAM_CORS_REQUEST_DECORATE); - - parseAndStore(configAllowedOrigins, configAllowedHttpMethods, - configAllowedHttpHeaders, configExposedHeaders, - configSupportsCredentials, configPreflightMaxAge, - configDecorateRequest); - } - } - - - /** - * 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 Simple - * Cross-Origin Request, Actual Request, and Redirects - */ - protected 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)) { - throw new IllegalArgumentException( - sm.getString("corsFilter.wrongType2", - CorsFilter.CORSRequestType.SIMPLE, - CorsFilter.CORSRequestType.ACTUAL)); - } - - 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); - } - - - /** - * 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 - */ - protected 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( - sm.getString("corsFilter.wrongType1", - 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 accessControlRequestHeaders = new LinkedList(); - 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 request, that's not a CORS request, but is a valid request i.e. - * it is not a cross-origin request. This implementation, just forwards the - * request down the filter chain. - * - * @param request - * The {@link HttpServletRequest} object. - * @param response - * The {@link HttpServletResponse} object. - * @param filterChain - * The {@link FilterChain} object. - * @throws IOException - * @throws ServletException - */ - private void handleNonCORS(final HttpServletRequest request, - final HttpServletResponse response, final FilterChain filterChain) - throws IOException, ServletException { - // Let request pass. - filterChain.doFilter(request, response); - } - - - /** - * Handles a CORS request that violates specification. - * - * @param request - * The {@link HttpServletRequest} object. - * @param response - * The {@link HttpServletResponse} object. - * @param filterChain - * The {@link FilterChain} object. - */ - private void handleInvalidCORS(final HttpServletRequest request, - final HttpServletResponse response, final FilterChain filterChain) { - String origin = request.getHeader(CorsFilter.REQUEST_HEADER_ORIGIN); - String method = request.getMethod(); - String accessControlRequestHeaders = request.getHeader( - REQUEST_HEADER_ACCESS_CONTROL_REQUEST_HEADERS); - - response.setContentType("text/plain"); - response.setStatus(HttpServletResponse.SC_FORBIDDEN); - response.resetBuffer(); - - if (log.isDebugEnabled()) { - // Debug so no need for i18n - StringBuilder message = - new StringBuilder("Invalid CORS request; Origin="); - message.append(origin); - message.append(";Method="); - message.append(method); - if (accessControlRequestHeaders != null) { - message.append(";Access-Control-Request-Headers="); - message.append(accessControlRequestHeaders); - } - log.debug(message.toString()); - } - } - - - @Override - public void destroy() { - // NOOP - } - - - /** - * Decorates the {@link HttpServletRequest}, with CORS attributes. - *
    - *
  • cors.isCorsRequest: Flag to determine if request is a CORS - * request. Set to true if CORS request; false - * otherwise.
  • - *
  • cors.request.origin: The Origin URL.
  • - *
  • cors.request.type: Type of request. Values: - * simple or preflight or not_cors or - * invalid_cors
  • - *
  • cors.request.headers: Request headers sent as - * 'Access-Control-Request-Headers' header, for pre-flight request.
  • - *
- * - * @param request - * The {@link HttpServletRequest} object. - * @param corsRequestType - * The {@link CORSRequestType} object. - */ - protected static void decorateCORSProperties( - final HttpServletRequest request, - final CORSRequestType corsRequestType) { - if (request == null) { - throw new IllegalArgumentException( - sm.getString("corsFilter.nullRequest")); - } - - if (corsRequestType == null) { - throw new IllegalArgumentException( - sm.getString("corsFilter.nullRequestType")); - } - - switch (corsRequestType) { - case SIMPLE: - request.setAttribute( - CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST, - Boolean.TRUE); - request.setAttribute(CorsFilter.HTTP_REQUEST_ATTRIBUTE_ORIGIN, - request.getHeader(CorsFilter.REQUEST_HEADER_ORIGIN)); - request.setAttribute( - CorsFilter.HTTP_REQUEST_ATTRIBUTE_REQUEST_TYPE, - corsRequestType.name().toLowerCase()); - break; - case ACTUAL: - request.setAttribute( - CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST, - Boolean.TRUE); - request.setAttribute(CorsFilter.HTTP_REQUEST_ATTRIBUTE_ORIGIN, - request.getHeader(CorsFilter.REQUEST_HEADER_ORIGIN)); - request.setAttribute( - CorsFilter.HTTP_REQUEST_ATTRIBUTE_REQUEST_TYPE, - corsRequestType.name().toLowerCase()); - break; - case PRE_FLIGHT: - request.setAttribute( - CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST, - Boolean.TRUE); - request.setAttribute(CorsFilter.HTTP_REQUEST_ATTRIBUTE_ORIGIN, - request.getHeader(CorsFilter.REQUEST_HEADER_ORIGIN)); - request.setAttribute( - CorsFilter.HTTP_REQUEST_ATTRIBUTE_REQUEST_TYPE, - corsRequestType.name().toLowerCase()); - String headers = request.getHeader( - REQUEST_HEADER_ACCESS_CONTROL_REQUEST_HEADERS); - if (headers == null) { - headers = ""; - } - request.setAttribute( - CorsFilter.HTTP_REQUEST_ATTRIBUTE_REQUEST_HEADERS, headers); - break; - case NOT_CORS: - request.setAttribute( - CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST, - Boolean.FALSE); - break; - default: - // Don't set any attributes - break; - } - } - - - /** - * Joins elements of {@link Set} into a string, where each element is - * separated by the provided separator. - * - * @param elements - * The {@link Set} containing elements to join together. - * @param joinSeparator - * The character to be used for separating elements. - * @return The joined {@link String}; null if elements - * {@link Set} is null. - */ - protected static String join(final Collection elements, - final String joinSeparator) { - String separator = ","; - if (elements == null) { - return null; - } - if (joinSeparator != null) { - separator = joinSeparator; - } - StringBuilder buffer = new StringBuilder(); - boolean isFirst = true; - for (String element : elements) { - if (!isFirst) { - buffer.append(separator); - } else { - isFirst = false; - } - - if (element != null) { - buffer.append(element); - } - } - - return buffer.toString(); - } - - - /** - * Determines the request type. - * - * @param request - */ - protected CORSRequestType checkRequestType(final HttpServletRequest request) { - CORSRequestType requestType = CORSRequestType.INVALID_CORS; - if (request == null) { - throw new IllegalArgumentException( - sm.getString("corsFilter.nullRequest")); - } - String originHeader = request.getHeader(REQUEST_HEADER_ORIGIN); - // Section 6.1.1 and Section 6.2.1 - if (originHeader != null) { - if (originHeader.isEmpty()) { - requestType = CORSRequestType.INVALID_CORS; - } else if (!isValidOrigin(originHeader)) { - requestType = CORSRequestType.INVALID_CORS; - } else { - String method = request.getMethod(); - if (method != null && HTTP_METHODS.contains(method)) { - if ("OPTIONS".equals(method)) { - String accessControlRequestMethodHeader = - request.getHeader( - REQUEST_HEADER_ACCESS_CONTROL_REQUEST_METHOD); - if (accessControlRequestMethodHeader != null && - !accessControlRequestMethodHeader.isEmpty()) { - requestType = CORSRequestType.PRE_FLIGHT; - } else if (accessControlRequestMethodHeader != null && - accessControlRequestMethodHeader.isEmpty()) { - requestType = CORSRequestType.INVALID_CORS; - } else { - requestType = CORSRequestType.ACTUAL; - } - } else if ("GET".equals(method) || "HEAD".equals(method)) { - requestType = CORSRequestType.SIMPLE; - } else if ("POST".equals(method)) { - String contentType = request.getContentType(); - if (contentType != null) { - contentType = contentType.toLowerCase().trim(); - if (SIMPLE_HTTP_REQUEST_CONTENT_TYPE_VALUES - .contains(contentType)) { - requestType = CORSRequestType.SIMPLE; - } else { - requestType = CORSRequestType.ACTUAL; - } - } - } else if (COMPLEX_HTTP_METHODS.contains(method)) { - requestType = CORSRequestType.ACTUAL; - } - } - } - } else { - requestType = CORSRequestType.NOT_CORS; - } - - return requestType; - } - - - /** - * Checks if the Origin is allowed to make a CORS request. - * - * @param origin - * The Origin. - * @return true if origin is allowed; false - * otherwise. - */ - private boolean isOriginAllowed(final String origin) { - if (anyOriginAllowed) { - return true; - } - - // If 'Origin' header is a case-sensitive match of any of allowed - // origins, then return true, else return false. - return allowedOrigins.contains(origin); - } - - - /** - * Parses each param-value and populates configuration variables. If a param - * is provided, it overrides the default. - * - * @param allowedOrigins - * A {@link String} of comma separated origins. - * @param allowedHttpMethods - * A {@link String} of comma separated HTTP methods. - * @param allowedHttpHeaders - * A {@link String} of comma separated HTTP headers. - * @param exposedHeaders - * A {@link String} of comma separated headers that needs to be - * exposed. - * @param supportsCredentials - * "true" if support credentials needs to be enabled. - * @param preflightMaxAge - * The amount of seconds the user agent is allowed to cache the - * result of the pre-flight request. - * @throws ServletException - */ - private void parseAndStore(final String allowedOrigins, - final String allowedHttpMethods, final String allowedHttpHeaders, - final String exposedHeaders, final String supportsCredentials, - final String preflightMaxAge, final String decorateRequest) - throws ServletException { - if (allowedOrigins != null) { - if (allowedOrigins.trim().equals("*")) { - this.anyOriginAllowed = true; - } else { - this.anyOriginAllowed = false; - Set setAllowedOrigins = - parseStringToSet(allowedOrigins); - this.allowedOrigins.clear(); - this.allowedOrigins.addAll(setAllowedOrigins); - } - } - - if (allowedHttpMethods != null) { - Set setAllowedHttpMethods = - parseStringToSet(allowedHttpMethods); - this.allowedHttpMethods.clear(); - this.allowedHttpMethods.addAll(setAllowedHttpMethods); - } - - if (allowedHttpHeaders != null) { - Set setAllowedHttpHeaders = - parseStringToSet(allowedHttpHeaders); - Set lowerCaseHeaders = new HashSet(); - for (String header : setAllowedHttpHeaders) { - String lowerCase = header.toLowerCase(); - lowerCaseHeaders.add(lowerCase); - } - this.allowedHttpHeaders.clear(); - this.allowedHttpHeaders.addAll(lowerCaseHeaders); - } - - if (exposedHeaders != null) { - Set setExposedHeaders = parseStringToSet(exposedHeaders); - this.exposedHeaders.clear(); - this.exposedHeaders.addAll(setExposedHeaders); - } - - if (supportsCredentials != null) { - // For any value other then 'true' this will be false. - this.supportsCredentials = Boolean - .parseBoolean(supportsCredentials); - } - - if (preflightMaxAge != null) { - try { - if (!preflightMaxAge.isEmpty()) { - this.preflightMaxAge = Long.parseLong(preflightMaxAge); - } else { - this.preflightMaxAge = 0L; - } - } catch (NumberFormatException e) { - throw new ServletException( - sm.getString("corsFilter.invalidPreflightMaxAge"), e); - } - } - - if (decorateRequest != null) { - // For any value other then 'true' this will be false. - this.decorateRequest = Boolean.parseBoolean(decorateRequest); - } - } - - /** - * Takes a comma separated list and returns a Set. - * - * @param data - * A comma separated list of strings. - * @return Set - */ - private Set parseStringToSet(final String data) { - String[] splits; - - if (data != null && data.length() > 0) { - splits = data.split(","); - } else { - splits = new String[] {}; - } - - Set set = new HashSet(); - if (splits.length > 0) { - for (String split : splits) { - set.add(split.trim()); - } - } - - return set; - } - - - /** - * Checks if a given origin is valid or not. Criteria: - *
    - *
  • If an encoded character is present in origin, it's not valid.
  • - *
  • Origin should be a valid {@link URI}
  • - *
- * - * @param origin - * @see RFC952 - */ - protected static boolean isValidOrigin(String origin) { - // Checks for encoded characters. Helps prevent CRLF injection. - if (origin.contains("%")) { - return false; - } - - URI originURI; - - try { - originURI = new URI(origin); - } catch (URISyntaxException e) { - return false; - } - // If scheme for URI is null, return false. Return true otherwise. - return originURI.getScheme() != null; - - } - - - /** - * Determines if any origin is allowed to make CORS request. - * - * @return true if it's enabled; false otherwise. - */ - public boolean isAnyOriginAllowed() { - return anyOriginAllowed; - } - - - /** - * Returns a {@link Set} of headers that should be exposed by browser. - */ - public Collection getExposedHeaders() { - return exposedHeaders; - } - - - /** - * Determines is supports credentials is enabled. - */ - public boolean isSupportsCredentials() { - return supportsCredentials; - } - - - /** - * Returns the preflight response cache time in seconds. - * - * @return Time to cache in seconds. - */ - public long getPreflightMaxAge() { - return preflightMaxAge; - } - - - /** - * Returns the {@link Set} of allowed origins that are allowed to make - * requests. - * - * @return {@link Set} - */ - public Collection getAllowedOrigins() { - return allowedOrigins; - } - - - /** - * Returns a {@link Set} of HTTP methods that are allowed to make requests. - * - * @return {@link Set} - */ - public Collection getAllowedHttpMethods() { - return allowedHttpMethods; - } - - - /** - * Returns a {@link Set} of headers support by resource. - * - * @return {@link Set} - */ - public Collection getAllowedHttpHeaders() { - return allowedHttpHeaders; - } - - - // -------------------------------------------------- CORS Response Headers - /** - * The Access-Control-Allow-Origin header indicates whether a resource can - * be shared based by returning the value of the Origin request header in - * the response. - */ - public static final String RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN = - "Access-Control-Allow-Origin"; - - /** - * The Access-Control-Allow-Credentials header indicates whether the - * response to request can be exposed when the omit credentials flag is - * unset. When part of the response to a preflight request it indicates that - * the actual request can include user credentials. - */ - public static final String RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS = - "Access-Control-Allow-Credentials"; - - /** - * The Access-Control-Expose-Headers header indicates which headers are safe - * to expose to the API of a CORS API specification - */ - public static final String RESPONSE_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS = - "Access-Control-Expose-Headers"; - - /** - * The Access-Control-Max-Age header indicates how long the results of a - * preflight request can be cached in a preflight result cache. - */ - public static final String RESPONSE_HEADER_ACCESS_CONTROL_MAX_AGE = - "Access-Control-Max-Age"; - - /** - * The Access-Control-Allow-Methods header indicates, as part of the - * response to a preflight request, which methods can be used during the - * actual request. - */ - public static final String RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_METHODS = - "Access-Control-Allow-Methods"; - - /** - * The Access-Control-Allow-Headers header indicates, as part of the - * response to a preflight request, which header field names can be used - * during the actual request. - */ - public static final String RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_HEADERS = - "Access-Control-Allow-Headers"; - - // -------------------------------------------------- CORS Request Headers - /** - * The Origin header indicates where the cross-origin request or preflight - * request originates from. - */ - public static final String REQUEST_HEADER_ORIGIN = "Origin"; - - /** - * The Access-Control-Request-Method header indicates which method will be - * used in the actual request as part of the preflight request. - */ - public static final String REQUEST_HEADER_ACCESS_CONTROL_REQUEST_METHOD = - "Access-Control-Request-Method"; - - /** - * The Access-Control-Request-Headers header indicates which headers will be - * used in the actual request as part of the preflight request. - */ - public static final String REQUEST_HEADER_ACCESS_CONTROL_REQUEST_HEADERS = - "Access-Control-Request-Headers"; - - // ----------------------------------------------------- Request attributes - /** - * The prefix to a CORS request attribute. - */ - public static final String HTTP_REQUEST_ATTRIBUTE_PREFIX = "cors."; - - /** - * Attribute that contains the origin of the request. - */ - public static final String HTTP_REQUEST_ATTRIBUTE_ORIGIN = - HTTP_REQUEST_ATTRIBUTE_PREFIX + "request.origin"; - - /** - * Boolean value, suggesting if the request is a CORS request or not. - */ - public static final String HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST = - HTTP_REQUEST_ATTRIBUTE_PREFIX + "isCorsRequest"; - - /** - * Type of CORS request, of type {@link CORSRequestType}. - */ - public static final String HTTP_REQUEST_ATTRIBUTE_REQUEST_TYPE = - HTTP_REQUEST_ATTRIBUTE_PREFIX + "request.type"; - - /** - * Request headers sent as 'Access-Control-Request-Headers' header, for - * pre-flight request. - */ - public static final String HTTP_REQUEST_ATTRIBUTE_REQUEST_HEADERS = - HTTP_REQUEST_ATTRIBUTE_PREFIX + "request.headers"; - - // -------------------------------------------------------------- Constants - /** - * Enumerates varies types of CORS requests. Also, provides utility methods - * to determine the request type. - */ - protected static enum CORSRequestType { - /** - * A simple HTTP request, i.e. it shouldn't be pre-flighted. - */ - SIMPLE, - /** - * A HTTP request that needs to be pre-flighted. - */ - ACTUAL, - /** - * A pre-flight CORS request, to get meta information, before a - * non-simple HTTP request is sent. - */ - PRE_FLIGHT, - /** - * Not a CORS request, but a normal request. - */ - NOT_CORS, - /** - * An invalid CORS request, i.e. it qualifies to be a CORS request, but - * fails to be a valid one. - */ - INVALID_CORS - } - - /** - * {@link Collection} of HTTP methods. Case sensitive. - * - * @see http://tools.ietf.org/html/rfc2616#section-5.1.1 - * - */ - public static final Collection HTTP_METHODS = - new HashSet(Arrays.asList("OPTIONS", "GET", "HEAD", "POST", - "PUT", "DELETE", "TRACE", "CONNECT")); - /** - * {@link Collection} of non-simple HTTP methods. Case sensitive. - */ - public static final Collection COMPLEX_HTTP_METHODS = - new HashSet(Arrays.asList("PUT", "DELETE", "TRACE", - "CONNECT")); - /** - * {@link Collection} of Simple HTTP methods. Case sensitive. - * - * @see http://www.w3.org/TR/cors/#terminology - */ - public static final Collection SIMPLE_HTTP_METHODS = - new HashSet(Arrays.asList("GET", "POST", "HEAD")); - - /** - * {@link Collection} of Simple HTTP request headers. Case in-sensitive. - * - * @see http://www.w3.org/TR/cors/#terminology - */ - public static final Collection SIMPLE_HTTP_REQUEST_HEADERS = - new HashSet(Arrays.asList("Accept", "Accept-Language", - "Content-Language")); - - /** - * {@link Collection} of Simple HTTP request headers. Case in-sensitive. - * - * @see http://www.w3.org/TR/cors/#terminology - */ - public static final Collection SIMPLE_HTTP_RESPONSE_HEADERS = - new HashSet(Arrays.asList("Cache-Control", - "Content-Language", "Content-Type", "Expires", - "Last-Modified", "Pragma")); - - /** - * {@link Collection} of Simple HTTP request headers. Case in-sensitive. - * - * @see http://www.w3.org/TR/cors/#terminology - */ - public static final Collection SIMPLE_HTTP_REQUEST_CONTENT_TYPE_VALUES = - new HashSet(Arrays.asList( - "application/x-www-form-urlencoded", - "multipart/form-data", "text/plain")); - - // ------------------------------------------------ Configuration Defaults - /** - * By default, all origins are allowed to make requests. - */ - public static final String DEFAULT_ALLOWED_ORIGINS = "*"; - - /** - * By default, following methods are supported: GET, POST, HEAD and OPTIONS. - */ - public static final String DEFAULT_ALLOWED_HTTP_METHODS = - "GET,POST,HEAD,OPTIONS"; - - /** - * By default, time duration to cache pre-flight response is 30 mins. - */ - public static final String DEFAULT_PREFLIGHT_MAXAGE = "1800"; - - /** - * By default, support credentials is turned on. - */ - public static final String DEFAULT_SUPPORTS_CREDENTIALS = "true"; - - /** - * By default, following headers are supported: - * Origin,Accept,X-Requested-With, Content-Type, - * Access-Control-Request-Method, and Access-Control-Request-Headers. - */ - public static final String DEFAULT_ALLOWED_HTTP_HEADERS = - "Origin,Accept,X-Requested-With,Content-Type," + - "Access-Control-Request-Method,Access-Control-Request-Headers"; - - /** - * By default, none of the headers are exposed in response. - */ - public static final String DEFAULT_EXPOSED_HEADERS = ""; - - /** - * By default, request is decorated with CORS attributes. - */ - public static final String DEFAULT_DECORATE_REQUEST = "true"; - - // ----------------------------------------Filter Config Init param-name(s) - /** - * Key to retrieve allowed origins from {@link FilterConfig}. - */ - public static final String PARAM_CORS_ALLOWED_ORIGINS = - "cors.allowed.origins"; - - /** - * Key to retrieve support credentials from {@link FilterConfig}. - */ - public static final String PARAM_CORS_SUPPORT_CREDENTIALS = - "cors.support.credentials"; - - /** - * Key to retrieve exposed headers from {@link FilterConfig}. - */ - public static final String PARAM_CORS_EXPOSED_HEADERS = - "cors.exposed.headers"; - - /** - * Key to retrieve allowed headers from {@link FilterConfig}. - */ - public static final String PARAM_CORS_ALLOWED_HEADERS = - "cors.allowed.headers"; - - /** - * Key to retrieve allowed methods from {@link FilterConfig}. - */ - public static final String PARAM_CORS_ALLOWED_METHODS = - "cors.allowed.methods"; - - /** - * Key to retrieve preflight max age from {@link FilterConfig}. - */ - public static final String PARAM_CORS_PREFLIGHT_MAXAGE = - "cors.preflight.maxage"; - - /** - * Key to determine if request should be decorated. - */ - public static final String PARAM_CORS_REQUEST_DECORATE = - "cors.request.decorate"; -}