add X-Origin to GET requests, so isso.dispatch works on a single host

This commit is contained in:
Martin Zimmermann 2013-11-17 11:16:46 +01:00
parent 8a408aea1d
commit 2e9c21db15
4 changed files with 37 additions and 62 deletions

View File

@ -7,6 +7,7 @@ try:
except ImportError:
from urllib.parse import urlparse
from werkzeug.wrappers import Request
from werkzeug.exceptions import ImATeapot
from isso import make_app, wsgi
@ -34,13 +35,13 @@ class Dispatcher(object):
def __call__(self, environ, start_response):
if "HTTP_ORIGIN" in environ:
origin = environ["HTTP_ORIGIN"]
elif "HTTP_REFERER" in environ:
rv = urlparse(environ["HTTP_REFERER"])
origin = rv.scheme + "://" + rv.hostname + (":" + str(rv.port) if rv.port else "")
else:
origin = wsgi.host(environ)
if Request(environ).url.endswith((".js", ".css")):
return self.isso.values()[0](environ, start_response)
if "HTTP_X_ORIGIN" in environ and "HTTP_ORIGIN" not in environ:
environ["HTTP_ORIGIN"] = environ["HTTP_X_ORIGIN"]
origin = environ.get("HTTP_ORIGIN", wsgi.host(environ))
try:
# logger.info("dispatch %s", origin)

View File

@ -216,11 +216,9 @@ comments for a relative URL to support HTTP, HTTPS and even domain transfers
without manual intervention. But you can chain Isso to support multiple
websites on different domains.
The following example uses `gunicorn <http://gunicorn.org/>`_ as WSGI server (you
can use uWSGI as well). It is *not* possible to run the isso executable for
multiple sites.
Let's say you maintain two websites, like foo.example and other.foo:
The following example uses `gunicorn <http://gunicorn.org/>`_ as WSGI server (
you can use uWSGI as well). Let's say you maintain two websites, like
foo.example and other.foo:
.. code-block:: bash
@ -234,67 +232,38 @@ Let's say you maintain two websites, like foo.example and other.foo:
host = http://other.foo/
dbpath = /var/lib/isso/other.foo.db
Then you run Isso with gunicorn like this:
Then you run Isso using gunicorn:
.. code-block:: bash
$ export ISSO_SETTINGS="/etc/isso.d/foo.example.cfg;/etc/isso.d/other.foo.cfg"
$ gunicorn isso.dispatch -b localhost:8080
Now, there are two options to configure the webserver:
In your webserver configuration, proxy Isso as usual:
1. using a single host to serve comments for both websites
2. different hosts for both websites
.. code-block:: nginx
In the former case, Isso dispatches based on the HTTP Referer and (if provided)
HTTP Origin. If you expect users to supress their referer completely, you
should use the second option.
server {
listen [::]:80;
server_name comments.example;
1. Using a single host to serve comments.
location / {
proxy_pass http://localhost:8080;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}
.. code-block:: nginx
To verify the setup, run:
server {
listen [::]:80;
server_name comments.example;
.. code-block:: bash
location / {
proxy_pass http://localhost:8080;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}
$ curl -vH "Origin: http://foo.example" http://comments.example/
...
$ curl -vH "Origin: http://other.foo" http://comments.example/
...
To verify the setup, run:
.. code-block:: bash
$ curl -vH "Origin: http://foo.example" http://comments.example/
...
$ curl -vH "Origin: http://other.foo" http://comments.example/
...
In case of a 418 (I'm a teapot), the setup is *not* correctly configured.
2. Using different hosts for both websites (no need for a dedicated domain,
you can also proxy Isso on a sub-uri like /isso).
.. code-block:: nginx
server {
listen [::]:80;
server_name comments.foo.example comments.other.foo;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}
No need to verify this setup, here the webserver automatically sets the
proper host.
In case of a 418 (I'm a teapot), the setup is *not* correctly configured.
Appendum

View File

@ -92,7 +92,12 @@ define(["q"], function(Q) {
try {
xhr.open(method, url, true);
xhr.withCredentials = true; // fuck you, fuck you, fuck you IE
xhr.withCredentials = true;
if (method === "GET") {
xhr.setRequestHeader("X-Origin", window.location.origin);
}
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
onload();

View File

@ -59,7 +59,7 @@ class CORSMiddleware(object):
def add_cors_headers(status, headers, exc_info=None):
headers = Headers(headers)
headers.add("Access-Control-Allow-Origin", self.origin(environ))
headers.add("Access-Control-Allow-Headers", "Origin, Content-Type")
headers.add("Access-Control-Allow-Headers", "Origin, Content-Type, X-Origin")
headers.add("Access-Control-Allow-Credentials", "true")
headers.add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
headers.add("Access-Control-Expose-Headers", "X-Set-Cookie")