Subject: Question about H2 and chunked encoding

From: Willy Tarreau <[email-masked]>
Date: Fri, 4 Aug 2017 06:54:18 +0200

Hi guys,

while implementing H2->H1 gateway support in haproxy, I'm facing a
situation in which I'm not sure about the most interoperable solution.

Let's say I'm receiving this response message from a H1 server that I
need to re-encode into H2 :

    HTTP/1.1 200 OK\r\n
    Transfer-encoding: chunked\r\n
    Content-Type: text-html\r\n
    \r\n
    0005\r\n
    Hello\r\n
    0\r\n

Please note that there is not any trailers yet nor is there the trailing
CRLF. At this point I can emit a HEADERS frame containing :

   :status=200
   content-type=text-html

and a DATA frame of size 5 containing "Hello".

But given that I have not yet seen what follows the 0\r\n, I can't yet
put the ES flag on the DATA frame. So once I get the end, either I'll
have to send a HEADERS frame containing the trailers, or I'll simply have
to close the stream.

My concern is what's the safest / most interoperable way to close the stream
at this point ? Should I send an empty DATA frame of size zero with ES bit
set or should I send a HEADERS frame of size zero with ES bit set ?

I tend to think that DATA+ES looks cleaner (ie: can be seen as last bit of
the DATA frame), but given that we're possibly expecting some trailers here,
it would also make sense to consider sending an empty HEADERS frame.

I'd like to avoid doing something that some clients may choke on, and I
suspect that empty HEADERS may not be that good.

Any enlightenment would be much appreciated :-)

thanks,
Willy

---

From: Martin Thomson <[email-masked]>
Date: Fri, 4 Aug 2017 15:01:26 +1000

If you don't actually have trailers, I would send an empty DATA + ES.
That is (to my knowledge) perfectly interoperable.

I'll let others speak about how well tested an empty HEADERS is, but
there's an important difference in the semantics if you use that.  As
soon as you send HEADERS with ES, you declare the presence of
trailers.  That they are empty is potentially confusing.

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 4 Aug 2017 07:07:47 +0200

> That is (to my knowledge) perfectly interoperable.

Great, that's perfect, thanks!

> trailers.  That they are empty is potentially confusing.

That's what I fear as well. I'd rather decide to always emit an empty
DATA+ES whenever I'd like to send an empty HEADERS if it's less risky.

Thank you for the fast response!
Willy

---

From: "Adrien de Croy" <[email-masked]>
Date: Fri, 04 Aug 2017 05:12:12 +0000

I've still never seen a chunk trailer yet, are they even in the wild?

Always seemed like a very bad idea to me, you can't make decisions on 
headers for policy if the header arrives at the very end.

Is there at least a limit on what headers you are prohibited from 
putting in a trailer (apart of course from framing headers) - e.g. 
Content-Type or Content-Encoding would be seriously problematic in a 
chunk trailer.

Adrien

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 4 Aug 2017 07:18:21 +0200

> headers for policy if the header arrives at the very end.

I haven't seen them in field, only in tests. The most likely use case is
to send a signature of the transferred data to avoid reading it twice
(eg: an operating system installation DVD could be read & summed in
parallel and the client could check the signature at the end of the
transfer).

> Is there at least a limit on what headers you are prohibited from putting in
> a trailer (apart of course from framing headers) - e.g. Content-Type or
> Content-Encoding would be seriously problematic in a chunk trailer.

I've seen somewhere in 7231 that you must not place there a field
which could alter the interpretation of the contents, so it is not
supposed to be an issue. In the case of haproxy, we don't even process
them, we just forward them as-is.

Willy

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Fri, 04 Aug 2017 05:18:48 +0000

--------
In message <em2111378b-a496-4a03-bf5c-81cd1290ad9d@bodybag>, "Adrien de Croy" w

>headers for policy if the header arrives at the very end.

The PostScript got this right back in 1980'es:  You had to make
a placeholder header that said "will be at the end".

If we ever want trailers to work, we need to do something similar.

-- 
Poul-Henning Kamp       | UNIX since Zilog Zeus 3.20
[email-masked]         | TCP/IP since RFC 956
FreeBSD committer       | BSD since 4.3-tahoe    
Never attribute to malice what can adequately be explained by incompetence.

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 4 Aug 2017 07:28:34 +0200

> If we ever want trailers to work, we need to do something similar.

Well, the Trailer header field does this by announcing which ones
you're expected to find there. It's not mandatory though.

Willy

---

From: Mike Bishop <[email-masked]>
Date: Fri, 4 Aug 2017 06:32:11 +0000

I'll second the empty DATA frame.  We do that pretty routinely and haven't hit any notable issues with it.

-----Original Message-----
From: Martin Thomson [mailto:[email-masked]] 
Sent: Thursday, August 3, 2017 10:01 PM
To: Willy Tarreau <[email-masked]>
Cc: HTTP Working Group <[email-masked]>
Subject: Re: Question about H2 and chunked encoding

I'll let others speak about how well tested an empty HEADERS is, but there's an important difference in the semantics if you use that.  As soon as you send HEADERS with ES, you declare the presence of trailers.  That they are empty is potentially confusing.

