comparison src/server/server.py @ 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 0cf250066b8a
children 6bdee34fa2f4
comparison
equal deleted inserted replaced
874:c030d8235c23 875:d9b98b8a1847
122 ## redirections 122 ## redirections
123 self.redirections = {} 123 self.redirections = {}
124 if options['url_redirections_dict'] and not options['url_redirections_profile']: 124 if options['url_redirections_dict'] and not options['url_redirections_profile']:
125 raise ValueError(u"url_redirections_profile need to be filled if you want to use url_redirections_dict") 125 raise ValueError(u"url_redirections_profile need to be filled if you want to use url_redirections_dict")
126 126
127 for old, new in options['url_redirections_dict'].iteritems(): 127 for old, new_data in options['url_redirections_dict'].iteritems():
128 # new_data can be a dictionary or a unicode url
129 if isinstance(new_data, dict):
130 # new_data dict must contain either "url" or "path" key (exclusive)
131 # if "path" is used, a file url is constructed with it
132 try:
133 new = new_data['url']
134 except KeyError:
135 try:
136 path = new_data['path']
137 except KeyError:
138 raise ValueError(u'if you use a dict for url_redirections data, it must contain the "url" or a "file" key')
139 else:
140 new = 'file:{}'.format(urllib.quote(path))
141 else:
142 if 'path' in new_data:
143 raise ValueError(u'You can\'t have "url" and "path" keys at the same time in url_redirections')
144 else:
145 new = new_data
146 new_data = {}
147
148 # some normalization
128 if not old.strip(): 149 if not old.strip():
129 # root URL special case 150 # root URL special case
130 old = '' 151 old = ''
131 elif not old.startswith('/'): 152 elif not old.startswith('/'):
132 raise ValueError(u"redirected url must start with '/', got {}".format(old)) 153 raise ValueError(u"redirected url must start with '/', got {}".format(old))
133 else: 154 else:
134 old = self._normalizeURL(old) 155 old = self._normalizeURL(old)
135 new_url = urlparse.urlsplit(new.encode('utf-8')) 156 new_url = urlparse.urlsplit(new.encode('utf-8'))
157
158 # we handle the known URL schemes
136 if new_url.scheme == 'xmpp': 159 if new_url.scheme == 'xmpp':
137 # XMPP URI 160 # XMPP URI
138 parsed_qs = urlparse.parse_qs(new_url.geturl()) 161 parsed_qs = urlparse.parse_qs(new_url.geturl())
139 try: 162 try:
140 item = parsed_qs['item'][0] 163 item = parsed_qs['item'][0]
145 location = "/blog/{profile}/{item}".format( 168 location = "/blog/{profile}/{item}".format(
146 profile=urllib.quote(options['url_redirections_profile'].encode('utf-8')), 169 profile=urllib.quote(options['url_redirections_profile'].encode('utf-8')),
147 item = urllib.quote_plus(item), 170 item = urllib.quote_plus(item),
148 ).decode('utf-8') 171 ).decode('utf-8')
149 request_data = self._getRequestData(location) 172 request_data = self._getRequestData(location)
173
150 elif new_url.scheme in ('', 'http', 'https'): 174 elif new_url.scheme in ('', 'http', 'https'):
151 # direct redirection 175 # direct redirection
152 if new_url.netloc: 176 if new_url.netloc:
153 raise NotImplementedError(u"netloc ({netloc}) is not implemented yet for url_redirections_dict, it is not possible to redirect to an external website".format( 177 raise NotImplementedError(u"netloc ({netloc}) is not implemented yet for url_redirections_dict, it is not possible to redirect to an external website".format(
154 netloc = new_url.netloc)) 178 netloc = new_url.netloc))
155 location = urlparse.urlunsplit(('', '', new_url.path, new_url.query, new_url.fragment)).decode('utf-8') 179 location = urlparse.urlunsplit(('', '', new_url.path, new_url.query, new_url.fragment)).decode('utf-8')
156 request_data = self._getRequestData(location) 180 request_data = self._getRequestData(location)
181
182 elif new_url.scheme in ('file'):
183 # file or directory
184 if new_url.netloc:
185 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(
186 netloc = new_url.netloc))
187 path = urllib.unquote(new_url.path)
188 if not os.path.isabs(path):
189 raise ValueError(u'file redirection must have an absolute path: e.g. file:/path/to/my/file')
190 # for file redirection, we directly put child here
191 segments, dummy, last_segment = old.rpartition('/')
192 url_segments = segments.split('/') if segments else []
193 current = self
194 for segment in url_segments:
195 resource = web_resource.NoResource()
196 current.putChild(segment, resource)
197 current = resource
198 resource_class = ProtectedFile if new_data.get('protected',True) else static.File
199 current.putChild(last_segment, resource_class(path))
200 log.debug(u"Added redirection from /{old} to file system path {path}".format(old=old.decode('utf-8'), path=path.decode('utf-8')))
201 continue # we don't want to use redirection system, so we continue here
202
157 else: 203 else:
158 raise NotImplementedError(u"{scheme}: scheme is not managed for url_redirections_dict".format(scheme=new_url.scheme)) 204 raise NotImplementedError(u"{scheme}: scheme is not managed for url_redirections_dict".format(scheme=new_url.scheme))
205
159 self.redirections[old] = request_data 206 self.redirections[old] = request_data
160 if not old: 207 if not old:
161 log.info(u"Root URL redirected to {uri}".format(uri=request_data[1].decode('utf-8'))) 208 log.info(u"Root URL redirected to {uri}".format(uri=request_data[1].decode('utf-8')))
209
210 # no need to keep url_redirections*, they will not be used anymore
162 del options['url_redirections_dict'] 211 del options['url_redirections_dict']
163 del options['url_redirections_profile'] 212 del options['url_redirections_profile']
164 213
214 # the default root URL, if not redirected
165 if not '' in self.redirections: 215 if not '' in self.redirections:
166 self.redirections[''] = self._getRequestData(C.LIBERVIA_MAIN_PAGE) 216 self.redirections[''] = self._getRequestData(C.LIBERVIA_MAIN_PAGE)
167 217
168 def _normalizeURL(self, url, lower=True): 218 def _normalizeURL(self, url, lower=True):
169 """Return URL normalized for self.redirections dict 219 """Return URL normalized for self.redirections dict