Subject: Semantics of multiple 103s in Early Hints

From: Kazuho Oku <[email-masked]>
Date: Mon, 7 Aug 2017 22:43:21 +0900

Hi,

As https://github.com/httpwg/http-extensions/pull/380, I have created
a PR that clarifies the meaning of consecutive 103 responses sent
before a final response. Basically, I consider it as an editorial
issue, however I would appreciate it if you could give me comments
(especially if you oppose to the text) before I merge.

The PR is in response to the issue
(https://github.com/httpwg/http-extensions/issues/371) recently raised
by Dragana. It asks if the following 103 replaces the header set
included in an older 103 or if it is just adding headers to the older
set, when multiple 103s are used.

My answer is that since the nonexistence of a header field in 103 is
not a speculation that the header field would be absent in the final
response, we should consider the following 103 as an addition of new
header fields to the older 103 rather than a replacement of the header
set; otherwise, we would be introducing a rule that is specific to the
multiple 103 case. The PR clarifies that.

-- 
Kazuho Oku

---

From: Willy Tarreau <[email-masked]>
Date: Mon, 7 Aug 2017 17:53:10 +0200

Hi Kazuho,

> multiple 103 case. The PR clarifies that.

I agree with you on the principle but I think it should be presented
differently to make it easier to understand. If you explain that multiple
layers of server-side intermediaries are able to each return their own
set of well-known resources to preload, then the expected resource set
that the client ought to preload is supposed to be the union of all the
provided links.

For example a global CDN delivers a link to the JS used to protect all
their clients, then a reverse proxy on the origin site sends a few links
to the company's CSS and logo, and the frontend facing the application
server also sends the background image corresponding to the current page
being loaded. Some of them may overlap, being aware of some of the elements
used globally but not aware of what was delivered (eg: the last one may
reference again the CSS and the logo). In such a context it makes much
more sense to understand why the list of resources is expected to be the
union of all the links from multiple requests.

Regards,
Willy

---

From: Stefan Eissing <[email-masked]>
Date: Mon, 7 Aug 2017 19:18:31 +0200

+1 on the interpretation. no opinion on the wording. 

> Am 07.08.2017 um 17:53 schrieb Willy Tarreau <[email-masked]>:
> 
> Willy

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 8 Aug 2017 10:51:09 +0900

Willy, Stefan,

Thank you for your comments.

I agree with Willy that we should explain what a client would expect
(rather than explaining what a client should not expect) for the
multiple 103 case. There is no reason to use uppercase verbs here,
considering the fact that it is a clarification of how the text should
be interpreted.

I have updated the PR to use the word "union" as suggested by Willy.
Please let me know if you have any other suggestions / concerns.

Thank you in advance.

-- 
Kazuho Oku

---

From: Willy Tarreau <[email-masked]>
Date: Tue, 8 Aug 2017 07:29:08 +0200

> Please let me know if you have any other suggestions / concerns.

It's better but I think there are still too many negations in the
sentence : "non-existence... does not indicate... absence... a server
can omit". I know that some people are having big difficulties with
such constructs, for having met some.

What about something like this instead :

  A client must be prepared to receive multiple 103 (Early Hints) responses
  in any order coming from multiple intermediaries as well as the origin
  server along the path between the client and the server. Given that such
  agents will often rely on different but overlapping policies to emit these
  responses, it is likely that some header fields may be repeated. The client
  is expected to simply consider the union of all these header fields as if
  they were received in a single response.

Regards,
Willy

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 8 Aug 2017 15:57:16 +0900

>   they were received in a single response.

Thank you for your comments and the suggestion.

I am worried of adding statements on how an intermediary could
generate 103 responses and using that as the reasoning for why the
client should consider the union of the header fields as the
server-provided expectation. This is because it is technically
possible to to require each intermediary to build (i.e. calculate the
union) and emit a complete set of header fields for every 103 response
that it sends.

Therefore, my preference goes to either (re)stating the general rule
(i.e. nonexistence in 103 is not an indication of absence in the final
response), or to state the expected behavior of the endpoints without
any reasoning. I also think that we should keep the "a server can
omit" statement, since it would be a direct answer for people
wondering how a server should adjust the expectation that it has
already sent.

Considering the points, how using something like below for the last paragraph:

   While emitting a series of 103 (Early Hints) responses, a server can
   omit a header field that was included in one response in the
   following responses, even when it is anticipated that the header
   field will be part of the final response.  A client would consider
   the union of all the header fields found in the multiple 103 (Early
   Hints) responses as the list of header fields that is likely to be
   found in the final response.

-- 
Kazuho Oku

---

From: Willy Tarreau <[email-masked]>
Date: Tue, 8 Aug 2017 09:38:29 +0200

On Tue, Aug 08, 2017 at 03:57:16PM +0900, Kazuho Oku wrote:
> server-provided expectation.

But isn't it expected to be the reality ? In the other example I gave
it makes a lot of sense and it becomes obvious :
  - for clients that any such response may be partial ;
  - for clients that any such response may overlap with others ;
  - for clients that even the union of these responses do not provide an
    exhaustive list
  - for clients that the final response will probably not contain the
    whole list of links given that some might have speculatively been
    added in anticipation
  - for servers that they don't know if upfront intermediaries have
    already sent equivalent links
  - for servers that based on the incertainty of what is done upfront,
    they need have to provide the final list with the final response

> This is because it is technically

In fact not exactly. Most of these will be built while processing the
request, long before the response arrives. When the response arrives,
conditions may have changed. For example in haproxy when processing
the response we don't have access to the request elements anymore. A
rule based on the Host field or on the URI prefix would be matched
only during the request and not during the response (we have the
ability to artificially copy them into variables for such explicit
processing but it's not natural). I tend to think that we should keep
in mind that what intermediaries add there is approximative but helps
fill dead time speculatively preloading contents that will be likely
needed, and that the final word is to the server's final response. We
could possibly even suggest that elements that were learned from 103
and not yet prefeteched could be aborted if they don't appear in the
final response.

> wondering how a server should adjust the expectation that it has

I see your point but I tend to think that explaining the workflow like
above makes all these responses much more obvious in fact. If you're
willing to go down that route, I can try to help provide a paragraph
to (try to) make this more natural.

>    field will be part of the final response.

To be honnest I'm having difficulties parsing it, which is not a good
sign for a standard ;-)

It would be nice if some native english speakers could bring some help
here, some of our sentences are not always the most natural we can think
of.

Cheers,
Willy

---

From: Stefan Eissing <[email-masked]>
Date: Tue, 8 Aug 2017 10:16:33 +0200

Ok, time to clarify the semantics, then words will come more easily.

In my mind, any header that comes with a 103 is not a header of the
resource that is requested. Same as with 100 and 101.

For a client/cache/intermediate any 1xx header is neutral to the
set of resource headers in the final response.

RFC 7231 says (ch. 6.2) "If the request did not contain an Expect 
header field containing the 100-continue expectation, the client 
can simply discard this interim response."

And "101 Switching Protocols" is obviously hop-by-hop anyway, so
it may never reach the consumer of the real response.

For 103, this is also true. Any HTTP/2 intermediate should discard
unknown 1xx responses, so the server can also not assume that its
headers reach all recipients.

That also relieves intermediates from any obligation of "folding"
103s into the final response (in case they do not want or can not
send on the 103s).

Which also requires any origin that *wants* these headers in the
final response that is about the resource , to duplicate them in 
its response.

Personally, I think of 1xx as a signalling channel from server
to client that can be used before the response is sent. 

For 100 and 101, this is pretty clear. For 103 there is some
temptation to see Link: headers as part of the final response,
but they really are not.

My interpretation.

-Stefan

> Am 08.08.2017 um 09:38 schrieb Willy Tarreau <[email-masked]>:
>

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 8 Aug 2017 17:55:10 +0900

> Ok, time to clarify the semantics, then words will come more easily.

Yeah I agree with the approach.

> set of resource headers in the final response.

I agree to the above.

> headers reach all recipients.

I do not agree. RFC 7231 section 6.2 states:

   A proxy MUST forward 1xx responses unless the proxy itself requested
   the generation of the 1xx response.

So it would be natural to assume that proxies that do not understand
103 will forward the hints to the client.

-- 
Kazuho Oku

---

From: Stefan Eissing <[email-masked]>
Date: Tue, 8 Aug 2017 11:06:12 +0200

> Am 08.08.2017 um 10:55 schrieb Kazuho Oku <[email-masked]>:
> 

You are right. A proxy MUST forward it. I have no idea if this works
in reality, though.

-Stefan

---

From: Willy Tarreau <[email-masked]>
Date: Tue, 8 Aug 2017 11:18:18 +0200

> 103 will forward the hints to the client.

Yep definitely, but we can keep this out of the equation. Given that
clients are assumed to ignore unknown 1xx responses, the server cannot
assume that the Link headers have been seen.

By the way I had two other thoughts to justify how an intermediary could
add inexact header fields that may or may not be repeated in the final
response :
  - those which are configured to unconditionally add a few resources
    that are very likely to be used on a given site.

  - caches : we could imagine a cache which sniffs Link headers from responses
    and emits the most common ones in 103 when it's known that responses for
    such requests take more than one RTT on average. Such a cache would not
    require hard-coded links, and would often be a bit wrong, advertising
    certain useless links and not advertising all needed ones. In such a case
    it's obvious that the final response has the last say.

Willy

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 9 Aug 2017 11:03:50 +0900

2017-08-08 16:38 GMT+09:00 Willy Tarreau <[email-masked]>:
> But isn't it expected to be the reality ?

I think that there can be use-cases for multiple 103s that does not
involve an intermediary.

For example, an origin server might emit the preload link to the
global CSS, and then, by checking whether the user has logged onto the
website emit an additional set of preload links. The web application
will then process the request and emit the final response.

That is one of the reasons I argue against laying down the client
behavior based on how an intermediary will behave. Behavior of an
intermediary is already discussed in the previous paragraph as an
example (we could expand it if it deems necessary).

> In the other example I gave
> needed, and that the final word is to the server's final response.

We agree that the speculations made by intermediaries can differ from
that expressed by the origin.

What I am trying to point out is that the fact does not lead to the
conclusion that the union needs to be calculated _by the client_, and
therefore that the text should not imply that the client is required
to calculate the union due to the way intermediaries behave.

(following text explains an alternative model that does not require
the client to calculate the union)

Consider the case where a gateway first speculates that the response
will contain "Link: </a.css>; rel=preload" and then a server
speculates that the response will "Link: </b.css>; rel=preload".

In the current model, a.css will be included in the first 103 response
and only b.css will be included in the second 103 response.

However, it is technically possible for the gateway to remember what
it has sent in the 103 response, and calculate the union of the
headers when it receives a 103 from upstream. Then, the intermediary
will emit the union of the headers as the second 103 response.

> We

I am opposed to the idea.

One reason is because adding such rule will be a non-editorial change
(as discussed above).

The other reason is that using a binary signal is not ideal. If you
really want to make weak suggestions in the first 103 response and
then update it in the following 103s, you should consider adding a
precedence parameter to the preload elements. Then the client can
schedule the fetch the preload links based on the precedence, and also
update the precedence (by calculating the sum of the precedence when
overlapping preload links are found in multiple 103s).

-- 
Kazuho Oku

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 9 Aug 2017 05:43:22 +0200

Hi Kazuho,

> will then process the request and emit the final response.

Oh absolutely! I mean, the intermediaries make it (in my opinion) easier
to understand why multiple, possibly overlapping responses may appear.
Some people tend to think that servers are smart and ought to do everything
consistently fine and will have a harder time understanding why a single
server responses in multiple steps.

> to calculate the union due to the way intermediaries behave.

Well not necessarily by the client, by anyone seeing the 103 responses,
so possibly any intermediary on the way to the client.

> will emit the union of the headers as the second 103 response.

I 100% agree on this one, it's even aligned with the example I gave of
a cache that would learn them and deliver them early based on previous
requests.

> precedence parameter to the preload elements.

Yep I thought about this yesterday evening as well. While it could be
nice, it would significantly complexify this stuff and would quickly
go out of the initial scope. We'd rather later propose to add new
properties to Link if we find a compelling use case, and 103 will
naturally work.

> Then the client can

Let's not start to speculate how this would be calculated, you're putting
your fingers in a dangerous area ;-)

