# HG changeset patch # User Goffi # Date 1516784258 -3600 # Node ID dc6c8c4d8ff6ba14af463fe5c9be54c1aa1ff38a # Parent f5661761b1b9e3de7be0b2904da6663f50b86c21 server: redirection rework: - redirection parsing is now launched after LiberviaPages are imported, this way the pages are accessible and their methods are usable - inv_redirections attribute in LiberviaRootResource keep a map from new URL to old URL, allowing to check if a redirected path can lead to the same page - LiberviaPage methods are used to retrieve their URL - fixed remaining args when going to a redirected page - new checkRedirection method to see if a redirection can lead to the same URL diff -r f5661761b1b9 -r dc6c8c4d8ff6 src/server/server.py --- a/src/server/server.py Mon Jan 22 22:25:37 2018 +0100 +++ b/src/server/server.py Wed Jan 24 09:57:38 2018 +0100 @@ -107,14 +107,11 @@ handle redirections declared in sat.conf """ - def __init__(self, options, *args, **kwargs): - """ - @param options(dict): configuration options, same as Libervia.options - """ - super(LiberviaRootResource, self).__init__(*args, **kwargs) - + def _initRedirections(self, options): ## redirections self.redirections = {} + self.inv_redirections = {} # new URL to old URL map + if options['url_redirections_dict'] and not options['url_redirections_profile']: # FIXME: url_redirections_profile should not be needed. It is currently used to # redirect to an URL which associate the profile with the service, but this @@ -157,29 +154,38 @@ new['query_args'][k] = [v] elif 'path' in new_data: new = 'file:{}'.format(urllib.quote(new_data['path'])) - else: + elif isinstance(new_data, basestring): new = new_data new_data = {} + else: + log.error(_(u"ignoring invalid redirection value: {new_data}").format(new_data=new_data)) + continue # some normalization if not old.strip(): # root URL special case old = '' elif not old.startswith('/'): - raise ValueError(u"redirected url must start with '/', got {}".format(old)) + log.error(_(u"redirected url must start with '/', got {value}. Ignoring").format(value=old)) + continue else: old = self._normalizeURL(old) if isinstance(new, dict): # dict are handled differently, they contain data - # which are use dynamically when the request is done + # which ared use dynamically when the request is done self.redirections[old] = new if not old: - if new['type'] == 'page': - log.info(_(u"Root URL redirected to page {name}").format(name=new['page'])) + if new[u'type'] == u'page': + log.info(_(u"Root URL redirected to page {name}").format(name=new[u'page'])) + else: + if new[u'type'] == u'page': + page = LiberviaPage.getPageByName(new[u'page']) + url = page.getURL(*new.get(u'path_args', [])) + self.inv_redirections[url] = old continue - # at this point we have a rediction URL in new, we can parse it + # at this point we have a redirection URL in new, we can parse it new_url = urlparse.urlsplit(new.encode('utf-8')) # we handle the known URL schemes @@ -197,6 +203,8 @@ item = urllib.quote_plus(item), ).decode('utf-8') request_data = self._getRequestData(location) + if old: + self.inv_redirections[location] = old elif new_url.scheme in ('', 'http', 'https'): # direct redirection @@ -205,6 +213,8 @@ netloc = new_url.netloc)) location = urlparse.urlunsplit(('', '', new_url.path, new_url.query, new_url.fragment)).decode('utf-8') request_data = self._getRequestData(location) + if old: + self.inv_redirections[location] = old elif new_url.scheme in ('file'): # file or directory @@ -224,7 +234,7 @@ 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'))) + log.info(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: @@ -297,7 +307,7 @@ dummy, uri, dummy, dummy = request_data except ValueError: uri = u'' - log.warning(D_(u"recursive redirection, please fix this URL:\n{old} ==> {new}").format( + log.error(D_(u"recursive redirection, please fix this URL:\n{old} ==> {new}").format( old=request.uri.decode('utf-8'), new=uri.decode('utf-8'), )) @@ -331,9 +341,9 @@ new=uri.decode('utf-8'), )) # we change the request to reflect the new url - request.postpath = path_list[1:] - request.uri = uri - request.path = path + request.postpath = path_list[1:] + request.postpath + request.uri = '/'.join([uri] + request.postpath) + request.path = '/'.join([path] + request.postpath) request.args = args # we start again to look for a child with the new url @@ -1433,7 +1443,7 @@ log.error(_(u"Can't get namespaces map: {msg}").format(msg=failure_)) def backendReady(self, dummy): - self.root = root = LiberviaRootResource(self.options, self.html_dir) + self.root = root = LiberviaRootResource(self.html_dir) _register = Register(self) _upload_radiocol = UploadManagerRadioCol(self) _upload_avatar = UploadManagerAvatar(self) @@ -1501,6 +1511,8 @@ if self.version[-1] == 'D': self.putChild('test', web_util.Redirect('/libervia_test.html')) + # redirections + root._initRedirections(self.options) server.Request.defaultContentType = 'text/html; charset=utf-8' wrapped = web_resource.EncodingResourceWrapper(root, [server.GzipEncoderFactory()]) @@ -1869,6 +1881,20 @@ os.path.join(split_result.path, path), query, fragment)) + def checkRedirection(self, url): + """check is a part of the URL prefix is redirected then replace it + + @param url(unicode): url to check + @return (unicode): possibly redirected URL which should link to the same location + """ + inv_redirections = self.root.inv_redirections + url_parts = url.strip(u'/').split(u'/') + for idx in xrange(len(url), 0, -1): + test_url = u'/' + u'/'.join(url_parts[:idx]) + if test_url in inv_redirections: + rem_url = url_parts[idx:] + return u'/'.join([inv_redirections[test_url]] + rem_url) + return url ## Sessions ##