Re: Server Push and Conditional Requests

Kazuho Oku <kazuhooku@gmail.com> Fri, 26 August 2016 18:07 UTC

Return-Path: <ietf-http-wg-request+bounce-httpbisa-archive-bis2juki=lists.ie@listhub.w3.org>
X-Original-To: ietfarch-httpbisa-archive-bis2Juki@ietfa.amsl.com
Delivered-To: ietfarch-httpbisa-archive-bis2Juki@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id 65574127735 for <ietfarch-httpbisa-archive-bis2Juki@ietfa.amsl.com>; Fri, 26 Aug 2016 11:07:13 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -7.569
X-Spam-Level:
X-Spam-Status: No, score=-7.569 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HEADER_FROM_DIFFERENT_DOMAINS=0.001, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-0.548, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.com
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id qKPDJjfhqtuq for <ietfarch-httpbisa-archive-bis2Juki@ietfa.amsl.com>; Fri, 26 Aug 2016 11:07:11 -0700 (PDT)
Received: from frink.w3.org (frink.w3.org [128.30.52.56]) (using TLSv1.2 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 2E3EB127A90 for <httpbisa-archive-bis2Juki@lists.ietf.org>; Fri, 26 Aug 2016 11:07:10 -0700 (PDT)
Received: from lists by frink.w3.org with local (Exim 4.80) (envelope-from <ietf-http-wg-request@listhub.w3.org>) id 1bdLRd-0007sT-TY for ietf-http-wg-dist@listhub.w3.org; Fri, 26 Aug 2016 18:01:33 +0000
Resent-Date: Fri, 26 Aug 2016 18:01:33 +0000
Resent-Message-Id: <E1bdLRd-0007sT-TY@frink.w3.org>
Received: from maggie.w3.org ([128.30.52.39]) by frink.w3.org with esmtps (TLS1.2:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.80) (envelope-from <kazuhooku@gmail.com>) id 1bdLRT-0007o8-BN for ietf-http-wg@listhub.w3.org; Fri, 26 Aug 2016 18:01:23 +0000
Received: from mail-wm0-f49.google.com ([74.125.82.49]) by maggie.w3.org with esmtps (TLS1.2:RSA_AES_128_CBC_SHA1:128) (Exim 4.80) (envelope-from <kazuhooku@gmail.com>) id 1bdLRR-0007To-57 for ietf-http-wg@w3.org; Fri, 26 Aug 2016 18:01:22 +0000
Received: by mail-wm0-f49.google.com with SMTP id o80so3031238wme.1 for <ietf-http-wg@w3.org>; Fri, 26 Aug 2016 11:01:00 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=WjuFX9tzSicgIbLop916IT0vl7az8Ejs0Poevcs8ucc=; b=XvoUiMOD8wHnjoMkvXo4toCUSiunK1dkX/8es46FcHFt6fWDWEUCj0+hNPmv2F+K7O UVLQV7F2xu7ecfG0eiMzsOODOFMBtqPlgFODRJleZSdA921NSgr2MyebQ4v1sxCjgmyf cTEunzI8noxeQppqIzTKlzidb20d3RxfaHO0D/kJyhq0YXQj8QucBdWD1YAozCzLTR3q rQBsqNmuplcdvvddZVZcaHrJzzLkj44qxvgeSvVs2MshSk6jp+pgRxhbd+Y3DY+bA8ih NcJxE+aeQuE9FACngTS9cbCgAANrAg7lwRA1r93uHkRk3+qq2axkSyRDlf0Yu0N++62E TyDA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=WjuFX9tzSicgIbLop916IT0vl7az8Ejs0Poevcs8ucc=; b=NXLZB8S6HT7nCdjMgjsnkqS9vXEq8ZavpJyV5iNotjRcRQ+nvOtx95Uq2brRWMDn32 VzcPmZEyPvA480i1MdiqHR+aIwswsoYW01KDXoKeqWJ+4cEasPg12z0bVRaR6CWCEshi 5HJQApwQ3X55nR5AY/Y9wRit4gbL7bTcN5ipcmKPSKwvDV5EsbR6UPev+numm3uog6qq 8JWRrAyHea83ZipYRMJTEuK9rKtv3Qu+xCJM97o+sPaOHk7XbFzMLB0lmboUe0LiO7FI jCBN2D7nQDlfqK+x4tLyPvE0p/Kk9iVLNQBv1f3qtgz6zxUNexEuk37QJTf6eDg5UqZX 44Bg==
X-Gm-Message-State: AE9vXwOUhs6zpbRBvAww6HCkhPhVX6kvlRHG22h+pwHTwmmisPuDgFNwjXCXqc5o3Dgr2Z1IhrMvyUVp2wtC3w==
X-Received: by 10.28.52.2 with SMTP id b2mr91628wma.109.1472234453444; Fri, 26 Aug 2016 11:00:53 -0700 (PDT)
MIME-Version: 1.0
Received: by 10.194.122.67 with HTTP; Fri, 26 Aug 2016 11:00:52 -0700 (PDT)
In-Reply-To: <29248881-24A5-41E1-A63F-0899A4022B65@greenbytes.de>
References: <FCF25267-9CE8-4DDB-A0B3-29C23F81124E@mnot.net> <CANatvzw967Xw67eYy3+0-=oABdeU5SPiXk-iThXJww9bc=x-TA@mail.gmail.com> <601BAF83-5ED1-4A4E-8A9E-979DDE5BCB1A@greenbytes.de> <CANatvzxHSZHCpF+OfZQXjBzN2=1e0NXQ0_-Jm2ioFLj5rZBiHw@mail.gmail.com> <29248881-24A5-41E1-A63F-0899A4022B65@greenbytes.de>
From: Kazuho Oku <kazuhooku@gmail.com>
Date: Sat, 27 Aug 2016 03:00:52 +0900
Message-ID: <CANatvzyFmapfQ0r1FjFmYrVVyGczJr3VNGi9WsSCRu8cigF68A@mail.gmail.com>
To: Stefan Eissing <stefan.eissing@greenbytes.de>
Cc: Mark Nottingham <mnot@mnot.net>, HTTP Working Group <ietf-http-wg@w3.org>
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass client-ip=74.125.82.49; envelope-from=kazuhooku@gmail.com; helo=mail-wm0-f49.google.com
X-W3C-Hub-Spam-Status: No, score=-5.5
X-W3C-Hub-Spam-Report: AWL=-0.763, BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, SPF_PASS=-0.001, W3C_AA=-1, W3C_WL=-1
X-W3C-Scan-Sig: maggie.w3.org 1bdLRR-0007To-57 8d49df5012add82d4a65674f89c45165
X-Original-To: ietf-http-wg@w3.org
Subject: Re: Server Push and Conditional Requests
Archived-At: <http://www.w3.org/mid/CANatvzyFmapfQ0r1FjFmYrVVyGczJr3VNGi9WsSCRu8cigF68A@mail.gmail.com>
Resent-From: ietf-http-wg@w3.org
X-Mailing-List: <ietf-http-wg@w3.org> archive/latest/32366
X-Loop: ietf-http-wg@w3.org
Resent-Sender: ietf-http-wg-request@w3.org
Precedence: list
List-Id: <ietf-http-wg.w3.org>
List-Help: <http://www.w3.org/Mail/>
List-Post: <mailto:ietf-http-wg@w3.org>
List-Unsubscribe: <mailto:ietf-http-wg-request@w3.org?subject=unsubscribe>

2016-08-26 21:31 GMT+09:00 Stefan Eissing <stefan.eissing@greenbytes.de>:
> Ok, now I understand the motivation better. Thanks.
>
> Not sure if I like the disconnect between Request/Response, sorry Promise/Response, e.g. answering conditionals that are not visible on the protocol level. Maybe the PROMISE should indicate sth like a 'If-Not-In-Cache-Digest: <digest-value>' to announce that some validation will be happening.

My understanding is that for all of the four proposed approaches (3 by
Mark + HEAD/200 by Stefan), the feature needs to be opted-in by the
browser, possibly by using a new flag in the SETTINGS frame. This is
because IIRC most (if not all) browsers that support push currently
don't recognize If-Match or If-None-Match header in a pushed request
nor does recognize a pushed 304.

Considering that, it _might not_ be necessary to have a header like
If-Not-In-Cache-Digest in a PUSH_PROMISE.

Personally, I also think that a server should be allowed to push a
cache validator (without pushing the content) regardless of if any
validation was performed on the server side.

I mean, a server that unconditionally pushes 304 would still be
useful, since it would reduce the RTT spent for stale cache
invalidation when the client has a stale-but-valid response in its
cache.

So even if we are to introduce an HTTP header to be used for pushing
304, I think the name should not imply any kind of server-side
validation.

>> Am 26.08.2016 um 14:10 schrieb Kazuho Oku <kazuhooku@gmail.com>:
>>
>> 2016-08-26 20:34 GMT+09:00 Stefan Eissing <stefan.eissing@greenbytes.de>:
>>> Isn't the unconditional PROMISED GET -> 304 better made a PROMISED HEAD -> 200?
>>
>> The issue with using HEAD for pushing etag only is that it might
>> introduce a trade-off on the server between delaying the main response
>> vs. not using push.
>>
>> This is because, as pointed out by Mark, a server needs to send
>> PUSH_PROMISE before sending HEADERS of the parent response. If we
>> decide to choose a different method depending on if we want to push
>> the content or only the etag, it would mean that we cannot send
>> PUSH_PROMISE until the etag value of the pushed stream is being
>> determined.
>>
>> In some deployments, an H2 endpoint that initiates push and the cache
>> that stores the contents of the resource to be pushed may exist on
>> different physical servers. In fact, such deployments might be common
>> considering most CDN POPs are constructed that way.
>>
>> So my preference goes to choosing an approach that allows an H2 server
>> to initiate push without the knowledge of the etag (and laterwards
>> decide to _not_ send the content).
>>
>>>> Am 26.08.2016 um 11:40 schrieb Kazuho Oku <kazuhooku@gmail.com>:
>>>>
>>>> Hi,
>>>>
>>>> Thank you for starting the discussion.
>>>>
>>>> Due to the following reasons, my preference goes to the third approach
>>>> that uses unconditional GET.
>>>>
>>>> For all of the three approaches, the client would need to verify the
>>>> status code of the response, as well as the etag response header. For
>>>> the first two approaches, the request header needs to be examined as
>>>> well.
>>>>
>>>> Considering the fact, I think from client’s perspective it would be
>>>> easiest to go with the third approach (i.e. unconditional GET + 304).
>>>>
>>>>> From server-side perspective, I agree that by using If-Match it is
>>>> possible to send etag before sending the response headers. But I
>>>> wonder if that has practical effect.
>>>>
>>>> If the server has the knowledge of the current etag value, it can push
>>>> the etag value as part of the response HEADERS frame right after
>>>> PUSH_PROMISE. The two frames would typically go into a single TCP
>>>> packet (note that a HEADERS frame containing a pushed response would
>>>> be tiny thanks to HPACK).
>>>>
>>>> So my feeling is that using unconditional GET + 304 would be the
>>>> easiest to implement both on the client- and server-side, at the same
>>>> time offering practically the best performance among the three
>>>> approaches.
>>>>
>>>> 2016-08-24 13:26 GMT+09:00 Mark Nottingham <mnot@mnot.net>:
>>>>> Thinking about how Server Push interacts with conditional requests <http://httpwg.org/specs/rfc7232.html>, I can see three interesting modes of operation, outlined below.
>>>>>
>>>>>
>>>>> 1. If-Match / If-Unmodified-Since
>>>>>
>>>>> If the server has immediate access to the response being pushed (e.g., if the server is authoritative for it, or it is fresh in cache), it might want to send conditional headers in the `PUSH_PROMISE` request, to give the client the earliest possible chance to send a `RST_STREAM` (since the promised stream might be delayed due to priorities, etc.).
>>>>>
>>>>> The most obvious way to do this with existing headers is using `If-Match` and/or `If-Unmodified-Since`; if the validator matches what the client has, it can send a `RST_STREAM`; otherwise, they can wait for the full response (which will presumably have validators matching those sent in the request).
>>>>>
>>>>> ~~~
>>>>> :method: GET
>>>>> :scheme: https
>>>>> :authority: www.example.com
>>>>> :path: /images/1234.jpg
>>>>> Host: www.example.com
>>>>> If-Match: "abcdef"
>>>>> ~~~
>>>>>
>>>>> Here, when a client receives these headers in a `PUSH_PROMISE`, it can send a `RST_STREAM` if it has a fresh cached response for `https://www.example.com/images/1234.jpg` with the `ETag` "abcdef". If it does not do so, the server will continue to push the successful (`2xx`) response (since the `ETag` does in fact match what is pushed).
>>>>>
>>>>>
>>>>> 2.  If-None-Match / If-Modified-Since
>>>>>
>>>>> If the server does not have a fresh local copy of the response, but does have access to a stale one (in the meaning of RFC7234), it can `PUSH_PROMISE` with `If-None-Match` and/or `If-Modified-Since`:
>>>>>
>>>>> ~~~
>>>>> :method: GET
>>>>> :scheme: https
>>>>> :authority: www.example.com
>>>>> :path: /images/5678.jpg
>>>>> Host: www.example.com
>>>>> If-None-Match: "lmnop"
>>>>> ~~~
>>>>>
>>>>> That way, the client again has an opportunity to send `RST_STREAM` if it already has a fresh copy with that validator in cache.
>>>>>
>>>>> Once the server has obtained a fresh (possibly validated) response, it can either push a `304 (Not Modified)` response in the case that the `ETag` hasn't changed, or a successful (`2xx`) response if it has.
>>>>>
>>>>> Note that if the client has a fresh copy in cache, but the server does not, the client can still use the fresh copy; it has not been invalidated just because the server has not kept its copy fresh.
>>>>>
>>>>>
>>>>> 3. 304 (Not Modified) without a Conditional
>>>>>
>>>>> If the server believes that the client does have a stale but valid copy in its cache (e.g., through the use of a cache digest), it can send a `PUSH_PROMISE` followed by a pushed `304 (Not Modified)` response to revalidate that cached response, thereby making it fresh in the client's cache.
>>>>>
>>>>> If the server has a local copy of the response that it wishes to use, it can send the PUSH_PROMISE with an `If-None-Match` and/or `If-Modified-Since` conditional, as above.
>>>>>
>>>>> However, if it does not, it will still be desirable to generate the `PUSH_PROMISE` as soon as possible, so as to avoid the race described in RFC7540, Section 8.2.1.
>>>>>
>>>>> To allow this, a request without a conditional can be sent:
>>>>>
>>>>> ~~~
>>>>> :method: GET
>>>>> :scheme: https
>>>>> :authority: www.example.com
>>>>> :path: /images/9012.jpg
>>>>> Host: www.example.com
>>>>> ~~~
>>>>>
>>>>> When the response body is available to the server, it can send a `304 (Not Modified)` if it believes that the client already holds a copy (fresh or stale); however, it MUST include the validators to allow the client to confirm this. For example:
>>>>>
>>>>> ~~~
>>>>> :status: 304
>>>>> ETag: "abc123"
>>>>> Date: Tue, 3 Sep 2016 04:34:12 GMT
>>>>> Content-Type: image/jpeg
>>>>> Cache-Control: max-age=3600
>>>>> ~~~
>>>>>
>>>>> In this case, if the client's cached response does not have the same `ETag` it SHOULD make a request to obtain a fresh response.
>>>>>
>>>>> On the other hand, if the server determines that the client does not have the appropriate cached response, it can send the full, successful (`2xx`) response:
>>>>>
>>>>> ~~~
>>>>> :status: 200
>>>>> ETag: "abc123"
>>>>> Date: Tue, 3 Sep 2016 04:34:12 GMT
>>>>> Content-Type: image/jpeg
>>>>> Cache-Control: max-age=3600
>>>>>
>>>>> [ body ]
>>>>> ~~~
>>>>>
>>>>> Note that this approach relies upon an _implicit conditional_ in the PUSH_PROMISE request. If felt necessary, this can be made explicit, for example by defining a new conditional header `If-In-Digest`.
>>>>>
>>>>>
>>>>>
>>>>> Which of these do people think are interesting to specify, implement and use? Are there problems, or other approaches we should be considering?
>>>>>
>>>>> Cheers,
>>>>>
>>>>> --
>>>>> Mark Nottingham   https://www.mnot.net/
>>>>>
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Kazuho Oku
>>>>
>>>
>>
>>
>>
>> --
>> Kazuho Oku
>>
>



-- 
Kazuho Oku