Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Right Content-range value for 0 results #109

Open
mercmobily opened this issue Mar 9, 2015 · 3 comments
Open

Right Content-range value for 0 results #109

mercmobily opened this issue Mar 9, 2015 · 3 comments

Comments

@mercmobily
Copy link

At the moment, in JsonRestStores (which I am finalising as we speak), when there are NO results I am returning:

Content-Range: 0-0/0

I realise that dstore only really cares about the last bit to return the total. However, it bothers me that `0-0/0' is actually telling the client "the first record out of 0 results", which is not formally correct.

Do you think 0-0/0 is the way to go? If not, what should I return?

@neonstalwart
Copy link
Contributor

i had noticed this too and wondered what to do about it. its a great question.

since indexing is 0-based, the representation for a result set that contains just a single item would be 0-0/1. i.e. the server is indicating it has returned items from index 0 to index 0 (i.e just the first item) of 1 items. so 0-0 actually means there is 1 item which led me to conclude that 0-0/0 probably wasn't the right representation for an empty response.

if we look at the spec

A Content-Range field value is invalid if it contains a
byte-range-resp that has a last-byte-pos value less than its
first-byte-pos value, or a complete-length value less than or equal
to its last-byte-pos value.

we cannot have x-y/z where z is less than or equal to y which also rules out 0-0/0 for an empty response.

so, what should we do if we are showing an empty range? the spec doesn't specifically call out this case but http://stackoverflow.com/a/19695159/251287 suggests a 416 status with Content-Range : */0 which seems to be in line with what the spec says about the 416 status

The 416 (Range Not Satisfiable) status code indicates that none of
the ranges in the request's Range header field (Section 3.1) overlap
the current extent of the selected resource...

we may have requested items 0-x but none of the items in that range "overlap the current extent" of the resource so 416 is the right response.

dstore doesn't support the 416 response but what i have found to work is 0--1/0 which is invalid according to the spec but gets the job done in this case.

i think this is a great question and it's worth considering whether or not 416 is the right response according to the spec. whatever the decision is about the way we think the spec means for it to happen, i tend to think that dstore probably doesn't do the right thing currently.

@mercmobily
Copy link
Author

I am glad I managed to ask a good question :D
I think the best route is to decide what we should do according to the
specs, change dstore so that it follows the specs, and document it in
dstore itself.
Looking at the code though, dstore completely ignores the first two fields
and only cares about the total. So, in terms of dstore, it should only be a
matter of making it 'like' a 416 response.

I am happy with anything :D I really want JsonRestStores to be compatible
with dstore... so, just let me know what the verdict is, and I will gladly
comply :D

On 11 March 2015 at 00:08, Ben Hockey [email protected] wrote:

i had noticed this too and wondered what to do about it. its a great
question.

since indexing is 0-based, the representation for a result set that
contains just a single item would be 0-0/1. i.e. the server is indicating
it has returned items from index 0 to index 0 (i.e just the first item) of
1 items. so 0-0 actually means there is 1 item which led me to conclude
that 0-0/0 probably wasn't the right representation for an empty response.

if we look at the spec http://tools.ietf.org/html/rfc7233#section-4.2

A Content-Range field value is invalid if it contains a
byte-range-resp that has a last-byte-pos value less than its
first-byte-pos value, or a complete-length value less than or equal
to its last-byte-pos value.

we cannot have x-y/z where z is less than or equal to y which also
rules out 0-0/0 for an empty response.

so, what should we do if we are showing an empty range? the spec
doesn't specifically call out this case but
http://stackoverflow.com/a/19695159/251287 suggests a 416 status with Content-Range
: */0 which seems to be in line with what the spec
http://tools.ietf.org/html/rfc7233#section-4.4 says about the 416 status

The 416 (Range Not Satisfiable) status code indicates that none of
the ranges in the request's Range header field (Section 3.1) overlap
the current extent of the selected resource...

we may have requested items 0-x but none of the items in that range
"overlap the current extent" of the resource so 416 is the right response.

dstore doesn't support the 416 response but what i have found to work is
0--1/0 which is invalid according to the spec but gets the job done in
this case.

i think this is a great question and it's worth considering whether or not
416 is the right response according to the spec. whatever the decision is
about the way we think the spec means for it to happen, i tend to think
that dstore probably doesn't do the right thing currently.


Reply to this email directly or view it on GitHub
#109 (comment).

@spook
Copy link

spook commented Apr 20, 2018

Howdy all, I know this is late in to this conversation, but perhaps this will help others who are searching for the same thing.

    TL;DR:   We use 1-0 to mean "zero-length content"

In my "day job" at HP (now HPE) we wrestled with this as well. We came to the conclusion that the RFCs are ambiguous and somewhat conflicting on the topic, so we changed our question from "what's right?" to "what's least wrong?". FWIW, here's an excerpt from our protocol spec:
. . .
About the Range header

The Range header is used only for requests that contain no content themselves - that is, GETs and HEADs. The Range header means the ask is for a portion of the server's content in the reply. It's the range for what you want back.

The format is units=M-N, where units is typically "bytes"; M and N are 0-based positive integers that indicate the inclusive range you're requesting. So 0-9 means ten (10) bytes, starting from the first, through and including the ninth. The length of the response you're requesting is N-M+1. Values of M and N that would cause a negative computed length cause a 416 Range Not Satisfiable error. To indicate no content, use M=N+1, typically 1-0. Example:

Range: bytes=1000-9999

Caution: The Range header is not the same as the Content-Range header - they are different!

About the Content-Range header

In a request message, the Content-Range header describes what's included in the content of this request (not what's coming back). It's used in PUTs and POSTs to state that you're uploading that part of the whole. (RFC 7231 section 4.3.4 says it's not a legal header for PUTs, but RFC 5789's PATCH semantics don't do what we need. This is the lesser of the evils; and plenty of client libraries allow it). In a response message, such as a response to a GET that used the above Range header, it indicates where this portion of the contents fits within the whole.

The format is "unit M-N/Z". The unit is typically "bytes"; M is the 0-based range-start number, N is the 0-based range-end number (inclusive), and Z is the complete-length of the final file's contents. Example:

Content-Range: bytes 1000-9999/31415926

The length of the content in the message must equal N-M+1. When Content-Range is used with M and N specified (both not asterix's), the Content-Length header is optional, since the Content-Range also indicates the length. Values of M and N that would cause a negative computed length cause a 416 Range Not Satisfiable error.

Empty Files

For a request, to indicate an empty (zero-byte) file or resource with the Content-Range, use Z=0. Thus, anything that is /0 means the empty file (or resource or page) ...[irrelevant section of spec omitted].... The M and N values SHOULD still be provided for a request message. However, for a response message to indicate an empty file, the shorter notation */0 is allowed. Any implementation interpreting a Content-Range specification that has Z=0 SHOULD disregard the M and N values given, and presume M=1 and N=0 (or if using signed integers, M=0 and N=-1 is internally acceptable, which often affords simpler algorithms – but negative values are not allowed in messages).

Zero-length Content Range

To indicate a zero-length content, use the special case "1-0". Because the computed length is N-M+1, this evaluates to a range length of zero. Note that this does not mean the file is of zero length (that's indicated with /0), just that this chunk is empty. A zero-length range is not an error. Additionally, any M-N combination with M and N >=0, where N-M+1=0 is valid – for example 7-6 – but that would be confusing, and is unnecessary, so an implementation SHOULD NOT do this.

A typical use case of a zero-length range is when beginning a resumable upload (UC3) to get back a handle or to "initialize" the file, but without sending any of the file. For example, 1-0/12345.

Some users have suggested using the range M=0 and N=-1, n.b. 0--1 ("zero" "dash" "minus" "one"). This is forbidden by some HTTP RFC's and results in an error from many web servers, because the start and end ranges are specified as only digits without a sign (The BNF is 1*DIGIT). However, the other interpretations allow a negative number in a range specification, but it's meaning is "from the end". That is, -1 means the last byte of the resource (the file), -2 means the second last byte, and so on. Some webservers interpret it this way; others simply ignore a bad range and return the whole resource.

Using 0-0 was also suggested, but this means the first, single byte of the entity (a range length of one, not zero).

Wildcards in Content-Range

In a request message, the range-start number M may be specified as an asterix '*'. For example, *-9999. This means that for new resources, it's zero, and for existing resources, it's the current size of the file/page/resource. In code, this is expressed as M ||= sizeof(file) || 0; Think of it as a way to say "always append to however much of the file is already there".

Also in a request message, the range-end number N may be specified as an asterix '*', such as 1000-* . This means that the range-end number can be computed from the size of the content that's included in the message. Normally, the Content-Length (L) header indicates this, thus N=M+L-1. But some transfer methods, such as multipart or chunked, use other mechanisms to indicate the size of or end-of the included content.

...[section of spec omitted]...

In a request, the complete-length Z may also be specified as an asterix "", such as 1000-9999/ . This means that the complete size is not yet known (or need not be specified at this time). However, to finalize a transfer, the Z must be specified.

Thus, in a request message, Content-Range: bytes *-*/* is valid. It means, 1) if the file/resource doesn't exist, start at 0; and if a partial file/resource exists, append to it. 2) the end of the range is computed by adding the Content-Length to the range-start value (0 or length of existing partial file), and 3) don't finalize the file yet - we may have more coming.

About the Content-Length header

When both Content-Range and Content-Length are included in a message, they must agree. That is, Content-Length L must equal M-N+1 of the Content-Range. If they do not match the server returns 400 Bad Request.

A Content-Length without Content-Range implies a content range of 0 to L-1, and that Z == L.

Note this is not true for Range and Content-Length – the former specifies how much we want back, the latter is the size of the content in this request (which should be 0).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants