Subject: Re: i107

From: Mark Nottingham <[email-masked]>
Date: Mon, 28 Jul 2008 15:34:15 +0100

Julian and I were just discussing this (alas, not yet over a Guinness).

I think the right thing to do here is to describe both variant  
selection (p3, section 5.1, p6, 16.5) and validator comparison (p4  
section 5) in terms of set theory (at least informally), so that the  
set of representations available for a given request is the  
intersection of those selected by negotiation and those requested  
conditionally.

Make sense?

On 13/03/2008, at 10:55 PM, Henrik Nordstrom wrote:

>
>
> On Wed, 2008-02-27 at 21:53 -0800, Brian Smith wrote:
>>> Last-Modified validation is defined in terms of
>>> 'requested variant', whereas ETag validation
>>> (If-Match, If-None-Match) seem to go out of
>>> their way to say that *any* entity that meets
>>> the conditional can be returned, and never
>>> mind the selecting headers.
>
> If-None-Match is pretty clearly defined to apply to "the selected
> representation" only.
>
>   If any of the entity tags match the entity tag of the entity that
>   would have been returned in the response to a similar GET request
>   (without the If-None-Match header) on that resource, or if "*" is
> [...]
>
>   The meaning of "If-None-Match: *" is that the method MUST NOT be
>   performed if the representation selected by the origin server (or by
>   a cache, possibly using the Vary mechanism, see section 14.44)
>
>
> Same thing for If-Match (exact same wording, only negated to match the
> condition).
>
> Regards
> Henrik
>
>

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

---

From: "Brian Smith" <[email-masked]>
Date: Mon, 28 Jul 2008 10:25:04 -0500

Mark Nottingham wrote:
> I think the right thing to do here is to describe both 
> variant selection (p3, section 5.1, p6, 16.5) and validator 
> comparison (p4 section 5) in terms of set theory (at least 
> informally), so that the set of representations available for 
> a given request is the intersection of those selected by 
> negotiation and those requested conditionally.
> 
> Make sense?

No, because content negotiation only effects the form of the response
entity, which isn't even a representation of the resource for most kinds of
request. In particular, you cannot use Accept-* headers to narrow the scope
of a PUT/POST/DELETE request to change only particular variants of the
resource, and the server continue to be free to ignore any or all request
header fields (Accept-* in particular) unless RFC 2616 specifically requires
them to not be ignored (e.g. If-* headers, sometimes Content-* headers).

A long time ago I listed some simple examples of how conditional requests
and content negotiation must interact for the most common case we have
today, namely Vary: Accept-Encoding. See
http://article.gmane.org/gmane.ietf.http-wg/795. I am really interested in
getting feedback from those examples.

Here is another example, where /some-image has two representations:
image/png (ETag: "png-1") and image/gif ("gif-1"):

PUT /some-image HTTP/1.1
Content-Type: image/png
If-Match: "gif-1"
Accept: text/html

The client downloaded the GIF variant previously but is uploading a PNG. As
far as content-negotiation is concerned, its only preference is that the
status message in the response entity should be in HTML if possible; the
Accept header isn't saying anything about the representations of the
resource. The only way the server can reasonable handle this request is by
considering the ETags of all representations of the resource when processing
the If-Match header field.

Regards,
Brian

---

From: Mark Nottingham <[email-masked]>
Date: Mon, 28 Jul 2008 16:56:24 +0100

On 28/02/2008, at 5:53 AM, Brian Smith wrote:

[ second representation corrected as per your later mail ]

>
> Consider a resource http://example.org/a with two representations,  
> where the server varies the representation based on Accept-Encoding:
>
> Last-Modified: Wed, 15 Nov 1995 06:00:00 GMT
> ETag: 1
> Content-Type: text/plain
> Vary: Accept-Encoding
>
> Last-Modified: Wed, 15 Nov 1995 12:00:00 GMT
> ETag: 2
> Content-Type: text/plain
> Content-Encoding: deflate
> Vary: Accept-Encoding
>
> Now, consider the following requests. What is the best status code,  
> and which entity (if any), ETag, and Last-Modified should be  
> returned for each request?
>
> (a) GET http://example.org/a HTTP/1.1
>    If-None-Match: 1
>    Accept-Encoding: deflate
>
>    HTTP/1.1 304 Not Modified
>    ETag: 2
>    Vary: Accept-Encoding

