include protocol in subdomain_host

makes everything easier, and tests are passing with and without subdomains (yay!)
This commit is contained in:
Min RK
2016-02-26 17:52:31 +01:00
parent f922561003
commit 335b47d7c1
9 changed files with 25 additions and 15 deletions

View File

@@ -15,3 +15,7 @@ script:
- py.test --cov jupyterhub jupyterhub/tests -v - py.test --cov jupyterhub jupyterhub/tests -v
after_success: after_success:
- codecov - codecov
matrix:
include:
- python: 3.5
env: JUPYTERHUB_TEST_SUBDOMAIN_HOST=http://127.0.0.1.xip.io:8000

View File

@@ -16,6 +16,7 @@ from datetime import datetime
from distutils.version import LooseVersion as V from distutils.version import LooseVersion as V
from getpass import getuser from getpass import getuser
from subprocess import Popen from subprocess import Popen
from urllib.parse import urlparse
if sys.version_info[:2] < (3,3): if sys.version_info[:2] < (3,3):
raise ValueError("Python < 3.3 not supported: %s" % sys.version) raise ValueError("Python < 3.3 not supported: %s" % sys.version)
@@ -239,6 +240,11 @@ class JupyterHub(Application):
Only used when subdomains are involved. Only used when subdomains are involved.
""" """
) )
def _subdomain_host_changed(self, name, old, new):
if new and '://' not in new:
# host should include '://'
# if not specified, assume https: You have to be really explicit about HTTP!
self.subdomain_host = 'https://' + new
port = Integer(8000, config=True, port = Integer(8000, config=True,
help="The public facing port of the proxy" help="The public facing port of the proxy"
@@ -923,7 +929,7 @@ class JupyterHub(Application):
version_hash=datetime.now().strftime("%Y%m%d%H%M%S"), version_hash=datetime.now().strftime("%Y%m%d%H%M%S"),
subdomain_host = self.subdomain_host subdomain_host = self.subdomain_host
domain = subdomain_host.rsplit(':', 1)[0] domain = urlparse(subdomain_host).hostname
settings = dict( settings = dict(
log_function=log_request, log_function=log_request,
config=self.config, config=self.config,

View File

@@ -476,7 +476,7 @@ class UserSpawnHandler(BaseHandler):
without_prefix = self.request.uri[len(self.hub.server.base_url):] without_prefix = self.request.uri[len(self.hub.server.base_url):]
target = url_path_join(self.base_url, without_prefix) target = url_path_join(self.base_url, without_prefix)
if self.use_subdomains: if self.use_subdomains:
target = '//' + current_user.host + target target = current_user.host + target
self.redirect(target) self.redirect(target)
else: else:
# not logged in to the right user, # not logged in to the right user,

View File

@@ -199,7 +199,7 @@ class Spawner(LoggingConfigurable):
'--port=%i' % self.user.server.port, '--port=%i' % self.user.server.port,
'--cookie-name=%s' % self.user.server.cookie_name, '--cookie-name=%s' % self.user.server.cookie_name,
'--base-url=%s' % self.user.server.base_url, '--base-url=%s' % self.user.server.base_url,
'--hub-host=%s' % ('//' + self.hub.host) if self.hub.host else '', '--hub-host=%s' % self.hub.host,
'--hub-prefix=%s' % self.hub.server.base_url, '--hub-prefix=%s' % self.hub.server.base_url,
'--hub-api-url=%s' % self.hub.api_url, '--hub-api-url=%s' % self.hub.api_url,
] ]

View File

@@ -168,10 +168,7 @@ class MockHub(JupyterHub):
self.db_file.close() self.db_file.close()
def login_user(self, name): def login_user(self, name):
if self.subdomain_host: base_url = public_url(self)
base_url = 'http://' + self.subdomain_host + self.proxy.public_server.base_url
else:
base_url = self.proxy.public_server.url
r = requests.post(base_url + 'hub/login', r = requests.post(base_url + 'hub/login',
data={ data={
'username': name, 'username': name,
@@ -191,13 +188,12 @@ def public_host(app):
def public_url(app): def public_url(app):
return 'http://%s%s' % (public_host(app), app.proxy.public_server.base_url) return public_host(app) + app.proxy.public_server.base_url
def user_url(user, app): def user_url(user, app):
print(user.host)
if app.use_subdomains: if app.use_subdomains:
host = user.host host = user.host
else: else:
host = public_host(app) host = public_host(app)
return url_path_join('http://%s' % host, user.server.base_url) return host + user.server.base_url

View File

@@ -364,7 +364,7 @@ def test_spawn(app, io_loop):
for expected in ['--user=%s' % name, '--base-url=%s' % user.server.base_url]: for expected in ['--user=%s' % name, '--base-url=%s' % user.server.base_url]:
assert expected in argv assert expected in argv
if app.use_subdomains: if app.use_subdomains:
assert '--hub-host=//%s' % app.subdomain_host in argv assert '--hub-host=%s' % app.subdomain_host in argv
r = api_request(app, 'users', name, 'server', method='delete') r = api_request(app, 'users', name, 'server', method='delete')
assert r.status_code == 204 assert r.status_code == 204

View File

@@ -22,6 +22,7 @@ def test_root_no_auth(app, io_loop):
print(routes) print(routes)
print(app.hub.server) print(app.hub.server)
url = public_url(app) url = public_url(app)
print(url)
r = requests.get(url) r = requests.get(url)
r.raise_for_status() r.raise_for_status()
assert r.url == ujoin(url, app.hub.server.base_url, 'login') assert r.url == ujoin(url, app.hub.server.base_url, 'login')

View File

@@ -4,6 +4,7 @@ import json
import os import os
from queue import Queue from queue import Queue
from subprocess import Popen from subprocess import Popen
from urllib.parse import urlparse
from .. import orm from .. import orm
from .mocking import MockHub from .mocking import MockHub
@@ -64,7 +65,7 @@ def test_external_proxy(request, io_loop):
routes = io_loop.run_sync(app.proxy.get_routes) routes = io_loop.run_sync(app.proxy.get_routes)
user_path = '/user/river' user_path = '/user/river'
if app.use_subdomains: if app.use_subdomains:
domain = app.subdomain_host.rsplit(':', 1)[0] domain = urlparse(app.subdomain_host).hostname
user_path = '/%s.%s' % (name, domain) + user_path user_path = '/%s.%s' % (name, domain) + user_path
assert sorted(routes.keys()) == ['/', user_path] assert sorted(routes.keys()) == ['/', user_path]

View File

@@ -2,7 +2,7 @@
# Distributed under the terms of the Modified BSD License. # Distributed under the terms of the Modified BSD License.
from datetime import datetime, timedelta from datetime import datetime, timedelta
from urllib.parse import quote from urllib.parse import quote, urlparse
from tornado import gen from tornado import gen
from tornado.log import app_log from tornado.log import app_log
@@ -171,7 +171,9 @@ class User(HasTraits):
def host(self): def host(self):
"""Get the *host* for my server (domain[:port])""" """Get the *host* for my server (domain[:port])"""
# FIXME: escaped_name probably isn't escaped enough in general for a domain fragment # FIXME: escaped_name probably isn't escaped enough in general for a domain fragment
return self.escaped_name + '.' + self.settings['subdomain_host'] parsed = urlparse(self.settings['subdomain_host'])
h = '%s://%s.%s' % (parsed.scheme, self.escaped_name, parsed.netloc)
return h
@property @property
def url(self): def url(self):
@@ -180,7 +182,7 @@ class User(HasTraits):
Full name.domain/path if using subdomains, otherwise just my /base/url Full name.domain/path if using subdomains, otherwise just my /base/url
""" """
if self.settings.get('use_subdomains'): if self.settings.get('use_subdomains'):
return '//{host}{path}'.format( return '{host}{path}'.format(
host=self.host, host=self.host,
path=self.server.base_url, path=self.server.base_url,
) )