Extract the builder of CorsConfig to top level
Motivation: Consistency in API design Modifications: - Deprecate CorsConfig.Builder and its factory methods - Deprecate CorsConfig.DateValueGenerator - Add CorsConfigBuilder and its factory methods - Fix typo (curcuit -> circuit) Result: Consistency with other builder APIs such as SslContextBuilder and Http2ConnectionHandlerBuilder
This commit is contained in:
parent
b62c5290ed
commit
412f719aa8
@ -17,16 +17,12 @@ package io.netty.handler.codec.http.cors;
|
|||||||
|
|
||||||
import io.netty.handler.codec.http.DefaultHttpHeaders;
|
import io.netty.handler.codec.http.DefaultHttpHeaders;
|
||||||
import io.netty.handler.codec.http.EmptyHttpHeaders;
|
import io.netty.handler.codec.http.EmptyHttpHeaders;
|
||||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
|
||||||
import io.netty.handler.codec.http.HttpHeaders;
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
import io.netty.handler.codec.http.HttpMethod;
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
import io.netty.util.internal.StringUtil;
|
import io.netty.util.internal.StringUtil;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@ -48,9 +44,9 @@ public final class CorsConfig {
|
|||||||
private final Set<String> allowedRequestHeaders;
|
private final Set<String> allowedRequestHeaders;
|
||||||
private final boolean allowNullOrigin;
|
private final boolean allowNullOrigin;
|
||||||
private final Map<CharSequence, Callable<?>> preflightHeaders;
|
private final Map<CharSequence, Callable<?>> preflightHeaders;
|
||||||
private final boolean shortCurcuit;
|
private final boolean shortCircuit;
|
||||||
|
|
||||||
private CorsConfig(final Builder builder) {
|
CorsConfig(final CorsConfigBuilder builder) {
|
||||||
origins = new LinkedHashSet<String>(builder.origins);
|
origins = new LinkedHashSet<String>(builder.origins);
|
||||||
anyOrigin = builder.anyOrigin;
|
anyOrigin = builder.anyOrigin;
|
||||||
enabled = builder.enabled;
|
enabled = builder.enabled;
|
||||||
@ -61,7 +57,7 @@ public final class CorsConfig {
|
|||||||
allowedRequestHeaders = builder.requestHeaders;
|
allowedRequestHeaders = builder.requestHeaders;
|
||||||
allowNullOrigin = builder.allowNullOrigin;
|
allowNullOrigin = builder.allowNullOrigin;
|
||||||
preflightHeaders = builder.preflightHeaders;
|
preflightHeaders = builder.preflightHeaders;
|
||||||
shortCurcuit = builder.shortCurcuit;
|
shortCircuit = builder.shortCircuit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -227,8 +223,16 @@ public final class CorsConfig {
|
|||||||
*
|
*
|
||||||
* @return {@code true} if a CORS request should short-curcuit upon receiving an invalid Origin header.
|
* @return {@code true} if a CORS request should short-curcuit upon receiving an invalid Origin header.
|
||||||
*/
|
*/
|
||||||
|
public boolean isShortCircuit() {
|
||||||
|
return shortCircuit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #isShortCircuit()} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public boolean isShortCurcuit() {
|
public boolean isShortCurcuit() {
|
||||||
return shortCurcuit;
|
return isShortCircuit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> T getValue(final Callable<T> callable) {
|
private static <T> T getValue(final Callable<T> callable) {
|
||||||
@ -253,19 +257,17 @@ public final class CorsConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Builder instance with it's origin set to '*'.
|
* @deprecated Use {@link CorsConfigBuilder#forAnyOrigin()} instead.
|
||||||
*
|
|
||||||
* @return Builder to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static Builder withAnyOrigin() {
|
public static Builder withAnyOrigin() {
|
||||||
return new Builder();
|
return new Builder();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link Builder} instance with the specified origin.
|
* @deprecated Use {@link CorsConfigBuilder#forOrigin(String)} instead.
|
||||||
*
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static Builder withOrigin(final String origin) {
|
public static Builder withOrigin(final String origin) {
|
||||||
if ("*".equals(origin)) {
|
if ("*".equals(origin)) {
|
||||||
return new Builder();
|
return new Builder();
|
||||||
@ -274,297 +276,158 @@ public final class CorsConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link Builder} instance with the specified origins.
|
* @deprecated Use {@link CorsConfigBuilder#forOrigins(String...)} instead.
|
||||||
*
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static Builder withOrigins(final String... origins) {
|
public static Builder withOrigins(final String... origins) {
|
||||||
return new Builder(origins);
|
return new Builder(origins);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder used to configure and build a CorsConfig instance.
|
* @deprecated Use {@link CorsConfigBuilder} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|
||||||
private final Set<String> origins;
|
private final CorsConfigBuilder builder;
|
||||||
private final boolean anyOrigin;
|
|
||||||
private boolean allowNullOrigin;
|
|
||||||
private boolean enabled = true;
|
|
||||||
private boolean allowCredentials;
|
|
||||||
private final Set<String> exposeHeaders = new HashSet<String>();
|
|
||||||
private long maxAge;
|
|
||||||
private final Set<HttpMethod> requestMethods = new HashSet<HttpMethod>();
|
|
||||||
private final Set<String> requestHeaders = new HashSet<String>();
|
|
||||||
private final Map<CharSequence, Callable<?>> preflightHeaders = new HashMap<CharSequence, Callable<?>>();
|
|
||||||
private boolean noPreflightHeaders;
|
|
||||||
private boolean shortCurcuit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Builder instance with the origin passed in.
|
* @deprecated Use {@link CorsConfigBuilder} instead.
|
||||||
*
|
|
||||||
* @param origins the origin to be used for this builder.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder(final String... origins) {
|
public Builder(final String... origins) {
|
||||||
this.origins = new LinkedHashSet<String>(Arrays.asList(origins));
|
builder = new CorsConfigBuilder(origins);
|
||||||
anyOrigin = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Builder instance allowing any origin, "*" which is the
|
* @deprecated Use {@link CorsConfigBuilder} instead.
|
||||||
* wildcard origin.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder() {
|
public Builder() {
|
||||||
anyOrigin = true;
|
builder = new CorsConfigBuilder();
|
||||||
origins = Collections.emptySet();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Web browsers may set the 'Origin' request header to 'null' if a resource is loaded
|
* @deprecated Use {@link CorsConfigBuilder#allowNullOrigin()} instead.
|
||||||
* from the local file system. Calling this method will enable a successful CORS response
|
|
||||||
* with a wildcard for the the CORS response header 'Access-Control-Allow-Origin'.
|
|
||||||
*
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder allowNullOrigin() {
|
public Builder allowNullOrigin() {
|
||||||
allowNullOrigin = true;
|
builder.allowNullOrigin();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disables CORS support.
|
* @deprecated Use {@link CorsConfigBuilder#disable()} instead.
|
||||||
*
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder disable() {
|
public Builder disable() {
|
||||||
enabled = false;
|
builder.disable();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the headers to be exposed to calling clients.
|
* @deprecated Use {@link CorsConfigBuilder#exposeHeaders(String...)} instead.
|
||||||
*
|
|
||||||
* During a simple CORS request, only certain response headers are made available by the
|
|
||||||
* browser, for example using:
|
|
||||||
* <pre>
|
|
||||||
* xhr.getResponseHeader("Content-Type");
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* The headers that are available by default are:
|
|
||||||
* <ul>
|
|
||||||
* <li>Cache-Control</li>
|
|
||||||
* <li>Content-Language</li>
|
|
||||||
* <li>Content-Type</li>
|
|
||||||
* <li>Expires</li>
|
|
||||||
* <li>Last-Modified</li>
|
|
||||||
* <li>Pragma</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* To expose other headers they need to be specified which is what this method enables by
|
|
||||||
* adding the headers to the CORS 'Access-Control-Expose-Headers' response header.
|
|
||||||
*
|
|
||||||
* @param headers the values to be added to the 'Access-Control-Expose-Headers' response header
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder exposeHeaders(final String... headers) {
|
public Builder exposeHeaders(final String... headers) {
|
||||||
exposeHeaders.addAll(Arrays.asList(headers));
|
builder.exposeHeaders(headers);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* By default cookies are not included in CORS requests, but this method will enable cookies to
|
* @deprecated Use {@link CorsConfigBuilder#allowCredentials()} instead.
|
||||||
* be added to CORS requests. Calling this method will set the CORS 'Access-Control-Allow-Credentials'
|
|
||||||
* response header to true.
|
|
||||||
*
|
|
||||||
* Please note, that cookie support needs to be enabled on the client side as well.
|
|
||||||
* The client needs to opt-in to send cookies by calling:
|
|
||||||
* <pre>
|
|
||||||
* xhr.withCredentials = true;
|
|
||||||
* </pre>
|
|
||||||
* The default value for 'withCredentials' is false in which case no cookies are sent.
|
|
||||||
* Settning this to true will included cookies in cross origin requests.
|
|
||||||
*
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder allowCredentials() {
|
public Builder allowCredentials() {
|
||||||
allowCredentials = true;
|
builder.allowCredentials();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When making a preflight request the client has to perform two request with can be inefficient.
|
* @deprecated Use {@link CorsConfigBuilder#maxAge(long)} instead.
|
||||||
* This setting will set the CORS 'Access-Control-Max-Age' response header and enables the
|
|
||||||
* caching of the preflight response for the specified time. During this time no preflight
|
|
||||||
* request will be made.
|
|
||||||
*
|
|
||||||
* @param max the maximum time, in seconds, that the preflight response may be cached.
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder maxAge(final long max) {
|
public Builder maxAge(final long max) {
|
||||||
maxAge = max;
|
builder.maxAge(max);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the allowed set of HTTP Request Methods that should be returned in the
|
* @deprecated Use {@link CorsConfigBuilder#allowedRequestMethods(HttpMethod...)} instead.
|
||||||
* CORS 'Access-Control-Request-Method' response header.
|
|
||||||
*
|
|
||||||
* @param methods the {@link HttpMethod}s that should be allowed.
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder allowedRequestMethods(final HttpMethod... methods) {
|
public Builder allowedRequestMethods(final HttpMethod... methods) {
|
||||||
requestMethods.addAll(Arrays.asList(methods));
|
builder.allowedRequestMethods(methods);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the if headers that should be returned in the CORS 'Access-Control-Allow-Headers'
|
* @deprecated Use {@link CorsConfigBuilder#allowedRequestHeaders(String...)} instead.
|
||||||
* response header.
|
|
||||||
*
|
|
||||||
* If a client specifies headers on the request, for example by calling:
|
|
||||||
* <pre>
|
|
||||||
* xhr.setRequestHeader('My-Custom-Header', "SomeValue");
|
|
||||||
* </pre>
|
|
||||||
* the server will recieve the above header name in the 'Access-Control-Request-Headers' of the
|
|
||||||
* preflight request. The server will then decide if it allows this header to be sent for the
|
|
||||||
* real request (remember that a preflight is not the real request but a request asking the server
|
|
||||||
* if it allow a request).
|
|
||||||
*
|
|
||||||
* @param headers the headers to be added to the preflight 'Access-Control-Allow-Headers' response header.
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder allowedRequestHeaders(final String... headers) {
|
public Builder allowedRequestHeaders(final String... headers) {
|
||||||
requestHeaders.addAll(Arrays.asList(headers));
|
builder.allowedRequestHeaders(headers);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns HTTP response headers that should be added to a CORS preflight response.
|
* @deprecated Use {@link CorsConfigBuilder#preflightResponseHeader(CharSequence, Object...)} instead.
|
||||||
*
|
|
||||||
* An intermediary like a load balancer might require that a CORS preflight request
|
|
||||||
* have certain headers set. This enables such headers to be added.
|
|
||||||
*
|
|
||||||
* @param name the name of the HTTP header.
|
|
||||||
* @param values the values for the HTTP header.
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder preflightResponseHeader(final CharSequence name, final Object... values) {
|
public Builder preflightResponseHeader(final CharSequence name, final Object... values) {
|
||||||
if (values.length == 1) {
|
builder.preflightResponseHeader(name, values);
|
||||||
preflightHeaders.put(name, new ConstantValueGenerator(values[0]));
|
|
||||||
} else {
|
|
||||||
preflightResponseHeader(name, Arrays.asList(values));
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns HTTP response headers that should be added to a CORS preflight response.
|
* @deprecated Use {@link CorsConfigBuilder#preflightResponseHeader(CharSequence, Iterable)} instead.
|
||||||
*
|
|
||||||
* An intermediary like a load balancer might require that a CORS preflight request
|
|
||||||
* have certain headers set. This enables such headers to be added.
|
|
||||||
*
|
|
||||||
* @param name the name of the HTTP header.
|
|
||||||
* @param value the values for the HTTP header.
|
|
||||||
* @param <T> the type of values that the Iterable contains.
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public <T> Builder preflightResponseHeader(final CharSequence name, final Iterable<T> value) {
|
public <T> Builder preflightResponseHeader(final CharSequence name, final Iterable<T> value) {
|
||||||
preflightHeaders.put(name, new ConstantValueGenerator(value));
|
builder.preflightResponseHeader(name, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns HTTP response headers that should be added to a CORS preflight response.
|
* @deprecated Use {@link CorsConfigBuilder#preflightResponseHeader(CharSequence, Callable)} instead.
|
||||||
*
|
|
||||||
* An intermediary like a load balancer might require that a CORS preflight request
|
|
||||||
* have certain headers set. This enables such headers to be added.
|
|
||||||
*
|
|
||||||
* Some values must be dynamically created when the HTTP response is created, for
|
|
||||||
* example the 'Date' response header. This can be occomplished by using a Callable
|
|
||||||
* which will have its 'call' method invoked when the HTTP response is created.
|
|
||||||
*
|
|
||||||
* @param name the name of the HTTP header.
|
|
||||||
* @param valueGenerator a Callable which will be invoked at HTTP response creation.
|
|
||||||
* @param <T> the type of the value that the Callable can return.
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public <T> Builder preflightResponseHeader(final String name, final Callable<T> valueGenerator) {
|
public <T> Builder preflightResponseHeader(final String name, final Callable<T> valueGenerator) {
|
||||||
preflightHeaders.put(name, valueGenerator);
|
builder.preflightResponseHeader(name, valueGenerator);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies that no preflight response headers should be added to a preflight response.
|
* @deprecated Use {@link CorsConfigBuilder#noPreflightResponseHeaders()} instead.
|
||||||
*
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder noPreflightResponseHeaders() {
|
public Builder noPreflightResponseHeaders() {
|
||||||
noPreflightHeaders = true;
|
builder.noPreflightResponseHeaders();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a {@link CorsConfig} with settings specified by previous method calls.
|
* @deprecated Use {@link CorsConfigBuilder#build()} instead.
|
||||||
*
|
|
||||||
* @return {@link CorsConfig} the configured CorsConfig instance.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public CorsConfig build() {
|
public CorsConfig build() {
|
||||||
if (preflightHeaders.isEmpty() && !noPreflightHeaders) {
|
return builder.build();
|
||||||
preflightHeaders.put(HttpHeaderNames.DATE, new DateValueGenerator());
|
|
||||||
preflightHeaders.put(HttpHeaderNames.CONTENT_LENGTH, new ConstantValueGenerator("0"));
|
|
||||||
}
|
|
||||||
return new CorsConfig(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies that a CORS request should be rejected if it's invalid before being
|
* @deprecated Use {@link CorsConfigBuilder#shortCircuit()} instead.
|
||||||
* further processing.
|
|
||||||
*
|
|
||||||
* CORS headers are set after a request is processed. This may not always be desired
|
|
||||||
* and this setting will check that the Origin is valid and if it is not valid no
|
|
||||||
* further processing will take place, and a error will be returned to the calling client.
|
|
||||||
*
|
|
||||||
* @return {@link Builder} to support method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder shortCurcuit() {
|
public Builder shortCurcuit() {
|
||||||
shortCurcuit = true;
|
builder.shortCircuit();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used for preflight HTTP response values that do not need to be
|
* @deprecated Removed without alternatives.
|
||||||
* generated, but instead the value is "static" in that the same value will be returned
|
|
||||||
* for each call.
|
|
||||||
*/
|
|
||||||
private static final class ConstantValueGenerator implements Callable<Object> {
|
|
||||||
|
|
||||||
private final Object value;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sole constructor.
|
|
||||||
*
|
|
||||||
* @param value the value that will be returned when the call method is invoked.
|
|
||||||
*/
|
|
||||||
private ConstantValueGenerator(final Object value) {
|
|
||||||
if (value == null) {
|
|
||||||
throw new IllegalArgumentException("value must not be null");
|
|
||||||
}
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object call() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This callable is used for the DATE preflight HTTP response HTTP header.
|
|
||||||
* It's value must be generated when the response is generated, hence will be
|
|
||||||
* different for every call.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static final class DateValueGenerator implements Callable<Date> {
|
public static final class DateValueGenerator implements Callable<Date> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -572,5 +435,4 @@ public final class CorsConfig {
|
|||||||
return new Date();
|
return new Date();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,352 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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 io.netty.handler.codec.http.cors;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||||
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder used to configure and build a {@link CorsConfig} instance.
|
||||||
|
*/
|
||||||
|
public final class CorsConfigBuilder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Builder instance with it's origin set to '*'.
|
||||||
|
*
|
||||||
|
* @return Builder to support method chaining.
|
||||||
|
*/
|
||||||
|
public static CorsConfigBuilder forAnyOrigin() {
|
||||||
|
return new CorsConfigBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link CorsConfigBuilder} instance with the specified origin.
|
||||||
|
*
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public static CorsConfigBuilder forOrigin(final String origin) {
|
||||||
|
if ("*".equals(origin)) {
|
||||||
|
return new CorsConfigBuilder();
|
||||||
|
}
|
||||||
|
return new CorsConfigBuilder(origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link CorsConfigBuilder} instance with the specified origins.
|
||||||
|
*
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public static CorsConfigBuilder forOrigins(final String... origins) {
|
||||||
|
return new CorsConfigBuilder(origins);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Set<String> origins;
|
||||||
|
final boolean anyOrigin;
|
||||||
|
boolean allowNullOrigin;
|
||||||
|
boolean enabled = true;
|
||||||
|
boolean allowCredentials;
|
||||||
|
final Set<String> exposeHeaders = new HashSet<String>();
|
||||||
|
long maxAge;
|
||||||
|
final Set<HttpMethod> requestMethods = new HashSet<HttpMethod>();
|
||||||
|
final Set<String> requestHeaders = new HashSet<String>();
|
||||||
|
final Map<CharSequence, Callable<?>> preflightHeaders = new HashMap<CharSequence, Callable<?>>();
|
||||||
|
private boolean noPreflightHeaders;
|
||||||
|
boolean shortCircuit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Builder instance with the origin passed in.
|
||||||
|
*
|
||||||
|
* @param origins the origin to be used for this builder.
|
||||||
|
*/
|
||||||
|
CorsConfigBuilder(final String... origins) {
|
||||||
|
this.origins = new LinkedHashSet<String>(Arrays.asList(origins));
|
||||||
|
anyOrigin = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Builder instance allowing any origin, "*" which is the
|
||||||
|
* wildcard origin.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
CorsConfigBuilder() {
|
||||||
|
anyOrigin = true;
|
||||||
|
origins = Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web browsers may set the 'Origin' request header to 'null' if a resource is loaded
|
||||||
|
* from the local file system. Calling this method will enable a successful CORS response
|
||||||
|
* with a wildcard for the the CORS response header 'Access-Control-Allow-Origin'.
|
||||||
|
*
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
CorsConfigBuilder allowNullOrigin() {
|
||||||
|
allowNullOrigin = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables CORS support.
|
||||||
|
*
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public CorsConfigBuilder disable() {
|
||||||
|
enabled = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the headers to be exposed to calling clients.
|
||||||
|
*
|
||||||
|
* During a simple CORS request, only certain response headers are made available by the
|
||||||
|
* browser, for example using:
|
||||||
|
* <pre>
|
||||||
|
* xhr.getResponseHeader("Content-Type");
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* The headers that are available by default are:
|
||||||
|
* <ul>
|
||||||
|
* <li>Cache-Control</li>
|
||||||
|
* <li>Content-Language</li>
|
||||||
|
* <li>Content-Type</li>
|
||||||
|
* <li>Expires</li>
|
||||||
|
* <li>Last-Modified</li>
|
||||||
|
* <li>Pragma</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* To expose other headers they need to be specified which is what this method enables by
|
||||||
|
* adding the headers to the CORS 'Access-Control-Expose-Headers' response header.
|
||||||
|
*
|
||||||
|
* @param headers the values to be added to the 'Access-Control-Expose-Headers' response header
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public CorsConfigBuilder exposeHeaders(final String... headers) {
|
||||||
|
exposeHeaders.addAll(Arrays.asList(headers));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default cookies are not included in CORS requests, but this method will enable cookies to
|
||||||
|
* be added to CORS requests. Calling this method will set the CORS 'Access-Control-Allow-Credentials'
|
||||||
|
* response header to true.
|
||||||
|
*
|
||||||
|
* Please note, that cookie support needs to be enabled on the client side as well.
|
||||||
|
* The client needs to opt-in to send cookies by calling:
|
||||||
|
* <pre>
|
||||||
|
* xhr.withCredentials = true;
|
||||||
|
* </pre>
|
||||||
|
* The default value for 'withCredentials' is false in which case no cookies are sent.
|
||||||
|
* Setting this to true will included cookies in cross origin requests.
|
||||||
|
*
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public CorsConfigBuilder allowCredentials() {
|
||||||
|
allowCredentials = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When making a preflight request the client has to perform two request with can be inefficient.
|
||||||
|
* This setting will set the CORS 'Access-Control-Max-Age' response header and enables the
|
||||||
|
* caching of the preflight response for the specified time. During this time no preflight
|
||||||
|
* request will be made.
|
||||||
|
*
|
||||||
|
* @param max the maximum time, in seconds, that the preflight response may be cached.
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public CorsConfigBuilder maxAge(final long max) {
|
||||||
|
maxAge = max;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the allowed set of HTTP Request Methods that should be returned in the
|
||||||
|
* CORS 'Access-Control-Request-Method' response header.
|
||||||
|
*
|
||||||
|
* @param methods the {@link HttpMethod}s that should be allowed.
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public CorsConfigBuilder allowedRequestMethods(final HttpMethod... methods) {
|
||||||
|
requestMethods.addAll(Arrays.asList(methods));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the if headers that should be returned in the CORS 'Access-Control-Allow-Headers'
|
||||||
|
* response header.
|
||||||
|
*
|
||||||
|
* If a client specifies headers on the request, for example by calling:
|
||||||
|
* <pre>
|
||||||
|
* xhr.setRequestHeader('My-Custom-Header', "SomeValue");
|
||||||
|
* </pre>
|
||||||
|
* the server will receive the above header name in the 'Access-Control-Request-Headers' of the
|
||||||
|
* preflight request. The server will then decide if it allows this header to be sent for the
|
||||||
|
* real request (remember that a preflight is not the real request but a request asking the server
|
||||||
|
* if it allow a request).
|
||||||
|
*
|
||||||
|
* @param headers the headers to be added to the preflight 'Access-Control-Allow-Headers' response header.
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public CorsConfigBuilder allowedRequestHeaders(final String... headers) {
|
||||||
|
requestHeaders.addAll(Arrays.asList(headers));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns HTTP response headers that should be added to a CORS preflight response.
|
||||||
|
*
|
||||||
|
* An intermediary like a load balancer might require that a CORS preflight request
|
||||||
|
* have certain headers set. This enables such headers to be added.
|
||||||
|
*
|
||||||
|
* @param name the name of the HTTP header.
|
||||||
|
* @param values the values for the HTTP header.
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public CorsConfigBuilder preflightResponseHeader(final CharSequence name, final Object... values) {
|
||||||
|
if (values.length == 1) {
|
||||||
|
preflightHeaders.put(name, new ConstantValueGenerator(values[0]));
|
||||||
|
} else {
|
||||||
|
preflightResponseHeader(name, Arrays.asList(values));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns HTTP response headers that should be added to a CORS preflight response.
|
||||||
|
*
|
||||||
|
* An intermediary like a load balancer might require that a CORS preflight request
|
||||||
|
* have certain headers set. This enables such headers to be added.
|
||||||
|
*
|
||||||
|
* @param name the name of the HTTP header.
|
||||||
|
* @param value the values for the HTTP header.
|
||||||
|
* @param <T> the type of values that the Iterable contains.
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public <T> CorsConfigBuilder preflightResponseHeader(final CharSequence name, final Iterable<T> value) {
|
||||||
|
preflightHeaders.put(name, new ConstantValueGenerator(value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns HTTP response headers that should be added to a CORS preflight response.
|
||||||
|
*
|
||||||
|
* An intermediary like a load balancer might require that a CORS preflight request
|
||||||
|
* have certain headers set. This enables such headers to be added.
|
||||||
|
*
|
||||||
|
* Some values must be dynamically created when the HTTP response is created, for
|
||||||
|
* example the 'Date' response header. This can be accomplished by using a Callable
|
||||||
|
* which will have its 'call' method invoked when the HTTP response is created.
|
||||||
|
*
|
||||||
|
* @param name the name of the HTTP header.
|
||||||
|
* @param valueGenerator a Callable which will be invoked at HTTP response creation.
|
||||||
|
* @param <T> the type of the value that the Callable can return.
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public <T> CorsConfigBuilder preflightResponseHeader(final CharSequence name, final Callable<T> valueGenerator) {
|
||||||
|
preflightHeaders.put(name, valueGenerator);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies that no preflight response headers should be added to a preflight response.
|
||||||
|
*
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public CorsConfigBuilder noPreflightResponseHeaders() {
|
||||||
|
noPreflightHeaders = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies that a CORS request should be rejected if it's invalid before being
|
||||||
|
* further processing.
|
||||||
|
*
|
||||||
|
* CORS headers are set after a request is processed. This may not always be desired
|
||||||
|
* and this setting will check that the Origin is valid and if it is not valid no
|
||||||
|
* further processing will take place, and a error will be returned to the calling client.
|
||||||
|
*
|
||||||
|
* @return {@link CorsConfigBuilder} to support method chaining.
|
||||||
|
*/
|
||||||
|
public CorsConfigBuilder shortCircuit() {
|
||||||
|
shortCircuit = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a {@link CorsConfig} with settings specified by previous method calls.
|
||||||
|
*
|
||||||
|
* @return {@link CorsConfig} the configured CorsConfig instance.
|
||||||
|
*/
|
||||||
|
public CorsConfig build() {
|
||||||
|
if (preflightHeaders.isEmpty() && !noPreflightHeaders) {
|
||||||
|
preflightHeaders.put(HttpHeaderNames.DATE, DateValueGenerator.INSTANCE);
|
||||||
|
preflightHeaders.put(HttpHeaderNames.CONTENT_LENGTH, new ConstantValueGenerator("0"));
|
||||||
|
}
|
||||||
|
return new CorsConfig(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used for preflight HTTP response values that do not need to be
|
||||||
|
* generated, but instead the value is "static" in that the same value will be returned
|
||||||
|
* for each call.
|
||||||
|
*/
|
||||||
|
private static final class ConstantValueGenerator implements Callable<Object> {
|
||||||
|
|
||||||
|
private final Object value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sole constructor.
|
||||||
|
*
|
||||||
|
* @param value the value that will be returned when the call method is invoked.
|
||||||
|
*/
|
||||||
|
private ConstantValueGenerator(final Object value) {
|
||||||
|
if (value == null) {
|
||||||
|
throw new IllegalArgumentException("value must not be null");
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object call() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This callable is used for the DATE preflight HTTP response HTTP header.
|
||||||
|
* It's value must be generated when the response is generated, hence will be
|
||||||
|
* different for every call.
|
||||||
|
*/
|
||||||
|
private static final class DateValueGenerator implements Callable<Date> {
|
||||||
|
|
||||||
|
static final DateValueGenerator INSTANCE = new DateValueGenerator();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date call() throws Exception {
|
||||||
|
return new Date();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,7 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
|
|||||||
import static io.netty.handler.codec.http.HttpMethod.*;
|
import static io.netty.handler.codec.http.HttpMethod.*;
|
||||||
import static io.netty.handler.codec.http.HttpResponseStatus.*;
|
import static io.netty.handler.codec.http.HttpResponseStatus.*;
|
||||||
import static io.netty.util.ReferenceCountUtil.*;
|
import static io.netty.util.ReferenceCountUtil.*;
|
||||||
|
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles <a href="http://www.w3.org/TR/cors/">Cross Origin Resource Sharing</a> (CORS) requests.
|
* Handles <a href="http://www.w3.org/TR/cors/">Cross Origin Resource Sharing</a> (CORS) requests.
|
||||||
@ -45,8 +46,11 @@ public class CorsHandler extends ChannelDuplexHandler {
|
|||||||
|
|
||||||
private HttpRequest request;
|
private HttpRequest request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance with the specified {@link CorsConfig}.
|
||||||
|
*/
|
||||||
public CorsHandler(final CorsConfig config) {
|
public CorsHandler(final CorsConfig config) {
|
||||||
this.config = config;
|
this.config = checkNotNull(config, "config");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -57,7 +61,7 @@ public class CorsHandler extends ChannelDuplexHandler {
|
|||||||
handlePreflight(ctx, request);
|
handlePreflight(ctx, request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (config.isShortCurcuit() && !validateOrigin()) {
|
if (config.isShortCircuit() && !validateOrigin()) {
|
||||||
forbidden(ctx, request);
|
forbidden(ctx, request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -109,7 +113,7 @@ public class CorsHandler extends ChannelDuplexHandler {
|
|||||||
setVaryHeader(response);
|
setVaryHeader(response);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
logger.debug("Request origin [" + origin + "] was not among the configured origins " + config.origins());
|
logger.debug("Request origin [{}]] was not among the configured origins [{}]", origin, config.origins());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -194,16 +198,9 @@ public class CorsHandler extends ChannelDuplexHandler {
|
|||||||
ctx.writeAndFlush(msg, promise);
|
ctx.writeAndFlush(msg, promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
|
|
||||||
logger.error("Caught error in CorsHandler", cause);
|
|
||||||
ctx.fireExceptionCaught(cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void forbidden(final ChannelHandlerContext ctx, final HttpRequest request) {
|
private static void forbidden(final ChannelHandlerContext ctx, final HttpRequest request) {
|
||||||
ctx.writeAndFlush(new DefaultFullHttpResponse(request.protocolVersion(), FORBIDDEN))
|
ctx.writeAndFlush(new DefaultFullHttpResponse(request.protocolVersion(), FORBIDDEN))
|
||||||
.addListener(ChannelFutureListener.CLOSE);
|
.addListener(ChannelFutureListener.CLOSE);
|
||||||
release(request);
|
release(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,9 +22,9 @@ import io.netty.handler.codec.http.HttpMethod;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static io.netty.handler.codec.http.HttpHeadersTestUtils.of;
|
import static io.netty.handler.codec.http.HttpHeadersTestUtils.of;
|
||||||
import static io.netty.handler.codec.http.cors.CorsConfig.withAnyOrigin;
|
import static io.netty.handler.codec.http.cors.CorsConfigBuilder.forAnyOrigin;
|
||||||
import static io.netty.handler.codec.http.cors.CorsConfig.withOrigin;
|
import static io.netty.handler.codec.http.cors.CorsConfigBuilder.forOrigin;
|
||||||
import static io.netty.handler.codec.http.cors.CorsConfig.withOrigins;
|
import static io.netty.handler.codec.http.cors.CorsConfigBuilder.forOrigins;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.CoreMatchers.hasItems;
|
import static org.hamcrest.CoreMatchers.hasItems;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
@ -35,13 +35,13 @@ public class CorsConfigTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void disabled() {
|
public void disabled() {
|
||||||
final CorsConfig cors = withAnyOrigin().disable().build();
|
final CorsConfig cors = forAnyOrigin().disable().build();
|
||||||
assertThat(cors.isCorsSupportEnabled(), is(false));
|
assertThat(cors.isCorsSupportEnabled(), is(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void anyOrigin() {
|
public void anyOrigin() {
|
||||||
final CorsConfig cors = withAnyOrigin().build();
|
final CorsConfig cors = forAnyOrigin().build();
|
||||||
assertThat(cors.isAnyOriginSupported(), is(true));
|
assertThat(cors.isAnyOriginSupported(), is(true));
|
||||||
assertThat(cors.origin(), is("*"));
|
assertThat(cors.origin(), is("*"));
|
||||||
assertThat(cors.origins().isEmpty(), is(true));
|
assertThat(cors.origins().isEmpty(), is(true));
|
||||||
@ -49,7 +49,7 @@ public class CorsConfigTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void wildcardOrigin() {
|
public void wildcardOrigin() {
|
||||||
final CorsConfig cors = withOrigin("*").build();
|
final CorsConfig cors = forOrigin("*").build();
|
||||||
assertThat(cors.isAnyOriginSupported(), is(true));
|
assertThat(cors.isAnyOriginSupported(), is(true));
|
||||||
assertThat(cors.origin(), equalTo("*"));
|
assertThat(cors.origin(), equalTo("*"));
|
||||||
assertThat(cors.origins().isEmpty(), is(true));
|
assertThat(cors.origins().isEmpty(), is(true));
|
||||||
@ -57,7 +57,7 @@ public class CorsConfigTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void origin() {
|
public void origin() {
|
||||||
final CorsConfig cors = withOrigin("http://localhost:7888").build();
|
final CorsConfig cors = forOrigin("http://localhost:7888").build();
|
||||||
assertThat(cors.origin(), is(equalTo("http://localhost:7888")));
|
assertThat(cors.origin(), is(equalTo("http://localhost:7888")));
|
||||||
assertThat(cors.isAnyOriginSupported(), is(false));
|
assertThat(cors.isAnyOriginSupported(), is(false));
|
||||||
}
|
}
|
||||||
@ -65,75 +65,75 @@ public class CorsConfigTest {
|
|||||||
@Test
|
@Test
|
||||||
public void origins() {
|
public void origins() {
|
||||||
final String[] origins = {"http://localhost:7888", "https://localhost:7888"};
|
final String[] origins = {"http://localhost:7888", "https://localhost:7888"};
|
||||||
final CorsConfig cors = withOrigins(origins).build();
|
final CorsConfig cors = forOrigins(origins).build();
|
||||||
assertThat(cors.origins(), hasItems(origins));
|
assertThat(cors.origins(), hasItems(origins));
|
||||||
assertThat(cors.isAnyOriginSupported(), is(false));
|
assertThat(cors.isAnyOriginSupported(), is(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void exposeHeaders() {
|
public void exposeHeaders() {
|
||||||
final CorsConfig cors = withAnyOrigin().exposeHeaders("custom-header1", "custom-header2").build();
|
final CorsConfig cors = forAnyOrigin().exposeHeaders("custom-header1", "custom-header2").build();
|
||||||
assertThat(cors.exposedHeaders(), hasItems("custom-header1", "custom-header2"));
|
assertThat(cors.exposedHeaders(), hasItems("custom-header1", "custom-header2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void allowCredentials() {
|
public void allowCredentials() {
|
||||||
final CorsConfig cors = withAnyOrigin().allowCredentials().build();
|
final CorsConfig cors = forAnyOrigin().allowCredentials().build();
|
||||||
assertThat(cors.isCredentialsAllowed(), is(true));
|
assertThat(cors.isCredentialsAllowed(), is(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void maxAge() {
|
public void maxAge() {
|
||||||
final CorsConfig cors = withAnyOrigin().maxAge(3000).build();
|
final CorsConfig cors = forAnyOrigin().maxAge(3000).build();
|
||||||
assertThat(cors.maxAge(), is(3000L));
|
assertThat(cors.maxAge(), is(3000L));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void requestMethods() {
|
public void requestMethods() {
|
||||||
final CorsConfig cors = withAnyOrigin().allowedRequestMethods(HttpMethod.POST, HttpMethod.GET).build();
|
final CorsConfig cors = forAnyOrigin().allowedRequestMethods(HttpMethod.POST, HttpMethod.GET).build();
|
||||||
assertThat(cors.allowedRequestMethods(), hasItems(HttpMethod.POST, HttpMethod.GET));
|
assertThat(cors.allowedRequestMethods(), hasItems(HttpMethod.POST, HttpMethod.GET));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void requestHeaders() {
|
public void requestHeaders() {
|
||||||
final CorsConfig cors = withAnyOrigin().allowedRequestHeaders("preflight-header1", "preflight-header2").build();
|
final CorsConfig cors = forAnyOrigin().allowedRequestHeaders("preflight-header1", "preflight-header2").build();
|
||||||
assertThat(cors.allowedRequestHeaders(), hasItems("preflight-header1", "preflight-header2"));
|
assertThat(cors.allowedRequestHeaders(), hasItems("preflight-header1", "preflight-header2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preflightResponseHeadersSingleValue() {
|
public void preflightResponseHeadersSingleValue() {
|
||||||
final CorsConfig cors = withAnyOrigin().preflightResponseHeader("SingleValue", "value").build();
|
final CorsConfig cors = forAnyOrigin().preflightResponseHeader("SingleValue", "value").build();
|
||||||
assertThat(cors.preflightResponseHeaders().get(of("SingleValue")), equalTo("value"));
|
assertThat(cors.preflightResponseHeaders().get(of("SingleValue")), equalTo("value"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preflightResponseHeadersMultipleValues() {
|
public void preflightResponseHeadersMultipleValues() {
|
||||||
final CorsConfig cors = withAnyOrigin().preflightResponseHeader("MultipleValues", "value1", "value2").build();
|
final CorsConfig cors = forAnyOrigin().preflightResponseHeader("MultipleValues", "value1", "value2").build();
|
||||||
assertThat(cors.preflightResponseHeaders().getAll(of("MultipleValues")), hasItems("value1", "value2"));
|
assertThat(cors.preflightResponseHeaders().getAll(of("MultipleValues")), hasItems("value1", "value2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void defaultPreflightResponseHeaders() {
|
public void defaultPreflightResponseHeaders() {
|
||||||
final CorsConfig cors = withAnyOrigin().build();
|
final CorsConfig cors = forAnyOrigin().build();
|
||||||
assertThat(cors.preflightResponseHeaders().get(HttpHeaderNames.DATE), is(notNullValue()));
|
assertThat(cors.preflightResponseHeaders().get(HttpHeaderNames.DATE), is(notNullValue()));
|
||||||
assertThat(cors.preflightResponseHeaders().get(HttpHeaderNames.CONTENT_LENGTH), is("0"));
|
assertThat(cors.preflightResponseHeaders().get(HttpHeaderNames.CONTENT_LENGTH), is("0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void emptyPreflightResponseHeaders() {
|
public void emptyPreflightResponseHeaders() {
|
||||||
final CorsConfig cors = withAnyOrigin().noPreflightResponseHeaders().build();
|
final CorsConfig cors = forAnyOrigin().noPreflightResponseHeaders().build();
|
||||||
assertThat(cors.preflightResponseHeaders(), equalTo((HttpHeaders) EmptyHttpHeaders.INSTANCE));
|
assertThat(cors.preflightResponseHeaders(), equalTo((HttpHeaders) EmptyHttpHeaders.INSTANCE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test (expected = IllegalArgumentException.class)
|
@Test (expected = IllegalArgumentException.class)
|
||||||
public void shouldThrowIfValueIsNull() {
|
public void shouldThrowIfValueIsNull() {
|
||||||
withOrigin("*").preflightResponseHeader("HeaderName", new Object[]{null}).build();
|
forOrigin("*").preflightResponseHeader("HeaderName", new Object[]{null}).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shortCurcuit() {
|
public void shortCircuit() {
|
||||||
final CorsConfig cors = withOrigin("http://localhost:8080").shortCurcuit().build();
|
final CorsConfig cors = forOrigin("http://localhost:8080").shortCircuit().build();
|
||||||
assertThat(cors.isShortCurcuit(), is(true));
|
assertThat(cors.isShortCircuit(), is(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,9 @@ import static io.netty.handler.codec.http.HttpMethod.OPTIONS;
|
|||||||
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
|
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
|
||||||
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
|
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
|
||||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||||
|
import static io.netty.handler.codec.http.cors.CorsConfigBuilder.forAnyOrigin;
|
||||||
|
import static io.netty.handler.codec.http.cors.CorsConfigBuilder.forOrigin;
|
||||||
|
import static io.netty.handler.codec.http.cors.CorsConfigBuilder.forOrigins;
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
@ -57,20 +60,20 @@ public class CorsHandlerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void nonCorsRequest() {
|
public void nonCorsRequest() {
|
||||||
final HttpResponse response = simpleRequest(CorsConfig.withAnyOrigin().build(), null);
|
final HttpResponse response = simpleRequest(forAnyOrigin().build(), null);
|
||||||
assertThat(response.headers().contains(ACCESS_CONTROL_ALLOW_ORIGIN), is(false));
|
assertThat(response.headers().contains(ACCESS_CONTROL_ALLOW_ORIGIN), is(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleRequestWithAnyOrigin() {
|
public void simpleRequestWithAnyOrigin() {
|
||||||
final HttpResponse response = simpleRequest(CorsConfig.withAnyOrigin().build(), "http://localhost:7777");
|
final HttpResponse response = simpleRequest(forAnyOrigin().build(), "http://localhost:7777");
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is("*"));
|
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is("*"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleRequestWithOrigin() {
|
public void simpleRequestWithOrigin() {
|
||||||
final String origin = "http://localhost:8888";
|
final String origin = "http://localhost:8888";
|
||||||
final HttpResponse response = simpleRequest(CorsConfig.withOrigin(origin).build(), origin);
|
final HttpResponse response = simpleRequest(forOrigin(origin).build(), origin);
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(origin));
|
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(origin));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,22 +82,23 @@ public class CorsHandlerTest {
|
|||||||
final String origin1 = "http://localhost:8888";
|
final String origin1 = "http://localhost:8888";
|
||||||
final String origin2 = "https://localhost:8888";
|
final String origin2 = "https://localhost:8888";
|
||||||
final String[] origins = {origin1, origin2};
|
final String[] origins = {origin1, origin2};
|
||||||
final HttpResponse response1 = simpleRequest(CorsConfig.withOrigins(origins).build(), origin1);
|
final HttpResponse response1 = simpleRequest(forOrigins(origins).build(), origin1);
|
||||||
assertThat(response1.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(origin1));
|
assertThat(response1.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(origin1));
|
||||||
final HttpResponse response2 = simpleRequest(CorsConfig.withOrigins(origins).build(), origin2);
|
final HttpResponse response2 = simpleRequest(forOrigins(origins).build(), origin2);
|
||||||
assertThat(response2.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(origin2));
|
assertThat(response2.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(origin2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleRequestWithNoMatchingOrigin() {
|
public void simpleRequestWithNoMatchingOrigin() {
|
||||||
final String origin = "http://localhost:8888";
|
final String origin = "http://localhost:8888";
|
||||||
final HttpResponse response = simpleRequest(CorsConfig.withOrigins("https://localhost:8888").build(), origin);
|
final HttpResponse response = simpleRequest(
|
||||||
|
forOrigins("https://localhost:8888").build(), origin);
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(nullValue()));
|
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(nullValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preflightDeleteRequestWithCustomHeaders() {
|
public void preflightDeleteRequestWithCustomHeaders() {
|
||||||
final CorsConfig config = CorsConfig.withOrigin("http://localhost:8888")
|
final CorsConfig config = forOrigin("http://localhost:8888")
|
||||||
.allowedRequestMethods(GET, DELETE)
|
.allowedRequestMethods(GET, DELETE)
|
||||||
.build();
|
.build();
|
||||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
||||||
@ -106,7 +110,7 @@ public class CorsHandlerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preflightGetRequestWithCustomHeaders() {
|
public void preflightGetRequestWithCustomHeaders() {
|
||||||
final CorsConfig config = CorsConfig.withOrigin("http://localhost:8888")
|
final CorsConfig config = forOrigin("http://localhost:8888")
|
||||||
.allowedRequestMethods(OPTIONS, GET, DELETE)
|
.allowedRequestMethods(OPTIONS, GET, DELETE)
|
||||||
.allowedRequestHeaders("content-type", "xheader1")
|
.allowedRequestHeaders("content-type", "xheader1")
|
||||||
.build();
|
.build();
|
||||||
@ -121,7 +125,7 @@ public class CorsHandlerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preflightRequestWithDefaultHeaders() {
|
public void preflightRequestWithDefaultHeaders() {
|
||||||
final CorsConfig config = CorsConfig.withOrigin("http://localhost:8888").build();
|
final CorsConfig config = forOrigin("http://localhost:8888").build();
|
||||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
||||||
assertThat(response.headers().get(CONTENT_LENGTH), is("0"));
|
assertThat(response.headers().get(CONTENT_LENGTH), is("0"));
|
||||||
assertThat(response.headers().get(DATE), is(notNullValue()));
|
assertThat(response.headers().get(DATE), is(notNullValue()));
|
||||||
@ -130,7 +134,7 @@ public class CorsHandlerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preflightRequestWithCustomHeader() {
|
public void preflightRequestWithCustomHeader() {
|
||||||
final CorsConfig config = CorsConfig.withOrigin("http://localhost:8888")
|
final CorsConfig config = forOrigin("http://localhost:8888")
|
||||||
.preflightResponseHeader("CustomHeader", "somevalue")
|
.preflightResponseHeader("CustomHeader", "somevalue")
|
||||||
.build();
|
.build();
|
||||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
||||||
@ -143,7 +147,7 @@ public class CorsHandlerTest {
|
|||||||
final String headerName = "CustomHeader";
|
final String headerName = "CustomHeader";
|
||||||
final String value1 = "value1";
|
final String value1 = "value1";
|
||||||
final String value2 = "value2";
|
final String value2 = "value2";
|
||||||
final CorsConfig config = CorsConfig.withOrigin("http://localhost:8888")
|
final CorsConfig config = forOrigin("http://localhost:8888")
|
||||||
.preflightResponseHeader(headerName, value1, value2)
|
.preflightResponseHeader(headerName, value1, value2)
|
||||||
.build();
|
.build();
|
||||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
||||||
@ -156,7 +160,7 @@ public class CorsHandlerTest {
|
|||||||
final String headerName = "CustomHeader";
|
final String headerName = "CustomHeader";
|
||||||
final String value1 = "value1";
|
final String value1 = "value1";
|
||||||
final String value2 = "value2";
|
final String value2 = "value2";
|
||||||
final CorsConfig config = CorsConfig.withOrigin("http://localhost:8888")
|
final CorsConfig config = forOrigin("http://localhost:8888")
|
||||||
.preflightResponseHeader(headerName, Arrays.asList(value1, value2))
|
.preflightResponseHeader(headerName, Arrays.asList(value1, value2))
|
||||||
.build();
|
.build();
|
||||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
||||||
@ -166,7 +170,7 @@ public class CorsHandlerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preflightRequestWithValueGenerator() {
|
public void preflightRequestWithValueGenerator() {
|
||||||
final CorsConfig config = CorsConfig.withOrigin("http://localhost:8888")
|
final CorsConfig config = forOrigin("http://localhost:8888")
|
||||||
.preflightResponseHeader("GenHeader", new Callable<String>() {
|
.preflightResponseHeader("GenHeader", new Callable<String>() {
|
||||||
@Override
|
@Override
|
||||||
public String call() throws Exception {
|
public String call() throws Exception {
|
||||||
@ -181,7 +185,7 @@ public class CorsHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void preflightRequestWithNullOrigin() {
|
public void preflightRequestWithNullOrigin() {
|
||||||
final String origin = "null";
|
final String origin = "null";
|
||||||
final CorsConfig config = CorsConfig.withOrigin(origin)
|
final CorsConfig config = forOrigin(origin)
|
||||||
.allowNullOrigin()
|
.allowNullOrigin()
|
||||||
.allowCredentials()
|
.allowCredentials()
|
||||||
.build();
|
.build();
|
||||||
@ -193,14 +197,14 @@ public class CorsHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void preflightRequestAllowCredentials() {
|
public void preflightRequestAllowCredentials() {
|
||||||
final String origin = "null";
|
final String origin = "null";
|
||||||
final CorsConfig config = CorsConfig.withOrigin(origin).allowCredentials().build();
|
final CorsConfig config = forOrigin(origin).allowCredentials().build();
|
||||||
final HttpResponse response = preflightRequest(config, origin, "content-type, xheader1");
|
final HttpResponse response = preflightRequest(config, origin, "content-type, xheader1");
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_CREDENTIALS), is(equalTo("true")));
|
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_CREDENTIALS), is(equalTo("true")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preflightRequestDoNotAllowCredentials() {
|
public void preflightRequestDoNotAllowCredentials() {
|
||||||
final CorsConfig config = CorsConfig.withOrigin("http://localhost:8888").build();
|
final CorsConfig config = forOrigin("http://localhost:8888").build();
|
||||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "");
|
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "");
|
||||||
// the only valid value for Access-Control-Allow-Credentials is true.
|
// the only valid value for Access-Control-Allow-Credentials is true.
|
||||||
assertThat(response.headers().contains(ACCESS_CONTROL_ALLOW_CREDENTIALS), is(false));
|
assertThat(response.headers().contains(ACCESS_CONTROL_ALLOW_CREDENTIALS), is(false));
|
||||||
@ -208,7 +212,7 @@ public class CorsHandlerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleRequestCustomHeaders() {
|
public void simpleRequestCustomHeaders() {
|
||||||
final CorsConfig config = CorsConfig.withAnyOrigin().exposeHeaders("custom1", "custom2").build();
|
final CorsConfig config = forAnyOrigin().exposeHeaders("custom1", "custom2").build();
|
||||||
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), equalTo("*"));
|
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), equalTo("*"));
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_EXPOSE_HEADERS), containsString("custom1"));
|
assertThat(response.headers().get(ACCESS_CONTROL_EXPOSE_HEADERS), containsString("custom1"));
|
||||||
@ -217,21 +221,21 @@ public class CorsHandlerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleRequestAllowCredentials() {
|
public void simpleRequestAllowCredentials() {
|
||||||
final CorsConfig config = CorsConfig.withAnyOrigin().allowCredentials().build();
|
final CorsConfig config = forAnyOrigin().allowCredentials().build();
|
||||||
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_CREDENTIALS), equalTo("true"));
|
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_CREDENTIALS), equalTo("true"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleRequestDoNotAllowCredentials() {
|
public void simpleRequestDoNotAllowCredentials() {
|
||||||
final CorsConfig config = CorsConfig.withAnyOrigin().build();
|
final CorsConfig config = forAnyOrigin().build();
|
||||||
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
||||||
assertThat(response.headers().contains(ACCESS_CONTROL_ALLOW_CREDENTIALS), is(false));
|
assertThat(response.headers().contains(ACCESS_CONTROL_ALLOW_CREDENTIALS), is(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void anyOriginAndAllowCredentialsShouldEchoRequestOrigin() {
|
public void anyOriginAndAllowCredentialsShouldEchoRequestOrigin() {
|
||||||
final CorsConfig config = CorsConfig.withAnyOrigin().allowCredentials().build();
|
final CorsConfig config = forAnyOrigin().allowCredentials().build();
|
||||||
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_CREDENTIALS), equalTo("true"));
|
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_CREDENTIALS), equalTo("true"));
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), equalTo("http://localhost:7777"));
|
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), equalTo("http://localhost:7777"));
|
||||||
@ -240,7 +244,7 @@ public class CorsHandlerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleRequestExposeHeaders() {
|
public void simpleRequestExposeHeaders() {
|
||||||
final CorsConfig config = CorsConfig.withAnyOrigin().exposeHeaders("one", "two").build();
|
final CorsConfig config = forAnyOrigin().exposeHeaders("one", "two").build();
|
||||||
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_EXPOSE_HEADERS), containsString("one"));
|
assertThat(response.headers().get(ACCESS_CONTROL_EXPOSE_HEADERS), containsString("one"));
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_EXPOSE_HEADERS), containsString("two"));
|
assertThat(response.headers().get(ACCESS_CONTROL_EXPOSE_HEADERS), containsString("two"));
|
||||||
@ -248,14 +252,14 @@ public class CorsHandlerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleRequestShortCurcuit() {
|
public void simpleRequestShortCurcuit() {
|
||||||
final CorsConfig config = CorsConfig.withOrigin("http://localhost:8080").shortCurcuit().build();
|
final CorsConfig config = forOrigin("http://localhost:8080").shortCircuit().build();
|
||||||
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
||||||
assertThat(response.status(), is(FORBIDDEN));
|
assertThat(response.status(), is(FORBIDDEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleRequestNoShortCurcuit() {
|
public void simpleRequestNoShortCurcuit() {
|
||||||
final CorsConfig config = CorsConfig.withOrigin("http://localhost:8080").build();
|
final CorsConfig config = forOrigin("http://localhost:8080").build();
|
||||||
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
||||||
assertThat(response.status(), is(OK));
|
assertThat(response.status(), is(OK));
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(nullValue()));
|
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(nullValue()));
|
||||||
@ -263,7 +267,7 @@ public class CorsHandlerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shortCurcuitNonCorsRequest() {
|
public void shortCurcuitNonCorsRequest() {
|
||||||
final CorsConfig config = CorsConfig.withOrigin("https://localhost").shortCurcuit().build();
|
final CorsConfig config = forOrigin("https://localhost").shortCircuit().build();
|
||||||
final HttpResponse response = simpleRequest(config, null);
|
final HttpResponse response = simpleRequest(config, null);
|
||||||
assertThat(response.status(), is(OK));
|
assertThat(response.status(), is(OK));
|
||||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(nullValue()));
|
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(nullValue()));
|
||||||
@ -271,7 +275,7 @@ public class CorsHandlerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preflightRequestShouldReleaseRequest() {
|
public void preflightRequestShouldReleaseRequest() {
|
||||||
final CorsConfig config = CorsConfig.withOrigin("http://localhost:8888")
|
final CorsConfig config = forOrigin("http://localhost:8888")
|
||||||
.preflightResponseHeader("CustomHeader", Arrays.asList("value1", "value2"))
|
.preflightResponseHeader("CustomHeader", Arrays.asList("value1", "value2"))
|
||||||
.build();
|
.build();
|
||||||
final EmbeddedChannel channel = new EmbeddedChannel(new CorsHandler(config));
|
final EmbeddedChannel channel = new EmbeddedChannel(new CorsHandler(config));
|
||||||
@ -282,7 +286,7 @@ public class CorsHandlerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void forbiddenShouldReleaseRequest() {
|
public void forbiddenShouldReleaseRequest() {
|
||||||
final CorsConfig config = CorsConfig.withOrigin("https://localhost").shortCurcuit().build();
|
final CorsConfig config = forOrigin("https://localhost").shortCircuit().build();
|
||||||
final EmbeddedChannel channel = new EmbeddedChannel(new CorsHandler(config), new EchoHandler());
|
final EmbeddedChannel channel = new EmbeddedChannel(new CorsHandler(config), new EchoHandler());
|
||||||
final FullHttpRequest request = createHttpRequest(GET);
|
final FullHttpRequest request = createHttpRequest(GET);
|
||||||
request.headers().set(ORIGIN, "http://localhost:8888");
|
request.headers().set(ORIGIN, "http://localhost:8888");
|
||||||
@ -349,5 +353,4 @@ public class CorsHandlerTest {
|
|||||||
assertThat(header, containsString(value));
|
assertThat(header, containsString(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import io.netty.handler.codec.http.HttpObjectAggregator;
|
|||||||
import io.netty.handler.codec.http.HttpRequestDecoder;
|
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||||
import io.netty.handler.codec.http.cors.CorsConfig;
|
import io.netty.handler.codec.http.cors.CorsConfig;
|
||||||
|
import io.netty.handler.codec.http.cors.CorsConfigBuilder;
|
||||||
import io.netty.handler.codec.http.cors.CorsHandler;
|
import io.netty.handler.codec.http.cors.CorsHandler;
|
||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.stream.ChunkedWriteHandler;
|
import io.netty.handler.stream.ChunkedWriteHandler;
|
||||||
@ -79,7 +80,7 @@ public class HttpCorsServerInitializer extends ChannelInitializer<SocketChannel>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initChannel(SocketChannel ch) {
|
public void initChannel(SocketChannel ch) {
|
||||||
CorsConfig corsConfig = CorsConfig.withAnyOrigin().build();
|
CorsConfig corsConfig = CorsConfigBuilder.forAnyOrigin().build();
|
||||||
ChannelPipeline pipeline = ch.pipeline();
|
ChannelPipeline pipeline = ch.pipeline();
|
||||||
if (sslCtx != null) {
|
if (sslCtx != null) {
|
||||||
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
|
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
|
||||||
|
Loading…
Reference in New Issue
Block a user