That's utterly confusing. The client asked to validate etag "1" and  
you told them that it wasn't modified, but returned an updated ETag  
and didn't say whether or not the entity is encoded.

13.3.4:
> An HTTP/1.1 origin server, upon receiving a conditional request that  
> includes both a Last-Modified date (e.g., in an If-Modified-Since or  
> If-Unmodified-Since header field) and one or more entity tags (e.g.,  
> in an If-Match, If-None-Match, or If-Range header field) as cache  
> validators, MUST NOT return a response status of 304 (Not Modified)  
> unless doing so is consistent with all of the conditional header  
> fields in the request.

> (b) GET http://example.org/a HTTP/1.1
>    If-None-Match: 1
>    Accept-Encoding: deflate;q=0
>
>    HTTP/1.1 304 Not Modified
>    ETag: 1
>    Vary: Accept-Encoding

See above.

> (c) GET http://example.org/a HTTP/1.1
>    If-None-Match: 2
>    Accept-Encoding: deflate
>
>    HTTP/1.1 304 Not Modified
>    ETag: 2
>    Vary: Accept-Encoding

OK

>
>
> (d) GET http://example.org/a HTTP/1.1
>    If-None-Match: 2
>    Accept-Encoding: deflate;q=0
>
>    HTTP/1.1 304 Not Modified
>    ETag: 1
>    Vary: Accept-Encoding

See above.

[ etc. ]

>
>
> (e) GET http://example.org/a HTTP/1.1
>    If-None-Match: nothing-matches-this
>    Accept-Encoding: deflate
>
>    HTTP/1.1 200 OK
>    ETag: 2
>    Vary: Accept-Encoding
>
>    (the response entity is variant 2)
>
> (f) GET http://example.org/a HTTP/1.1
>    If-None-Match: nothing-matches-this
>    Accept-Encoding: deflate;q=0
>
>    HTTP/1.1 200 OK
>    ETag: 2
>    Vary: Accept-Encoding
>
>    (the response entity is variant 1)
>
> Now, make the following substitutions:
>
> * replace: "If-None-Match: 1"
>  with:    "If-Unmodified-Since: Wed, 15 Nov 1995 06:00:00 GMT"
>
> * replace: "If-None-Match: 2"
>  with:    "If-Unmodified-Since: Wed, 15 Nov 1995 12:00:00 GMT"
>
> * replace: "If-None-Match: nothing-matches-this"
>  with:    "If-Unmodified-Since: Wed, 15 Nov 1995 00:00:00 GMT"
>
> What should the results be? I believe they should be exactly the  
> same as the ones I gave above, except (a) and (b) MAY return the  
> same results as (e) and (f), since one of the variants was modified  
> since the given time ("Wed, 15 Nov 1995 06:00:00 GMT").
>
> I think this demonstrates that If-[Un]modified-Since validation  
> needs to be changed to be more like the current ETag validation, and  
> not the other way around.
>
> - Brian
>
>

---

From: "Brian Smith" <[email-masked]>
Date: Mon, 28 Jul 2008 11:35:51 -0500

Mark Nottingham wrote:
> I don't agree that that's the only reasonable way to handle 
> the request; another would be to send a 412 -- i.e., send the 
> etag for the representation you're trying to upload.

I disagree. If the server returns a 412, I am going to issue the same
request that got me the GIF representation in the first place:
    GET /some-image HTTP/1.1
    
And the server is required to respond with the GIF unless it had returned
"Vary: *":
    HTTP/1.1 200 OK
    ETag: "gif-1"
    Content-Type: image/gif
    ...

No progress will have been made. It is unreasonable to expect the Accept-*
headers (if any) of some previous GET request to somehow be aligned with the
Content-* headers of a subsequent PUT request. It isn't obvious to me that
it is even possible to do so in every case.