OK so let's get back to the text. My previous concern was a lack of
fluidity in your proposed updated sentence. Now I get a better idea of
your intent, I'll see if I can propose to slightly adapt it to keep the
same spirit without introducing intermediaries into the mix.

Cheers,
Willy

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 10 Aug 2017 09:38:59 +0900

Hi Willy,

> same spirit without introducing intermediaries into the mix.

Thank you very much. I am looking forward to seeing the text.

FWIW, please let me restate my position that the "alternative
approach" is not what we should permit in Early Data for two reasons;
i) it introduces a rule specific to how multiple 103 should be handled
(which could be considered as a non-editorial change), ii) such rule
is not ideal compared to adding precedence to the preload links.

-- 
Kazuho Oku

---

From: Willy Tarreau <[email-masked]>
Date: Thu, 10 Aug 2017 05:45:41 +0200

Hi Kazuho,

> approach" is not what we should permit in Early Data for two reasons;

s/Early Data/Early Hints ;-)

> is not ideal compared to adding precedence to the preload links.

I agree with you. Still it's a bit normal that we have to specify how
header fields have to be handled because in previous 1xx (101 aside),
they were ignored.

How about replacing this :

   Since the nonexistence of a header field within a 103 (Early Hints)
   response does not indicate the absence of that header field in the
   final response, a server can omit a header field that was included
   in one 103 (Early Hints) response in the following 103 (Early Hints)
   responses, even when it is still anticipated that the header field
   will be part of the final response.
   What a client would expect in the final response is a union of the
   header fields that were found in the multiple 103 (Early Hints)
   responses.
 
