summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2018-08-14 19:25:05 -0400
committerGitHub <noreply@github.com>2018-08-14 19:25:05 -0400
commit157a4e409551f4008e15e38fd3991aadcd8abbcd (patch)
treeb4d9ebde516261b4aa6453678c781bfe1c65a92c
parent8090b79ea406d9d5f909432267f81ce90542c2dd (diff)
parent94c31e8c1d8851584210afbc2b6e1d4882c48c87 (diff)
downloadcherrypy-git-157a4e409551f4008e15e38fd3991aadcd8abbcd.tar.gz
Merge pull request #1692 from SURFscz/masterv17.2.0
Fix static file cached 304 response
-rw-r--r--CHANGES.rst6
-rw-r--r--cherrypy/_cprequest.py12
-rw-r--r--cherrypy/lib/caching.py15
-rwxr-xr-xsetup.py1
4 files changed, 31 insertions, 3 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 6618df7e..44f377fc 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,3 +1,9 @@
+v17.2.0
+-------
+
+* :issue:`1690`: Prevent orphaned Event object in cached
+ 304 response.
+
v17.1.0
-------
diff --git a/cherrypy/_cprequest.py b/cherrypy/_cprequest.py
index f9943ff7..bde09891 100644
--- a/cherrypy/_cprequest.py
+++ b/cherrypy/_cprequest.py
@@ -2,9 +2,12 @@ import sys
import time
import uuid
+
import six
from six.moves.http_cookies import SimpleCookie, CookieError
+from more_itertools.recipes import consume
+
import cherrypy
from cherrypy._cpcompat import text_or_bytes, ntob
from cherrypy import _cpreqbody
@@ -879,6 +882,14 @@ class Response(object):
self.body = newbody
return newbody
+ def _flush_body(self):
+ """
+ Discard self.body but consume any generator such that
+ any finalization can occur, such as is required by
+ caching.tee_output().
+ """
+ consume(iter(self.body))
+
def finalize(self):
"""Transform headers (and cookies) into self.header_list. (Core)"""
try:
@@ -903,6 +914,7 @@ class Response(object):
# and 304 (not modified) responses MUST NOT
# include a message-body."
dict.pop(headers, 'Content-Length', None)
+ self._flush_body()
self.body = b''
else:
# Responses which are not streamed should have a Content-Length,
diff --git a/cherrypy/lib/caching.py b/cherrypy/lib/caching.py
index aa265164..fed325a6 100644
--- a/cherrypy/lib/caching.py
+++ b/cherrypy/lib/caching.py
@@ -405,10 +405,19 @@ def tee_output():
output.append(chunk)
yield chunk
- # save the cache data
+ # Save the cache data, but only if the body isn't empty.
+ # e.g. a 304 Not Modified on a static file response will
+ # have an empty body.
+ # If the body is empty, delete the cache because it
+ # contains a stale Threading._Event object that will
+ # stall all consecutive requests until the _Event times
+ # out
body = b''.join(output)
- cherrypy._cache.put((response.status, response.headers or {},
- body, response.time), len(body))
+ if not body:
+ cherrypy._cache.delete()
+ else:
+ cherrypy._cache.put((response.status, response.headers or {},
+ body, response.time), len(body))
response = cherrypy.serving.response
response.body = tee(response.body)
diff --git a/setup.py b/setup.py
index 3e2baa3f..79886904 100755
--- a/setup.py
+++ b/setup.py
@@ -63,6 +63,7 @@ params = dict(
'six>=1.11.0',
'cheroot>=6.2.4',
'portend>=2.1.1',
+ 'more_itertools',
],
extras_require={
'docs': [