##// END OF EJS Templates
hgweb: rename req to wsgireq...
Gregory Szorc -
r36822:b9b968e2 default
parent child Browse files
Show More
@@ -22,7 +22,6 b' from .common import ('
22 22 cspvalues,
23 23 permhooks,
24 24 )
25 from .request import wsgirequest
26 25
27 26 from .. import (
28 27 encoding,
@@ -41,6 +40,7 b' from .. import ('
41 40 )
42 41
43 42 from . import (
43 request as requestmod,
44 44 webcommands,
45 45 webutil,
46 46 wsgicgi,
@@ -142,11 +142,11 b' class requestcontext(object):'
142 142 if typ in allowed or self.configbool('web', 'allow%s' % typ):
143 143 yield {'type': typ, 'extension': spec[2], 'node': nodeid}
144 144
145 def templater(self, req):
145 def templater(self, wsgireq):
146 146 # determine scheme, port and server name
147 147 # this is needed to create absolute urls
148 148
149 proto = req.env.get('wsgi.url_scheme')
149 proto = wsgireq.env.get('wsgi.url_scheme')
150 150 if proto == 'https':
151 151 proto = 'https'
152 152 default_port = '443'
@@ -154,13 +154,13 b' class requestcontext(object):'
154 154 proto = 'http'
155 155 default_port = '80'
156 156
157 port = req.env[r'SERVER_PORT']
157 port = wsgireq.env[r'SERVER_PORT']
158 158 port = port != default_port and (r':' + port) or r''
159 urlbase = r'%s://%s%s' % (proto, req.env[r'SERVER_NAME'], port)
159 urlbase = r'%s://%s%s' % (proto, wsgireq.env[r'SERVER_NAME'], port)
160 160 logourl = self.config('web', 'logourl')
161 161 logoimg = self.config('web', 'logoimg')
162 162 staticurl = (self.config('web', 'staticurl')
163 or pycompat.sysbytes(req.url) + 'static/')
163 or pycompat.sysbytes(wsgireq.url) + 'static/')
164 164 if not staticurl.endswith('/'):
165 165 staticurl += '/'
166 166
@@ -172,18 +172,18 b' class requestcontext(object):'
172 172 # figure out which style to use
173 173
174 174 vars = {}
175 styles, (style, mapfile) = getstyle(req, self.config,
175 styles, (style, mapfile) = getstyle(wsgireq, self.config,
176 176 self.templatepath)
177 177 if style == styles[0]:
178 178 vars['style'] = style
179 179
180 start = '&' if req.url[-1] == r'?' else '?'
180 start = '&' if wsgireq.url[-1] == r'?' else '?'
181 181 sessionvars = webutil.sessionvars(vars, start)
182 182
183 183 if not self.reponame:
184 184 self.reponame = (self.config('web', 'name', '')
185 or req.env.get('REPO_NAME')
186 or req.url.strip(r'/') or self.repo.root)
185 or wsgireq.env.get('REPO_NAME')
186 or wsgireq.url.strip(r'/') or self.repo.root)
187 187
188 188 def websubfilter(text):
189 189 return templatefilters.websub(text, self.websubtable)
@@ -191,7 +191,7 b' class requestcontext(object):'
191 191 # create the templater
192 192 # TODO: export all keywords: defaults = templatekw.keywords.copy()
193 193 defaults = {
194 'url': pycompat.sysbytes(req.url),
194 'url': pycompat.sysbytes(wsgireq.url),
195 195 'logourl': logourl,
196 196 'logoimg': logoimg,
197 197 'staticurl': staticurl,
@@ -200,7 +200,7 b' class requestcontext(object):'
200 200 'encoding': encoding.encoding,
201 201 'motd': motd,
202 202 'sessionvars': sessionvars,
203 'pathdef': makebreadcrumb(pycompat.sysbytes(req.url)),
203 'pathdef': makebreadcrumb(pycompat.sysbytes(wsgireq.url)),
204 204 'style': style,
205 205 'nonce': self.nonce,
206 206 }
@@ -301,10 +301,10 b' class hgweb(object):'
301 301
302 302 This may be called by multiple threads.
303 303 """
304 req = wsgirequest(env, respond)
304 req = requestmod.wsgirequest(env, respond)
305 305 return self.run_wsgi(req)
306 306
307 def run_wsgi(self, req):
307 def run_wsgi(self, wsgireq):
308 308 """Internal method to run the WSGI application.
309 309
310 310 This is typically only called by Mercurial. External consumers
@@ -313,45 +313,45 b' class hgweb(object):'
313 313 with self._obtainrepo() as repo:
314 314 profile = repo.ui.configbool('profiling', 'enabled')
315 315 with profiling.profile(repo.ui, enabled=profile):
316 for r in self._runwsgi(req, repo):
316 for r in self._runwsgi(wsgireq, repo):
317 317 yield r
318 318
319 def _runwsgi(self, req, repo):
319 def _runwsgi(self, wsgireq, repo):
320 320 rctx = requestcontext(self, repo)
321 321
322 322 # This state is global across all threads.
323 323 encoding.encoding = rctx.config('web', 'encoding')
324 rctx.repo.ui.environ = req.env
324 rctx.repo.ui.environ = wsgireq.env
325 325
326 326 if rctx.csp:
327 327 # hgwebdir may have added CSP header. Since we generate our own,
328 328 # replace it.
329 req.headers = [h for h in req.headers
330 if h[0] != 'Content-Security-Policy']
331 req.headers.append(('Content-Security-Policy', rctx.csp))
329 wsgireq.headers = [h for h in wsgireq.headers
330 if h[0] != 'Content-Security-Policy']
331 wsgireq.headers.append(('Content-Security-Policy', rctx.csp))
332 332
333 333 # work with CGI variables to create coherent structure
334 334 # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME
335 335
336 req.url = req.env[r'SCRIPT_NAME']
337 if not req.url.endswith(r'/'):
338 req.url += r'/'
339 if req.env.get('REPO_NAME'):
340 req.url += req.env[r'REPO_NAME'] + r'/'
336 wsgireq.url = wsgireq.env[r'SCRIPT_NAME']
337 if not wsgireq.url.endswith(r'/'):
338 wsgireq.url += r'/'
339 if wsgireq.env.get('REPO_NAME'):
340 wsgireq.url += wsgireq.env[r'REPO_NAME'] + r'/'
341 341
342 if r'PATH_INFO' in req.env:
343 parts = req.env[r'PATH_INFO'].strip(r'/').split(r'/')
344 repo_parts = req.env.get(r'REPO_NAME', r'').split(r'/')
342 if r'PATH_INFO' in wsgireq.env:
343 parts = wsgireq.env[r'PATH_INFO'].strip(r'/').split(r'/')
344 repo_parts = wsgireq.env.get(r'REPO_NAME', r'').split(r'/')
345 345 if parts[:len(repo_parts)] == repo_parts:
346 346 parts = parts[len(repo_parts):]
347 347 query = r'/'.join(parts)
348 348 else:
349 query = req.env[r'QUERY_STRING'].partition(r'&')[0]
349 query = wsgireq.env[r'QUERY_STRING'].partition(r'&')[0]
350 350 query = query.partition(r';')[0]
351 351
352 352 # Route it to a wire protocol handler if it looks like a wire protocol
353 353 # request.
354 protohandler = wireprotoserver.parsehttprequest(rctx, req, query,
354 protohandler = wireprotoserver.parsehttprequest(rctx, wsgireq, query,
355 355 self.check_perm)
356 356
357 357 if protohandler:
@@ -366,83 +366,83 b' class hgweb(object):'
366 366 # translate user-visible url structure to internal structure
367 367
368 368 args = query.split(r'/', 2)
369 if 'cmd' not in req.form and args and args[0]:
369 if 'cmd' not in wsgireq.form and args and args[0]:
370 370 cmd = args.pop(0)
371 371 style = cmd.rfind('-')
372 372 if style != -1:
373 req.form['style'] = [cmd[:style]]
373 wsgireq.form['style'] = [cmd[:style]]
374 374 cmd = cmd[style + 1:]
375 375
376 376 # avoid accepting e.g. style parameter as command
377 377 if util.safehasattr(webcommands, cmd):
378 req.form['cmd'] = [cmd]
378 wsgireq.form['cmd'] = [cmd]
379 379
380 380 if cmd == 'static':
381 req.form['file'] = ['/'.join(args)]
381 wsgireq.form['file'] = ['/'.join(args)]
382 382 else:
383 383 if args and args[0]:
384 384 node = args.pop(0).replace('%2F', '/')
385 req.form['node'] = [node]
385 wsgireq.form['node'] = [node]
386 386 if args:
387 req.form['file'] = args
387 wsgireq.form['file'] = args
388 388
389 ua = req.env.get('HTTP_USER_AGENT', '')
389 ua = wsgireq.env.get('HTTP_USER_AGENT', '')
390 390 if cmd == 'rev' and 'mercurial' in ua:
391 req.form['style'] = ['raw']
391 wsgireq.form['style'] = ['raw']
392 392
393 393 if cmd == 'archive':
394 fn = req.form['node'][0]
394 fn = wsgireq.form['node'][0]
395 395 for type_, spec in rctx.archivespecs.iteritems():
396 396 ext = spec[2]
397 397 if fn.endswith(ext):
398 req.form['node'] = [fn[:-len(ext)]]
399 req.form['type'] = [type_]
398 wsgireq.form['node'] = [fn[:-len(ext)]]
399 wsgireq.form['type'] = [type_]
400 400 else:
401 cmd = req.form.get('cmd', [''])[0]
401 cmd = wsgireq.form.get('cmd', [''])[0]
402 402
403 403 # process the web interface request
404 404
405 405 try:
406 tmpl = rctx.templater(req)
406 tmpl = rctx.templater(wsgireq)
407 407 ctype = tmpl('mimetype', encoding=encoding.encoding)
408 408 ctype = templater.stringify(ctype)
409 409
410 410 # check read permissions non-static content
411 411 if cmd != 'static':
412 self.check_perm(rctx, req, None)
412 self.check_perm(rctx, wsgireq, None)
413 413
414 414 if cmd == '':
415 req.form['cmd'] = [tmpl.cache['default']]
416 cmd = req.form['cmd'][0]
415 wsgireq.form['cmd'] = [tmpl.cache['default']]
416 cmd = wsgireq.form['cmd'][0]
417 417
418 418 # Don't enable caching if using a CSP nonce because then it wouldn't
419 419 # be a nonce.
420 420 if rctx.configbool('web', 'cache') and not rctx.nonce:
421 caching(self, req) # sets ETag header or raises NOT_MODIFIED
421 caching(self, wsgireq) # sets ETag header or raises NOT_MODIFIED
422 422 if cmd not in webcommands.__all__:
423 423 msg = 'no such method: %s' % cmd
424 424 raise ErrorResponse(HTTP_BAD_REQUEST, msg)
425 elif cmd == 'file' and 'raw' in req.form.get('style', []):
425 elif cmd == 'file' and 'raw' in wsgireq.form.get('style', []):
426 426 rctx.ctype = ctype
427 content = webcommands.rawfile(rctx, req, tmpl)
427 content = webcommands.rawfile(rctx, wsgireq, tmpl)
428 428 else:
429 content = getattr(webcommands, cmd)(rctx, req, tmpl)
430 req.respond(HTTP_OK, ctype)
429 content = getattr(webcommands, cmd)(rctx, wsgireq, tmpl)
430 wsgireq.respond(HTTP_OK, ctype)
431 431
432 432 return content
433 433
434 434 except (error.LookupError, error.RepoLookupError) as err:
435 req.respond(HTTP_NOT_FOUND, ctype)
435 wsgireq.respond(HTTP_NOT_FOUND, ctype)
436 436 msg = pycompat.bytestr(err)
437 437 if (util.safehasattr(err, 'name') and
438 438 not isinstance(err, error.ManifestLookupError)):
439 439 msg = 'revision not found: %s' % err.name
440 440 return tmpl('error', error=msg)
441 441 except (error.RepoError, error.RevlogError) as inst:
442 req.respond(HTTP_SERVER_ERROR, ctype)
442 wsgireq.respond(HTTP_SERVER_ERROR, ctype)
443 443 return tmpl('error', error=pycompat.bytestr(inst))
444 444 except ErrorResponse as inst:
445 req.respond(inst, ctype)
445 wsgireq.respond(inst, ctype)
446 446 if inst.code == HTTP_NOT_MODIFIED:
447 447 # Not allowed to return a body on a 304
448 448 return ['']
@@ -26,7 +26,6 b' from .common import ('
26 26 paritygen,
27 27 staticfile,
28 28 )
29 from .request import wsgirequest
30 29
31 30 from .. import (
32 31 configitems,
@@ -43,6 +42,7 b' from .. import ('
43 42
44 43 from . import (
45 44 hgweb_mod,
45 request as requestmod,
46 46 webutil,
47 47 wsgicgi,
48 48 )
@@ -197,10 +197,10 b' class hgwebdir(object):'
197 197 wsgicgi.launch(self)
198 198
199 199 def __call__(self, env, respond):
200 req = wsgirequest(env, respond)
201 return self.run_wsgi(req)
200 wsgireq = requestmod.wsgirequest(env, respond)
201 return self.run_wsgi(wsgireq)
202 202
203 def read_allowed(self, ui, req):
203 def read_allowed(self, ui, wsgireq):
204 204 """Check allow_read and deny_read config options of a repo's ui object
205 205 to determine user permissions. By default, with neither option set (or
206 206 both empty), allow all users to read the repo. There are two ways a
@@ -209,7 +209,7 b' class hgwebdir(object):'
209 209 allow_read is not empty and the user is not in allow_read. Return True
210 210 if user is allowed to read the repo, else return False."""
211 211
212 user = req.env.get('REMOTE_USER')
212 user = wsgireq.env.get('REMOTE_USER')
213 213
214 214 deny_read = ui.configlist('web', 'deny_read', untrusted=True)
215 215 if deny_read and (not user or ismember(ui, user, deny_read)):
@@ -222,31 +222,31 b' class hgwebdir(object):'
222 222
223 223 return False
224 224
225 def run_wsgi(self, req):
225 def run_wsgi(self, wsgireq):
226 226 profile = self.ui.configbool('profiling', 'enabled')
227 227 with profiling.profile(self.ui, enabled=profile):
228 for r in self._runwsgi(req):
228 for r in self._runwsgi(wsgireq):
229 229 yield r
230 230
231 def _runwsgi(self, req):
231 def _runwsgi(self, wsgireq):
232 232 try:
233 233 self.refresh()
234 234
235 235 csp, nonce = cspvalues(self.ui)
236 236 if csp:
237 req.headers.append(('Content-Security-Policy', csp))
237 wsgireq.headers.append(('Content-Security-Policy', csp))
238 238
239 virtual = req.env.get("PATH_INFO", "").strip('/')
240 tmpl = self.templater(req, nonce)
239 virtual = wsgireq.env.get("PATH_INFO", "").strip('/')
240 tmpl = self.templater(wsgireq, nonce)
241 241 ctype = tmpl('mimetype', encoding=encoding.encoding)
242 242 ctype = templater.stringify(ctype)
243 243
244 244 # a static file
245 if virtual.startswith('static/') or 'static' in req.form:
245 if virtual.startswith('static/') or 'static' in wsgireq.form:
246 246 if virtual.startswith('static/'):
247 247 fname = virtual[7:]
248 248 else:
249 fname = req.form['static'][0]
249 fname = wsgireq.form['static'][0]
250 250 static = self.ui.config("web", "static", None,
251 251 untrusted=False)
252 252 if not static:
@@ -254,7 +254,7 b' class hgwebdir(object):'
254 254 if isinstance(tp, str):
255 255 tp = [tp]
256 256 static = [os.path.join(p, 'static') for p in tp]
257 staticfile(static, fname, req)
257 staticfile(static, fname, wsgireq)
258 258 return []
259 259
260 260 # top-level index
@@ -262,16 +262,16 b' class hgwebdir(object):'
262 262 repos = dict(self.repos)
263 263
264 264 if (not virtual or virtual == 'index') and virtual not in repos:
265 req.respond(HTTP_OK, ctype)
266 return self.makeindex(req, tmpl)
265 wsgireq.respond(HTTP_OK, ctype)
266 return self.makeindex(wsgireq, tmpl)
267 267
268 268 # nested indexes and hgwebs
269 269
270 270 if virtual.endswith('/index') and virtual not in repos:
271 271 subdir = virtual[:-len('index')]
272 272 if any(r.startswith(subdir) for r in repos):
273 req.respond(HTTP_OK, ctype)
274 return self.makeindex(req, tmpl, subdir)
273 wsgireq.respond(HTTP_OK, ctype)
274 return self.makeindex(wsgireq, tmpl, subdir)
275 275
276 276 def _virtualdirs():
277 277 # Check the full virtual path, each parent, and the root ('')
@@ -286,11 +286,11 b' class hgwebdir(object):'
286 286 for virtualrepo in _virtualdirs():
287 287 real = repos.get(virtualrepo)
288 288 if real:
289 req.env['REPO_NAME'] = virtualrepo
289 wsgireq.env['REPO_NAME'] = virtualrepo
290 290 try:
291 291 # ensure caller gets private copy of ui
292 292 repo = hg.repository(self.ui.copy(), real)
293 return hgweb_mod.hgweb(repo).run_wsgi(req)
293 return hgweb_mod.hgweb(repo).run_wsgi(wsgireq)
294 294 except IOError as inst:
295 295 msg = encoding.strtolocal(inst.strerror)
296 296 raise ErrorResponse(HTTP_SERVER_ERROR, msg)
@@ -300,20 +300,20 b' class hgwebdir(object):'
300 300 # browse subdirectories
301 301 subdir = virtual + '/'
302 302 if [r for r in repos if r.startswith(subdir)]:
303 req.respond(HTTP_OK, ctype)
304 return self.makeindex(req, tmpl, subdir)
303 wsgireq.respond(HTTP_OK, ctype)
304 return self.makeindex(wsgireq, tmpl, subdir)
305 305
306 306 # prefixes not found
307 req.respond(HTTP_NOT_FOUND, ctype)
307 wsgireq.respond(HTTP_NOT_FOUND, ctype)
308 308 return tmpl("notfound", repo=virtual)
309 309
310 310 except ErrorResponse as err:
311 req.respond(err, ctype)
311 wsgireq.respond(err, ctype)
312 312 return tmpl('error', error=err.message or '')
313 313 finally:
314 314 tmpl = None
315 315
316 def makeindex(self, req, tmpl, subdir=""):
316 def makeindex(self, wsgireq, tmpl, subdir=""):
317 317
318 318 def archivelist(ui, nodeid, url):
319 319 allowed = ui.configlist("web", "allow_archive", untrusted=True)
@@ -369,8 +369,8 b' class hgwebdir(object):'
369 369
370 370 parts = [name]
371 371 parts.insert(0, '/' + subdir.rstrip('/'))
372 if req.env['SCRIPT_NAME']:
373 parts.insert(0, req.env['SCRIPT_NAME'])
372 if wsgireq.env['SCRIPT_NAME']:
373 parts.insert(0, wsgireq.env['SCRIPT_NAME'])
374 374 url = re.sub(r'/+', '/', '/'.join(parts) + '/')
375 375
376 376 # show either a directory entry or a repository
@@ -413,7 +413,7 b' class hgwebdir(object):'
413 413 if u.configbool("web", "hidden", untrusted=True):
414 414 continue
415 415
416 if not self.read_allowed(u, req):
416 if not self.read_allowed(u, wsgireq):
417 417 continue
418 418
419 419 # update time with local timezone
@@ -465,8 +465,8 b' class hgwebdir(object):'
465 465 self.refresh()
466 466 sortable = ["name", "description", "contact", "lastchange"]
467 467 sortcolumn, descending = sortdefault
468 if 'sort' in req.form:
469 sortcolumn = req.form['sort'][0]
468 if 'sort' in wsgireq.form:
469 sortcolumn = wsgireq.form['sort'][0]
470 470 descending = sortcolumn.startswith('-')
471 471 if descending:
472 472 sortcolumn = sortcolumn[1:]
@@ -479,14 +479,14 b' class hgwebdir(object):'
479 479 for column in sortable]
480 480
481 481 self.refresh()
482 self.updatereqenv(req.env)
482 self.updatereqenv(wsgireq.env)
483 483
484 484 return tmpl("index", entries=entries, subdir=subdir,
485 485 pathdef=hgweb_mod.makebreadcrumb('/' + subdir, self.prefix),
486 486 sortcolumn=sortcolumn, descending=descending,
487 487 **dict(sort))
488 488
489 def templater(self, req, nonce):
489 def templater(self, wsgireq, nonce):
490 490
491 491 def motd(**map):
492 492 if self.motd is not None:
@@ -497,14 +497,14 b' class hgwebdir(object):'
497 497 def config(section, name, default=uimod._unset, untrusted=True):
498 498 return self.ui.config(section, name, default, untrusted)
499 499
500 self.updatereqenv(req.env)
500 self.updatereqenv(wsgireq.env)
501 501
502 url = req.env.get('SCRIPT_NAME', '')
502 url = wsgireq.env.get('SCRIPT_NAME', '')
503 503 if not url.endswith('/'):
504 504 url += '/'
505 505
506 506 vars = {}
507 styles, (style, mapfile) = hgweb_mod.getstyle(req, config,
507 styles, (style, mapfile) = hgweb_mod.getstyle(wsgireq, config,
508 508 self.templatepath)
509 509 if style == styles[0]:
510 510 vars['style'] = style
@@ -36,7 +36,7 b" HGERRTYPE = 'application/hg-error'"
36 36 SSHV1 = wireprototypes.SSHV1
37 37 SSHV2 = wireprototypes.SSHV2
38 38
39 def decodevaluefromheaders(req, headerprefix):
39 def decodevaluefromheaders(wsgireq, headerprefix):
40 40 """Decode a long value from multiple HTTP request headers.
41 41
42 42 Returns the value as a bytes, not a str.
@@ -45,7 +45,7 b' def decodevaluefromheaders(req, headerpr'
45 45 i = 1
46 46 prefix = headerprefix.upper().replace(r'-', r'_')
47 47 while True:
48 v = req.env.get(r'HTTP_%s_%d' % (prefix, i))
48 v = wsgireq.env.get(r'HTTP_%s_%d' % (prefix, i))
49 49 if v is None:
50 50 break
51 51 chunks.append(pycompat.bytesurl(v))
@@ -54,8 +54,8 b' def decodevaluefromheaders(req, headerpr'
54 54 return ''.join(chunks)
55 55
56 56 class httpv1protocolhandler(wireprototypes.baseprotocolhandler):
57 def __init__(self, req, ui, checkperm):
58 self._req = req
57 def __init__(self, wsgireq, ui, checkperm):
58 self._wsgireq = wsgireq
59 59 self._ui = ui
60 60 self._checkperm = checkperm
61 61
@@ -79,26 +79,26 b' class httpv1protocolhandler(wireprototyp'
79 79 return [data[k] for k in keys]
80 80
81 81 def _args(self):
82 args = util.rapply(pycompat.bytesurl, self._req.form.copy())
83 postlen = int(self._req.env.get(r'HTTP_X_HGARGS_POST', 0))
82 args = util.rapply(pycompat.bytesurl, self._wsgireq.form.copy())
83 postlen = int(self._wsgireq.env.get(r'HTTP_X_HGARGS_POST', 0))
84 84 if postlen:
85 85 args.update(urlreq.parseqs(
86 self._req.read(postlen), keep_blank_values=True))
86 self._wsgireq.read(postlen), keep_blank_values=True))
87 87 return args
88 88
89 argvalue = decodevaluefromheaders(self._req, r'X-HgArg')
89 argvalue = decodevaluefromheaders(self._wsgireq, r'X-HgArg')
90 90 args.update(urlreq.parseqs(argvalue, keep_blank_values=True))
91 91 return args
92 92
93 93 def forwardpayload(self, fp):
94 if r'HTTP_CONTENT_LENGTH' in self._req.env:
95 length = int(self._req.env[r'HTTP_CONTENT_LENGTH'])
94 if r'HTTP_CONTENT_LENGTH' in self._wsgireq.env:
95 length = int(self._wsgireq.env[r'HTTP_CONTENT_LENGTH'])
96 96 else:
97 length = int(self._req.env[r'CONTENT_LENGTH'])
97 length = int(self._wsgireq.env[r'CONTENT_LENGTH'])
98 98 # If httppostargs is used, we need to read Content-Length
99 99 # minus the amount that was consumed by args.
100 length -= int(self._req.env.get(r'HTTP_X_HGARGS_POST', 0))
101 for s in util.filechunkiter(self._req, limit=length):
100 length -= int(self._wsgireq.env.get(r'HTTP_X_HGARGS_POST', 0))
101 for s in util.filechunkiter(self._wsgireq, limit=length):
102 102 fp.write(s)
103 103
104 104 @contextlib.contextmanager
@@ -118,9 +118,9 b' class httpv1protocolhandler(wireprototyp'
118 118
119 119 def client(self):
120 120 return 'remote:%s:%s:%s' % (
121 self._req.env.get('wsgi.url_scheme') or 'http',
122 urlreq.quote(self._req.env.get('REMOTE_HOST', '')),
123 urlreq.quote(self._req.env.get('REMOTE_USER', '')))
121 self._wsgireq.env.get('wsgi.url_scheme') or 'http',
122 urlreq.quote(self._wsgireq.env.get('REMOTE_HOST', '')),
123 urlreq.quote(self._wsgireq.env.get('REMOTE_USER', '')))
124 124
125 125 def addcapabilities(self, repo, caps):
126 126 caps.append('httpheader=%d' %
@@ -150,7 +150,7 b' class httpv1protocolhandler(wireprototyp'
150 150 def iscmd(cmd):
151 151 return cmd in wireproto.commands
152 152
153 def parsehttprequest(rctx, req, query, checkperm):
153 def parsehttprequest(rctx, wsgireq, query, checkperm):
154 154 """Parse the HTTP request for a wire protocol request.
155 155
156 156 If the current request appears to be a wire protocol request, this
@@ -158,17 +158,17 b' def parsehttprequest(rctx, req, query, c'
158 158 an ``abstractprotocolserver`` instance suitable for handling the
159 159 request. Otherwise, ``None`` is returned.
160 160
161 ``req`` is a ``wsgirequest`` instance.
161 ``wsgireq`` is a ``wsgirequest`` instance.
162 162 """
163 163 repo = rctx.repo
164 164
165 165 # HTTP version 1 wire protocol requests are denoted by a "cmd" query
166 166 # string parameter. If it isn't present, this isn't a wire protocol
167 167 # request.
168 if 'cmd' not in req.form:
168 if 'cmd' not in wsgireq.form:
169 169 return None
170 170
171 cmd = req.form['cmd'][0]
171 cmd = wsgireq.form['cmd'][0]
172 172
173 173 # The "cmd" request parameter is used by both the wire protocol and hgweb.
174 174 # While not all wire protocol commands are available for all transports,
@@ -180,24 +180,24 b' def parsehttprequest(rctx, req, query, c'
180 180 if not iscmd(cmd):
181 181 return None
182 182
183 proto = httpv1protocolhandler(req, repo.ui,
184 lambda perm: checkperm(rctx, req, perm))
183 proto = httpv1protocolhandler(wsgireq, repo.ui,
184 lambda perm: checkperm(rctx, wsgireq, perm))
185 185
186 186 return {
187 187 'cmd': cmd,
188 188 'proto': proto,
189 'dispatch': lambda: _callhttp(repo, req, proto, cmd),
190 'handleerror': lambda ex: _handlehttperror(ex, req, cmd),
189 'dispatch': lambda: _callhttp(repo, wsgireq, proto, cmd),
190 'handleerror': lambda ex: _handlehttperror(ex, wsgireq, cmd),
191 191 }
192 192
193 def _httpresponsetype(ui, req, prefer_uncompressed):
193 def _httpresponsetype(ui, wsgireq, prefer_uncompressed):
194 194 """Determine the appropriate response type and compression settings.
195 195
196 196 Returns a tuple of (mediatype, compengine, engineopts).
197 197 """
198 198 # Determine the response media type and compression engine based
199 199 # on the request parameters.
200 protocaps = decodevaluefromheaders(req, r'X-HgProto').split(' ')
200 protocaps = decodevaluefromheaders(wsgireq, r'X-HgProto').split(' ')
201 201
202 202 if '0.2' in protocaps:
203 203 # All clients are expected to support uncompressed data.
@@ -230,7 +230,7 b' def _httpresponsetype(ui, req, prefer_un'
230 230 opts = {'level': ui.configint('server', 'zliblevel')}
231 231 return HGTYPE, util.compengines['zlib'], opts
232 232
233 def _callhttp(repo, req, proto, cmd):
233 def _callhttp(repo, wsgireq, proto, cmd):
234 234 def genversion2(gen, engine, engineopts):
235 235 # application/mercurial-0.2 always sends a payload header
236 236 # identifying the compression engine.
@@ -243,9 +243,9 b' def _callhttp(repo, req, proto, cmd):'
243 243 yield chunk
244 244
245 245 if not wireproto.commands.commandavailable(cmd, proto):
246 req.respond(HTTP_OK, HGERRTYPE,
247 body=_('requested wire protocol command is not available '
248 'over HTTP'))
246 wsgireq.respond(HTTP_OK, HGERRTYPE,
247 body=_('requested wire protocol command is not '
248 'available over HTTP'))
249 249 return []
250 250
251 251 proto.checkperm(wireproto.commands[cmd].permission)
@@ -253,14 +253,14 b' def _callhttp(repo, req, proto, cmd):'
253 253 rsp = wireproto.dispatch(repo, proto, cmd)
254 254
255 255 if isinstance(rsp, bytes):
256 req.respond(HTTP_OK, HGTYPE, body=rsp)
256 wsgireq.respond(HTTP_OK, HGTYPE, body=rsp)
257 257 return []
258 258 elif isinstance(rsp, wireprototypes.bytesresponse):
259 req.respond(HTTP_OK, HGTYPE, body=rsp.data)
259 wsgireq.respond(HTTP_OK, HGTYPE, body=rsp.data)
260 260 return []
261 261 elif isinstance(rsp, wireprototypes.streamreslegacy):
262 262 gen = rsp.gen
263 req.respond(HTTP_OK, HGTYPE)
263 wsgireq.respond(HTTP_OK, HGTYPE)
264 264 return gen
265 265 elif isinstance(rsp, wireprototypes.streamres):
266 266 gen = rsp.gen
@@ -268,32 +268,32 b' def _callhttp(repo, req, proto, cmd):'
268 268 # This code for compression should not be streamres specific. It
269 269 # is here because we only compress streamres at the moment.
270 270 mediatype, engine, engineopts = _httpresponsetype(
271 repo.ui, req, rsp.prefer_uncompressed)
271 repo.ui, wsgireq, rsp.prefer_uncompressed)
272 272 gen = engine.compressstream(gen, engineopts)
273 273
274 274 if mediatype == HGTYPE2:
275 275 gen = genversion2(gen, engine, engineopts)
276 276
277 req.respond(HTTP_OK, mediatype)
277 wsgireq.respond(HTTP_OK, mediatype)
278 278 return gen
279 279 elif isinstance(rsp, wireprototypes.pushres):
280 280 rsp = '%d\n%s' % (rsp.res, rsp.output)
281 req.respond(HTTP_OK, HGTYPE, body=rsp)
281 wsgireq.respond(HTTP_OK, HGTYPE, body=rsp)
282 282 return []
283 283 elif isinstance(rsp, wireprototypes.pusherr):
284 284 # This is the httplib workaround documented in _handlehttperror().
285 req.drain()
285 wsgireq.drain()
286 286
287 287 rsp = '0\n%s\n' % rsp.res
288 req.respond(HTTP_OK, HGTYPE, body=rsp)
288 wsgireq.respond(HTTP_OK, HGTYPE, body=rsp)
289 289 return []
290 290 elif isinstance(rsp, wireprototypes.ooberror):
291 291 rsp = rsp.message
292 req.respond(HTTP_OK, HGERRTYPE, body=rsp)
292 wsgireq.respond(HTTP_OK, HGERRTYPE, body=rsp)
293 293 return []
294 294 raise error.ProgrammingError('hgweb.protocol internal failure', rsp)
295 295
296 def _handlehttperror(e, req, cmd):
296 def _handlehttperror(e, wsgireq, cmd):
297 297 """Called when an ErrorResponse is raised during HTTP request processing."""
298 298
299 299 # Clients using Python's httplib are stateful: the HTTP client
@@ -304,20 +304,20 b' def _handlehttperror(e, req, cmd):'
304 304 # the HTTP response. In other words, it helps prevent deadlocks
305 305 # on clients using httplib.
306 306
307 if (req.env[r'REQUEST_METHOD'] == r'POST' and
307 if (wsgireq.env[r'REQUEST_METHOD'] == r'POST' and
308 308 # But not if Expect: 100-continue is being used.
309 (req.env.get('HTTP_EXPECT',
310 '').lower() != '100-continue') or
309 (wsgireq.env.get('HTTP_EXPECT',
310 '').lower() != '100-continue') or
311 311 # Or the non-httplib HTTP library is being advertised by
312 312 # the client.
313 req.env.get('X-HgHttp2', '')):
314 req.drain()
313 wsgireq.env.get('X-HgHttp2', '')):
314 wsgireq.drain()
315 315 else:
316 req.headers.append((r'Connection', r'Close'))
316 wsgireq.headers.append((r'Connection', r'Close'))
317 317
318 318 # TODO This response body assumes the failed command was
319 319 # "unbundle." That assumption is not always valid.
320 req.respond(e, HGTYPE, body='0\n%s\n' % pycompat.bytestr(e))
320 wsgireq.respond(e, HGTYPE, body='0\n%s\n' % pycompat.bytestr(e))
321 321
322 322 return ''
323 323
General Comments 0
You need to be logged in to leave comments. Login now