> If we want to support the case that you're talking about, it 
> seems to me that we'd either need to:
> 
> a) Allow a cache to return a response which doesn't match 
> selecting headers. For example, if a cached response has:
> 
> Vary: Accept-Encoding ; request had 'gzip'
> ETag: "123"
> 
> and a request comes in with
> 
> Accept-Encoding: deflate
> If-None-Match: "123"

> the cache would be allowed to return it (doesn't make much sense), or

The cache has to forward the request on because the Accept-Encoding header
doesn't match and Accept-Encoding was listed in the Vary header. If the
origin server returns a 304 with an ETag: "123" then the cache can indeed
return a 304 with ETag: "123" just as the origin server would. If the client
request was not conditional, then it indeed could return the representation
with ETag: "123" even if the encoding doesn't match (the origin server chose
to ignore the Accept-Encoding header, so the cache can too). In the future,
the cache will be able to return the representation with ETag: "123"
whenever the Accept-Encoding header is "gzip" or "deflate", since that is
what the origin server does.

Cheers,
Brian

---

From: "Brian Smith" <[email-masked]>
Date: Mon, 28 Jul 2008 11:47:31 -0500

Mark Nottingham wrote:
> That's utterly confusing. The client asked to validate etag 
> "1" and you told them that it wasn't modified, but returned 
> an updated ETag and didn't say whether or not the entity is encoded.

I read section 10.3.5 as saying that the ETag returned must be the same one
as would be returned in a 200 response to the same request. It seems to me
that if a 200 response could return a different ETag then the 304 response
should also be able to.

The response doesn't say whether or not the entity is encoded because 10.3.5
says "the response SHOULD NOT include other entity-headers" or "the response
MUST NOT include other entity-headers" depending on whether a strong or weak
validator is being used.

The main point of the examples is to point out that "304 Not Modified" is an
appropriate response, even though a 200 response would have returned a
representation with a different ETag from the one supplied in the
conditional request header. Which ETag should be returned is a related, but
different issue.

> > unless doing so is consistent with all of the conditional header 

That doesn't apply here since none of my example requests mixed
last-modified dates and etags.

Cheers,
Brian

---

From: Mark Nottingham <[email-masked]>
Date: Mon, 28 Jul 2008 16:56:32 +0100

I don't agree that that's the only reasonable way to handle the  
request; another would be to send a 412 -- i.e., send the etag for the  
representation you're trying to upload.

If we want to support the case that you're talking about, it seems to  
me that we'd either need to:

a) Allow a cache to return a response which doesn't match selecting  
headers. For example, if a cached response has:

Accept-Encoding: deflate
If-None-Match: "123"

b) define the set of representations that conditional requests apply  
to on a per-method basis.

Neither of these options seems desirable to me, but I'd like to hear  
what others think.

This is somewhat related to both issues 22 and 69, btw.

---

From: Mark Nottingham <[email-masked]>
Date: Tue, 29 Jul 2008 08:11:10 +0100

14.26;

> given and any current entity exists for that resource, then the  
> server MUST NOT perform the requested method, unless required to do  
> so because the resource's modification date fails to match that  
> supplied in an If-Modified-Since header field in the request.  
> Instead, if the request method was GET or HEAD, the server SHOULD  
> respond with a 304 (Not Modified) response, including the cache-  
> related header fields (particularly ETag) of one of the entities  
> that matched. For all other request methods, the server MUST respond  
> with a status of 412 (Precondition Failed).
While this doesn't specifically preclude sending 304 if it doesn't  
match, the semantics of doing so aren't defined, and the intent seems  
pretty clear here.

---

From: "Brian Smith" <[email-masked]>
Date: Tue, 29 Jul 2008 12:51:47 -0500

Mark Nottingham wrote:
> > given and any current entity exists for that resource, then 
> > the server MUST NOT perform the requested method
> > unless required to do so because the resource's modification
> > date fails to match that supplied in an If-Modified-Since
> > header field in the request.
> >
> > related header fields (particularly ETag) of one of the 
> > entities that matched. For all other request methods, the server
> > MUST respond with a status of 412 (Precondition Failed).
> While this doesn't specifically preclude sending 304 if it 
> doesn't match, the semantics of doing so aren't defined, and 
> the intent seems pretty clear here.

