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