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: except ImportError:
from urllib.parse import urlparse from urllib.parse import urlparse
from werkzeug.wrappers import Request
from werkzeug.exceptions import ImATeapot from werkzeug.exceptions import ImATeapot
from isso import make_app, wsgi from isso import make_app, wsgi
@ -34,13 +35,13 @@ class Dispatcher(object):
def __call__(self, environ, start_response): def __call__(self, environ, start_response):
if "HTTP_ORIGIN" in environ: if Request(environ).url.endswith((".js", ".css")):
origin = environ["HTTP_ORIGIN"] return self.isso.values()[0](environ, start_response)
elif "HTTP_REFERER" in environ:
rv = urlparse(environ["HTTP_REFERER"]) if "HTTP_X_ORIGIN" in environ and "HTTP_ORIGIN" not in environ:
origin = rv.scheme + "://" + rv.hostname + (":" + str(rv.port) if rv.port else "") environ["HTTP_ORIGIN"] = environ["HTTP_X_ORIGIN"]
else:
origin = wsgi.host(environ) origin = environ.get("HTTP_ORIGIN", wsgi.host(environ))
try: try:
# logger.info("dispatch %s", origin) # 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 without manual intervention. But you can chain Isso to support multiple
websites on different domains. websites on different domains.
The following example uses `gunicorn <http://gunicorn.org/>`_ as WSGI server (you The following example uses `gunicorn <http://gunicorn.org/>`_ as WSGI server (
can use uWSGI as well). It is *not* possible to run the isso executable for you can use uWSGI as well). Let's say you maintain two websites, like
multiple sites. foo.example and other.foo:
Let's say you maintain two websites, like foo.example and other.foo:
.. code-block:: bash .. code-block:: bash
@ -234,25 +232,16 @@ Let's say you maintain two websites, like foo.example and other.foo:
host = http://other.foo/ host = http://other.foo/
dbpath = /var/lib/isso/other.foo.db dbpath = /var/lib/isso/other.foo.db
Then you run Isso with gunicorn like this: Then you run Isso using gunicorn:
.. code-block:: bash .. code-block:: bash
$ export ISSO_SETTINGS="/etc/isso.d/foo.example.cfg;/etc/isso.d/other.foo.cfg" $ export ISSO_SETTINGS="/etc/isso.d/foo.example.cfg;/etc/isso.d/other.foo.cfg"
$ gunicorn isso.dispatch -b localhost:8080 $ 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 .. code-block:: nginx
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
server { server {
listen [::]:80; listen [::]:80;
@ -265,36 +254,16 @@ should use the second option.
} }
} }
To verify the setup, run: To verify the setup, run:
.. code-block:: bash .. code-block:: bash
$ curl -vH "Origin: http://foo.example" http://comments.example/ $ curl -vH "Origin: http://foo.example" http://comments.example/
... ...
$ curl -vH "Origin: http://other.foo" 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. 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.
Appendum Appendum

View File

@ -92,7 +92,12 @@ define(["q"], function(Q) {
try { try {
xhr.open(method, url, true); 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 () { xhr.onreadystatechange = function () {
if (xhr.readyState === 4) { if (xhr.readyState === 4) {
onload(); onload();

View File

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