This interpretation effectively requires implementations to use the same
Accept-* headers (more generally, whatever headers are listed in the Vary
header) for every request for each resource, across methods. For example, if
you put "Accept-Encoding: deflate" in GET requests to fetch resources, then
you need to include the same "Accept-Encoding: deflate" in all your
conditional editing requests (PUT, POST, and DELETE) on that resource
(assuming Vary: Accept-Encoding) in order to ensure that the conditional
request does what it is expected to do.

I don't understand why that restriction is useful and I don't think
conditional requests are universally implemented that way (especially for
editable resources behind mod_deflate-like filters). On the other hand, I am
sure that some servers *do* implement that restriction so my expectations
for how things should work universally are unrealistic. In other words, I
don't think that the specification can be changed to make the undefined case
well-defined, since any additional requirements are going to break existing
servers. 

By the way, does a 304 response mean that a particular variant has not been
modified, or the whole resource has not been modified? I've always assumed
304 Not Modified meant that the resource was unmodified--i.e. all variants
are unmodified. RFC 2616 says "the document has not been modified" but it
isn't clear to me whether "document" means "resource" or "variant."

Regards,
Brian

> > I read section 10.3.5 as saying that the ETag returned must be the 
> > same one as would be returned in a 200 response to the same 
> request. 
> > It seems to me that if a 200 response could return a different ETag 
> > then the 304 response should also be able to.
> >
> > The response doesn't say whether or not the entity is 
> encoded because 
> > 10.3.5 says "the response SHOULD NOT include other 
> entity-headers" or 
> > "the response MUST NOT include other entity-headers" depending on 
> > whether a strong or weak validator is being used.
> >
> > The main point of the examples is to point out that "304 
> Not Modified" 
> > is an appropriate response, even though a 200 response would have 
> > returned a representation with a different ETag from the 
> one supplied 
> > in the conditional request header. Which ETag should be 
> returned is a 
> > related, but different issue.
> >
> >> 13.3.4:

---

From: Henrik Nordstrom <[email-masked]>
Date: Thu, 31 Jul 2008 04:05:28 +0200

