io.vertx.ext.web.handler.impl.CSPHandlerImpl Maven / Gradle / Ivy
package io.vertx.ext.web.handler.impl;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.CSPHandler;
import io.vertx.ext.web.handler.HttpException;
import java.util.*;
public class CSPHandlerImpl implements CSPHandler {
private static final List MUST_BE_QUOTED = Arrays.asList(
"none",
"self",
"unsafe-inline",
"unsafe-eval"
);
private final Map policy = new LinkedHashMap<>();
// cache the computed policy
private String policyString;
private boolean reportOnly;
public CSPHandlerImpl() {
addDirective("default-src", "self");
}
@Override
public synchronized CSPHandler setDirective(String name, String value) {
if (name == null) {
throw new IllegalArgumentException("name cannot be null");
}
if (value == null) {
policy.remove(name);
}
if (MUST_BE_QUOTED.contains(value)) {
// these policies are special, they must be quoted
value = "'" + value + "'";
}
policy.put(name, value);
// invalidate cache
policyString = null;
return this;
}
@Override
public CSPHandler addDirective(String name, String value) {
if (name == null) {
throw new IllegalArgumentException("name cannot be null");
}
if (value == null) {
policy.remove(name);
}
if (MUST_BE_QUOTED.contains(value)) {
// these policies are special, they must be quoted
value = "'" + value + "'";
}
String previous = policy.get(name);
if (previous == null || "".equals(previous)) {
policy.put(name, value);
} else {
policy.put(name, previous + " " + value);
}
// invalidate cache
policyString = null;
return this;
}
@Override
public CSPHandler setReportOnly(boolean reportOnly) {
this.reportOnly = reportOnly;
return this;
}
private String getPolicyString() {
if (policyString == null) {
final StringBuilder buffer = new StringBuilder();
for (Map.Entry entry : policy.entrySet()) {
if (buffer.length() > 0) {
buffer.append("; ");
}
buffer
.append(entry.getKey())
.append(' ')
.append(entry.getValue());
}
policyString = buffer.toString();
}
return policyString;
}
@Override
public void handle(RoutingContext ctx) {
final String policyString = getPolicyString();
if (reportOnly) {
// add support for 'report-to'
if (!policy.containsKey("report-uri") && !policy.containsKey("report-to")) {
ctx.fail(new HttpException(500, "Please disable CSP reportOnly or add a report-uri/report-to policy."));
} else {
ctx.response()
.putHeader("Content-Security-Policy-Report-Only", policyString);
ctx.next();
}
} else {
ctx.response()
.putHeader("Content-Security-Policy", policyString);
ctx.next();
}
}
}