package org.glassfish.grizzly.http2;
import static org.glassfish.grizzly.http2.Termination.IN_FIN_TERMINATION;
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 javax.net.ssl.SSLEngine;
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.DataChunk;
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;
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 final Collection<Connection> activeConnections = new HashSet<>(1024);
private final AtomicBoolean shuttingDown = new AtomicBoolean();
public Http2ServerFilter(final Http2Configuration configuration) {
super(configuration);
}
public boolean isAllowPayloadForUndefinedHttpMethods() {
return allowPayloadForUndefinedHttpMethods;
}
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();
}
@Override
public NextAction handleRead(final FilterChainContext ctx) throws IOException {
LOGGER.finest(() -> String.format("handleRead(ctx=%s)", ctx));
if (checkIfHttp2StreamChain(ctx)) {
LOGGER.finest("Already registered HTTP2 stream chain, invoking action.");
return ctx.getInvokeAction();
}
final Connection connection = ctx.getConnection();
Http2State http2State = Http2State.get(connection);
if (http2State != null && http2State.isNeverHttp2()) {
LOGGER.finest("Not a HTTP2 connection, invoking action.");
return ctx.getInvokeAction();
}
final HttpContent httpContent = ctx.getMessage();
final HttpHeader httpHeader = httpContent.getHttpHeader();
if (http2State == null) {
assert httpHeader.isRequest();
if (httpHeader.isSecure()) {
LOGGER.finest("Secure connection, but http2State was null, ALPN was bypassed. Invoking action.");
Http2State.create(connection).setNeverHttp2();
return ctx.getInvokeAction();
}
final HttpRequestPacket httpRequest = (HttpRequestPacket) httpHeader;
if (Method.PRI.equals(httpRequest.getMethod())) {
http2State = doDirectUpgrade(ctx);
} else {
final boolean isLast = httpContent.isLast();
if (tryHttpUpgrade(ctx, httpRequest, isLast) && isLast) {
enableOpReadNow(ctx);
}
return ctx.getInvokeAction();
}
}
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 {
LOGGER.finest(() -> String.format("handleEvent(ctx=%s, event=%s)", ctx, event));
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) {
LOGGER.finest(() -> String.format("doDirectUpgrade(ctx=%s)", 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() - 2 < 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
protected void (final HttpHeader httpHeader, final FilterChainContext ctx) {
Http2Request request = (Http2Request) httpHeader;
DataChunk hostDC = null;
final DataChunk uriBC = request.getRequestURIRef().getRequestURIBC();
if (uriBC.startsWithIgnoreCase("https", 0)) {
int pos = uriBC.indexOf("://", 5);
int uriBCStart = uriBC.getStart();
int slashPos;
if (pos != -1) {
slashPos = uriBC.indexOf('/', pos + 3);
if (slashPos == -1) {
slashPos = uriBC.getLength();
uriBC.setStart(uriBCStart + pos + 1);
uriBC.setEnd(uriBCStart + pos + 2);
} else {
uriBC.setStart(uriBCStart + slashPos);
uriBC.setEnd(uriBC.getEnd());
}
hostDC = request.getHeaders().setValue(Header.Host);
hostDC.set(uriBC, uriBCStart + pos + 3, uriBCStart + slashPos);
}
}
if (hostDC == null) {
hostDC = request.getHeaders().getValue(Header.Host);
}
if (hostDC == null || hostDC.isNull()) {
return;
}
request.setUnparsedHostC(hostDC);
}
@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) {
LOGGER.finest(() -> String.format("doPush(ctx=%s, pushEvent=%s)", ctx, 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;
}
}
}
pushStream.onSendPushPromise();
http2Session.getOutputSink().writeDownStream(pushPromiseFrames);
} finally {
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());
}
}