8.2.10. Cross Origin Resource Sharing

The ‘same origin policy’ implies that a script is allowed to request resources just from the same domain it itself is served (see: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). The PDR is served from https://mycontexts.com. This would imply that the PDR could only request models (and other resources) from that same domain. It would preclude the repositories at arbitrary locations as described in this document.

However, a server may be configured such that it sends CORS headers. Couchdb supports such configuration. Part of that configuration is to declare a set of origin domains. In our case, that would be https://mycontexts.com.

Every hosting party that supplies a Couchdb server for repositories, should therefore configure CORS in the same way. As a consequence, PDR sources, served from https://mycontexts.com, are allowed to see resources served from such servers.

8.2.10.1. HTTPS and certificates

All domains should be approached using the https scheme. This holds for domains that redirect, too. So, in our example, the server that redirects from joopringelberg.nl should have a certificate for that domain.

8.2.10.2. Redirection: problematic

In paragraph Storage service providers we suggest that if a domain is hosted by party A, while the repository where models in that domain are stored is hosted by party B on another domain, party A redirects requests to party B’s domain. However, CORS does not always allow this (see: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSExternalRedirectNotAllowed).

This holds especially for so called ‘pre-flight requests’ (made with the OPTION verb). From MDN:

Not all browsers currently support following redirects after a preflighted request. (…​) The CORS protocol originally required that behavior but was subsequently changed to no longer require it. However, not all browsers have implemented the change, and thus still exhibit the originally required behavior (https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests).

In contrast, redirect is always allowed on simple requests. The PDR requests models in a way that seems to satisfy the criteria for such simple requests, excepting that the content-type header is application/json (which is not allowed). Nevertheless, in Chrome (version 100.0.4896.88) no pre-flight request seems to be done.

The redirecting party should implement CORS for mycontexts.com, too.

We implement the PDR on the assumption that browsers allow redirection on our CORS requests.

An example redirection directive for Apache, for example to be used in the configuration file for VirtualHost joopringelberg.nl, where the actual hosting is done on the address perspectives.domains:

RedirectMatch permanent "^/models(.*)$" https://perspectives.domains/models$1

A similar effect (but without redirect HTTP status code) can be achieved by a reverse proxy:

ProxyPassMatch "^/models(.*)$" https://perspectives.domains/models$1
Observations

On the local version of perspectives.domains, we observe that

  • the redirection fails because of the preflight problem with CORS (The preflight request cannot be observed in Chrome);

  • the reverse proxy works, but only if the database is public (i.e. if no members or admins are defined.

Obviously, the PDR does not send credentials for the reverse proxy (mycontexts.com) with the request for the domain (perspectives.domains). So, while the reverse proxy works, no credentials are sent along with it.

While retrieving models without credentials might be ok, uploading models certainly needs credentials. This is a problem to be solved.

8.2.10.3. Rewriting

Instead of redirecting or proxying, we may rewrite an url. Continuing the example above for VirtualHost joopringelberg.nl:

  RewriteEngine On
  RewriteCond %{REQUEST_URI} ^/models(.*)$
  RewriteRule ^(/.*)$  https://perspectives.domains/$1  [R=204]

A url of the form https://joopringelberg.nl/models_joopringelberg_nl will now be rewritten to https://perspectives.domains/models_joopringelberg_nl, while other URLs in the same domain would be left untouched.

Now it turns out that Couchdb does not handle OPTIONS requests or at least not in the way we need it. Therefore, we handle all preflight requests here. We redirect an OPTIONS request to the default index.html, while stipulating that the response has the 204 (no content) code. We also add all the required headers and make sure that there are no doubles by first removing any existing values.

  RewriteCond %{REQUEST_METHOD} ^(OPTIONS)$
  RewriteCond %{REQUEST_URI} ^/models.*$
  RewriteRule ^/.*$  index.html  [R=204]

  Header unset Access-Control-Allow-Credentials
  Header unset Access-Control-Allow-Methods
  Header unset Access-Control-Allow-Origin
  Header unset Access-Control-Allow-Headers

  Header always set Access-Control-Allow-Credentials "true"
  Header always set Access-Control-Allow-Methods "GET, PUT, POST, DELETE, OPTIONS"
  Header always set Access-Control-Allow-Origin https://mycontexts.com
  Header always set Access-Control-Allow-Headers "content-type"

This code rewrites an url with the OPTIONS verb, when its path starts with "models". Notice that we allow the origin https://mycontexts.com.

We now should adapt our rewriting for URLs whose path start with "models_", stipulating that it should not run for the OPTIONS verb:

  RewriteEngine On
  RewriteCond %{REQUEST_METHOD} !^(OPTIONS)$
  RewriteCond %{REQUEST_URI} ^/models(.*)$
  RewriteRule ^(/.*)$  https://perspectives.domains/$1  [R=204]

Again, this only works for databases that can be accessed without credentials. That will be enough for reading DomeinFiles (models) from public repositories.