##// END OF EJS Templates
hgweb: refactor 304 handling code...
Gregory Szorc -
r36894:ccb70a77 default
parent child Browse files
Show More
@@ -15,7 +15,6 b' 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,
@@ -391,7 +390,10 b' class hgweb(object):'
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
@@ -426,9 +428,6 b' class hgweb(object):'
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):
@@ -15,7 +15,6 b' import wsgiref.headers as wsgiheaders'
15
15
16 from .common import (
16 from .common import (
17 ErrorResponse,
17 ErrorResponse,
18 HTTP_NOT_MODIFIED,
19 statusmessage,
18 statusmessage,
20 )
19 )
21
20
@@ -361,7 +360,10 b' class wsgiresponse(object):'
361 raise error.ProgrammingError('cannot define body multiple times')
360 raise error.ProgrammingError('cannot define body multiple times')
362
361
363 def setbodybytes(self, b):
362 def setbodybytes(self, b):
364 """Define the response body as static bytes."""
363 """Define the response body as static bytes.
364
365 The empty string signals that there is no response body.
366 """
365 self._verifybody()
367 self._verifybody()
366 self._bodybytes = b
368 self._bodybytes = b
367 self.headers['Content-Length'] = '%d' % len(b)
369 self.headers['Content-Length'] = '%d' % len(b)
@@ -408,6 +410,35 b' class wsgiresponse(object):'
408 and not self._bodywillwrite):
410 and not self._bodywillwrite):
409 raise error.ProgrammingError('response body not defined')
411 raise error.ProgrammingError('response body not defined')
410
412
413 # RFC 7232 Section 4.1 states that a 304 MUST generate one of
414 # {Cache-Control, Content-Location, Date, ETag, Expires, Vary}
415 # and SHOULD NOT generate other headers unless they could be used
416 # to guide cache updates. Furthermore, RFC 7230 Section 3.3.2
417 # states that no response body can be issued. Content-Length can
418 # be sent. But if it is present, it should be the size of the response
419 # that wasn't transferred.
420 if self.status.startswith('304 '):
421 # setbodybytes('') will set C-L to 0. This doesn't conform with the
422 # spec. So remove it.
423 if self.headers.get('Content-Length') == '0':
424 del self.headers['Content-Length']
425
426 # Strictly speaking, this is too strict. But until it causes
427 # problems, let's be strict.
428 badheaders = {k for k in self.headers.keys()
429 if k.lower() not in ('date', 'etag', 'expires',
430 'cache-control',
431 'content-location',
432 'vary')}
433 if badheaders:
434 raise error.ProgrammingError(
435 'illegal header on 304 response: %s' %
436 ', '.join(sorted(badheaders)))
437
438 if self._bodygen is not None or self._bodywillwrite:
439 raise error.ProgrammingError("must use setbodybytes('') with "
440 "304 responses")
441
411 # Various HTTP clients (notably httplib) won't read the HTTP response
442 # Various HTTP clients (notably httplib) won't read the HTTP response
412 # until the HTTP request has been sent in full. If servers (us) send a
443 # until the HTTP request has been sent in full. If servers (us) send a
413 # response before the HTTP request has been fully sent, the connection
444 # response before the HTTP request has been fully sent, the connection
@@ -539,13 +570,6 b' class wsgirequest(object):'
539
570
540 if isinstance(status, ErrorResponse):
571 if isinstance(status, ErrorResponse):
541 self.headers.extend(status.headers)
572 self.headers.extend(status.headers)
542 if status.code == HTTP_NOT_MODIFIED:
543 # RFC 2616 Section 10.3.5: 304 Not Modified has cases where
544 # it MUST NOT include any headers other than these and no
545 # body
546 self.headers = [(k, v) for (k, v) in self.headers if
547 k in ('Date', 'ETag', 'Expires',
548 'Cache-Control', 'Vary')]
549 status = statusmessage(status.code, pycompat.bytestr(status))
573 status = statusmessage(status.code, pycompat.bytestr(status))
550 elif status == 200:
574 elif status == 200:
551 status = '200 Script output follows'
575 status = '200 Script output follows'
General Comments 0
You need to be logged in to leave comments. Login now