RejectedSoftware Forums

Sign up

Adding CORS to vibe.web.rest

In another post I have volunteered to implement CORS support for the RestInterface.

Here follows the specification that I pieced together from the W3.

Simple method

A method is said to be a simple method if it is a case-sensitive match for one of the following:

GET
HEAD
POST

Simple Request Header

A header is said to be a simple header if the header field name is an ASCII case-insensitive match for Accept, Accept-Language, or Content-Language or if it is an ASCII case-insensitive match for Content-Type and the header field value media type (excluding parameters) is an ASCII case-insensitive match for application/x-www-form-urlencoded, multipart/form-data, or text/plain.

Simple Response Header

A header is said to be a simple response header if the header field name is an ASCII case-insensitive match for one of the following:

Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma

Simple Cross-Origin Request, Actual Request, and Redirects

In response to a simple cross-origin request or actual request the resource indicates whether or not to share the response.

  1. If the Origin header is not present terminate this set of steps. The request is outside the scope of this specification.

  2. If the value of the Origin header is not a case-sensitive match for any of the values in list of origins, do not set any additional headers and terminate this set of steps.

    Always matching is acceptable since the list of origins can be unbounded.

  3. If the resource supports credentials add a single Access-Control-Allow-Origin header, with the value of the Origin header as value, and add a single Access-Control-Allow-Credentials header with the case-sensitive string "true" as value.

    Otherwise, add a single Access-Control-Allow-Origin header, with either the value of the Origin header or the string "*" as value.

    The string "*" cannot be used for a resource that supports credentials.

  4. If the list of exposed headers is not empty add one or more Access-Control-Expose-Headers headers, with as values the header field names given in the list of exposed headers.

    By not adding the appropriate headers resource can also clear the preflight result cache of all entries where origin is a case-sensitive match for the value of the Origin header and url is a case-sensitive match for the URL of the resource.

Preflight Request

In response to a preflight request the resource indicates which methods and headers (other than simple methods and simple headers) it is willing to handle and whether it supports credentials.

  1. If the Origin header is not present terminate this set of steps. The request is outside the scope of this specification.

  2. If the value of the Origin header is not a case-sensitive match for any of the values in list of origins do not set any additional headers and terminate this set of steps.

    Always matching is acceptable since the list of origins can be unbounded.

    The Origin header can only contain a single origin as the user agent will not follow redirects.

  3. Let method be the value as result of parsing the Access-Control-Request-Method header.

    If there is no Access-Control-Request-Method header or if parsing failed, do not set any additional headers and terminate this set of steps. The request is outside the scope of this specification.

  4. Let header field-names be the values as result of parsing the Access-Control-Request-Headers headers.

    If there are no Access-Control-Request-Headers headers let header field-names be the empty list.

    If parsing failed do not set any additional headers and terminate this set of steps. The request is outside the scope of this specification.

  5. If method is not a case-sensitive match for any of the values in list of methods do not set any additional headers and terminate this set of steps.

    Always matching is acceptable since the list of methods can be unbounded.

  6. If any of the header field-names is not a ASCII case-insensitive match for any of the values in list of headers do not set any additional headers and terminate this set of steps.

    Always matching is acceptable since the list of headers can be unbounded.

  7. If the resource supports credentials add a single Access-Control-Allow-Origin header, with the value of the Origin header as value, and add a single Access-Control-Allow-Credentials header with the case-sensitive string "true" as value.

    Otherwise, add a single Access-Control-Allow-Origin header, with either the value of the Origin header or the string "*" as value.

    The string "*" cannot be used for a resource that supports credentials.

  8. Optionally add a single Access-Control-Max-Age header with as value the amount of seconds the user agent is allowed to cache the result of the request.

  9. If method is a simple method this step may be skipped.

    Add one or more Access-Control-Allow-Methods headers consisting of (a subset of) the list of methods.

    If a method is a simple method it does not need to be listed, but this is not prohibited.

    Since the list of methods can be unbounded, simply returning the method indicated by Access-Control-Request-Method (if supported) can be enough.

  10. If each of the header field-names is a simple header and none is Content-Type, this step may be skipped.

    Add one or more Access-Control-Allow-Headers headers consisting of (a subset of) the list of headers.

    If a header field name is a simple header and is not Content-Type, it is not required to be listed. Content-Type is to be listed as only a subset of its values makes it qualify as simple header.

    Since the list of headers can be unbounded, simply returning supported headers from Access-Control-Allow-Headers can be enough.

Re: Adding CORS to vibe.web.rest

Extracting all the moving parts from the above I get to the following variables:

Global Variables:

  • The list of allowed origins

Variables Per Resource:

  • whether the resource supports credentials. Which are cookies, HTTP authentication, or client-side SSL certificates.
  • a list of exposed headers (simple headers are always exposed)
  • an optional max-age in delta-seconds (could also be a global setting)
  • an list of allowed headers (simple headers are always allowed) (this we can derive from the headers that were deduced in the RestInterface for a given resource)

This is a very thorough list, and most implementation/people don't really care about most of it. They just want it to work.

I am just wondering how much a CORS implementation needs to support.

Out-of-the-box it should Just Work.

Anyway, what are your ideas?