Discussion:
Final DATA frames
Mike Bishop
2018-12-06 18:57:13 UTC
Permalink
One other change to draw the working groups' attention to, on the opposite end of the stream from initial PRIORITY frames:

Issue #1885<https://github.com/quicwg/base-drafts/issues/1885> points out that, as in HTTP/2, it is inefficient to have to length-prefix each chunk of a response which is being generated incrementally. In H2, this is unavoidable, because the frames are also the unit of multiplexing. In H3, the QUIC STREAM frames are always length-prefixed, but we can have very large HTTP-layer frames because they're within a QUIC stream. This was briefly mentioned in Bangkok.

There are multiple possible approaches to making this better:

* Move DATA off-stream. Considered too extreme a change for this stage of the process and not helpful in all cases, but this can be implemented as an extension. (See this unsubmitted draft<https://github.com/MikeBishop/quic-external-data>.)
* Frames of length 0 extend to the end of the stream. This seemed like the architecturally cleanest way to solve it, but the prospect of arbitrary frames whose length isn't known from the beginning was potentially challenging for some implementations.
* DATA frames of length 0 extend to the end of the stream. This is a more scoped change, but special-cases the DATA frame.

After discussion on the issue and on the submitted PR (#2098)<https://github.com/quicwg/base-drafts/pull/2098>, the consensus seemed roughly split between the latter two options, but most participants in the discussion seemed amenable to either. I've merged the PR, which changed the behavior only of DATA frames.

However, Martin pointed out<https://github.com/quicwg/base-drafts/pull/2098#issuecomment-444763104> that this discussion has been entirely on GitHub, and that perhaps an opportunity for list discussion was in order. If there's not WG consensus to proceed with this change at all, I'll revert it. If there's consensus to use a different solution instead, I'll create a follow-up PR.

Thanks,
Mike Bishop
Dmitri Tikhonov
2018-12-06 19:23:56 UTC
Permalink
However, Martin pointed out [1] that this discussion has been
entirely on GitHub
This is not quite correct, we did discuss it on the mailing list
first, albeit not in a dedicated thread:

https://www.ietf.org/mail-archive/web/quic/current/msg05003.html

- Dmitri.

1. https://github.com/quicwg/base-drafts/pull/2098#issuecomment-444763104
Dmitri Tikhonov
2018-12-07 18:45:41 UTC
Permalink
Given the current inline (interleaved) expression of push-promise within
a stream, you don’t want to prevent yourself from being able to insert
the push-promise description into the stream when you need to do it.
It’d also make trailers “interesting”, i.e. likely prevent them
from working properly.
I agree. I made similar argument here:

https://github.com/quicwg/base-drafts/issues/1885#issuecomment-431478990

- Dmitri.
Ryan Hamilton
2018-12-07 20:11:23 UTC
Permalink
AFAICT, the github conversation didn’t touch on the interrelation of
framing-on-stream and push-promise, or trailers.
Given the current inline (interleaved) expression of push-promise within a
stream, you don’t want to prevent yourself from being able to insert the
push-promise description into the stream when you need to do it.
It’d also make trailers “interesting”, i.e. likely prevent them from
working properly.
If having a zero-length frame is considered a problem, then another way to
solve that would be to assert that the length of a frame is the stated size
+ 1, i.e. if that field is zero, then the length of the payload is one.
Well, the motivation for the change is to avoid extra overhead in the very
common case of an HTTP message with no trailers and no associated pushes
(and dynamically generated content). If a particular HTTP message does not
have those properties then it can easily use a non-zero length to terminate
the DATA frame and follow it up with pushes or trailers.
Lucas Pardue
2018-12-07 20:22:11 UTC
Permalink
I was swayed by the discussion on this topic to support the proposal we
ended up with. As Ryan puts it so well, we don't discount such other use
cases, we just need the server to have enough information to decide how to
respond on the initial DATA frame it responds with.

And to that end, I think it has enough enpowerment. If risk averse, it
would not use this optimisation. If sensitive to push or trailers, it can
take the care to allow them.

Lucas
Post by Ryan Hamilton
AFAICT, the github conversation didn’t touch on the interrelation of
framing-on-stream and push-promise, or trailers.
Given the current inline (interleaved) expression of push-promise within
a stream, you don’t want to prevent yourself from being able to insert the
push-promise description into the stream when you need to do it.
It’d also make trailers “interesting”, i.e. likely prevent them from
working properly.
If having a zero-length frame is considered a problem, then another way
to solve that would be to assert that the length of a frame is the stated
size + 1, i.e. if that field is zero, then the length of the payload is one.
Well, the motivation for the change is to avoid extra overhead in the very
common case of an HTTP message with no trailers and no associated pushes
(and dynamically generated content). If a particular HTTP message does not
have those properties then it can easily use a non-zero length to terminate
the DATA frame and follow it up with pushes or trailers.
Mike Bishop
2018-12-07 22:50:25 UTC
Permalink
Trailers SHOULD be declared in the headers, but it’s true that a proxy whose origin violates that SHOULD could find itself in a state where it has to drop the trailers.

From: Roberto Peon <***@fb.com>
Sent: Friday, December 7, 2018 1:27 PM
To: Lucas Pardue <***@gmail.com>; Ryan Hamilton <rch=***@dmarc.ietf.org>
Cc: Jana Iyengar <***@gmail.com>; IETF QUIC WG <***@ietf.org>; Mike Bishop <***@evequefou.be>; HTTP Working Group <ietf-http-***@w3.org>
Subject: Re: Final DATA frames

It will become very easy for an implementation which otherwise seems conforming to mess up and have no way of using push, or communicating trailers.
This really seems like premature optimization, especially in the case where we’re taking options off the table already (like having the payload be separate).
A little inefficiency seems much less scary than features no longer interoperating (e.g. because a proxy is very unlikely to know whether the response will have trailers, etc. without some very interesting coordination). That would feel very HTTP/1.1 pipelining (which was a good idea, but couldn’t effectively be implemented interoperably) to me. That was not at all a fun situation.

This makes me feel very uneasy.
-=R

From: Lucas Pardue <***@gmail.com<mailto:***@gmail.com>>
Date: Friday, December 7, 2018 at 12:23 PM
To: Ryan Hamilton <rch=***@dmarc.ietf.org<mailto:rch=***@dmarc.ietf.org>>
Cc: Roberto Peon <***@fb.com<mailto:***@fb.com>>, Jana Iyengar <***@gmail.com<mailto:***@gmail.com>>, IETF QUIC WG <***@ietf.org<mailto:***@ietf.org>>, Mike Bishop <***@evequefou.be<mailto:***@evequefou.be>>, HTTP Working Group <ietf-http-***@w3.org<mailto:ietf-http-***@w3.org>>
Subject: Re: Final DATA frames

I was swayed by the discussion on this topic to support the proposal we ended up with. As Ryan puts it so well, we don't discount such other use cases, we just need the server to have enough information to decide how to respond on the initial DATA frame it responds with.

And to that end, I think it has enough enpowerment. If risk averse, it would not use this optimisation. If sensitive to push or trailers, it can take the care to allow them.

Lucas

On Fri, 7 Dec 2018, 20:12 Ryan Hamilton <rch=***@dmarc.ietf.org<mailto:***@dmarc.ietf.org> wrote:
On Fri, Dec 7, 2018 at 10:16 AM Roberto Peon <***@fb.com<mailto:***@fb.com>> wrote:
AFAICT, the github conversation didn’t touch on the interrelation of framing-on-stream and push-promise, or trailers.

Given the current inline (interleaved) expression of push-promise within a stream, you don’t want to prevent yourself from being able to insert the push-promise description into the stream when you need to do it.
It’d also make trailers “interesting”, i.e. likely prevent them from working properly.

If having a zero-length frame is considered a problem, then another way to solve that would be to assert that the length of a frame is the stated size + 1, i.e. if that field is zero, then the length of the payload is one.

Well, the motivation for the change is to avoid extra overhead in the very common case of an HTTP message with no trailers and no associated pushes (and dynamically generated content). If a particular HTTP message does not have those properties then it can easily use a non-zero length to terminate the DATA frame and follow it up with pushes or trailers.
Lucas Pardue
2018-12-07 23:38:46 UTC
Permalink
Perhaps I'm overlooking a few things but the way I'd see it is that such a
proxy could be conservative and chose never to use len=0 on responses that
it is in control of.

If it wanted to be more flexible at cost of risk, a proxy might also use
the content-length header to make an informed decision. The header is not
required, which sort of aligns with an origin generating a dynamic response
of unknown total length.

Wrt to push. A proxy could use reception of a link header, with preload, to
decide to push before generating the parent request-response payload. If
the upstream wants to support "pass through" of push promise properly,
being conservative with length=0 would also be sensible.

Trailers, well they are are hard I agree. Mike's provided some options but
I'd ask exactly what trailers are applicable to H3. Is this design really a
blocker to use?
Post by Mike Bishop
Trailers SHOULD be declared in the headers, but it’s true that a proxy
whose origin violates that SHOULD could find itself in a state where it has
to drop the trailers.
*Sent:* Friday, December 7, 2018 1:27 PM
*Subject:* Re: Final DATA frames
It will become very easy for an implementation which otherwise seems
conforming to mess up and have no way of using push, or communicating
trailers.
This really seems like premature optimization, especially in the case
where we’re taking options off the table already (like having the payload
be separate).
A little inefficiency seems much less scary than features no longer
interoperating (e.g. because a proxy is very unlikely to know whether the
response will have trailers, etc. without some very interesting
coordination). That would feel very HTTP/1.1 pipelining (which was a good
idea, but couldn’t effectively be implemented interoperably) to me. That
was not at all a fun situation.
This makes me feel very uneasy.
-=R
*Date: *Friday, December 7, 2018 at 12:23 PM
*Subject: *Re: Final DATA frames
I was swayed by the discussion on this topic to support the proposal we
ended up with. As Ryan puts it so well, we don't discount such other use
cases, we just need the server to have enough information to decide how to
respond on the initial DATA frame it responds with.
And to that end, I think it has enough enpowerment. If risk averse, it
would not use this optimisation. If sensitive to push or trailers, it can
take the care to allow them.
Lucas
AFAICT, the github conversation didn’t touch on the interrelation of
framing-on-stream and push-promise, or trailers.
Given the current inline (interleaved) expression of push-promise within a
stream, you don’t want to prevent yourself from being able to insert the
push-promise description into the stream when you need to do it.
It’d also make trailers “interesting”, i.e. likely prevent them from
working properly.
If having a zero-length frame is considered a problem, then another way to
solve that would be to assert that the length of a frame is the stated size
+ 1, i.e. if that field is zero, then the length of the payload is one.
Well, the motivation for the change is to avoid extra overhead in the very
common case of an HTTP message with no trailers and no associated pushes
(and dynamically generated content). If a particular HTTP message does not
have those properties then it can easily use a non-zero length to terminate
the DATA frame and follow it up with pushes or trailers.
Mike Bishop
2018-12-08 00:01:03 UTC
Permalink
Not a blocker in my view, but it’s a fair critique that this design is mutually exclusive with those features. A server (whether proxy or application library) that wants to retain the ability to do mid-content push or trailers can’t use this feature. A server that is reasonably certain that it won’t need them could use this feature as an optimization. It’s worth noting that a “final DATA frame” is only ever that, and need not be used.

I wasn’t planning to get into this yet, but since it’s relevant, I have an alternate design as an extension (not yet published) here<https://mikebishop.github.io/quic-external-data/draft-bishop-quic-external-data.html>. One option is to revert this change and interested parties can work on the extension instead, if there’s interest.

From: Lucas Pardue <***@gmail.com>
Sent: Friday, December 7, 2018 3:39 PM
To: Mike Bishop <***@evequefou.be>
Cc: Roberto Peon <***@fb.com>; Ryan Hamilton <rch=***@dmarc.ietf.org>; Jana Iyengar <***@gmail.com>; IETF QUIC WG <***@ietf.org>; HTTP Working Group <ietf-http-***@w3.org>
Subject: Re: Final DATA frames

Perhaps I'm overlooking a few things but the way I'd see it is that such a proxy could be conservative and chose never to use len=0 on responses that it is in control of.

If it wanted to be more flexible at cost of risk, a proxy might also use the content-length header to make an informed decision. The header is not required, which sort of aligns with an origin generating a dynamic response of unknown total length.

Wrt to push. A proxy could use reception of a link header, with preload, to decide to push before generating the parent request-response payload. If the upstream wants to support "pass through" of push promise properly, being conservative with length=0 would also be sensible.

Trailers, well they are are hard I agree. Mike's provided some options but I'd ask exactly what trailers are applicable to H3. Is this design really a blocker to use?

On Fri, 7 Dec 2018, 22:50 Mike Bishop <***@evequefou.be<mailto:***@evequefou.be> wrote:
Trailers SHOULD be declared in the headers, but it’s true that a proxy whose origin violates that SHOULD could find itself in a state where it has to drop the trailers.

From: Roberto Peon <***@fb.com<mailto:***@fb.com>>
Sent: Friday, December 7, 2018 1:27 PM
To: Lucas Pardue <***@gmail.com<mailto:***@gmail.com>>; Ryan Hamilton <rch=***@dmarc.ietf.org<mailto:***@dmarc.ietf.org>>
Cc: Jana Iyengar <***@gmail.com<mailto:***@gmail.com>>; IETF QUIC WG <***@ietf.org<mailto:***@ietf.org>>; Mike Bishop <***@evequefou.be<mailto:***@evequefou.be>>; HTTP Working Group <ietf-http-***@w3.org<mailto:ietf-http-***@w3.org>>
Subject: Re: Final DATA frames

It will become very easy for an implementation which otherwise seems conforming to mess up and have no way of using push, or communicating trailers.
This really seems like premature optimization, especially in the case where we’re taking options off the table already (like having the payload be separate).
A little inefficiency seems much less scary than features no longer interoperating (e.g. because a proxy is very unlikely to know whether the response will have trailers, etc. without some very interesting coordination). That would feel very HTTP/1.1 pipelining (which was a good idea, but couldn’t effectively be implemented interoperably) to me. That was not at all a fun situation.

This makes me feel very uneasy.
-=R

From: Lucas Pardue <***@gmail.com<mailto:***@gmail.com>>
Date: Friday, December 7, 2018 at 12:23 PM
To: Ryan Hamilton <rch=***@dmarc.ietf.org<mailto:rch=***@dmarc.ietf.org>>
Cc: Roberto Peon <***@fb.com<mailto:***@fb.com>>, Jana Iyengar <***@gmail.com<mailto:***@gmail.com>>, IETF QUIC WG <***@ietf.org<mailto:***@ietf.org>>, Mike Bishop <***@evequefou.be<mailto:***@evequefou.be>>, HTTP Working Group <ietf-http-***@w3.org<mailto:ietf-http-***@w3.org>>
Subject: Re: Final DATA frames

I was swayed by the discussion on this topic to support the proposal we ended up with. As Ryan puts it so well, we don't discount such other use cases, we just need the server to have enough information to decide how to respond on the initial DATA frame it responds with.

And to that end, I think it has enough enpowerment. If risk averse, it would not use this optimisation. If sensitive to push or trailers, it can take the care to allow them.

Lucas

On Fri, 7 Dec 2018, 20:12 Ryan Hamilton <rch=***@dmarc.ietf.org<mailto:***@dmarc.ietf.org> wrote:
On Fri, Dec 7, 2018 at 10:16 AM Roberto Peon <***@fb.com<mailto:***@fb.com>> wrote:
AFAICT, the github conversation didn’t touch on the interrelation of framing-on-stream and push-promise, or trailers.

Given the current inline (interleaved) expression of push-promise within a stream, you don’t want to prevent yourself from being able to insert the push-promise description into the stream when you need to do it.
It’d also make trailers “interesting”, i.e. likely prevent them from working properly.

If having a zero-length frame is considered a problem, then another way to solve that would be to assert that the length of a frame is the stated size + 1, i.e. if that field is zero, then the length of the payload is one.

Well, the motivation for the change is to avoid extra overhead in the very common case of an HTTP message with no trailers and no associated pushes (and dynamically generated content). If a particular HTTP message does not have those properties then it can easily use a non-zero length to terminate the DATA frame and follow it up with pushes or trailers.
Lucas Pardue
2018-12-08 00:06:09 UTC
Permalink
Hmm, an out of order delivery issue there. I was defending this design
rather than poking holes is. Regardless, the reason I like it is that it
has flexibility down to the per-request level. I understand concerns but
think a server actor can mitigate them by simply not supporting len=0. I
can't see the interop issue, but perhaps I'm just missing it.

Licas
Post by Mike Bishop
Not a blocker in my view, but it’s a fair critique that this design is
mutually exclusive with those features. A server (whether proxy or
application library) that wants to retain the ability to do mid-content
push or trailers can’t use this feature. A server that is reasonably
certain that it won’t need them could use this feature as an optimization.
It’s worth noting that a “final DATA frame” is only ever that, and need not
be used.
I wasn’t planning to get into this yet, but since it’s relevant, I have an
alternate design as an extension (not yet published) here
<https://mikebishop.github.io/quic-external-data/draft-bishop-quic-external-data.html>.
One option is to revert this change and interested parties can work on the
extension instead, if there’s interest.
*Sent:* Friday, December 7, 2018 3:39 PM
*Subject:* Re: Final DATA frames
Perhaps I'm overlooking a few things but the way I'd see it is that such a
proxy could be conservative and chose never to use len=0 on responses that
it is in control of.
If it wanted to be more flexible at cost of risk, a proxy might also use
the content-length header to make an informed decision. The header is not
required, which sort of aligns with an origin generating a dynamic response
of unknown total length.
Wrt to push. A proxy could use reception of a link header, with preload,
to decide to push before generating the parent request-response payload. If
the upstream wants to support "pass through" of push promise properly,
being conservative with length=0 would also be sensible.
Trailers, well they are are hard I agree. Mike's provided some options but
I'd ask exactly what trailers are applicable to H3. Is this design really a
blocker to use?
Trailers SHOULD be declared in the headers, but it’s true that a proxy
whose origin violates that SHOULD could find itself in a state where it has
to drop the trailers.
*Sent:* Friday, December 7, 2018 1:27 PM
*Subject:* Re: Final DATA frames
It will become very easy for an implementation which otherwise seems
conforming to mess up and have no way of using push, or communicating
trailers.
This really seems like premature optimization, especially in the case
where we’re taking options off the table already (like having the payload
be separate).
A little inefficiency seems much less scary than features no longer
interoperating (e.g. because a proxy is very unlikely to know whether the
response will have trailers, etc. without some very interesting
coordination). That would feel very HTTP/1.1 pipelining (which was a good
idea, but couldn’t effectively be implemented interoperably) to me. That
was not at all a fun situation.
This makes me feel very uneasy.
-=R
*Date: *Friday, December 7, 2018 at 12:23 PM
*Subject: *Re: Final DATA frames
I was swayed by the discussion on this topic to support the proposal we
ended up with. As Ryan puts it so well, we don't discount such other use
cases, we just need the server to have enough information to decide how to
respond on the initial DATA frame it responds with.
And to that end, I think it has enough enpowerment. If risk averse, it
would not use this optimisation. If sensitive to push or trailers, it can
take the care to allow them.
Lucas
AFAICT, the github conversation didn’t touch on the interrelation of
framing-on-stream and push-promise, or trailers.
Given the current inline (interleaved) expression of push-promise within a
stream, you don’t want to prevent yourself from being able to insert the
push-promise description into the stream when you need to do it.
It’d also make trailers “interesting”, i.e. likely prevent them from
working properly.
If having a zero-length frame is considered a problem, then another way to
solve that would be to assert that the length of a frame is the stated size
+ 1, i.e. if that field is zero, then the length of the payload is one.
Well, the motivation for the change is to avoid extra overhead in the very
common case of an HTTP message with no trailers and no associated pushes
(and dynamically generated content). If a particular HTTP message does not
have those properties then it can easily use a non-zero length to terminate
the DATA frame and follow it up with pushes or trailers.
Mike Bishop
2018-12-08 00:10:57 UTC
Permalink
The interop issue is that a proxy might inspect the headers, see no indication of trailers, use a len=0 DATA frame, then arrive at the end of the origin’s response and discover trailers there anyway that it now can’t send. As you say, the proxy can be cautious, and proxies are also allowed to discard trailers, so it’s not a hard interop failure. But it’s an unfortunate corner-case in an otherwise beneficial change.

From: Lucas Pardue <***@gmail.com>
Sent: Friday, December 7, 2018 4:06 PM
To: Mike Bishop <***@evequefou.be>
Cc: Roberto Peon <***@fb.com>; Ryan Hamilton <rch=***@dmarc.ietf.org>; Jana Iyengar <***@gmail.com>; IETF QUIC WG <***@ietf.org>; HTTP Working Group <ietf-http-***@w3.org>
Subject: Re: Final DATA frames

Hmm, an out of order delivery issue there. I was defending this design rather than poking holes is. Regardless, the reason I like it is that it has flexibility down to the per-request level. I understand concerns but think a server actor can mitigate them by simply not supporting len=0. I can't see the interop issue, but perhaps I'm just missing it.

Licas

On Sat, 8 Dec 2018, 00:01 Mike Bishop <***@evequefou.be<mailto:***@evequefou.be> wrote:
Not a blocker in my view, but it’s a fair critique that this design is mutually exclusive with those features. A server (whether proxy or application library) that wants to retain the ability to do mid-content push or trailers can’t use this feature. A server that is reasonably certain that it won’t need them could use this feature as an optimization. It’s worth noting that a “final DATA frame” is only ever that, and need not be used.

I wasn’t planning to get into this yet, but since it’s relevant, I have an alternate design as an extension (not yet published) here<https://mikebishop.github.io/quic-external-data/draft-bishop-quic-external-data.html>. One option is to revert this change and interested parties can work on the extension instead, if there’s interest.

From: Lucas Pardue <***@gmail.com<mailto:***@gmail.com>>
Sent: Friday, December 7, 2018 3:39 PM
To: Mike Bishop <***@evequefou.be<mailto:***@evequefou.be>>
Cc: Roberto Peon <***@fb.com<mailto:***@fb.com>>; Ryan Hamilton <rch=***@dmarc.ietf.org<mailto:***@dmarc.ietf.org>>; Jana Iyengar <***@gmail.com<mailto:***@gmail.com>>; IETF QUIC WG <***@ietf.org<mailto:***@ietf.org>>; HTTP Working Group <ietf-http-***@w3.org<mailto:ietf-http-***@w3.org>>
Subject: Re: Final DATA frames

Perhaps I'm overlooking a few things but the way I'd see it is that such a proxy could be conservative and chose never to use len=0 on responses that it is in control of.

If it wanted to be more flexible at cost of risk, a proxy might also use the content-length header to make an informed decision. The header is not required, which sort of aligns with an origin generating a dynamic response of unknown total length.

Wrt to push. A proxy could use reception of a link header, with preload, to decide to push before generating the parent request-response payload. If the upstream wants to support "pass through" of push promise properly, being conservative with length=0 would also be sensible.

Trailers, well they are are hard I agree. Mike's provided some options but I'd ask exactly what trailers are applicable to H3. Is this design really a blocker to use?

On Fri, 7 Dec 2018, 22:50 Mike Bishop <***@evequefou.be<mailto:***@evequefou.be> wrote:
Trailers SHOULD be declared in the headers, but it’s true that a proxy whose origin violates that SHOULD could find itself in a state where it has to drop the trailers.

From: Roberto Peon <***@fb.com<mailto:***@fb.com>>
Sent: Friday, December 7, 2018 1:27 PM
To: Lucas Pardue <***@gmail.com<mailto:***@gmail.com>>; Ryan Hamilton <rch=***@dmarc.ietf.org<mailto:***@dmarc.ietf.org>>
Cc: Jana Iyengar <***@gmail.com<mailto:***@gmail.com>>; IETF QUIC WG <***@ietf.org<mailto:***@ietf.org>>; Mike Bishop <***@evequefou.be<mailto:***@evequefou.be>>; HTTP Working Group <ietf-http-***@w3.org<mailto:ietf-http-***@w3.org>>
Subject: Re: Final DATA frames

It will become very easy for an implementation which otherwise seems conforming to mess up and have no way of using push, or communicating trailers.
This really seems like premature optimization, especially in the case where we’re taking options off the table already (like having the payload be separate).
A little inefficiency seems much less scary than features no longer interoperating (e.g. because a proxy is very unlikely to know whether the response will have trailers, etc. without some very interesting coordination). That would feel very HTTP/1.1 pipelining (which was a good idea, but couldn’t effectively be implemented interoperably) to me. That was not at all a fun situation.

This makes me feel very uneasy.
-=R

From: Lucas Pardue <***@gmail.com<mailto:***@gmail.com>>
Date: Friday, December 7, 2018 at 12:23 PM
To: Ryan Hamilton <rch=***@dmarc.ietf.org<mailto:rch=***@dmarc.ietf.org>>
Cc: Roberto Peon <***@fb.com<mailto:***@fb.com>>, Jana Iyengar <***@gmail.com<mailto:***@gmail.com>>, IETF QUIC WG <***@ietf.org<mailto:***@ietf.org>>, Mike Bishop <***@evequefou.be<mailto:***@evequefou.be>>, HTTP Working Group <ietf-http-***@w3.org<mailto:ietf-http-***@w3.org>>
Subject: Re: Final DATA frames

I was swayed by the discussion on this topic to support the proposal we ended up with. As Ryan puts it so well, we don't discount such other use cases, we just need the server to have enough information to decide how to respond on the initial DATA frame it responds with.

And to that end, I think it has enough enpowerment. If risk averse, it would not use this optimisation. If sensitive to push or trailers, it can take the care to allow them.

Lucas

On Fri, 7 Dec 2018, 20:12 Ryan Hamilton <rch=***@dmarc.ietf.org<mailto:***@dmarc.ietf.org> wrote:
On Fri, Dec 7, 2018 at 10:16 AM Roberto Peon <***@fb.com<mailto:***@fb.com>> wrote:
AFAICT, the github conversation didn’t touch on the interrelation of framing-on-stream and push-promise, or trailers.

Given the current inline (interleaved) expression of push-promise within a stream, you don’t want to prevent yourself from being able to insert the push-promise description into the stream when you need to do it.
It’d also make trailers “interesting”, i.e. likely prevent them from working properly.

If having a zero-length frame is considered a problem, then another way to solve that would be to assert that the length of a frame is the stated size + 1, i.e. if that field is zero, then the length of the payload is one.

Well, the motivation for the change is to avoid extra overhead in the very common case of an HTTP message with no trailers and no associated pushes (and dynamically generated content). If a particular HTTP message does not have those properties then it can easily use a non-zero length to terminate the DATA frame and follow it up with pushes or trailers.
Kazuho Oku
2018-12-08 01:18:04 UTC
Permalink
The interop issue is that a proxy might inspect the headers, see no indication of trailers, use a len=0 DATA frame, then arrive at the end of the origin’s response and discover trailers there anyway that it now can’t send. As you say, the proxy can be cautious, and proxies are also allowed to discard trailers, so it’s not a hard interop failure. But it’s an unfortunate corner-case in an otherwise beneficial change.
I tend to agree with what Mike and Roberto says. Use of len=0 is a
hack that does not always work.

At least, there are two better ways of addressing the issue. One way
is to use a different stream for carrying trailers.

The other way (which is my preference) is to let the transport layer
carry the boundaries of streams. For example, we could add a
START_OF_CHUNK flag to STREAMs frame, and also a NEXT_CHUNK frame
(with no payload) that indicates the start of a next chunk of the
preceding STREAM frame. Then, we can get rid of length field of every
HTTP frame.

Admittedly, the alternatives have less chance in making it to v1. But
the question is, is always using length field so bad that we cannot
wait for a more ideal fix?
Sent: Friday, December 7, 2018 4:06 PM
Subject: Re: Final DATA frames
Hmm, an out of order delivery issue there. I was defending this design rather than poking holes is. Regardless, the reason I like it is that it has flexibility down to the per-request level. I understand concerns but think a server actor can mitigate them by simply not supporting len=0. I can't see the interop issue, but perhaps I'm just missing it.
Licas
Not a blocker in my view, but it’s a fair critique that this design is mutually exclusive with those features. A server (whether proxy or application library) that wants to retain the ability to do mid-content push or trailers can’t use this feature. A server that is reasonably certain that it won’t need them could use this feature as an optimization. It’s worth noting that a “final DATA frame” is only ever that, and need not be used.
I wasn’t planning to get into this yet, but since it’s relevant, I have an alternate design as an extension (not yet published) here. One option is to revert this change and interested parties can work on the extension instead, if there’s interest.
Sent: Friday, December 7, 2018 3:39 PM
Subject: Re: Final DATA frames
Perhaps I'm overlooking a few things but the way I'd see it is that such a proxy could be conservative and chose never to use len=0 on responses that it is in control of.
If it wanted to be more flexible at cost of risk, a proxy might also use the content-length header to make an informed decision. The header is not required, which sort of aligns with an origin generating a dynamic response of unknown total length.
Wrt to push. A proxy could use reception of a link header, with preload, to decide to push before generating the parent request-response payload. If the upstream wants to support "pass through" of push promise properly, being conservative with length=0 would also be sensible.
Trailers, well they are are hard I agree. Mike's provided some options but I'd ask exactly what trailers are applicable to H3. Is this design really a blocker to use?
Trailers SHOULD be declared in the headers, but it’s true that a proxy whose origin violates that SHOULD could find itself in a state where it has to drop the trailers.
Sent: Friday, December 7, 2018 1:27 PM
Subject: Re: Final DATA frames
It will become very easy for an implementation which otherwise seems conforming to mess up and have no way of using push, or communicating trailers.
This really seems like premature optimization, especially in the case where we’re taking options off the table already (like having the payload be separate).
A little inefficiency seems much less scary than features no longer interoperating (e.g. because a proxy is very unlikely to know whether the response will have trailers, etc. without some very interesting coordination). That would feel very HTTP/1.1 pipelining (which was a good idea, but couldn’t effectively be implemented interoperably) to me. That was not at all a fun situation.
This makes me feel very uneasy.
-=R
Date: Friday, December 7, 2018 at 12:23 PM
Subject: Re: Final DATA frames
I was swayed by the discussion on this topic to support the proposal we ended up with. As Ryan puts it so well, we don't discount such other use cases, we just need the server to have enough information to decide how to respond on the initial DATA frame it responds with.
And to that end, I think it has enough enpowerment. If risk averse, it would not use this optimisation. If sensitive to push or trailers, it can take the care to allow them.
Lucas
AFAICT, the github conversation didn’t touch on the interrelation of framing-on-stream and push-promise, or trailers.
Given the current inline (interleaved) expression of push-promise within a stream, you don’t want to prevent yourself from being able to insert the push-promise description into the stream when you need to do it.
It’d also make trailers “interesting”, i.e. likely prevent them from working properly.
If having a zero-length frame is considered a problem, then another way to solve that would be to assert that the length of a frame is the stated size + 1, i.e. if that field is zero, then the length of the payload is one.
Well, the motivation for the change is to avoid extra overhead in the very common case of an HTTP message with no trailers and no associated pushes (and dynamically generated content). If a particular HTTP message does not have those properties then it can easily use a non-zero length to terminate the DATA frame and follow it up with pushes or trailers.
--
Kazuho Oku
Mike Bishop
2018-12-10 23:35:49 UTC
Permalink
I'm personally hoping that the HTTP spec will change less frequently than the QUIC spec will, and that changes will be primarily via extensions. But the choice I'd like to make on list right now is:

* Keep the change - it's an optimization for a common case, and proxies can disable it if they expect the uncommon case to apply
* Revert the change - the optimization isn't worth the possibility that proxies shoot themselves in the foot



Whether we can do better in an extension or by adding new transport features in v2 doesn't block either option - we can keep this change and still publish something better later. My count of people on this thread so far is split about 50/50 between keeping the change in versus various reasons to reject it.



-----Original Message-----
From: Dmitri Tikhonov <***@litespeedtech.com>
Sent: Sunday, December 9, 2018 1:27 PM
To: Kazuho Oku <***@gmail.com>
Cc: Mike Bishop <***@evequefou.be>; Jana Iyengar <***@gmail.com>; Roberto Peon <***@fb.com>; rch=***@dmarc.ietf.org; HTTP Working Group <ietf-http-***@w3.org>; ***@gmail.com; IETF QUIC WG <***@ietf.org>
Subject: Re: Final DATA frames
Post by Kazuho Oku
Admittedly, the alternatives have less chance in making it to v1. But
the question is, is always using length field so bad that we cannot
wait for a more ideal fix?
I don't think it's so bad. The overhead incurred by the DATA frames is small: 0.2% to 0.02% [1]. I think we can live with it for v1.



- Dmitri.



1. https://github.com/quicwg/base-drafts/issues/1885#issuecomment-431348155
Martin Thomson
2018-12-11 00:18:55 UTC
Permalink
FWIW, there is a valid use case here, but I'm not happy with the
specific design.

For instance, an extension that used a unidirectional stream for the
body of a request might be a better option.

On that basis, I would revert the change.
Keep the change – it’s an optimization for a common case, and proxies can disable it if they expect the uncommon case to apply
Revert the change – the optimization isn’t worth the possibility that proxies shoot themselves in the foot
Whether we can do better in an extension or by adding new transport features in v2 doesn’t block either option – we can keep this change and still publish something better later. My count of people on this thread so far is split about 50/50 between keeping the change in versus various reasons to reject it.
-----Original Message-----
Sent: Sunday, December 9, 2018 1:27 PM
Subject: Re: Final DATA frames
Post by Kazuho Oku
Admittedly, the alternatives have less chance in making it to v1. But
the question is, is always using length field so bad that we cannot
wait for a more ideal fix?
I don't think it's so bad. The overhead incurred by the DATA frames is small: 0.2% to 0.02% [1]. I think we can live with it for v1.
- Dmitri.
1. https://github.com/quicwg/base-drafts/issues/1885#issuecomment-431348155
Ryan Hamilton
2018-12-11 01:34:34 UTC
Permalink
As you say, there's a valid use case here. There's nothing about this
particular design which would prevent any sort of "send the body on a
unidirectional stream" extension from being worked on or implemented. That
some future extension might (or might not) be a better solution to this use
case does not seem to me to be a terribly compelling argument for reverting
this, particularly given the simplicity of this design.

(I'll also point out that delivering the body on a unidirectional stream
doesn't necessarily work will with server push, as the PUSH_PROMISE is
required to arrive before the reference to the promised resource. So if the
PUSH_PROMISE happens on the main stream and the body goes on a different
stream, that ordering is not guaranteed without some addition properties.)
Post by Martin Thomson
FWIW, there is a valid use case here, but I'm not happy with the
specific design.
For instance, an extension that used a unidirectional stream for the
body of a request might be a better option.
On that basis, I would revert the change.
Martin Thomson
2018-12-11 01:55:11 UTC
Permalink
As you say, there's a valid use case here. There's nothing about this particular design which would prevent any sort of "send the body on a unidirectional stream" extension from being worked on or implemented. That some future extension might (or might not) be a better solution to this use case does not seem to me to be a terribly compelling argument for reverting this, particularly given the simplicity of this design.
It creates uncertainty about whether the design is appropriate.
(I'll also point out that delivering the body on a unidirectional stream doesn't necessarily work will with server push, as the PUSH_PROMISE is required to arrive before the reference to the promised resource. So if the PUSH_PROMISE happens on the main stream and the body goes on a different stream, that ordering is not guaranteed without some addition properties.)
I apologize. I didn't mean to imply that I thought this had better
properties WRT PUSH_PROMISE.
Ryan Hamilton
2018-12-11 01:55:58 UTC
Permalink
Not all endpoints are proxies :) And some of those endpoint which are
proxies are able to communicate with their backends in order to establish
such knowledge. The endpoints I work with are both able to establish such
knowledge, fwiw.
This simplicity of the design here is also a trap. Sure, the extension is
simple, but it also makes it simple to fail to interoperate!
To be clear, only those proxies which have established some prior
knowledge that there will be no PUSH_PROMISE can safely use this
optimization with the protocol as designed today.
-=R
*Date: *Monday, December 10, 2018 at 5:35 PM
*Subject: *Re: Final DATA frames
As you say, there's a valid use case here. There's nothing about this
particular design which would prevent any sort of "send the body on a
unidirectional stream" extension from being worked on or implemented. That
some future extension might (or might not) be a better solution to this use
case does not seem to me to be a terribly compelling argument for reverting
this, particularly given the simplicity of this design.
(I'll also point out that delivering the body on a unidirectional stream
doesn't necessarily work will with server push, as the PUSH_PROMISE is
required to arrive before the reference to the promised resource. So if the
PUSH_PROMISE happens on the main stream and the body goes on a different
stream, that ordering is not guaranteed without some addition properties.)
FWIW, there is a valid use case here, but I'm not happy with the
specific design.
For instance, an extension that used a unidirectional stream for the
body of a request might be a better option.
On that basis, I would revert the change.
David Schinazi
2018-12-08 00:49:34 UTC
Permalink
I don't see the proxy case as an issue. Maybe this can be resolved by
adding some implementation guidance along the lines of "do not send length
0 unless you are absolutely sure there will be no trailers or other bits
after your payload". This is a performance optimization for a widespread
use-case of the web today, and no one is required to take advantage of it -
if someone is writing a proxy they can simply not use the optimization.

David
Post by Mike Bishop
The interop issue is that a proxy might inspect the headers, see no
indication of trailers, use a len=0 DATA frame, then arrive at the end of
the origin’s response and discover trailers there anyway that it now can’t
send. As you say, the proxy can be cautious, and proxies are also allowed
to discard trailers, so it’s not a hard interop failure. But it’s an
unfortunate corner-case in an otherwise beneficial change.
*Sent:* Friday, December 7, 2018 4:06 PM
*Subject:* Re: Final DATA frames
Hmm, an out of order delivery issue there. I was defending this design
rather than poking holes is. Regardless, the reason I like it is that it
has flexibility down to the per-request level. I understand concerns but
think a server actor can mitigate them by simply not supporting len=0. I
can't see the interop issue, but perhaps I'm just missing it.
Licas
Not a blocker in my view, but it’s a fair critique that this design is
mutually exclusive with those features. A server (whether proxy or
application library) that wants to retain the ability to do mid-content
push or trailers can’t use this feature. A server that is reasonably
certain that it won’t need them could use this feature as an optimization.
It’s worth noting that a “final DATA frame” is only ever that, and need not
be used.
I wasn’t planning to get into this yet, but since it’s relevant, I have an
alternate design as an extension (not yet published) here
<https://mikebishop.github.io/quic-external-data/draft-bishop-quic-external-data.html>.
One option is to revert this change and interested parties can work on the
extension instead, if there’s interest.
*Sent:* Friday, December 7, 2018 3:39 PM
*Subject:* Re: Final DATA frames
Perhaps I'm overlooking a few things but the way I'd see it is that such a
proxy could be conservative and chose never to use len=0 on responses that
it is in control of.
If it wanted to be more flexible at cost of risk, a proxy might also use
the content-length header to make an informed decision. The header is not
required, which sort of aligns with an origin generating a dynamic response
of unknown total length.
Wrt to push. A proxy could use reception of a link header, with preload,
to decide to push before generating the parent request-response payload. If
the upstream wants to support "pass through" of push promise properly,
being conservative with length=0 would also be sensible.
Trailers, well they are are hard I agree. Mike's provided some options but
I'd ask exactly what trailers are applicable to H3. Is this design really a
blocker to use?
Trailers SHOULD be declared in the headers, but it’s true that a proxy
whose origin violates that SHOULD could find itself in a state where it has
to drop the trailers.
*Sent:* Friday, December 7, 2018 1:27 PM
*Subject:* Re: Final DATA frames
It will become very easy for an implementation which otherwise seems
conforming to mess up and have no way of using push, or communicating
trailers.
This really seems like premature optimization, especially in the case
where we’re taking options off the table already (like having the payload
be separate).
A little inefficiency seems much less scary than features no longer
interoperating (e.g. because a proxy is very unlikely to know whether the
response will have trailers, etc. without some very interesting
coordination). That would feel very HTTP/1.1 pipelining (which was a good
idea, but couldn’t effectively be implemented interoperably) to me. That
was not at all a fun situation.
This makes me feel very uneasy.
-=R
*Date: *Friday, December 7, 2018 at 12:23 PM
*Subject: *Re: Final DATA frames
I was swayed by the discussion on this topic to support the proposal we
ended up with. As Ryan puts it so well, we don't discount such other use
cases, we just need the server to have enough information to decide how to
respond on the initial DATA frame it responds with.
And to that end, I think it has enough enpowerment. If risk averse, it
would not use this optimisation. If sensitive to push or trailers, it can
take the care to allow them.
Lucas
AFAICT, the github conversation didn’t touch on the interrelation of
framing-on-stream and push-promise, or trailers.
Given the current inline (interleaved) expression of push-promise within a
stream, you don’t want to prevent yourself from being able to insert the
push-promise description into the stream when you need to do it.
It’d also make trailers “interesting”, i.e. likely prevent them from
working properly.
If having a zero-length frame is considered a problem, then another way to
solve that would be to assert that the length of a frame is the stated size
+ 1, i.e. if that field is zero, then the length of the payload is one.
Well, the motivation for the change is to avoid extra overhead in the very
common case of an HTTP message with no trailers and no associated pushes
(and dynamically generated content). If a particular HTTP message does not
have those properties then it can easily use a non-zero length to terminate
the DATA frame and follow it up with pushes or trailers.
Loading...