On 4 August 2017 at 14:54, Willy Tarreau <[email-masked]> wrote:
> Please note that there is not any trailers yet nor is there the 
> trailing CRLF. At this point I can emit a HEADERS frame containing :
>
>    :status=200
>    content-type=text-html
>
> have to send a HEADERS frame containing the trailers, or I'll simply 
> have to close the stream.
>
> My concern is what's the safest / most interoperable way to close the 
> stream at this point ? Should I send an empty DATA frame of size zero 
> with ES bit set or should I send a HEADERS frame of size zero with ES bit set ?
>
> I tend to think that DATA+ES looks cleaner (ie: can be seen as last 
> bit of the DATA frame), but given that we're possibly expecting some 
> trailers here, it would also make sense to consider sending an empty HEADERS frame.
>
> I'd like to avoid doing something that some clients may choke on, and 
> I suspect that empty HEADERS may not be that good.
>

---

From: Daniel Stenberg <[email-masked]>
Date: Fri, 4 Aug 2017 09:18:13 +0200 (CEST)

> I've still never seen a chunk trailer yet, are they even in the wild?

It probably depends on what you mean with "in the wild". libcurl supports 
trailers and we have users of this HTTP feature, but I suppose they might 
primarily be used within special networks or just for dedicated apps/backends.

-- 

  / daniel.haxx.se

---

From: Stefan Eissing <[email-masked]>
Date: Fri, 4 Aug 2017 09:43:26 +0200

> Am 04.08.2017 um 09:18 schrieb Daniel Stenberg <[email-masked]>:
> 
> It probably depends on what you mean with "in the wild". libcurl supports trailers and we have users of this HTTP feature, but I suppose they might primarily be used within special networks or just for dedicated apps/backends.

The live, so far, in my test cases for Apache httpd. I'd expect them to get used when the web starts worrying about message integrity more, once the https everywhere thing is done. ;-)

-Stefan

---

From: Cory Benfield <[email-masked]>
Date: Fri, 4 Aug 2017 13:15:41 +0100

> On 4 Aug 2017, at 08:43, Stefan Eissing <[email-masked]> wrote:
> 

Adding to the list, HTTP/1.1 trailers are barely supported in the Python ecosystem: none of the major libraries or tools can emit them, and many fail to parse them. The better implementations parse-but-ignore. The Python HTTP/2 stack supports emitting and parsing trailers.

Cory

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 4 Aug 2017 15:36:41 +0200

> haven't hit any notable issues with it.

Thanks Mike for confirming. That's what I've implemented now. I'm now seeing
H2 contents in Firefox connecting via haproxy :-) The code is ugly and broken
everywhere but it's pleasant to feel like I'm getting close!

Willy

---

From: Stefan Eissing <[email-masked]>
Date: Fri, 4 Aug 2017 15:43:44 +0200

Go, Willly! \o/

> Am 04.08.2017 um 15:36 schrieb Willy Tarreau <[email-masked]>:
>

---

From: Mark Nottingham <[email-masked]>
Date: Sun, 6 Aug 2017 23:26:41 +0800

> On 4 Aug 2017, at 8:15 pm, Cory Benfield <[email-masked]> wrote:
> 
> 
> 

This thread makes me wonder if we can't improve things slightly in HTTPtre. E.g., we could say:

> A header field MUST NOT appear in trailers unless its definition allows it. Receiving implementations MUST ignore header fields appearing in trailers when their definitions do not allow it.

... with an appropriate column in the header field registry to record this. I don't think this would break any existing implementations, because trailers are so seldom used right now, and I think there's a strong argument that this is the case anyway; the consuming application has to expect something in trailers to act upon it.

<https://github.com/httpwg/http11bis/issues/16#issuecomment-320513541>

--
Mark Nottingham   https://www.mnot.net/

---

From: Willy Tarreau <[email-masked]>
Date: Sun, 6 Aug 2017 22:19:25 +0200

On Sun, Aug 06, 2017 at 11:26:41PM +0800, Mark Nottingham wrote:
> > A header field MUST NOT appear in trailers unless its definition allows it.
> > Receiving implementations MUST ignore header fields appearing in trailers
> > when their definitions do not allow it.
> 
> ... with an appropriate column in the header field registry to record this. I
> don't think this would break any existing implementations, because trailers
> are so seldom used right now, and I think there's a strong argument that this
> is the case anyway; the consuming application has to expect something in
> trailers to act upon it.

I think it's a good idea. Ie: if the consumer didn't expect to process them,
they will indeed be ignored so it's pointless for the sender to send random
ones there. So ensuring that they're not mixed with the others in case of
mistake or malicious attempt seems reasonable to me.

Willy

---

From: Stefan Eissing <[email-masked]>
Date: Mon, 7 Aug 2017 08:15:48 +0200

+1

> Am 06.08.2017 um 22:19 schrieb Willy Tarreau <[email-masked]>:
>

---

From: Amos Jeffries <[email-masked]>
Date: Tue, 8 Aug 2017 03:26:59 +1200

On 07/08/17 03:26, Mark Nottingham wrote:
> 
>> On 4 Aug 2017, at 8:15 pm, Cory Benfield wrote:
>>
>>
>>
>>> On 4 Aug 2017, at 08:43, Stefan Eissing wrote:
>>>

Is it worth an erratum to encourage that practice be enacted before a 
new spec happens?

Amos