allow multiple hosts, e.g. HTTP and HTTPS sites

This commit is contained in:
Martin Zimmermann 2013-10-29 12:22:13 +01:00
parent cb40c7ca42
commit b672dae624
3 changed files with 69 additions and 14 deletions

View File

@ -47,6 +47,17 @@ host
fails, Isso may not be able check if a web page exists, thus fails to fails, Isso may not be able check if a web page exists, thus fails to
accept new comments. accept new comments.
You can supply more than one host:
.. code-block:: ini
[general]
host =
http://localhost/
https://localhost/
This is useful, when your website is available on HTTP and HTTPS.
session-key session-key
private session key to validate client cookies. If you restart the private session key to validate client cookies. If you restart the
application several times per hour for whatever reason, use a fixed application several times per hour for whatever reason, use a fixed

View File

@ -40,10 +40,8 @@ from argparse import ArgumentParser
try: try:
import httplib import httplib
import urlparse
except ImportError: except ImportError:
import http.client as httplib import http.client as httplib
import urllib.parse as urlparse
import misaka import misaka
from itsdangerous import URLSafeTimedSerializer from itsdangerous import URLSafeTimedSerializer
@ -128,12 +126,24 @@ class Isso(object):
return e return e
def wsgi_app(self, environ, start_response): def wsgi_app(self, environ, start_response):
response = self.dispatch(Request(environ), start_response) response = self.dispatch(Request(environ), start_response)
if hasattr(response, 'headers'):
response.headers["Access-Control-Allow-Origin"] = self.conf.get('general', 'host').rstrip('/') # add CORS header
response.headers["Access-Control-Allow-Headers"] = "Origin, Content-Type" if hasattr(response, 'headers') and 'HTTP_ORIGN' in environ:
response.headers["Access-Control-Allow-Credentials"] = "true" for host in self.conf.getiter('general', 'host'):
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE" if environ["HTTP_ORIGIN"] == host.rstrip("/"):
origin = host.rstrip("/")
break
else:
origin = host.rstrip("/")
hdrs = response.headers
hdrs["Access-Control-Allow-Origin"] = origin
hdrs["Access-Control-Allow-Headers"] = "Origin, Content-Type"
hdrs["Access-Control-Allow-Credentials"] = "true"
hdrs["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE"
return response(environ, start_response) return response(environ, start_response)
def __call__(self, environ, start_response): def __call__(self, environ, start_response):
@ -153,12 +163,17 @@ def make_app(conf=None):
isso = App(conf) isso = App(conf)
try: for line in conf.getiter("general", "host"):
host, port, ssl = parse.host(conf.get("general", "host")) try:
con = httplib.HTTPSConnection if ssl else httplib.HTTPConnection host, port, ssl = parse.host(line)
con(host, port, timeout=5).request('GET', '/') con = httplib.HTTPSConnection if ssl else httplib.HTTPConnection
logger.info("connected to HTTP server") con(host, port, timeout=5).request('GET', '/')
except (httplib.HTTPException, socket.error): except (httplib.HTTPException, socket.error):
continue
else:
logger.info("connected to HTTP server")
break
else:
logger.warn("unable to connect to HTTP server") logger.warn("unable to connect to HTTP server")
app = ProxyFix(wsgi.SubURI(SharedDataMiddleware(isso.wsgi_app, { app = ProxyFix(wsgi.SubURI(SharedDataMiddleware(isso.wsgi_app, {
@ -195,7 +210,6 @@ def main():
run_simple(conf.get('server', 'host'), conf.getint('server', 'port'), make_app(conf), run_simple(conf.get('server', 'host'), conf.getint('server', 'port'), make_app(conf),
threaded=True, use_reloader=conf.getboolean('server', 'reload')) threaded=True, use_reloader=conf.getboolean('server', 'reload'))
try: try:
import uwsgi import uwsgi
except ImportError: except ImportError:

View File

@ -28,11 +28,36 @@ else:
from isso import notify from isso import notify
from isso.utils import parse from isso.utils import parse
from isso.compat import text_type as str
logger = logging.getLogger("isso") logger = logging.getLogger("isso")
class IssoParser(ConfigParser): class IssoParser(ConfigParser):
"""
Extended :class:`ConfigParser` to parse human-readable timedeltas
into seconds and handles multiple values per key.
>>> import io
>>> parser = IssoParser(allow_no_value=True)
>>> parser.read_file(io.StringIO(u'''
... [foo]
... bar = 1h
... baz = 12
... bla =
... spam
... ham
... asd = fgh
... '''))
>>> parser.getint("foo", "bar")
3600
>>> parser.getint("foo", "baz")
12
>>> list(parser.getiter("foo", "bla")) # doctest: +IGNORE_UNICODE
['spam', 'ham']
>>> list(parser.getiter("foo", "asd")) # doctest: +IGNORE_UNICODE
['fgh']
"""
@classmethod @classmethod
def _total_seconds(cls, td): def _total_seconds(cls, td):
@ -49,6 +74,11 @@ class IssoParser(ConfigParser):
except AttributeError: except AttributeError:
return int(IssoParser._total_seconds(delta)) return int(IssoParser._total_seconds(delta))
def getiter(self, section, key):
for item in map(str.strip, self.get(section, key).split('\n')):
if item:
yield item
class Config: class Config: