FT_HTTP2

HTTP/2 protocol filter.

Category:

Protocol filter

Indicates object parts:

yes

HTTP/2 objects contain 3 streams (indexed by ePF_Http2Stream):

H2S_INFO (0)

HTTP2 stream id as x-exhdr-streamid: <id>

H2S_HEADER (1)

HTTP2 header

H2S_CONTENT (2)

decoded and uncompressed content

HTTP/2 provides an optimized transport for HTTP semantics. HTTP/2 supports all of the core features of HTTP/1.1 but aims to be more efficient in several ways.

The basic protocol unit in HTTP/2 is a frame. Each frame type serves a different purpose. For example, HEADERS and DATA frames form the basis of HTTP requests and responses; other frame types like SETTINGS, WINDOW_UPDATE, and PUSH_PROMISE are used in support of other HTTP/2 features. The HTTP2 filter collects only requests and responses from HEADERS and DATA frames, and passes the other frame types as-is without indications in events.

Multiplexing of requests is achieved by having each HTTP request/response exchange associated with its own stream within a single TCP connection. Streams are largely independent of each other, so a blocked or stalled request or response does not prevent progress on other streams. It is necessary to keep and specify the stream identifier in the H2S_INFO field of each request and response, which specifies which stream the object belongs to.

The HTTP/2 headers are compressed using HPACK encoding. The HTTP2 filter decodes the headers when parsing frames and indicates them in generic text header format, then encodes them back to HPACK format when the object data is passed to the destination.

HTTP2 responses contain the following custom fields in header:

x-exhdr-method

:method header field value from the appropriate request

x-exhdr-authority

:authority header field value from the appropriate request

x-exhdr-path

:path header field value from the appropriate request

It is possible to use these fields in responses to get the requested URL as :authority (host name) concatenated with :path (URI). The :method header value contains the first token of the HTTP/1.x status line, like GET/POST etc.

Between receiving the HTTP header and the full content, the library indicates object parts via the dataPartAvailable event. It makes sense to classify the header and a part of the content in dataPartAvailable to avoid buffering the full content, which can be very large. It allows optimizing filtering and avoiding long delays in the browser, which can abort connections on timeout. dataAvailable is called when the full object is available for filtering, unless dataPartAvailable returned DPCR_BYPASS, DPCR_BLOCK or DPCR_UPDATE_AND_BYPASS. It is possible to update object content in dataPartAvailable and return the DPCR_UPDATE_AND_BYPASS or DPCR_UPDATE_AND_FILTER_READ_ONLY code. In this case, the changes are applied to the available part of the data. The rest of the request/response object is bypassed, or the full object will be indicated in read-only mode via dataAvailable, according to the returned code. This method is useful if it is necessary to change only a small part of the request/response at the beginning without waiting until the full response is downloaded from the server, e.g. to insert a script into an HTML page.

The filter does not decompress objects having Content-Type: application/* in the header. This is because some servers specify an invalid content-type for this MIME category. The filtering application can analyze the value of the content-encoding header and decompress the data if needed after deeper analysis.

HTTP2 protocol is negotiated via a TLS tunnel. By default, the required TLS ALPN extension is disabled. When the FT_HTTP2 filter is added, the SSL filter automatically enables the ALPN extension (FF_SSL_ENABLE_ALPN flag) and negotiates the h2 protocol during the TLS handshake.

Note that all header names in HTTP/2 use lower-case letters. It is necessary to consider this when a header for a request/response is generated by code.

FF_HTTP_DONT_UNCOMPRESS_CONTENT

The FF_HTTP_DONT_UNCOMPRESS_CONTENT flag disables decompression for HTTP content.

FF_HTTP_INDICATE_INCOMPLETE_OBJECTS

When this flag is enabled, the filter exposes in dataAvailable the request/response buffers as read-only OT_HTTP2_REQUEST_INCOMPLETE/OT_HTTP2_RESPONSE_INCOMPLETE objects if a stream reset occurs before the objects are filtered.

QUIC protocol

Google Chrome and other browsers can switch to QUIC and use it instead of HTTP/1.x/2. As a workaround, it is possible to block protocols that cannot be filtered. In this case, browsers switch to HTTP.

To disable QUIC, add blocking UDP rules for the default remote ports 80/443:

C/C++:

NF_RULE rule;

memset(&rule, 0, sizeof(rule));
rule.protocol = IPPROTO_UDP;
rule.remotePort = htons(80);
rule.filteringFlag = NF_BLOCK;
nf_addRule(&rule, TRUE);

memset(&rule, 0, sizeof(rule));
rule.protocol = IPPROTO_UDP;
rule.remotePort = htons(443);
rule.filteringFlag = NF_BLOCK;
nf_addRule(&rule, TRUE);

Delphi:

FillChar(rule, sizeof(rule), 0);

rule.protocol := IPPROTO_UDP;
rule.remotePort := ntohs(80);
rule.filteringFlag := NF_BLOCK;
nf_addRule(rule, 1);

rule.protocol := IPPROTO_UDP;
rule.remotePort := ntohs(443);
rule.filteringFlag := NF_BLOCK;
nf_addRule(rule, 1);

C#:

rule = new NF_RULE();
rule.protocol = (int)ProtocolType.Udp;
rule.remotePort = (ushort)IPAddress.HostToNetworkOrder((Int16)80);
rule.filteringFlag = (uint)NF_FILTERING_FLAG.NF_BLOCK;
NFAPI.nf_addRule(rule, 0);

rule = new NF_RULE();
rule.protocol = (int)ProtocolType.Udp;
rule.remotePort = (ushort)IPAddress.HostToNetworkOrder((Int16)443);
rule.filteringFlag = (uint)NF_FILTERING_FLAG.NF_BLOCK;
NFAPI.nf_addRule(rule, 0);
References: