Weird HTTP/2 HPACK encoding in Firefox

2019-07-26 06:50发布

问题:

I'm working on a server-side HTTP/2 implementation and using Firefox as a test client. Sometimes I get a request that looks wrongly encoded by FF. But before blaming FF I'd like to confirm with you if I'm decoding the HPACK data properly.

Here is the original request (sorted by name as seen in the Firefox dev console):

GET /images/rewards/icon-profile-on.png?81aa8356289ae0f1e4715f4f04f681cfe85147f0
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.5
Connection: keep-alive
Cookie: _ga=GA1.3.1983042994.1521655507
Cookie: _gid=GA1.3.1027405523.1521655507
Host: static.kfc.com.my
Referer: https://kfc.com.my/
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0

Note that some of the headers are transformed before encoding, like Host is encoded as :authority, Connection is removed - these are requirements of HTTP/2). The order is changed as well. The headers of interests are Cookie and Host (:authority)

Here is the HEADERS frame data (hex) for this request (in the first stream in the connection) with my interpretation of the data:

    // ix=2; :method: GET
    "82"

    // ix=5; :path: /images/rewards/icon-profile-on.png?81aa8356289ae0f1e4715f4f04f681cfe85147f0
    // (not stored in the header table)
    "05 b6 60 d4 8e 62 a1 8b 0b e0 76 48 86 0c 43 d4 "
    "b5 76 1e 53 50 55 8f 52 f5 d5 37 f8 f0 46 37 99 "
    "6d c1 3c f8 ca 09 42 56 9d 0b 72 b5 28 1a 95 c7 "
    "82 49 4a f3 61 69 d9 41"

    // ix=1->62 (lookup at index 1, store at 62); :authority: static.kfc.com.my
    "41 8c 42 46 93 11 7e b2 91 72 1e 95 e9 f5 "

    // ix=7; :scheme: https
    "87"

    // ix=58->63; User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0
    "7a b4 d0 7f 66 a2 81 b0 da e0 53 fa fc 08 7e d4 "
    "ce 6a ad f2 a7 97 9c 89 c6 be d4 b3 bd c6 df 5c "
    "1f da 98 8a 4e a7 60 40 08 00 10 05 4c 26 b0 b2 "
    "9f cb 0d be b8 3f"

    // ix=19->64; Accept: */*
    "53 83 f9 63 e7 "

    // ix=17->65; Accept-Language: en-US,en;q=0.5
    "51 8b 2d 4b 70 dd f4 5a be fb 40 05 db "

    // ix=16->66; Accept-Encoding: gzip, deflate, br
    "50 8d 9b d9 ab fa 52 42 cb 40 d2 5f a5 23 b3 "

    // ix=51->67; Referer: https://kfc.com.my/
    "73 8e 9d 29 ad 17 18 63 ac a4 5c 87 a5 7a 7d 31 "

    // ix=32->68; Cookie: _ga=GA1.3.1983042994.1521655507
    "60 97 8a 61 c1 8a 10 ae ca e1 7d e6 40 d0 9f 7d "
    "a5 c2 d8 82 e3 6d b6 07 7f "

    // The issue is here:
    // ix=62->69 :authority:_gid=GA1.3.1027405523.1521655507
    "7e 97 8a 63 49 06 28 42 bb 2b 84 02 75 a0 36 d8 "
    "99 5c 2d 88 2e 36 db 60 77"

The last decoded header should have been Cookie: _gid=... and must be encoded as either 32->69 or 68->69 (looking up an existing Cookie and storing it under 69 index) However instead Firefox encoded the index 62 which is :authority, thus producing a duplicate :authority header with the value of the second Cookie.

Or am I missing something?

PS. Chrome does not have this issue.

回答1:

From the HPACK spec:

The dynamic table consists of a list of header fields maintained in first-in, first-out order. The first and newest entry in a dynamic table is at the lowest index, and the oldest entry of a dynamic table is at the highest index.

This means that authority is added as index 62 as you suggest, but that is then incremented to 63 when the User-Agent is added (which takes over index position 62). Then it is incremented to 64...etc.

So when it comes to add the second cookie, the first cookie is at index 62. At this point you have two references to the cookie header - the original one from the static table at position 32, and the new one at position 62. Either can be used to reference the new cookie and it looks like Chrome uses the former while Firefox uses the latter.

Incidentally Wireshark is your friend here as it allows you to see the decoded messages (including the index value) and if you had looked at the next message, than you would have seen the references in the reverse order.



标签: http http2