With this :

   A server MAY emit multiple 103 (Early Hints) responses with additional
   header fields as new information become available while the request is
   being processed. It does not need to repeat the fields that were
   already emitted, though it is doesn't have to exclude them either. The
   client will consider the union of all header fields received in multiple
   103 (Early Hints) responses when anticipating the list of header fields
   expected in the final response.

I think that adding an example like this one would cover all situations :

  HTTP/1.1 103 Early Hints
  Link: </main.css>; rel=preload; as=style

  HTTP/1.1 103 Early Hints
  Link: </style.css>; rel=preload; as=style
  Link: </script.js>; rel=preload; as=script

  HTTP/1.1 200 OK
  Date: Fri, 26 May 2017 10:02:11 GMT
  Content-Length: 1234
  Content-Type: text/html; charset=utf-8
  Link: </main.css>; rel=preload; as=style
  Link: </newstyle.css>; rel=preload; as=style
  Link: </script.js>; rel=preload; as=script

(style.css not used, replaced with newstyle.css, and list delivered over
multiple responses).

I'd be tempted to in fact remove the section about mutiple 103 and fold
that text along the previous one before the example, it would make it
even clearer.

Cheers,
Willy

---

From: Mark Nottingham <[email-masked]>
Date: Thu, 10 Aug 2017 16:01:26 -0700

