From 2e9c21db1595f368266a0479eff4ee5982217d21 Mon Sep 17 00:00:00 2001 From: Martin Zimmermann Date: Sun, 17 Nov 2013 11:16:46 +0100 Subject: [PATCH] add X-Origin to GET requests, so isso.dispatch works on a single host --- dispatch.py | 15 +++++---- docs/CONFIGURATION.rst | 75 +++++++++++++----------------------------- isso/js/app/api.js | 7 +++- isso/wsgi.py | 2 +- 4 files changed, 37 insertions(+), 62 deletions(-) diff --git a/dispatch.py b/dispatch.py index 08758c6..04d64f7 100644 --- a/dispatch.py +++ b/dispatch.py @@ -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) diff --git a/docs/CONFIGURATION.rst b/docs/CONFIGURATION.rst index d8b8c46..3e3cd6f 100644 --- a/docs/CONFIGURATION.rst +++ b/docs/CONFIGURATION.rst @@ -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 `_ 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 `_ 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: - -1. using a single host to serve comments for both websites -2. different hosts for both websites - -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. - -1. Using a single host to serve comments. - - .. code-block:: nginx +In your webserver configuration, proxy Isso as usual: - server { - listen [::]:80; - server_name comments.example; +.. code-block:: nginx - 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; - } - } + server { + listen [::]:80; + server_name comments.example; - To verify the setup, run: + 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:: bash +To verify the setup, run: - $ 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; +.. code-block:: bash - 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; - } - } + $ curl -vH "Origin: http://foo.example" http://comments.example/ + ... + $ curl -vH "Origin: http://other.foo" http://comments.example/ + ... - 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 diff --git a/isso/js/app/api.js b/isso/js/app/api.js index 157d36f..144415e 100644 --- a/isso/js/app/api.js +++ b/isso/js/app/api.js @@ -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(); diff --git a/isso/wsgi.py b/isso/wsgi.py index 891aaeb..1b3e202 100644 --- a/isso/wsgi.py +++ b/isso/wsgi.py @@ -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")