package org.glassfish.grizzly.http2;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.Connection;
import org.glassfish.grizzly.Grizzly;
import org.glassfish.grizzly.Transport;
import org.glassfish.grizzly.attributes.Attribute;
import org.glassfish.grizzly.attributes.AttributeBuilder;
import org.glassfish.grizzly.filterchain.Filter;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.FilterChainEvent;
import org.glassfish.grizzly.filterchain.NextAction;
import org.glassfish.grizzly.filterchain.ShutdownEvent;
import org.glassfish.grizzly.http.HttpBrokenContentException;
import org.glassfish.grizzly.http.HttpContent;
import org.glassfish.grizzly.http.HttpContext;
import org.glassfish.grizzly.http.HttpEvents;
import org.glassfish.grizzly.http.HttpHeader;
import org.glassfish.grizzly.http.HttpPacket;
import org.glassfish.grizzly.http.HttpRequestPacket;
import org.glassfish.grizzly.http.HttpResponsePacket;
import org.glassfish.grizzly.http.Method;
import org.glassfish.grizzly.http.Protocol;
import org.glassfish.grizzly.http.server.http2.PushEvent;
import org.glassfish.grizzly.http.util.FastHttpDateFormat;
import org.glassfish.grizzly.http.util.Header;
import org.glassfish.grizzly.http.util.HttpStatus;
import org.glassfish.grizzly.http2.NetLogger.Context;
import org.glassfish.grizzly.http2.frames.ErrorCode;
import org.glassfish.grizzly.http2.frames.HeaderBlockHead;
import org.glassfish.grizzly.http2.frames.HeadersFrame;
import org.glassfish.grizzly.http2.frames.Http2Frame;
import org.glassfish.grizzly.http2.frames.PushPromiseFrame;
import org.glassfish.grizzly.http2.frames.SettingsFrame;
import org.glassfish.grizzly.impl.FutureImpl;
import org.glassfish.grizzly.memory.Buffers;
import org.glassfish.grizzly.ssl.SSLUtils;
import javax.net.ssl.SSLEngine;
import static org.glassfish.grizzly.http2.Termination.IN_FIN_TERMINATION;
public class Http2ServerFilter extends Http2BaseFilter {
private final static Logger LOGGER = Grizzly.logger(Http2ServerFilter.class);
private static final String[] CIPHER_SUITE_BLACK_LIST = {
"TLS_NULL_WITH_NULL_NULL",
"TLS_RSA_WITH_NULL_MD5",
"TLS_RSA_WITH_NULL_SHA",
"TLS_RSA_EXPORT_WITH_RC4_40_MD5",
"TLS_RSA_WITH_RC4_128_MD5",
"TLS_RSA_WITH_RC4_128_SHA",
"TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
"TLS_RSA_WITH_IDEA_CBC_SHA",
"TLS_RSA_EXPORT_WITH_DES40_CBC_SHA",
"TLS_RSA_WITH_DES_CBC_SHA",
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
"TLS_DH_DSS_WITH_DES_CBC_SHA",
"TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA",
"TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
"TLS_DH_RSA_WITH_DES_CBC_SHA",
"TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
"TLS_DHE_DSS_WITH_DES_CBC_SHA",
"TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
"TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"TLS_DHE_RSA_WITH_DES_CBC_SHA",
"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_DH_anon_EXPORT_WITH_RC4_40_MD5",
"TLS_DH_anon_WITH_RC4_128_MD5",
"TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
"TLS_DH_anon_WITH_DES_CBC_SHA",
"TLS_DH_anon_WITH_3DES_EDE_CBC_SHA",
"TLS_KRB5_WITH_DES_CBC_SHA",
"TLS_KRB5_WITH_3DES_EDE_CBC_SHA",
"TLS_KRB5_WITH_RC4_128_SHA",
"TLS_KRB5_WITH_IDEA_CBC_SHA",
"TLS_KRB5_WITH_DES_CBC_MD5",
"TLS_KRB5_WITH_3DES_EDE_CBC_MD5",
"TLS_KRB5_WITH_RC4_128_MD5",
"TLS_KRB5_WITH_IDEA_CBC_MD5",
"TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA",
"TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
"TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5",
"TLS_KRB5_EXPORT_WITH_RC4_40_MD5",
"TLS_PSK_WITH_NULL_SHA",
"TLS_DHE_PSK_WITH_NULL_SHA",
"TLS_RSA_PSK_WITH_NULL_SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"TLS_DH_DSS_WITH_AES_128_CBC_SHA",
"TLS_DH_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DH_anon_WITH_AES_128_CBC_SHA",
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_DH_DSS_WITH_AES_256_CBC_SHA",
"TLS_DH_RSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_DH_anon_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_NULL_SHA256",
"TLS_RSA_WITH_AES_128_CBC_SHA256",
"TLS_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DH_DSS_WITH_AES_128_CBC_SHA256",
"TLS_DH_RSA_WITH_AES_128_CBC_SHA256",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_DH_DSS_WITH_AES_256_CBC_SHA256",
"TLS_DH_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DH_anon_WITH_AES_128_CBC_SHA256",
"TLS_DH_anon_WITH_AES_256_CBC_SHA256",
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA",
"TLS_PSK_WITH_RC4_128_SHA",
"TLS_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_PSK_WITH_AES_128_CBC_SHA",
"TLS_PSK_WITH_AES_256_CBC_SHA",
"TLS_DHE_PSK_WITH_RC4_128_SHA",
"TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_DHE_PSK_WITH_AES_128_CBC_SHA",
"TLS_DHE_PSK_WITH_AES_256_CBC_SHA",
"TLS_RSA_PSK_WITH_RC4_128_SHA",
"TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_PSK_WITH_AES_128_CBC_SHA",
"TLS_RSA_PSK_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_SEED_CBC_SHA",
"TLS_DH_DSS_WITH_SEED_CBC_SHA",
"TLS_DH_RSA_WITH_SEED_CBC_SHA",
"TLS_DHE_DSS_WITH_SEED_CBC_SHA",
"TLS_DHE_RSA_WITH_SEED_CBC_SHA",
"TLS_DH_anon_WITH_SEED_CBC_SHA",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_DH_RSA_WITH_AES_128_GCM_SHA256",
"TLS_DH_RSA_WITH_AES_256_GCM_SHA384",
"TLS_DH_DSS_WITH_AES_128_GCM_SHA256",
"TLS_DH_DSS_WITH_AES_256_GCM_SHA384",
"TLS_DH_anon_WITH_AES_128_GCM_SHA256",
"TLS_DH_anon_WITH_AES_256_GCM_SHA384",
"TLS_PSK_WITH_AES_128_GCM_SHA256",
"TLS_PSK_WITH_AES_256_GCM_SHA384",
"TLS_RSA_PSK_WITH_AES_128_GCM_SHA256",
"TLS_RSA_PSK_WITH_AES_256_GCM_SHA384",
"TLS_PSK_WITH_AES_128_CBC_SHA256",
"TLS_PSK_WITH_AES_256_CBC_SHA384",
"TLS_PSK_WITH_NULL_SHA256",
"TLS_PSK_WITH_NULL_SHA384",
"TLS_DHE_PSK_WITH_AES_128_CBC_SHA256",
"TLS_DHE_PSK_WITH_AES_256_CBC_SHA384",
"TLS_DHE_PSK_WITH_NULL_SHA256",
"TLS_DHE_PSK_WITH_NULL_SHA384",
"TLS_RSA_PSK_WITH_AES_128_CBC_SHA256",
"TLS_RSA_PSK_WITH_AES_256_CBC_SHA384",
"TLS_RSA_PSK_WITH_NULL_SHA256",
"TLS_RSA_PSK_WITH_NULL_SHA384",
"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
"TLS_ECDH_ECDSA_WITH_NULL_SHA",
"TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_NULL_SHA",
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDH_RSA_WITH_NULL_SHA",
"TLS_ECDH_RSA_WITH_RC4_128_SHA",
"TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_NULL_SHA",
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDH_anon_WITH_NULL_SHA",
"TLS_ECDH_anon_WITH_RC4_128_SHA",
"TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
"TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
"TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA",
"TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA",
"TLS_SRP_SHA_WITH_AES_128_CBC_SHA",
"TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA",
"TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA",
"TLS_SRP_SHA_WITH_AES_256_CBC_SHA",
"TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA",
"TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_PSK_WITH_RC4_128_SHA",
"TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_PSK_WITH_NULL_SHA",
"TLS_ECDHE_PSK_WITH_NULL_SHA256",
"TLS_ECDHE_PSK_WITH_NULL_SHA384",
"TLS_RSA_WITH_ARIA_128_CBC_SHA256",
"TLS_RSA_WITH_ARIA_256_CBC_SHA384",
"TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256",
"TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384",
"TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256",
"TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384",
"TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256",
"TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384",
"TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384",
"TLS_DH_anon_WITH_ARIA_128_CBC_SHA256",
"TLS_DH_anon_WITH_ARIA_256_CBC_SHA384",
"TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384",
"TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256",
"TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384",
"TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384",
"TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256",
"TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384",
"TLS_RSA_WITH_ARIA_128_GCM_SHA256",
"TLS_RSA_WITH_ARIA_256_GCM_SHA384",
"TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256",
"TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384",
"TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256",
"TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384",
"TLS_DH_anon_WITH_ARIA_128_GCM_SHA256",
"TLS_DH_anon_WITH_ARIA_256_GCM_SHA384",
"TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256",
"TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384",
"TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256",
"TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384",
"TLS_PSK_WITH_ARIA_128_CBC_SHA256",
"TLS_PSK_WITH_ARIA_256_CBC_SHA384",
"TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256",
"TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384",
"TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256",
"TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384",
"TLS_PSK_WITH_ARIA_128_GCM_SHA256",
"TLS_PSK_WITH_ARIA_256_GCM_SHA384",
"TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256",
"TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384",
"TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256",
"TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384",
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_RSA_WITH_AES_128_CCM",
"TLS_RSA_WITH_AES_256_CCM",
"TLS_RSA_WITH_AES_128_CCM_8",
"TLS_RSA_WITH_AES_256_CCM_8",
"TLS_PSK_WITH_AES_128_CCM",
"TLS_PSK_WITH_AES_256_CCM",
"TLS_PSK_WITH_AES_128_CCM_8",
"TLS_PSK_WITH_AES_256_CCM_8"
};
static {
Arrays.sort(CIPHER_SUITE_BLACK_LIST);
}
private boolean allowPayloadForUndefinedHttpMethods;
private final Attribute<Connection> CIPHER_CHECKED =
AttributeBuilder.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("BLACK_LIST_CIPHER_SUITE_CHEKCED");
private Collection<Connection> activeConnections = new HashSet<>(1024);
private AtomicBoolean shuttingDown = new AtomicBoolean();
public Http2ServerFilter(final Http2Configuration configuration) {
super(configuration);
}
@SuppressWarnings("unused")
public boolean isAllowPayloadForUndefinedHttpMethods() {
return allowPayloadForUndefinedHttpMethods;
}
@SuppressWarnings("unused")
public void setAllowPayloadForUndefinedHttpMethods(boolean allowPayloadForUndefinedHttpMethods) {
this.allowPayloadForUndefinedHttpMethods = allowPayloadForUndefinedHttpMethods;
}
@Override
public NextAction handleAccept(final FilterChainContext ctx) throws IOException {
if (!shuttingDown.get()) {
activeConnections.add(ctx.getConnection());
}
return ctx.getInvokeAction();
}
@Override
public NextAction handleClose(final FilterChainContext ctx) throws IOException {
if (!shuttingDown.get()) {
activeConnections.remove(ctx.getConnection());
}
return ctx.getInvokeAction();
}
@SuppressWarnings("unchecked")
@Override
public NextAction handleRead(final FilterChainContext ctx)
throws IOException {
if (checkIfHttp2StreamChain(ctx)) {
return ctx.getInvokeAction();
}
final Connection connection = ctx.getConnection();
Http2State http2State = Http2State.get(connection);
if (http2State != null && http2State.isNeverHttp2()) {
return ctx.getInvokeAction();
}
final HttpContent httpContent = ctx.getMessage();
final HttpHeader httpHeader = httpContent.getHttpHeader();
if (http2State == null) {
assert httpHeader.isRequest();
if (httpHeader.isSecure()) {
Http2State.create(connection).setNeverHttp2();
return ctx.getInvokeAction();
}
final HttpRequestPacket httpRequest =
(HttpRequestPacket) httpHeader;
if (!Method.PRI.equals(httpRequest.getMethod())) {
final boolean isLast = httpContent.isLast();
if (tryHttpUpgrade(ctx, httpRequest, isLast) && isLast) {
enableOpReadNow(ctx);
}
return ctx.getInvokeAction();
}
http2State = doDirectUpgrade(ctx);
}
final Http2Session http2Session =
obtainHttp2Session(http2State, ctx, true);
if (httpHeader.isSecure() && !getConfiguration().isDisableCipherCheck() && !CIPHER_CHECKED.isSet(connection)) {
CIPHER_CHECKED.set(connection, connection);
final SSLEngine engine = SSLUtils.getSSLEngine(connection);
if (engine != null) {
if (Arrays.binarySearch(CIPHER_SUITE_BLACK_LIST, engine.getSession().getCipherSuite()) >= 0) {
http2Session.terminate(ErrorCode.INADEQUATE_SECURITY, null);
return ctx.getStopAction();
}
}
}
final Buffer framePayload;
if (!http2Session.isHttp2InputEnabled()) {
if (http2State.isHttpUpgradePhase()) {
if (httpContent.isLast()) {
http2State.setDirectUpgradePhase();
enableOpReadNow(ctx);
}
return ctx.getInvokeAction();
}
final HttpRequestPacket httpRequest = (HttpRequestPacket) httpHeader;
try {
if (!checkPRI(httpRequest, httpContent)) {
return ctx.getStopAction(httpContent);
}
} catch (Exception e) {
httpRequest.getProcessingState().setError(true);
httpRequest.getProcessingState().setKeepAlive(false);
final HttpResponsePacket httpResponse = httpRequest.getResponse();
httpResponse.setStatus(HttpStatus.BAD_REQUEST_400);
ctx.write(httpResponse);
connection.closeSilently();
return ctx.getStopAction();
}
final Buffer payload = httpContent.getContent();
framePayload = payload.split(payload.position() + PRI_PAYLOAD.length);
} else {
framePayload = httpContent.getContent();
}
httpContent.recycle();
if (connection.getAttributes().getAttribute(HTTP2_PUSH_ENABLED) == null) {
connection.getAttributes().setAttribute(HTTP2_PUSH_ENABLED, Boolean.TRUE);
}
final List<Http2Frame> framesList =
frameCodec.parse(http2Session,
http2State.getFrameParsingState(),
framePayload);
if (!processFrames(ctx, http2Session, framesList)) {
return ctx.getSuspendAction();
}
return ctx.getStopAction();
}
@Override
public NextAction handleEvent(final FilterChainContext ctx,
final FilterChainEvent event) throws IOException {
final Object type = event.type();
if (type == ShutdownEvent.TYPE) {
if (shuttingDown.compareAndSet(false, true)) {
((ShutdownEvent) event).addShutdownTask(new Callable<Filter>() {
@Override
public Filter call() throws Exception {
final Collection<Connection> activeConnections = shuttingDown();
if (!activeConnections.isEmpty()) {
final List<FutureImpl> futures = new ArrayList<>(activeConnections.size());
for (final Connection c : activeConnections) {
if (c.isOpen()) {
final Http2Session session = Http2Session.get(c);
if (session != null) {
futures.add(session.terminateGracefully());
}
}
}
for (final FutureImpl f : futures) {
f.get();
}
}
return Http2ServerFilter.this;
}
});
}
}
if (type == HttpEvents.IncomingHttpUpgradeEvent.TYPE) {
final HttpHeader header
= ((HttpEvents.IncomingHttpUpgradeEvent) event).getHttpHeader();
if (header.isRequest()) {
if (checkRequestHeadersOnUpgrade((HttpRequestPacket) header)) {
header.setIgnoreContentModifiers(false);
return ctx.getStopAction();
}
}
return ctx.getInvokeAction();
}
final Http2State state = Http2State.get(ctx.getConnection());
if (state == null || state.isNeverHttp2()) {
return ctx.getInvokeAction();
}
if (type == PushEvent.TYPE) {
doPush(ctx, (PushEvent) event);
return ctx.getSuspendAction();
}
if (type == HttpEvents.ResponseCompleteEvent.TYPE) {
final HttpContext httpContext = HttpContext.get(ctx);
final Http2Stream stream = (Http2Stream) httpContext.getContextStorage();
stream.onProcessingComplete();
final Http2Session http2Session = stream.getHttp2Session();
if (!http2Session.isHttp2InputEnabled()) {
state.finishHttpUpgradePhase();
return ctx.getInvokeAction();
}
return ctx.getStopAction();
}
return super.handleEvent(ctx, event);
}
@Override
protected void onPrefaceReceived(Http2Session http2Session) {
http2Session.sendPreface();
}
private Http2State doDirectUpgrade(final FilterChainContext ctx) {
final Connection connection = ctx.getConnection();
final Http2Session http2Session =
new Http2Session(connection, true, this);
final Http2State http2State = Http2State.create(connection);
http2State.setHttp2Session(http2Session);
http2State.setDirectUpgradePhase();
http2Session.setupFilterChains(ctx, true);
http2Session.sendPreface();
return http2State;
}
Collection<Connection> shuttingDown() {
shuttingDown.compareAndSet(false, true);
return activeConnections;
}
private boolean tryHttpUpgrade(final FilterChainContext ctx,
final HttpRequestPacket httpRequest, final boolean isLast)
throws Http2StreamException {
if (!checkHttpMethodOnUpgrade(httpRequest)) {
return false;
}
if (!checkRequestHeadersOnUpgrade(httpRequest)) {
return false;
}
final boolean http2Upgrade = isHttp2UpgradingVersion(httpRequest);
if (!http2Upgrade) {
return false;
}
final SettingsFrame settingsFrame =
getHttp2UpgradeSettings(httpRequest);
if (settingsFrame == null) {
return false;
}
final Connection connection = ctx.getConnection();
final Http2Session http2Session =
new Http2Session(connection, true, this);
final Http2State http2State = Http2State.create(connection);
http2State.setHttp2Session(http2Session);
http2Session.setupFilterChains(ctx, true);
if (isLast) {
http2State.setDirectUpgradePhase();
}
try {
applySettings(http2Session, settingsFrame);
} catch (Http2SessionException e) {
Http2State.remove(connection);
return false;
}
final HttpResponsePacket httpResponse = httpRequest.getResponse();
httpResponse.setStatus(HttpStatus.SWITCHING_PROTOCOLS_101);
httpResponse.setHeader(Header.Connection, "Upgrade");
httpResponse.setHeader(Header.Upgrade, HTTP2_CLEAR);
httpResponse.setIgnoreContentModifiers(true);
ctx.write(httpResponse);
httpResponse.setCommitted(false);
http2Session.sendPreface();
httpResponse.setStatus(HttpStatus.OK_200);
httpResponse.getHeaders().clear();
httpRequest.setProtocol(Protocol.HTTP_2_0);
httpResponse.setProtocol(Protocol.HTTP_2_0);
httpRequest.getUpgradeDC().recycle();
httpResponse.getProcessingState().setKeepAlive(true);
if (http2Session.isGoingAway()) {
Http2State.remove(connection);
return false;
}
final Http2Stream stream = http2Session.acceptUpgradeStream(
httpRequest, 0, !httpRequest.isExpectContent());
final HttpContext httpContext = HttpContext.newInstance(stream,
stream, stream, httpRequest);
httpRequest.getProcessingState().setHttpContext(httpContext);
httpRequest.setAttribute(Http2Stream.HTTP2_STREAM_ATTRIBUTE, stream);
httpContext.attach(ctx);
return true;
}
private boolean checkHttpMethodOnUpgrade(
final HttpRequestPacket httpRequest) {
return httpRequest.getMethod() != Method.CONNECT;
}
private boolean checkPRI(final HttpRequestPacket httpRequest,
final HttpContent httpContent) {
if (!Method.PRI.equals(httpRequest.getMethod())) {
throw new HttpBrokenContentException();
}
final Buffer payload = httpContent.getContent();
if (payload.remaining() < PRI_PAYLOAD.length) {
return false;
}
final int pos = payload.position();
for (int i = 0; i < PRI_PAYLOAD.length; i++) {
if (payload.get(pos + i) != PRI_PAYLOAD[i]) {
throw new HttpBrokenContentException();
}
}
return true;
}
@Override
protected void (
final Http2Session http2Session,
final FilterChainContext context,
final HeaderBlockHead firstHeaderFrame) throws IOException {
if (!ignoreFrameForStreamId(http2Session, firstHeaderFrame.getStreamId())) {
processInRequest(http2Session, context, (HeadersFrame) firstHeaderFrame);
}
}
private void (final Http2Session http2Session,
final FilterChainContext context, final HeadersFrame headersFrame)
throws IOException {
final Http2Request request = Http2Request.create();
request.setConnection(context.getConnection());
Http2Stream stream = http2Session.getStream(headersFrame.getStreamId());
if (stream != null) {
final Http2Stream.State state = stream.getState();
if (state == Http2Stream.State.HALF_CLOSED_REMOTE || state == Http2Stream.State.CLOSED) {
if (headersFrame.isEndStream()) {
throw new Http2SessionException(ErrorCode.STREAM_CLOSED);
}
throw new Http2StreamException(stream.getId(), ErrorCode.STREAM_CLOSED);
}
if (!headersFrame.isEndStream()) {
throw new Http2StreamException(stream.getId(),
ErrorCode.PROTOCOL_ERROR,
"Received second HEADERS frame, but was not marked fin.");
}
try {
stream.onRcvHeaders(headersFrame.isEndStream());
final Map<String,String> capture = ((NetLogger.isActive()) ? new HashMap<>() : null);
DecoderUtils.decodeTrailerHeaders(http2Session, stream.getRequest(), capture);
NetLogger.log(Context.RX, http2Session, headersFrame, capture);
} catch (IOException ioe) {
throw new Http2SessionException(ErrorCode.COMPRESSION_ERROR, ioe.getCause().getMessage());
} catch (HeaderDecodingException hde) {
if (hde.getErrorType() == HeaderDecodingException.ErrorType.SESSION) {
throw new Http2SessionException(hde.getErrorCode(), hde.getMessage());
} else {
throw new Http2StreamException(stream.getId(), hde.getErrorCode(), hde.getMessage());
}
}
if (headersFrame.isTruncated()) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING,
"[{0}, {1}] Trailer headers truncated. Some headers may not be available.",
new Object[] { http2Session.toString(), headersFrame.getStreamId()});
}
}
stream.flushInputData();
stream.inputBuffer.close(IN_FIN_TERMINATION);
return;
}
stream = http2Session.acceptStream(request,
headersFrame.getStreamId(),
headersFrame.getStreamDependency(),
headersFrame.isExclusive(),
0);
if (stream == null) {
request.recycle();
return;
}
try {
final Map<String,String> capture = ((NetLogger.isActive()) ? new LinkedHashMap<>() : null);
DecoderUtils.decodeRequestHeaders(http2Session, request, capture);
NetLogger.log(Context.RX, http2Session, headersFrame, capture);
} catch (IOException ioe) {
throw new Http2SessionException(ErrorCode.COMPRESSION_ERROR, ioe.getCause().getMessage());
} catch (HeaderDecodingException hde) {
if (hde.getErrorType() == HeaderDecodingException.ErrorType.SESSION) {
throw new Http2SessionException(hde.getErrorCode(), hde.getMessage());
} else {
throw new Http2StreamException(stream.getId(), hde.getErrorCode(), hde.getMessage());
}
}
if (headersFrame.isTruncated()) {
final HttpResponsePacket response = request.getResponse();
HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE.setValues(response);
final HttpHeader header = response.getHttpHeader();
header.setContentLength(0);
header.setExpectContent(false);
processOutgoingHttpHeader(context, http2Session, header, response);
return;
}
onHttpHeadersParsed(request, context);
request.getHeaders().mark();
prepareIncomingRequest(stream, request);
final boolean isEOS = headersFrame.isEndStream();
stream.onRcvHeaders(isEOS);
if (isEOS) {
request.setExpectContent(false);
}
final boolean isExpectContent = request.isExpectContent();
if (!isExpectContent) {
stream.inputBuffer.terminate(IN_FIN_TERMINATION);
}
sendUpstream(http2Session,
stream,
request.httpContentBuilder().content(Buffers.EMPTY_BUFFER).last(!isExpectContent).build());
}
@Override
@SuppressWarnings("unchecked")
protected void (final FilterChainContext ctx,
final Http2Session http2Session,
final HttpHeader httpHeader,
final HttpPacket entireHttpPacket) throws IOException {
final HttpResponsePacket response = (HttpResponsePacket) httpHeader;
final Http2Stream stream = Http2Stream.getStreamFor(response);
assert stream != null;
if (!response.isCommitted()) {
prepareOutgoingResponse(response);
}
final FilterChainContext.TransportContext transportContext = ctx.getTransportContext();
stream.getOutputSink().writeDownStream(entireHttpPacket,
ctx,
transportContext.getCompletionHandler(),
transportContext.getMessageCloner());
}
private void doPush(final FilterChainContext ctx, final PushEvent pushEvent) {
final Http2Session http2Session = Http2Session.get(ctx.getConnection());
if (http2Session == null) {
throw new IllegalStateException("Unable to find valid Http2Session");
}
try {
final HttpRequestPacket source = (HttpRequestPacket) pushEvent.getHttpRequest();
Http2Stream parentStream = (Http2Stream) source.getAttribute(Http2Stream.HTTP2_PARENT_STREAM_ATTRIBUTE);
if (parentStream == null) {
parentStream = Http2Stream.getStreamFor(pushEvent.getHttpRequest());
}
if (parentStream == null) {
return;
}
final String eventPath = pushEvent.getPath();
String path = eventPath;
String query = null;
final int idx = eventPath.indexOf('?');
if (idx != -1) {
path = eventPath.substring(0, idx);
query = eventPath.substring(idx + 1);
}
final Http2Request request = Http2Request.create();
request.setAttribute(Http2Stream.HTTP2_PARENT_STREAM_ATTRIBUTE, parentStream);
request.setConnection(ctx.getConnection());
request.getRequestURIRef().init(path);
request.getQueryStringDC().setString(query);
request.setProtocol(Protocol.HTTP_2_0);
request.setMethod(pushEvent.getMethod());
request.setSecure(pushEvent.getHttpRequest().isSecure());
request.getHeaders().copyFrom(pushEvent.getHeaders());
request.setExpectContent(false);
prepareOutgoingRequest(request);
prepareOutgoingResponse(request.getResponse());
final Http2Stream pushStream;
http2Session.getNewClientStreamLock().lock();
try {
pushStream = http2Session.openStream(
request,
http2Session.getNextLocalStreamId(), parentStream.getId(),
false, 0);
pushStream.inputBuffer.terminate(IN_FIN_TERMINATION);
http2Session.getDeflaterLock().lock();
try {
boolean logging = NetLogger.isActive();
final Map<String,String> capture = ((logging) ? new LinkedHashMap<>() : null);
List<Http2Frame> pushPromiseFrames =
http2Session.encodeHttpRequestAsPushPromiseFrames(
ctx, pushStream.getRequest(), parentStream.getId(),
pushStream.getId(), null, capture);
if (logging) {
for (Http2Frame http2Frame : pushPromiseFrames) {
if (http2Frame.getType() == PushPromiseFrame.TYPE) {
NetLogger.log(Context.TX, http2Session, (PushPromiseFrame) http2Frame, capture);
break;
}
}
}
http2Session.getOutputSink().writeDownStream(pushPromiseFrames);
} finally {
pushStream.onSendPushPromise();
http2Session.getDeflaterLock().unlock();
}
} finally {
http2Session.getNewClientStreamLock().unlock();
}
request.getProcessingState().setHttpContext(
HttpContext.newInstance(pushStream, pushStream, pushStream, request));
submit(ctx.getConnection(), new Runnable() {
@Override
public void run() {
http2Session.sendMessageUpstream(pushStream,
HttpContent
.builder(request)
.content(Buffers.EMPTY_BUFFER)
.build());
}
});
} catch (Exception e) {
LOGGER.log(Level.SEVERE,
"Unable to push resource identified by path [{0}]", pushEvent.getPath());
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} finally {
pushEvent.recycle();
ctx.resume(ctx.getStopAction());
}
}
private void submit(final Connection c, final Runnable runnable) {
if (threadPool != null) {
threadPool.submit(runnable);
} else {
final Transport t = c.getTransport();
final ExecutorService workerThreadPool = t.getWorkerThreadPool();
if (workerThreadPool != null) {
workerThreadPool.submit(runnable);
} else {
t.getKernelThreadPool().submit(runnable);
}
}
}
private void prepareOutgoingResponse(final HttpResponsePacket response) {
response.setProtocol(Protocol.HTTP_2_0);
String contentType = response.getContentType();
if (contentType != null) {
response.getHeaders().setValue(Header.ContentType).setString(contentType);
}
if (response.getContentLength() != -1) {
FIXED_LENGTH_ENCODING.prepareSerialize(null, response, null);
}
if (!response.containsHeader(Header.Date)) {
response.getHeaders().addValue(Header.Date)
.setBytes(FastHttpDateFormat.getCurrentDateBytes());
}
}
private void enableOpReadNow(final FilterChainContext ctx) {
final FilterChainContext newContext = ctx.copy();
ctx.getInternalContext().removeAllLifeCycleListeners();
newContext.resume(newContext.getStopAction());
}
}