changeset 875:d9b98b8a1847

server: handling of dict and "file:" urls in url_redirections_dict: - file: urls can be specified, they can redirect to a directory or of file. In the case of directory, all the hierarchy with subdirectories will be available - a dict can be used instead of plain string url, to specify options - if a dict is used, either "url" or "path" must be specified. "url" has the same meaning as the plain string url, "path" is used to construct a file: url - for file: redirections, there is a "protected" option which can be specified in the dict (JSON boolean). If true (default) the directories listings will not be displayed.
author Goffi <goffi@goffi.org>
date Wed, 02 Mar 2016 17:14:02 +0100
parents c030d8235c23
children ca31e4f677e5
files src/server/server.py
diffstat 1 files changed, 51 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/server/server.py	Wed Mar 02 15:08:42 2016 +0100
+++ b/src/server/server.py	Wed Mar 02 17:14:02 2016 +0100
@@ -124,7 +124,28 @@
         if options['url_redirections_dict'] and not options['url_redirections_profile']:
             raise ValueError(u"url_redirections_profile need to be filled if you want to use url_redirections_dict")
 
-        for old, new in options['url_redirections_dict'].iteritems():
+        for old, new_data in options['url_redirections_dict'].iteritems():
+            # new_data can be a dictionary or a unicode url
+            if isinstance(new_data, dict):
+                # new_data dict must contain either "url" or "path" key (exclusive)
+                # if "path" is used, a file url is constructed with it
+                try:
+                    new = new_data['url']
+                except KeyError:
+                    try:
+                        path = new_data['path']
+                    except KeyError:
+                        raise ValueError(u'if you use a dict for url_redirections data, it must contain the "url" or a "file" key')
+                    else:
+                        new = 'file:{}'.format(urllib.quote(path))
+                else:
+                    if 'path' in new_data:
+                        raise ValueError(u'You can\'t have "url" and "path" keys at the same time in url_redirections')
+            else:
+                new = new_data
+                new_data = {}
+
+            # some normalization
             if not old.strip():
                 # root URL special case
                 old = ''
@@ -133,6 +154,8 @@
             else:
                 old = self._normalizeURL(old)
             new_url = urlparse.urlsplit(new.encode('utf-8'))
+
+            # we handle the known URL schemes
             if new_url.scheme == 'xmpp':
                 # XMPP URI
                 parsed_qs = urlparse.parse_qs(new_url.geturl())
@@ -147,6 +170,7 @@
                     item = urllib.quote_plus(item),
                     ).decode('utf-8')
                 request_data = self._getRequestData(location)
+
             elif new_url.scheme in ('', 'http', 'https'):
                 # direct redirection
                 if new_url.netloc:
@@ -154,14 +178,40 @@
                         netloc = new_url.netloc))
                 location = urlparse.urlunsplit(('', '', new_url.path, new_url.query, new_url.fragment)).decode('utf-8')
                 request_data = self._getRequestData(location)
+
+            elif new_url.scheme in ('file'):
+                # file or directory
+                if new_url.netloc:
+                    raise NotImplementedError(u"netloc ({netloc}) is not implemented for url redirection to file system, it is not possible to redirect to an external host".format(
+                        netloc = new_url.netloc))
+                path = urllib.unquote(new_url.path)
+                if not os.path.isabs(path):
+                    raise ValueError(u'file redirection must have an absolute path: e.g. file:/path/to/my/file')
+                # for file redirection, we directly put child here
+                segments, dummy, last_segment = old.rpartition('/')
+                url_segments = segments.split('/') if segments else []
+                current = self
+                for segment in url_segments:
+                    resource = web_resource.NoResource()
+                    current.putChild(segment, resource)
+                    current = resource
+                resource_class = ProtectedFile if new_data.get('protected',True) else static.File
+                current.putChild(last_segment, resource_class(path))
+                log.debug(u"Added redirection from /{old} to file system path {path}".format(old=old.decode('utf-8'), path=path.decode('utf-8')))
+                continue # we don't want to use redirection system, so we continue here
+
             else:
                 raise NotImplementedError(u"{scheme}: scheme is not managed for url_redirections_dict".format(scheme=new_url.scheme))
+
             self.redirections[old] = request_data
             if not old:
                 log.info(u"Root URL redirected to {uri}".format(uri=request_data[1].decode('utf-8')))
+
+        # no need to keep url_redirections*, they will not be used anymore
         del options['url_redirections_dict']
         del options['url_redirections_profile']
 
+        # the default root URL, if not redirected
         if not '' in self.redirections:
             self.redirections[''] = self._getRequestData(C.LIBERVIA_MAIN_PAGE)