diff --git a/deluge/ui/webui/config_tabs_webui.py b/deluge/ui/webui/config_tabs_webui.py index 3e8793339..d3e7ef6b7 100644 --- a/deluge/ui/webui/config_tabs_webui.py +++ b/deluge/ui/webui/config_tabs_webui.py @@ -34,6 +34,7 @@ from deluge.ui.client import sclient as proxy from deluge.log import LOG as log + import utils import lib.newforms_plus as forms import config_forms @@ -61,12 +62,28 @@ class Template(config_forms.WebCfgForm): class Server(config_forms.WebCfgForm): title = _("Server") + info = _("Manually restart webui to apply changes.") + port = forms.IntegerField(label = _("Port"),min_value=80) + https = forms.CheckBox(_("Https")) + + def validate(self, data): + import os + from deluge.common import get_default_config_dir + + if data.https: + cert_path = os.path.join(get_default_config_dir("ssl") ,"deluge.cert.pem" ) + if not os.path.exists (cert_path): + raise forms.ValidationError(_("Certificate not found at '%s'" % cert_path)) + key_path = os.path.join(get_default_config_dir("ssl") ,"deluge.key.pem" ) + if not os.path.exists (key_path): + raise forms.ValidationError(_("Key not found at '%s'" % key_path)) + def post_save(self): pass #raise forms.ValidationError( - # _("Manually restart server to apply these changes.")) + # ) class Password(forms.Form): title = _("Password") diff --git a/deluge/ui/webui/deluge_webserver.py b/deluge/ui/webui/deluge_webserver.py index 2a41239f7..4558beb73 100644 --- a/deluge/ui/webui/deluge_webserver.py +++ b/deluge/ui/webui/deluge_webserver.py @@ -38,6 +38,7 @@ from deluge.ui.client import sclient import components from deluge.log import LOG as log + # Initialize gettext if deluge.common.windows_check() or deluge.common.osx_check(): locale.setlocale(locale.LC_ALL, '') @@ -121,7 +122,21 @@ def create_webserver(debug = False, base_url =None): server_address=("0.0.0.0", int(config.get('port'))) server = CherryPyWSGIServer(server_address, wsgi_app, server_name="localhost") - log.info("http://%s:%d/" % server_address) + https = False + if config.get("https"): + import os + from deluge.common import get_default_config_dir + cert_path = os.path.join(get_default_config_dir("ssl") ,"deluge.cert.pem" ) + key_path = os.path.join(get_default_config_dir("ssl") ,"deluge.key.pem" ) + if os.path.exists (key_path) and os.path.exists (cert_path): + server.ssl_certificate = cert_path + server.ssl_private_key = key_path + https = True + + if https: + log.info("https://%s:%d/" % server_address) + else: + log.info("http://%s:%d/" % server_address) return server def run(debug = False, base_url = ""): diff --git a/deluge/ui/webui/lib/webpy022/webapi.py b/deluge/ui/webui/lib/webpy022/webapi.py index 39d3be873..35a67d88e 100644 --- a/deluge/ui/webui/lib/webpy022/webapi.py +++ b/deluge/ui/webui/lib/webpy022/webapi.py @@ -9,7 +9,7 @@ __all__ = [ "header", "output", "flush", "debug", "input", "data", "setcookie", "cookies", - "ctx", + "ctx", "loadhooks", "load", "unloadhooks", "unload", "_loadhooks", "wsgifunc" ] @@ -59,19 +59,19 @@ def internalerror(): def header(hdr, value, unique=False): """ Adds the header `hdr: value` with the response. - + If `unique` is True and a header with that name already exists, - it doesn't add a new one. + it doesn't add a new one. """ hdr, value = utf8(hdr), utf8(value) # protection against HTTP response splitting attack if '\n' in hdr or '\r' in hdr or '\n' in value or '\r' in value: raise ValueError, 'invalid characters in header' - + if unique is True: for h, v in ctx.headers: if h.lower() == hdr.lower(): return - + ctx.headers.append((hdr, value)) def output(string_): @@ -88,20 +88,20 @@ def flush(): def input(*requireds, **defaults): """ - Returns a `storage` object with the GET and POST arguments. + Returns a `storage` object with the GET and POST arguments. See `storify` for how `requireds` and `defaults` work. """ from cStringIO import StringIO def dictify(fs): return dict([(k, fs[k]) for k in fs.keys()]) - + _method = defaults.pop('_method', 'both') - + e = ctx.env.copy() a = b = {} - + if _method.lower() in ['both', 'post']: if e['REQUEST_METHOD'] == 'POST': - a = cgi.FieldStorage(fp = StringIO(data()), environ=e, + a = cgi.FieldStorage(fp = StringIO(data()), environ=e, keep_blank_values=1) a = dictify(a) @@ -125,15 +125,15 @@ def data(): def setcookie(name, value, expires="", domain=None): """Sets a cookie.""" - if expires < 0: - expires = -1000000000 + if expires < 0: + expires = -1000000000 kargs = {'expires': expires, 'path':'/'} - if domain: + if domain: kargs['domain'] = domain # @@ should we limit cookies to a different path? cookie = Cookie.SimpleCookie() cookie[name] = value - for key, val in kargs.iteritems(): + for key, val in kargs.iteritems(): cookie[name][key] = val header('Set-Cookie', cookie.items()[0][1].OutputString()) @@ -154,18 +154,18 @@ def debug(*args): """ Prints a prettyprinted version of `args` to stderr. """ - try: + try: out = ctx.environ['wsgi.errors'] - except: + except: out = sys.stderr for arg in args: print >> out, pprint.pformat(arg) return '' def _debugwrite(x): - try: + try: out = ctx.environ['wsgi.errors'] - except: + except: out = sys.stderr out.write(x) debug.write = _debugwrite @@ -173,8 +173,8 @@ debug.write = _debugwrite class _outputter: """Wraps `sys.stdout` so that print statements go into the response.""" def __init__(self, file): self.file = file - def write(self, string_): - if hasattr(ctx, 'output'): + def write(self, string_): + if hasattr(ctx, 'output'): return output(string_) else: self.file.write(string_) @@ -186,7 +186,7 @@ def _capturedstdout(): while hasattr(sysstd, 'file'): if isinstance(sys.stdout, _outputter): return True sysstd = sysstd.file - if isinstance(sys.stdout, _outputter): return True + if isinstance(sys.stdout, _outputter): return True return False if not _capturedstdout(): @@ -197,7 +197,7 @@ ctx = context = threadeddict(_context) ctx.__doc__ = """ A `storage` object containing various information about the request: - + `environ` (aka `env`) : A dictionary containing the standard WSGI environment variables. @@ -215,7 +215,7 @@ A `storage` object containing various information about the request: `path` : The path request. - + `query` : If there are no query arguments, the empty string. Otherwise, a `?` followed by the query string. @@ -241,8 +241,8 @@ _loadhooks = {} def load(): """ Loads a new context for the thread. - - You can ask for a function to be run at loadtime by + + You can ask for a function to be run at loadtime by adding it to the dictionary `loadhooks`. """ _context[threading.currentThread()] = storage() @@ -251,7 +251,7 @@ def load(): if config.get('db_parameters'): import db db.connect(**config.db_parameters) - + for x in loadhooks.values(): x() def _load(env): @@ -259,7 +259,13 @@ def _load(env): ctx.output = '' ctx.environ = ctx.env = env ctx.host = env.get('HTTP_HOST') - ctx.homedomain = 'http://' + env.get('HTTP_HOST', '[unknown]') + + #http://groups.google.com/group/webpy/browse_thread/thread/2a4665e54b07c991?pli=1 + if env.get('HTTPS'): + ctx.protocol = "https" + else: + ctx.protocol = "http" + ctx.homedomain = ctx.protocol + "://" + env.get('HTTP_HOST','[unknown]') ctx.homepath = os.environ.get('REAL_SCRIPT_NAME', env.get('SCRIPT_NAME', '')) ctx.home = ctx.homedomain + ctx.homepath ctx.ip = env.get('REMOTE_ADDR') @@ -267,14 +273,14 @@ def _load(env): ctx.path = env.get('PATH_INFO') # http://trac.lighttpd.net/trac/ticket/406 requires: if env.get('SERVER_SOFTWARE', '').startswith('lighttpd/'): - ctx.path = lstrips(env.get('REQUEST_URI').split('?')[0], + ctx.path = lstrips(env.get('REQUEST_URI').split('?')[0], os.environ.get('REAL_SCRIPT_NAME', env.get('SCRIPT_NAME', ''))) if env.get('QUERY_STRING'): ctx.query = '?' + env.get('QUERY_STRING', '') else: ctx.query = '' - + ctx.fullpath = ctx.path + ctx.query for x in _loadhooks.values(): x() @@ -283,7 +289,7 @@ unloadhooks = {} def unload(): """ Unloads the context for the thread. - + You can ask for a function to be run at loadtime by adding it ot the dictionary `unloadhooks`. """ @@ -297,7 +303,7 @@ def _unload(): def wsgifunc(func, *middleware): """Returns a WSGI-compatible function from a webpy-function.""" middleware = list(middleware) - + def wsgifunc(env, start_resp): _load(env) try: @@ -307,7 +313,7 @@ def wsgifunc(func, *middleware): except: print >> debug, traceback.format_exc() result = internalerror() - + is_generator = result and hasattr(result, 'next') if is_generator: # wsgi requires the headers first @@ -322,19 +328,19 @@ def wsgifunc(func, *middleware): ctx._write = start_resp(status, headers) # and now, the fun: - + def cleanup(): # we insert this little generator # at the end of our itertools.chain # so that it unloads the request # when everything else is done - + yield '' # force it to be a generator _unload() # result is the output of calling the webpy function # it could be a generator... - + if is_generator: if firstchunk is flush: # oh, it's just our special flush mode @@ -348,22 +354,22 @@ def wsgifunc(func, *middleware): return [] else: return itertools.chain([firstchunk], result, cleanup()) - + # ... but it's usually just None - # + # # output is the stuff in ctx.output # it's usually a string... if isinstance(output, str): #@@ other stringlikes? _unload() - return [output] + return [output] # it could be a generator... elif hasattr(output, 'next'): return itertools.chain(output, cleanup()) else: _unload() raise Exception, "Invalid ctx.output" - - for mw_func in middleware: + + for mw_func in middleware: wsgifunc = mw_func(wsgifunc) - + return wsgifunc diff --git a/deluge/ui/webui/templates/classic/header.html b/deluge/ui/webui/templates/classic/header.html index 8cc960e70..2b6f413cd 100644 --- a/deluge/ui/webui/templates/classic/header.html +++ b/deluge/ui/webui/templates/classic/header.html @@ -5,6 +5,15 @@ $def with (title, active_tab="NONE") + + + + + + $for js in include_javascript: +