163 default_port = '443' |
163 default_port = '443' |
164 else: |
164 else: |
165 proto = 'http' |
165 proto = 'http' |
166 default_port = '80' |
166 default_port = '80' |
167 |
167 |
168 port = req.env['SERVER_PORT'] |
168 port = req.env[r'SERVER_PORT'] |
169 port = port != default_port and (':' + port) or '' |
169 port = port != default_port and (r':' + port) or r'' |
170 urlbase = '%s://%s%s' % (proto, req.env['SERVER_NAME'], port) |
170 urlbase = r'%s://%s%s' % (proto, req.env[r'SERVER_NAME'], port) |
171 logourl = self.config('web', 'logourl') |
171 logourl = self.config('web', 'logourl') |
172 logoimg = self.config('web', 'logoimg') |
172 logoimg = self.config('web', 'logoimg') |
173 staticurl = self.config('web', 'staticurl') or req.url + 'static/' |
173 staticurl = self.config('web', 'staticurl') or req.url + 'static/' |
174 if not staticurl.endswith('/'): |
174 if not staticurl.endswith('/'): |
175 staticurl += '/' |
175 staticurl += '/' |
339 req.headers.append(('Content-Security-Policy', rctx.csp)) |
339 req.headers.append(('Content-Security-Policy', rctx.csp)) |
340 |
340 |
341 # work with CGI variables to create coherent structure |
341 # work with CGI variables to create coherent structure |
342 # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME |
342 # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME |
343 |
343 |
344 req.url = req.env['SCRIPT_NAME'] |
344 req.url = req.env[r'SCRIPT_NAME'] |
345 if not req.url.endswith('/'): |
345 if not req.url.endswith('/'): |
346 req.url += '/' |
346 req.url += '/' |
347 if req.env.get('REPO_NAME'): |
347 if req.env.get('REPO_NAME'): |
348 req.url += req.env['REPO_NAME'] + '/' |
348 req.url += req.env[r'REPO_NAME'] + r'/' |
349 |
349 |
350 if 'PATH_INFO' in req.env: |
350 if r'PATH_INFO' in req.env: |
351 parts = req.env['PATH_INFO'].strip('/').split('/') |
351 parts = req.env[r'PATH_INFO'].strip('/').split('/') |
352 repo_parts = req.env.get('REPO_NAME', '').split('/') |
352 repo_parts = req.env.get(r'REPO_NAME', r'').split(r'/') |
353 if parts[:len(repo_parts)] == repo_parts: |
353 if parts[:len(repo_parts)] == repo_parts: |
354 parts = parts[len(repo_parts):] |
354 parts = parts[len(repo_parts):] |
355 query = '/'.join(parts) |
355 query = '/'.join(parts) |
356 else: |
356 else: |
357 query = req.env['QUERY_STRING'].partition('&')[0] |
357 query = req.env[r'QUERY_STRING'].partition(r'&')[0] |
358 query = query.partition(';')[0] |
358 query = query.partition(r';')[0] |
359 |
359 |
360 # process this if it's a protocol request |
360 # process this if it's a protocol request |
361 # protocol bits don't need to create any URLs |
361 # protocol bits don't need to create any URLs |
362 # and the clients always use the old URL structure |
362 # and the clients always use the old URL structure |
363 |
363 |
364 cmd = req.form.get('cmd', [''])[0] |
364 cmd = pycompat.sysbytes(req.form.get(r'cmd', [r''])[0]) |
365 if protocol.iscmd(cmd): |
365 if protocol.iscmd(cmd): |
366 try: |
366 try: |
367 if query: |
367 if query: |
368 raise ErrorResponse(HTTP_NOT_FOUND) |
368 raise ErrorResponse(HTTP_NOT_FOUND) |
369 if cmd in perms: |
369 if cmd in perms: |
384 return '' |
384 return '' |
385 |
385 |
386 # translate user-visible url structure to internal structure |
386 # translate user-visible url structure to internal structure |
387 |
387 |
388 args = query.split('/', 2) |
388 args = query.split('/', 2) |
389 if 'cmd' not in req.form and args and args[0]: |
389 if r'cmd' not in req.form and args and args[0]: |
390 |
|
391 cmd = args.pop(0) |
390 cmd = args.pop(0) |
392 style = cmd.rfind('-') |
391 style = cmd.rfind('-') |
393 if style != -1: |
392 if style != -1: |
394 req.form['style'] = [cmd[:style]] |
393 req.form['style'] = [cmd[:style]] |
395 cmd = cmd[style + 1:] |
394 cmd = cmd[style + 1:] |
396 |
395 |
397 # avoid accepting e.g. style parameter as command |
396 # avoid accepting e.g. style parameter as command |
398 if util.safehasattr(webcommands, cmd): |
397 if util.safehasattr(webcommands, cmd): |
399 req.form['cmd'] = [cmd] |
398 req.form[r'cmd'] = [cmd] |
400 |
399 |
401 if cmd == 'static': |
400 if cmd == 'static': |
402 req.form['file'] = ['/'.join(args)] |
401 req.form['file'] = ['/'.join(args)] |
403 else: |
402 else: |
404 if args and args[0]: |
403 if args and args[0]: |
429 # check read permissions non-static content |
428 # check read permissions non-static content |
430 if cmd != 'static': |
429 if cmd != 'static': |
431 self.check_perm(rctx, req, None) |
430 self.check_perm(rctx, req, None) |
432 |
431 |
433 if cmd == '': |
432 if cmd == '': |
434 req.form['cmd'] = [tmpl.cache['default']] |
433 req.form[r'cmd'] = [tmpl.cache['default']] |
435 cmd = req.form['cmd'][0] |
434 cmd = req.form[r'cmd'][0] |
436 |
435 |
437 # Don't enable caching if using a CSP nonce because then it wouldn't |
436 # Don't enable caching if using a CSP nonce because then it wouldn't |
438 # be a nonce. |
437 # be a nonce. |
439 if rctx.configbool('web', 'cache') and not rctx.nonce: |
438 if rctx.configbool('web', 'cache') and not rctx.nonce: |
440 caching(self, req) # sets ETag header or raises NOT_MODIFIED |
439 caching(self, req) # sets ETag header or raises NOT_MODIFIED |
441 if cmd not in webcommands.__all__: |
440 if cmd not in webcommands.__all__: |
442 msg = 'no such method: %s' % cmd |
441 msg = 'no such method: %s' % cmd |
443 raise ErrorResponse(HTTP_BAD_REQUEST, msg) |
442 raise ErrorResponse(HTTP_BAD_REQUEST, msg) |
444 elif cmd == 'file' and 'raw' in req.form.get('style', []): |
443 elif cmd == 'file' and r'raw' in req.form.get(r'style', []): |
445 rctx.ctype = ctype |
444 rctx.ctype = ctype |
446 content = webcommands.rawfile(rctx, req, tmpl) |
445 content = webcommands.rawfile(rctx, req, tmpl) |
447 else: |
446 else: |
448 content = getattr(webcommands, cmd)(rctx, req, tmpl) |
447 content = getattr(webcommands, cmd)(rctx, req, tmpl) |
449 req.respond(HTTP_OK, ctype) |
448 req.respond(HTTP_OK, ctype) |