> the cache would be allowed to return it (doesn't make much sense), or

No it can't, unless the server says it's ok.

> to on a per-method basis.

Some methods apply to the URI, some to the requested variant. Nothing
strange with that. Conditions always apply on the requested variant.

Remember that HTTP is defined in such way that each resource variant
SHOULD (but not MUST) have an unique URL of it's own, as indicated by
Content-Location. If you want to DELETE just a specific language then
this is the URL you use in DELETE. 

For PUT it's less obvious, as how a PUT updates the server state is
implementation defined. But my reading is that for PUT to
content-negotiation enabled request-URI then the content headers
(Content-*) possibly define the resource variant to be stored and
negotiated headers (i.e. Accept-* as indicated by Vary) the variant to
match in conditionals used in the PUT request.

PUT /resource HTTP/1.0
If-Match: "a"
Accept-Language: en
Content-Language: sv

MAY stores the Swedish variant of the resource IF

* the english variant exists and has etag "a"
* content-negotiation is enabled on the resource

The response to the PUT request then carries a ETag for the created
variant, and unique Content-Location, and Vary indicating the axis of
variance on the resource.

If content negotiation is not enabled for the request-URI then the PUT
simply replaces any existing resource (and all variants) at the request
URI. Many servers may well have this as the only implementation
requiring PUT on specific variant unique URLs to create or update
negotiated resources, and the structure of those is implementation
dependent and not specified in HTTP/1.1. 

Servers MAY also use 307 to the to be created variants unique URL if
seeing a PUT to a negotiated URL. But it's then not possible to build
conditions across variants as above. For many implementations this is
perhaps the cleaner approach.

Regards
Henrik

---

From: Henrik Nordstrom <[email-masked]>
Date: Thu, 31 Jul 2008 04:08:41 +0200

> what the origin server does.

Or more accurately claims it does... Many broken servers our there not
getting this right.

But the specs is quite clear on this. Just a bit spread out over a long
document before the reorganisation.

Regards
Henrik

---

From: Henrik Nordstrom <[email-masked]>
Date: Thu, 31 Jul 2008 04:48:19 +0200

> isn't clear to me whether "document" means "resource" or "variant."

Variant.

The variants may change individually.

And it's also the means by which caches can find which variant is the
right for this request.

Consider a for example a negotiated resource /object having
Accept-Language netotiated variants /object.sv and /object.en.
content-negotiation based on Accept-Language selects at most one of
these, and each carries their own ETag. Conditionals is towards the
requested variant, not "any" variant.

Regards
Henrik

---

From: Henrik Nordstrom <[email-masked]>
Date: Thu, 31 Jul 2008 05:23:07 +0200

> intersection of those selected by negotiation and those requested  

Selection perhaps, as you there usually start out with a set of resource
variants and this then gets narrowed down by content-negotiation. (but
it doesn't need to be an existing set, may well be dynamically generated
in terms of auto translation/transformation etc.. implementation detail)

But using set theory on conditionals probably gets too confusing, at
least if we are talking about If(-None)-Match where the condition
applies to the SINGLE selected representation after content negotiation
has done it's play.

The two is a bit opposite of each other when thinking of sets. In
negotiation the "set" is on the server side, while in conditions the
"set" is on the requesting site. There never is a set operation on both
sides.

Regards
Henrik

---

From: "Brian Smith" <[email-masked]>
Date: Thu, 31 Jul 2008 08:24:31 -0500

Henrik Nordstrom wrote:
> Remember that HTTP is defined in such way that each resource 
> variant SHOULD (but not MUST) have an unique URL of it's own, 
> as indicated by Content-Location. If you want to DELETE just 
> a specific language then this is the URL you use in DELETE. 

In a thread earlier this year, we basically came to the conclusion that
Content-Location is generally useless for anything except cache invalidation
due to the possibility of spoofing.

> For PUT it's less obvious, as how a PUT updates the server 
> state is implementation defined. But my reading is that for 
> PUT to content-negotiation enabled request-URI then the 
> content headers (Content-*) possibly define the resource
> variant to be stored and negotiated headers (i.e.
> Accept-* as indicated by Vary) the variant to match in
> conditionals used in the PUT request.

Where do you get that? Content-* describe the request entity, Accept-*
describe the preferred form of the response entity. Any use of those fields
for other purposes--especially addressing individual variants--is giving
these fields a meaning they are not defined to have.

PUT is defined in terms of editing resources, not editing variants of
resources. Unless my request has a header that indicates some extension to
HTTP is wanted, I expect any PUT to a resource URI to replace all the
variants for that resource. I don't see how any other reading of the
definition of PUT makes sense. Similarly, DELETE is defined as a request to
"delete the resource identified by the Request-URI," not to delete some
subset of its variants.

Further, PUT and DELETE invalidate all cached entities for the Request-URI,
regardless of any other header field value. It wouldn't make sense to
require that unless the server is allowed to modify any or all variants of a
resource based solely on the Request-URI.

> * content-negotiation is enabled on the resource

Yes, but not "if and only if." I think it makes sense to say that clients
should send the same request headers (as much as possible) in a conditional
POST/PUT/DELETE request that they sent in the GET request that retrieved the
validators, in order to avoid 412 responses from servers that do selection
before they evaluate conditionals. However, the evaluation of the
conditionals is different than deciding which variants are to be edited. 

> The response to the PUT request then carries a ETag for the 
> created variant, and unique Content-Location, and Vary 
> indicating the axis of variance on the resource.

Where is the meaning of Vary on a PUT response defined? As far as I can tell
it is meaningless. Plus, a resource can have more than one applicable "axis
of variance" as (Resource-URI -> Vary) is not a function, as you said in the
other thread.

> If content negotiation is not enabled for the request-URI 
> then the PUT simply replaces any existing resource (and all 
> variants) at the request URI.

There is no need to qualify it with "If content negotiation is not enabled."
The server should replace and/or regenerate all the variants at the request
URI unless the request indicates otherwise. RFC 2616 doesn't define any
mechanism for the client to indicate that only a particular variant should
be edited. RFC 3253 does have the "Label" request header field to address a
particular variant. 

> Many servers may well have this 
> as the only implementation requiring PUT on specific variant 
> unique URLs to create or update negotiated resources, and the 
> structure of those is implementation dependent and not 
> specified in HTTP/1.1. 

That part I agree on. More generally, HTTP/1.1 doesn't provide any mechanism
for editing a specific variant of a resource; it only provides mechanisms
for editing resources in their entirety.

> Servers MAY also use 307 to the to be created variants unique 
> URL if seeing a PUT to a negotiated URL. But it's then not 
> possible to build conditions across variants as above. For 
> many implementations this is perhaps the cleaner approach.

I don't know what you mean by "it's then not possible to build conditions
across variants."

Regards,
Brian

---

From: Henrik Nordstrom <[email-masked]>
Date: Thu, 31 Jul 2008 17:22:46 +0200

> due to the possibility of spoofing.

I disagree.

You can't cache content across Request-URI and Content-Location as being
authorative for the Content-Location URI, but it's fine to use the
Content-Location URI for updates and other modifications to the
resource.

The specs is imho quite fine on when Content-Location can or should be
used. Possibly with the exception for defining the base URI, which is
fine in theory but not implemented by anyone.

> these fields a meaning they are not defined to have.

PUT carries entity headers. Content-* headers is valid request headers
in a PUT request, and describes the properties of the entity carried
within the request.

> validators

Yes, ofcourse. Sorry for not making that clear, thought it was obvious..

> However, the evaluation of the

Yes, which was my point.

> it is meaningless.

Not entirely. The PUT response do carry meta headers for the created
resource. But yes, probably...

> Plus, a resource can have more than one applicable "axis

Indeed. But more importantly I already demonstrated that the selectors
in the PUT request has nothing to do with the created resource..

> be edited.

RFC2616 doesn't define how a PUT affects the server state at all. But it
is implicitly assumed you never do PUT to negotiated resources and only
non-negotiated resources and that the request entity is normally stored
as-is. The effects of content negotiation on PUT requests is not
explored at all in the spec, except for Content-Location indicating the
actual resource URI of the created/modified resource.

> I don't know what you mean by "it's then not possible to build conditions

The example I gave earlier where PUT of a swedish variant is dependent
on the validator for the english variant.

Regards
Henrik

---

From: "Brian Smith" <[email-masked]>
Date: Thu, 31 Jul 2008 12:14:14 -0500

Henrik Nordstrom wrote:
> > In a thread earlier this year, we basically came to the conclusion 
> > that Content-Location is generally useless for anything 
> > except cache invalidation due to the possibility of spoofing.
> 
> I disagree.
> 
> You can't cache content across Request-URI and 
> Content-Location as being authorative for the 
> Content-Location URI, but it's fine to use the 
> Content-Location URI for updates and other modifications to 
> the resource.

I assume by "the resource" you mean the resource at the original request
URI, not the resource at the Content-Location URI. HTTP provides no
assurances that there is any useful relationship between the original
request URI and the resource referenced in the Content-Location URI. For
example:

   GET http://example.org/foo.html HTTP/1.1
   ...

   HTTP/1.1 200 OK
   Content-Location: http://example.com/foo.html

RFC 2616 doesn't say that the client may delete any of the variants of
http://example.org/foo.html by sending a DELETE request to
http://example.com/foo.html. Doing so requires a leap of faith that is not
supported or encouraged by the specification. A protocol for that would be
an extension to HTTP. In any case, there may be more than one variant of the
resource at the Content-Location URI, so Content-Location doesn't even
address a specific variant of *any* resource. 

> RFC2616 doesn't define how a PUT affects the server state at 
> all. But it is implicitly assumed you never do PUT to 
> negotiated resources and only non-negotiated resources and 
> that the request entity is normally stored as-is. The effects 
> of content negotiation on PUT requests is not explored at all 
> in the spec, except for Content-Location indicating the 

It is unrealistic to assume that we never PUT to negotiated resources
because many (on some servers, all) resources are negotiated as  "Vary:
Accept-Encoding" at least. To refuse to define what happens when one
requests a PUT (or DELETE) on content-negotiated resources effectively makes
PUT and DELETE undefined for extremely common uses. If a server changes (or
deletes) the uncompressed variant of the resource upon a PUT (or delete) but
leaves the compressed variant as-is, then I would say that server is
definitely wrong, unless there is some explicit indicator in the request
that says that only some specific variants are to be modified. But, HTTP
doesn't provide any such indicator.

Regards,
Brian

---

From: Henrik Nordstrom <[email-masked]>
Date: Thu, 31 Jul 2008 22:13:12 +0200

On tor, 2008-07-31 at 12:14 -0500, Brian Smith wrote:

> URI, not the resource at the Content-Location URI.

Content-Location IS the specific URI to this resource. Or if you like
the non-negotiated direct access URI to a specific variant of a
resource.

> http://example.com/foo.html.

To me it's exacly what it says. Quote from p3 6.7 Content-Location:

   The Content-Location value is not a replacement for the original
   requested URI; it is only a statement of the location of the resource
   corresponding to this particular entity at the time of the request.

   Future requests MAY specify the Content-Location URI as the request-
   URI if the desire is to identify the source of that particular
   entity.

> address a specific variant of *any* resource. 

No. The Content-Location URI is not supposed to be a negotiated
resource. If it is then the server implementation is wrong.

If the server can not provide unique URIs to each variant then no
Content-Location should be returned.

> Accept-Encoding" at least.

Indeed. The catch is that implementations of dynamic content-encoding
hasn't really followed the entity variant model of HTTP that well.. so
the Content-Location model fails for such setups. And clients have to
work around it by not using Accept-Encoding if they want to be able to
update the resource.

> To refuse to define what happens when one
> PUT and DELETE undefined for extremely common uses.

Not really.

> If a server changes (or

Try it and you will find it's exacly what servers using separate storage
for both the compressed and identity encoded variants is doing. But in
such setups you often MUST use the Content-Location URIs on updates or
negotiation will get disabled for the resource.

If you think of Content-Language then it makes more sense.

 Content-Encoding is a bit of a special case here and not a good
Content-* header to base any reasoning on, especially not considering
how it's most commonly implemented..

Regards
Henrik

---

From: "Brian Smith" <[email-masked]>
Date: Thu, 31 Jul 2008 17:37:16 -0500

Henrik Nordstrom wrote:
> > I assume by "the resource" you mean the resource at the original 
> > request URI, not the resource at the Content-Location URI.
> 
> Content-Location IS the specific URI to this resource. Or if 
> you like the non-negotiated direct access URI to a specific 
> variant of a resource.

>    requested URI; it is only a statement of the location of 
>    the resource corresponding to this particular entity at the
>    time of the request.

example.org says that the entity that it is returning in the response is
available at the time of the request at http://example.com/foo.html, which
is not even the same domain. RFC 2616 doesn't say that must be a true
statement; in fact, in another part the specification makes it quite clear
that we shouldn't make any such assumptions.

>    Future requests MAY specify the Content-Location URI as 
>    the request-URI if the desire is to identify the source
>    of that particular entity.

That *doesn't* say that editing the resource at the Content-Location URI
will have any effect on any variant of the resource identified by the
original request URI. 

> > an extension to HTTP. In any case, there may be more than 
> > one variant of the resource at the Content-Location URI,
> > so Content-Location doesn't even address a specific
> > variant of *any* resource.
> 
> No. The Content-Location URI is not supposed to be a 
> negotiated resource. If it is then the server implementation is wrong.

The specification doesn't say that anywhere, although I agree that some of
the wording kind of hints to it. In practice protocols like AtomPub that
place extra meaning when Location=Content-Location mean that
Content-Location will often reference a content-negotiated resource (again,
because of Vary: Accept-Encoding) which is beyond the application's control
(again, because of things like encoding proxies or mod_deflate).

> If the server can not provide unique URIs to each variant 
> then no Content-Location should be returned.

The specification says only the converse of that:
   
   A server SHOULD provide a Content-Location for the
   variant corresponding to the response entity; especially in
   the case where a resource has multiple entities associated
   with it, and those entities actually have separate locations
   by which they might be individually accessed, the server
   SHOULD provide a Content-Location for the particular
   variant which is returned.

In particular, the specification never says that the server SHOULD NOT or
MUST NOT provide a Content-Location header when the predicate is false.
AtomPub and other similar servers will often return a Content-Location
header that doesn't uniquely identify a variant as I mentioned above.

> > It is unrealistic to assume that we never PUT to negotiated 
> > resources because many (on some servers, all) resources are 
> > negotiated as  "Vary: Accept-Encoding" at least.
> 
> Indeed. The catch is that implementations of dynamic 
> content-encoding hasn't really followed the entity variant 
> model of HTTP that well.. so the Content-Location model fails 
> for such setups. And clients have to work around it by not 
> using Accept-Encoding if they want to be able to update the
> resource.

The Content-Location model fails because it requires a trust model that HTTP
leaves undefined.

> > If a server changes (or
> > deletes) the uncompressed variant of the resource upon a PUT
> > (or delete) but leaves the compressed variant as-is, then I 
> > would say that server is definitely wrong, unless there is
> > some explicit indicator in the request that says that only
> > some specific variants are to be modified. But, HTTP doesn't
> > provide any such indicator.
> 
> Try it and you will find it's exacly what servers using 
> separate storage for both the compressed and identity encoded 
> variants is doing. But in such setups you often MUST use the 
> Content-Location URIs on updates or negotiation will get 
> disabled for the resource.

Negotiation getting disabled is acceptable even if it is sub-optimal.
Continuing to serve an old variant alongside a new one is not okay. 

> If you think of Content-Language then it makes more sense.

I disagree. If the goal is to edit each language variant independently, then
you need some mechanism to identify the individual variants as separate
resources. HTTP itself doesn't define any mechanism for doing that; you need
some extension. That extension might be an extension that simply says
"Editing the resource at the Content-Location returned for X variant of
resource Y will update that variant of resource Y" and with a trust model
added. But, it is not something that exists in HTTP now.

> Content-* header to base any reasoning on, especially not 
> considering how it's most commonly implemented..

Again, I disagree. The specification doesn't give any special treatment to
Content-Encoding. I understand where you are coming from, but I don't think
anybody here wants to define a whole set of rules for Content-Encoding
separate from every other entity header. (Right?) That is why I use
Content-Encoding instead of Content-Language in all my examples. It is the
most common case by far. It is also the one that causes the most problems
when one tries to define a mechanism for editing individual variants,
because any mechanism that doesn't allow the server to keep the unencoded
and encoded variants in sync by default can be shown to be obviously
defective.

But, it is easy to show that the same holds for Content-Type too. Let's say
I have a resource http://example.org/my-girlfriend with image/png and
image/jpeg variants, and I issue this request:

PUT /my-girlfriend HTTP/1.1
Content-Type: image/jpeg
Accept: image/jpeg
...

It would be very surprising for the server to return a picture of my old
girlfriend for this request:

   GET /my-girlfriend HTTP/1.1

while simultaneously returning a picture of my new girlfriend for this
request:

   GET /my-girlfriend HTTP/1.1
   Accept: image/jpeg

That is why I am so strongly advocating a requirement that PUT and DELETE
requests on a resource should operate on all variants of the resource by
default, unless the request somehow explicitly indicates otherwise. At the
very least, servers must be *allowed* to operate that way, if they are not
*required* to do so.

Also, keep in mind that there is no requirement for the server to return a
Vary header field on a negotiated response unless the response is cacheable.
Thus, the client generally has no way of knowing what resources are even
content-negotiated.

Regards,
Brian