Re: [cors] Redirects

Hi Anne,

Sorry, I think I was unclear in my email. Most of the questions that
are still unclear to me is how the HTTP spec intends requests to work.
I.e. not what the CORS spec say that UAs should do for CORS requests,
but what HTTP says should be done for various requests on a protocol
level. This specifically was the case for the A-D questions.

I think this is important since we should in general try to follow the
letter and spirit of the HTTP spec.

On Thu, Apr 23, 2009 at 1:54 AM, Anne van Kesteren <annevk@opera.com> wrote:
> On Thu, 23 Apr 2009 02:06:41 +0200, Jonas Sicking <jonas@sicking.cc> wrote:
>>
>> So there are a few design decisions we need to make:
>>
>> Should we treat a redirect of a preflight request, as redirecting the
>> actual request? The answer to this may depend on which type of
>> redirect it is.
>>
>> What does a 303 redirect of a preflight request even mean. According
>> to the letter of the spec you should make a GET request, but it seems
>> weird to use GET request to result in a response that contains
>> descriptions of capabilities.
>
> According to the letter of the latest editor's draft this results in a
> network error.

Here I was referring to the HTTP spec. OPTIONS requests are intended
to get the capabilities for a given URI. A 303 means that you should
issue a GET request to another URI to get the response for the given
URI. Does this mean that you are expected to get a capabilities
response from a GET request? This seems strange to me.

>> What level of redirects do we want to support:
>> 1. Fail on all redirects.
>> 2. Fail all redirects when doing preflighted requests. Both for
>> preflight and actual request alike.
>> 3. Only allow redirects of the request if the redirected request is
>> 'safe' (i.e. would not require a preflight).
>> 4. Allow all redirects of the actual request.
>
> I want to support redirects on simple requests (as is already done for e.g.
> <img> and <form>) and preflight requests, but not on actual requests. This
> is what the specification specifies and I believe this is what WebKit
> implements.

I think the spec currently assumes some things about HTTP which I
don't think are correct assumptions. More details below.

>> For the first two questions I think we should try to consult the HTTP
>> spec. As I understand HTTP, the following things are true:
>>
>> * A 303 should be considered redirecting the response.
>
> I believe 303 originally was a way to change the request method but that has
> been changed because of the obvious security flaws so now it always changes
> to GET.

This is not my reading of the http 1.1 spec. It says:

# The response to the request can be found under a different URI and
# SHOULD be retrieved using a GET method on that resource. This method
# exists primarily to allow the output of a POST-activated script to
# redirect the user agent to a selected resource.

It further says about 302 redirects:

# However, most
# existing user agent implementations treat 302 as if it were a 303
# response, performing a GET on the Location field-value regardless
# of the original request method. The status codes 303 and 307 have
# been added for servers that wish to make unambiguously clear which
# kind of reaction is expected of the client.

So my understanding is that 303 unambiguously means that action has
been taken for the current request, but that the resource returned
should be fetched from another URI. Fetching resources is done using
GET, thus a new GET request is created.

>> * A 307 should be considered redirecting the request and the response.
>> * UAs should treat 302 as either a 303 or 307. Ideally which one
>> should be decided by the user, but many UAs simply choose one or the
>> other.
>> * UAs are allowed to treat 301 as 302.
>
> You're not correct about HTTP allowing what you say about 301 and 302 as far
> as I can tell, but I agree that it is what user agents do. (And I believe
> the HTTP WG has an open issue on the matter.)

Yeah, upon reading this again it does indeed seem like the HTTP 1.1
spec says that 302 should be treated as 307, while acknowledging that
UAs often treat it as 303.

>> What I don't know is:
>>
>> A) How is 301 different from 302. For example can the UA cache the
>> fact that a redirect is occuring in addition to treating it as a 302?
>
> Yes.

Where does it say this in the HTTP spec? And what does this mean for a
POST or DELETE request?

>> B) If you get a 303 response from a OPTIONS request, are you allowed
>> to make an OPTIONS request to the redirected URI. Would it make sense
>> to?
>
> This is not allowed by CORS.

My question was in the context of what the HTTP spec says.