> On 9 Aug 2017, at 8:45 pm, Willy Tarreau <[email-masked]> wrote:
> 

FWIW +1 from me. You might want to s/will/can/ -- remember, these are hints, so the client can selectively ignore any or all of them (I don't *think* we want to say that if you pay attention to hints, you have to process them all, do we?)

Cheers,

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

---

From: Tom Bergan <[email-masked]>
Date: Thu, 10 Aug 2017 16:42:39 -0700

On Thu, Aug 10, 2017 at 4:01 PM, Mark Nottingham <[email-masked]> wrote:

> FWIW +1 from me. You might want to s/will/can/ -- remember, these are
> hints, so the client can selectively ignore any or all of them (I don't
> *think* we want to say that if you pay attention to hints, you have to
> process them all, do we?)
>

My two cents: I agree -- the client should not be forced to process all
hints.

If I may make a small suggestion: try to avoid the word "union". All
examples in the RFC and in this discussion revolve around the Link header,
where the union of Link headers has a sensible meaning. But the RFC doesn't
place any restrictions on the header fields that can appear in a 103
response. Other header fields, such as ETag or Last-Modified, are
single-valued. It's entirely possible that some day, a crazy server or set
of intermediaries will send two 103 responses with different ETag values.
(Why? I don't know, but eventually something like this will happen.) I
would instead say:

   A server MAY emit multiple 103 (Early Hints) responses with additional
   header fields as new information becomes available while the request is
   being processed. It does not need to repeat the fields that were
   already emitted, though it is doesn't have to exclude them either. The
   client may consider any combination of header fields received in multiple
   103 (Early Hints) responses when anticipating the list of header fields
   expected in the final response.

(Minor changes from Willy's text: "become" -> "becomes", "the union of all"
-> "any combination of")

---

From: Mark Nottingham <[email-masked]>
Date: Thu, 10 Aug 2017 17:37:15 -0700

> On 10 Aug 2017, at 4:42 pm, Tom Bergan <[email-masked]> wrote:
> 

I like that.

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 11 Aug 2017 05:13:06 +0200

> >    expected in the final response.

I prefer it as well, thanks for your suggestion!

Willy

---

From: Kazuho Oku <[email-masked]>
Date: Fri, 11 Aug 2017 13:04:37 +0900

Will, Tom, Mark,

Thank you for your suggestions.

I have merged https://github.com/httpwg/http-extensions/pull/380,
using the text suggested by Tom (with slight changes) and the example
suggested by Willy. For details, please refer to the commit log of the
PR.

Please let me know if you see any problem.

-- 
Kazuho Oku

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 11 Aug 2017 07:48:36 +0200

Hi Kazuho,

> Please let me know if you see any problem.

Looks good :-)

Willy