Mercurial > public > mercurial-scm > hg
comparison mercurial/hgweb/hgweb_mod.py @ 36878:ccb70a77f746
hgweb: refactor 304 handling code
We had generic code in wsgirequest for handling HTTP 304 responses.
We also had a special case for it in the catch all exception handler
in the WSGI application.
We only ever raise 304 in one place. So, we don't need to treat it
specially in the catch all exception handler.
But it is useful to validate behavior of 304 responses. We port the
code that sends a 304 to use the new response API. We then move the
code for screening 304 sanity into the new response API.
As part of doing so, we discovered that we would send
Content-Length: 0. This is not allowed. So, we fix our response code
to not emit that header for empty response bodies.
Differential Revision: https://phab.mercurial-scm.org/D2794
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Sat, 10 Mar 2018 18:42:00 -0800 |
parents | 02bea04b4c54 |
children | 9675147aec06 |
comparison
equal
deleted
inserted
replaced
36877:02bea04b4c54 | 36878:ccb70a77f746 |
---|---|
13 | 13 |
14 from .common import ( | 14 from .common import ( |
15 ErrorResponse, | 15 ErrorResponse, |
16 HTTP_BAD_REQUEST, | 16 HTTP_BAD_REQUEST, |
17 HTTP_NOT_FOUND, | 17 HTTP_NOT_FOUND, |
18 HTTP_NOT_MODIFIED, | |
19 HTTP_OK, | 18 HTTP_OK, |
20 HTTP_SERVER_ERROR, | 19 HTTP_SERVER_ERROR, |
21 cspvalues, | 20 cspvalues, |
22 permhooks, | 21 permhooks, |
23 ) | 22 ) |
389 # Don't enable caching if using a CSP nonce because then it wouldn't | 388 # Don't enable caching if using a CSP nonce because then it wouldn't |
390 # be a nonce. | 389 # be a nonce. |
391 if rctx.configbool('web', 'cache') and not rctx.nonce: | 390 if rctx.configbool('web', 'cache') and not rctx.nonce: |
392 tag = 'W/"%d"' % self.mtime | 391 tag = 'W/"%d"' % self.mtime |
393 if req.headers.get('If-None-Match') == tag: | 392 if req.headers.get('If-None-Match') == tag: |
394 raise ErrorResponse(HTTP_NOT_MODIFIED) | 393 res.status = '304 Not Modified' |
394 # Response body not allowed on 304. | |
395 res.setbodybytes('') | |
396 return res.sendresponse() | |
395 | 397 |
396 wsgireq.headers.append((r'ETag', pycompat.sysstr(tag))) | 398 wsgireq.headers.append((r'ETag', pycompat.sysstr(tag))) |
397 res.headers['ETag'] = tag | 399 res.headers['ETag'] = tag |
398 | 400 |
399 if cmd not in webcommands.__all__: | 401 if cmd not in webcommands.__all__: |
424 except (error.RepoError, error.RevlogError) as inst: | 426 except (error.RepoError, error.RevlogError) as inst: |
425 wsgireq.respond(HTTP_SERVER_ERROR, ctype) | 427 wsgireq.respond(HTTP_SERVER_ERROR, ctype) |
426 return tmpl('error', error=pycompat.bytestr(inst)) | 428 return tmpl('error', error=pycompat.bytestr(inst)) |
427 except ErrorResponse as inst: | 429 except ErrorResponse as inst: |
428 wsgireq.respond(inst, ctype) | 430 wsgireq.respond(inst, ctype) |
429 if inst.code == HTTP_NOT_MODIFIED: | |
430 # Not allowed to return a body on a 304 | |
431 return [''] | |
432 return tmpl('error', error=pycompat.bytestr(inst)) | 431 return tmpl('error', error=pycompat.bytestr(inst)) |
433 | 432 |
434 def check_perm(self, rctx, req, op): | 433 def check_perm(self, rctx, req, op): |
435 for permhook in permhooks: | 434 for permhook in permhooks: |
436 permhook(rctx, req, op) | 435 permhook(rctx, req, op) |