Subject: If-None-Match + Range

From: Zhong Yu <[email-masked]>
Date: Fri, 13 Jan 2012 06:29:14 -0600

Suppose a GET request contains `If-None-Match` and `Range` headers;
the If-None-Match condition fails, the Range is unsatisfiable. Which
code should be returned, 304 or 416? There are conflicting statements
in the draft:

Part 4, section 3.2.

   If the request would, without the If-None-Match header field, result
   in anything other than a 2xx or 304 status code, then the If-None-
   Match header field MUST be ignored.

(that means 416 should be returned)

Part 5, section 5.4.2.

   o  The presence of a Range header field in a conditional GET (a
      request using one or both of If-Modified-Since and If-None-Match,
      or one or both of If-Unmodified-Since and If-Match) modifies what
      is returned if the GET is otherwise successful and the condition
      is true.  It does not affect the 304 (Not Modified) response
      returned if the conditional is false.

(that means 304 should be returned)

If the server decides that such a bad request is not worth honoring,
which error code should be returned to client?

Best Regards,
Zhong Yu

---

From: Julian Reschke <[email-masked]>
Date: Sun, 15 Jan 2012 18:21:09 +0100

> which error code should be returned to client?

I don't think we know. Does it really matter?

(I think this is the same issue as 
<http://trac.tools.ietf.org/wg/httpbis/trac/ticket/241>)

Best regards, Julian

---

From: Amos Jeffries <[email-masked]>
Date: Mon, 16 Jan 2012 19:06:31 +1300

> <http://trac.tools.ietf.org/wg/httpbis/trac/ticket/241>)

There is another ambiguity with the If-Match texts:
" If the request would, without the If-Match header field, result in
    anything other than a 2xx or 412 status code, then the If-Match
    header field MUST be ignored.
"

So the example of two resources A (200 bytes) and B (100 bytes). The 
request:

   If-Match: "B"
   If-None-Match: "A"
   If-Range: 1-150/200

If-Range could potentially return true from the "A" resource. Leading to 
ambiguity whether the If-Match MUST be ignored (resulting in 304) or not 
(resulting in 206).

I think the If-Match text should be brought inline with the other 
definitions which say "anything other than a 2xx or 304 status code". 
That way we can use AND logics consistently between them. Or have I 
missed  discussion about why If-Match MUST be OR'd against the other 
conditionals?

Taking another stab at #421 would it not be be clearer to re-write the 
section 3 intro along the lines of:
"
  Conditional headers defined by this specification are []. When 
combined they form a boolean AND condition on the request success or 
failure.

  If any one of the conditionals contains invalid syntax, or directly 
contradicts another conditional then the appropriate 4xx should be 
returned.

  If all of the conditionals produce true then a 2xx status with 
appropriate entity should be returned.

  If one or more of the conditionals produces false then the whole 
conditional is false and a 304 should be returned.
"

That way all the confusing text about when one condition or another 
"MUST be ignored" can be dropped. Since none of them are ignored pre-se, 
but they may not need checking if another conditional already produced 
false.

Then a list of the conditionals with specific descriptions including:
  * what is tested by each and how to compare for true/false result
  * whether 304 or something else constitutes a 'false' response. It 
seems very weird to be getting 304 out when seeking to fetch a Range: 
with only If-Match: presented.
  * other considerations?

Just my 2c to get things rolling.

AYJ

---

From: Zhong Yu <[email-masked]>
Date: Mon, 16 Jan 2012 00:58:58 -0600

> I don't think we know. Does it really matter?

Not really, except for a server implementation, which must yield a
result for any situation, so the question is what kind of results are
acceptable for this case. It's OK if the spec explicitly states that
such case is undefined; but my reading is that the draft contradicts
itself here.

(400 is apparently a legit response according to the new draft)

Zhong Yu

---

From: Amos Jeffries <[email-masked]>
Date: Tue, 17 Jan 2012 02:25:12 +1300

On 16/01/2012 7:58 p.m., Zhong Yu wrote:
> On Sun, Jan 15, 2012 at 11:21 AM, Julian Reschke wrote:

Meaning 206 or 304 or any 4xx or any 5xx may be returned.

> such case is undefined; but my reading is that the draft contradicts

But ... it *is* defined as having If-None-Match condition tested then 
the Range checked. 200 or 206 or 304 or 4xx or 5xx are all valid 
responses the server gets to choose from.

On first reading your post I get the impression maybe you think Range as 
being always unsatisfiable with If-None-Match indicating false (object 
has not changed). This is not correct. The If-None-Match is there to 
make available the small 304 response instead of a 4xx error or 206 with 
data wasting work if the object has not changed at all.

It is perfectly reasonable for some client application to grab a preview 
snippet of the first X bytes of an object only if it has changed from 
some previous copy seen.

For example, an AV scanner polling over a download site for infections 
in exectuable binaries headers (small fixed size of bytes in the 
infectable header area) can use If-None-Match and Range to get a 
scannable preview without having to download the whole object when it 
changes. With a supportive server it only gets a small 206 and partial 
body for scanning if the object has changed (with MB binaries the speed 
difference from 200 status can be impressive). 304 (unchanged, skip) or 
206 (new content, scan) or 412 (range is invalid, object gone?) are all 
reasonable replies from the server.

It is an unlikely case that clients would emit such a combo normally but 
not impossible.

Your final statement "If the server decides that such a bad request is 
not worth honoring, which error code should be returned to client?" 
assumes that the server is going to produce a 4xx message. Which 
indicates you/server have already decided the 304 is not suitable 
response for some reason. Which in turn means the Part 4, section 3.2 
has been chosen and the Part 5, section 5.4.2 texts about 304 are not 
relevant.

> (400 is apparently a legit response according to the new draft)

It would be valid yes. But more specific errors (ie 416) are preferred 
over the generic 400. To give the client a strong hint where the problem is.

It is unclear whithout knowing a lot more about the application context 
and expectations whether 416 or 412 or some other error status is _best_.

AYJ

---

From: Zhong Yu <[email-masked]>
Date: Mon, 16 Jan 2012 10:38:13 -0600

Let me clarify my question with an example.

The representation remains unchanged between requests; the ETag
remains "v0". The length of the representation body is 1000 bytes. Now
consider this request

    GET /resource HTTP/1.1
    If-None-Match: "v0"
    Range: bytes=2000-3000

of course, this is a bad request. The question is, which status code
should be returned? 304 or 416? The two sections I quoted seem to
yield to each other.

Zhong Yu

---

From: "Roy T. Fielding" <[email-masked]>
Date: Mon, 16 Jan 2012 12:08:49 -0800

> should be returned? 304 or 416? The two sections I quoted seem to

304 is the answer.  The text on precedence still needs work, but the conditions
are tested before performing the requested method.

....Roy

---

From: Zhong Yu <[email-masked]>
Date: Mon, 16 Jan 2012 14:46:36 -0600

On Mon, Jan 16, 2012 at 2:08 PM, Roy T. Fielding <[email-masked]> wrote:
> 304 is the answer.

Thanks

> The text on precedence still needs work, but the conditions

The current spec suggests a much more complex rule. The conditions are
ignored if it can be speculated that the request-sans-conditions would
fail. It's more like:

first, perform the request without conditions
    if it fails, return the failure. (conditions ignored)
    if it succeeds, test the conditions
        if conditions hold, return success
        if conditions fail, *rollback* the work done in first step
            and return 416 or 304

It would be nice if it's simplified as you just stated
    conditions are tested before performing the requested method.

Zhong Yu

---

From: Amos Jeffries <[email-masked]>
Date: Tue, 17 Jan 2012 11:48:54 +1300

> should be returned? 304 or 416? The two sections I quoted seem to

IMHO the MUST about returning other errors when they occur is most 
appropriate
"
    If the request would, without the If-None-Match header field, result
    in anything other than a 2xx or 304 status code, then the If-None-
    Match header field MUST be ignored.
"

ASUI the intent is for 2xx / 3xx response from If-* is an optimisation 
feature and only comes into effect if all the other features in the 
headers are valid and would produce a 2xx response. This is highlighted 
by the MAY clause at the very beginning of the If-None-Match description 
which says it can be ignored entirely by any part of the system.

AYJ

---

From: Amos Jeffries <[email-masked]>
Date: Tue, 17 Jan 2012 12:03:11 +1300

> are tested before performing the requested method.

Really?

I'll admit that makes implementation a whole lot easier and raises the 
servers visible success rate (er, "watermelon metrics" comes to mind 
there). The identification and recovery from object corruption or 
disappearance becomes more difficult for the client.

See my earlier post(s) for an AV scenario where 4xx is very desirable 
and useful.

AYJ