FT_HTTP2

HTTP2 protocol filter.

Category: Protocol filter

Supported flags:

FF_DONT_FILTER_IN
FF_DONT_FILTER_OUT
FF_READ_ONLY_IN
FF_READ_ONLY_OUT
FF_HTTP_DONT_UNCOMPRESS_CONTENT

Object types:
OT_HTTP2_REQUEST - outgoing HTTP data
OT_HTTP2_RESPONSE - incoming HTTP data

Indicates object parts: yes

HTTP2 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. HTTP2 filter collects only requests and responses from HEADERS and DATA frames, and passes as-is the other frame types 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 H2S_INFO field of each request and response, which specifies which stream the object belongs to.

HTTP/2 headers are compressed using HPACK encoding. HTTP2 filter decodes the headers during parsing frames and indicates them in generic text header format. Then encodes back to HPACK format when the object data passed to 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). :method header value contains the first token of HTTP/1.x status line like GET/POST etc.

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

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

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

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

The flag FF_HTTP_DONT_UNCOMPRESS_CONTENT disables decompression for HTTP content.

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 the protocols, which cannot be filtered. In this case the 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:

http://www.faqs.org/rfcs/rfc7540.html