Why does the CORS spec treat 303 different from 302 and 301 here?
Please note that I only use 303 in my examples as its behavior is much
less ambigious than 302 in my reading of the spec. 302 has the problem
of the spec saying one thing, but real world requiring something else,
so I try to stay away from it for the purposes of discussing how we
should treat redirects. Ultimately I don't see any reason to treat 301
or 302 any different from 303, other than possibly allowing some extra
caching for 301.

>> C) If the answer is 'no' to the question above, if you make an OPTIONS
>> request to uri X, which 303 redirects to uri Y. Should the UA then
>> make a GET request to uri Y and assume that the response to that
>> describes the capabilities of Y? In other words, does a 303 response
>> to an OPTIONS request basically mean "The resource at Y describes my
>> capabilities"?
>
> It doesn't matter, the redirect is prohibited.

Again, the question was asked in the context of what HTTP says.

CORS currently answer 'yes' to question B, so question C doesn't apply.

>> D) If you get a 307 response from an OPTIONS request to a URI, does it
>> make sense to assume that a 307 would be returned for other methods,
>> such as a POST, DELETE or XMYMETHOD request?
>
> I don't understand this question. If you follow the 307 (only possible if it
> opts in itself) the final URI still has to say whether it allows
> POST/DELETE/XMYMETHOD.

(sorry to repeat myself) This question was intended as what does the
HTTP spec say on the matter.

The CORS spec currently assumes two things:

* If a CGI handling requests to URI X receives a OPTIONS request and
307 redirects it to URI Y, it will also do the same for a DELETE
request to URI Y and 307 redirect it to URI Y.
* It also assumes that the DELETE request will have no side effects.
I.e. it assumes that the CGI will take no action upon receiving the
DELETE request other than returning the 307 response.

Are this a valid assumption according to HTTP spec? My gut feeling is
that they are not, at least not the first bullet.

A CGI that returns a 307 for a OPTIONS request, but not for a DELETE
request would behave differently for a XMLHttpRequest from same-origin
than for different-origin. This seems like a bad thing to me, unless
such a CGI request is violating the letter or spirit of the HTTP spec,
in which case I think it is ok to blame the CGI author.

>> Without knowing the answers to these questions I am uncertain what the
>> correct design is for redirects of preflighted requests.
>>
>> I think we can choose whichever level of redirect support we want in
>> this version of the spec, without limiting ourselves for future
>> versions. So my gut instinct right now if we just want to get the spec
>> out the door is to go with level 2 as that is the simplest to spec
>> while still keeping support for redirects for the most common cases.
>>
>> If we want level 3 or 4 I really think we first need to answer the
>> questions A-D.
>
> We have discussed redirects many times and the specification has been stable
> on them (apart from the minor change to preflight requests) for a long time.
> WebKit has implemented them as well now. I don't really see the problem.

The problems that I see in the spec currently are:

1. It treats 301/302 redirects as 307 redirects. This is good
according to the HTTP spec, however it goes against how UAs handle 302
redirects everywhere else. IMHO we should treat 301/302 as 303 (with
the exception of caching) since that is what UAs normally do.
2. It assumes that a 307 response to an OPTIONS request also means
that the server will respond with a 307 response to a
DELETE/POST/XMYMETHOD request. It also assumes that it'll *just*
respond with that and take no other actions.
3. It treats a 303 response to an actual request as an error. If we
support any form of redirects I think this is the most obvious and
simple one to support. A 303 response to a POST means that the POST
has been processed and that the result can be fetched at a different
URI. This is probably the most common type of redirects that we'll run
into when it comes to preflighted requests since this is the proper
way to deal with responses to POST requests. It's also one we can do
safely assuming no custom headers have been added.

So my suggested actions are as follows:

Either make all redirects of the preflight request an error, or get
review from the IETF or someone that knows HTTP better to make sure
that our treatment of them are correct (specifically the answers to
questions B-D with regards to the HTTP spec). It is clear to me that
no one with sufficient knowledge of HTTP has reviewed the spec
currently.

Either add support for 303 (and thus 301/302) redirects of the
response to the actual request when the list of custom headers is
empty, or drop support for all redirects when making non-simple
requests.

/ Jonas

Received on Thursday, 23 April 2009 10:36:22 UTC