CORS restrictions on preflight (too) strict?

Dear all,

I recently had a rather troublesome experience
getting CORS to work with the Memento framework.
I've filed it as an issue [0] with the newer Fetch standard,
but wanted to document it here as well.

Memento (RFC7089) [1] provides additional HTTP headers
to perform time-based content negotiation. Concretely:
– client requests indicate their preference with Accept-Datetime
– server responses indicate the timestamp with Memento-Datetime
Negotiation can be performed in two ways [1]:
– the server redirects to the negotiated representation with 302
– the server serves the negotiated representation with 200
  (using Content-Location to indicate its URL)
For various reasons, 302-style negotiation is preferred.

In contrast to regular content type and language negotiation,
however, it is impossible to make time-based content negotiation
work in the browser cross-origin with 302-style negotiation.
This is because the CORS spec [2] requires that
requests with non-simple headers [3] (such as Accept-Datetime)
are preceded by a preflight OPTIONS request
asking the server permission to use such headers.
Moreover, in cases that need such a preflight request,
30x responses from the server are not accepted.

In other words: if the client wants to negotiate cross-origin
on content type and language, 302 is allowed.
If the client wants to negotiate cross-origin on time,
302 is not allowed and 200 is needed
(which is not appropriate in several use cases).


With regard to this problem, I have two questions:

1) Could it be a considered, in a later version of CORS,
    to mark Accept-* headers safe on requests?
    After all, no harm can be done with such headers
    (not more than with Accept or Accept-Language),
    so requiring preflight is not necessary.

2) Instead of blocking redirects after preflights altogether,
    could it be considered to either:
    a) send a second preflight request to the redirected resource?
    b) allow the preflight OPTIONS response to redirect?
    (I'd prefer a, but b saves a request.)

The practical discussion of such a use case can be found here [4],
together with a live demo [5] that uses a preflight performance hack [6].
A related discussion was held here [7].

Best regards,

Ruben
-- 
Ruben Verborgh
Postdoctoral Researcher in Semantic Hypermedia
Ghent University – iMinds – Data Science Lab
http://ruben.verborgh.org/ – @RubenVerborgh


[0] https://github.com/whatwg/fetch/issues/326
[1] https://tools.ietf.org/html/rfc7089
[2] https://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0
[3] https://www.w3.org/TR/cors/#simple-header
[4] http://ruben.verborgh.org/blog/2016/06/22/querying-history-with-linked-data/
[5] http://bit.ly/artists-york-2012
[6] https://github.com/LinkedDataFragments/Client.js/commit/a0438531bbfcbd36aec04c73ab16e8d0279f3ef1
[7] https://lists.w3.org/Archives/Public/public-webappsec/2016Jan/0119.html

Received on Wednesday, 22 June 2016 20:58:38 UTC