Skip to content

Commit

Permalink
#431 Added CORS handler
Browse files Browse the repository at this point in the history
  • Loading branch information
svenkubiak committed Aug 29, 2019
1 parent 0c83db9 commit e7abd8f
Show file tree
Hide file tree
Showing 10 changed files with 460 additions and 1 deletion.
66 changes: 66 additions & 0 deletions mangooio-core/src/main/java/io/mangoo/core/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -39,6 +40,8 @@ public class Config {
private static final Logger LOG = LogManager.getLogger(Config.class);
private static final String CRYPTEX_TAG = "cryptex{";
private static final String ARG_TAG = "arg{}";
private Pattern corsUrl;
private Pattern corsAllowOrigin;
private String mode;
private Props props = Props.create();
private boolean decrypted = true;
Expand Down Expand Up @@ -717,4 +720,67 @@ public boolean isSmtpPlaintextOverTLS() {
public boolean isSmtpStartTlsRequired() {
return getBoolean(Key.SMTP_STARTTLS, Default.SMTP_STARTTLS.toBoolean());
}

/**
* @return cors.enable or default value if undefined
*/
public boolean isCorsEnable() {
return getBoolean(Key.CORS_ENABLE, Default.CORS_ENABLE.toBoolean());
}

/**
* @return cors.urlpattern as compiled pattern or default value if undefined
*/
public Pattern getCorsUrlPattern() {
if (this.corsUrl == null) {
this.corsUrl = Pattern.compile(getString(Key.CORS_URLPATTERN, Default.CORS_URLPATTERN.toString()));
}
return this.corsUrl;
}

/**
* @return cors.policyclass as compiled pattern or default value if undefined
*/
public Pattern getCorsAllowOrigin() {
if (this.corsAllowOrigin == null) {
this.corsAllowOrigin = Pattern.compile(getString(Key.CORS_ALLOWORIGIN, Default.CORS_ALLOWORIGIN.toString()));
}

return this.corsAllowOrigin;
}

/**
* @return cors.headers.allowcredentials or default value if undefined
*/
public String getCorsHeadersAllowCredentials() {
return getString(Key.CORS_HEADERS_ALLOWCREDENTIALS, Default.CORS_HEADERS_ALLOWCREDENTIALS.toString());
}

/**
* @return cors.headers.allowheaders or default value if undefined
*/
public String getCorsHeadersAllowHeaders() {
return getString(Key.CORS_HEADERS_ALLOWHEADERS, Default.CORS_HEADERS_ALLOWHEADERS.toString());
}

/**
* @return cors.headers.allowheaders or default value if undefined
*/
public String getCorsHeadersAllowMethods() {
return getString(Key.CORS_HEADERS_ALLOWMETHODS, Default.CORS_HEADERS_ALLOWMETHODS.toString());
}

/**
* @return cors.headers.exposeheaders or default value if undefined
*/
public String getCorsHeadersExposeHeaders() {
return getString(Key.CORS_HEADERS_EXPOSEHEADERS, Default.CORS_HEADERS_EXPOSEHEADERS.toString());
}

/**
* @return cors.headers.maxage
*/
public String getCorsHeadersMaxAge() {
return getString(Key.CORS_HEADERS_MAXAGE, Default.CORS_HEADERS_MAXAGE.toString());
}
}
8 changes: 8 additions & 0 deletions mangooio-core/src/main/java/io/mangoo/enums/Default.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ public enum Default {
CONFIG_PATH("/src/main/resources/config.props"),
CONFIGURATION_FILE("config.props"),
CONTENT_TYPE("text/html; charset=UTF-8"),
CORS_ALLOWORIGIN("^http(s)?://(www\\.)?example\\.(com|org)$"),
CORS_ENABLE(Constants.FALSE),
CORS_HEADERS_ALLOWCREDENTIALS(Constants.TRUE),
CORS_HEADERS_ALLOWHEADERS("Authorization,Content-Type,Link,X-Total-Count,Range"),
CORS_HEADERS_ALLOWMETHODS("DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT"),
CORS_HEADERS_EXPOSEHEADERS("Accept-Ranges,Content-Length,Content-Range,ETag,Link,Server,X-Total-Count"),
CORS_HEADERS_MAXAGE("864000"),
CORS_URLPATTERN("^http(s)?://([^/]+)(:([^/]+))?(/([^/])+)?/api(/.*)?$"),
DATA_DELIMITER("#"),
DEFAULT_CONFIGURATION("default"),
DEFAULT_TEMPLATES_DIR("/templates/defaults/"),
Expand Down
8 changes: 8 additions & 0 deletions mangooio-core/src/main/java/io/mangoo/enums/Key.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ public enum Key {
CONNECTOR_AJP_PORT("connector.ajp.port"),
CONNECTOR_HTTP_HOST("connector.http.host"),
CONNECTOR_HTTP_PORT("connector.http.port"),
CORS_ALLOWORIGIN("cors.alloworigin"),
CORS_ENABLE("cors.enable"),
CORS_HEADERS_ALLOWCREDENTIALS("cors.headers.allowcredentials"),
CORS_HEADERS_ALLOWHEADERS("cors.headers.allowheaders"),
CORS_HEADERS_ALLOWMETHODS("cors.headers.allowmethods"),
CORS_HEADERS_EXPOSEHEADERS("cors.headers.exposeheaders"),
CORS_HEADERS_MAXAGE("cors.headers.maxage"),
CORS_URLPATTERN("cors.urlpattern"),
FLASH_COOKIE_ENCRYPTIONKEY("flash.cookie.encryptionkey"),
FLASH_COOKIE_NAME("flash.cookie.name"),
FLASH_COOKIE_SIGNKEY("flash.cookie.signkey"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package io.mangoo.routing.handlers;

import java.util.Objects;

import org.apache.commons.lang3.StringUtils;

import com.google.inject.Inject;

import io.mangoo.core.Application;
import io.mangoo.core.Config;
import io.mangoo.enums.Required;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.HeaderValues;
import io.undertow.util.HttpString;

/**
*
* @author svenkubiak
*
*/
public class CorsHandler implements HttpHandler {
private static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
private static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
private static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
private static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
private static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
private Config config;

@Inject
public CorsHandler(Config config) {
this.config = Objects.requireNonNull(config, Required.CONFIG.toString());
}

@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
if (this.config.isCorsEnable() && config.getCorsUrlPattern().matcher(exchange.getRequestURL()).matches()) {
applyHeader(exchange);
}
nextHandler(exchange);
}

private void applyHeader(HttpServerExchange exchange) {
String origin = getOrigin(exchange);
if (StringUtils.isNotBlank(origin) && this.config.getCorsAllowOrigin().matcher(origin).matches()) {
if (doesNotHaveHeader(ACCESS_CONTROL_ALLOW_ORIGIN, exchange)) {
System.out.println("aDDING HEADER");
addHeader(exchange, ACCESS_CONTROL_ALLOW_ORIGIN, origin);
}

if (doesNotHaveHeader(ACCESS_CONTROL_ALLOW_HEADERS, exchange)) {
addHeader(exchange, ACCESS_CONTROL_ALLOW_HEADERS, this.config.getCorsHeadersAllowHeaders());
}

if (doesNotHaveHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS, exchange)) {
addHeader(exchange, ACCESS_CONTROL_ALLOW_CREDENTIALS, this.config.getCorsHeadersAllowCredentials());
}

if (doesNotHaveHeader(ACCESS_CONTROL_ALLOW_METHODS, exchange)) {
addHeader(exchange, ACCESS_CONTROL_ALLOW_METHODS, this.config.getCorsHeadersAllowMethods());
}

if (doesNotHaveHeader(ACCESS_CONTROL_EXPOSE_HEADERS, exchange)) {
addHeader(exchange, ACCESS_CONTROL_EXPOSE_HEADERS, this.config.getCorsHeadersExposeHeaders());
}

if (doesNotHaveHeader(ACCESS_CONTROL_MAX_AGE, exchange)) {
addHeader(exchange, ACCESS_CONTROL_MAX_AGE, this.config.getCorsHeadersMaxAge());
}
}
}

private String getOrigin(HttpServerExchange exchange) {
HeaderValues headers = ((HttpServerExchange) exchange).getRequestHeaders().get("Origin");
return headers == null ? null : headers.peekFirst();
}

private boolean doesNotHaveHeader(String name, HttpServerExchange exchange) {
return exchange.getResponseHeaders().get(name) == null;
}

private void addHeader(HttpServerExchange exchange, String name, String value) {
exchange.getResponseHeaders().add(HttpString.tryFromString(name), value);
}

/**
* Handles the next request in the handler chain
*
* @param exchange The HttpServerExchange
* @throws Exception Thrown when an exception occurs
*/
protected void nextHandler(HttpServerExchange exchange) throws Exception {
Application.getInstance(ResponseHandler.class).handleRequest(exchange);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,6 @@ protected void setFlashCookie(HttpServerExchange exchange) {
* @throws Exception Thrown when an exception occurs
*/
protected void nextHandler(HttpServerExchange exchange) throws Exception {
Application.getInstance(ResponseHandler.class).handleRequest(exchange);
Application.getInstance(CorsHandler.class).handleRequest(exchange);
}
}
1 change: 1 addition & 0 deletions mangooio-integration-test/src/main/java/app/Bootstrap.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ public void initializeRoutes() {
On.get().to("/route").respondeWith("route"),
On.post().to("/").respondeWith("index"),
On.put().to("/put").respondeWith("put"),
On.options().to("/api").respondeWith("api"),
On.patch().to("/").respondeWith("index"),
On.head().to("/").respondeWith("index"),
On.delete().to("/").respondeWith("index"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ public Response error() {
public Response route() {
return Response.withOk();
}

public Response api() {
return Response.withOk().andEmptyBody();
}

public Response redirect() {
return Response.withRedirect("/");
Expand Down
9 changes: 9 additions & 0 deletions mangooio-integration-test/src/main/resources/config.props
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@
[smtp<test>]
port = 3025
username = bla
[cors<test>]
enable = true
alloworigin = ^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$
urlpattern = ^http(s)?://([^/]+)(:([^/]+))?(/([^/])+)?/api(/.*)?$
headers.allowcredentials = true
headers.allowheaders = Content-Range,ETag
headers.allowmethods = GET,POST,PATCH
headers.exposeheaders = Authorization,Content-Type
headers.maxage = 86400
[]

[application<dev>]
Expand Down
Loading

0 comments on commit e7abd8f

Please sign in to comment.