Skip to content

Commit

Permalink
wsgi: minimize API changes for 100-continue fix (#569)
Browse files Browse the repository at this point in the history
In commit b9bf369, we stopped sending
100 Continue responses in the middle of a response when the application
was over-eager to start sending back bytes, but I did that by pulling
the headers_sent state out of handle_one_response(), up into
handle_one_request(), and plumbing it through to

  * get_environ(),
  * Input.__init__(), and finally
  * handle_one_response().

This works, but updates a whole bunch of HttpProtocol APIs in ways that
consumers may not have been expecting. For example, if someone wanted to
subclass HttpProtocol and override get_environ(), they may not have
bothered to include *args and **kwargs to accommodate future API changes.
That code should certainly be fixed, but we shouldn't break them
gratuitously.

Now, wait to introduce the headers_sent state until
handle_one_response() once more, and push it directly into the request's
Input. All the same protections with minimal API disruption.
  • Loading branch information
tipabu committed May 23, 2019
1 parent b9bf369 commit 1df1fb1
Showing 1 changed file with 14 additions and 11 deletions.
25 changes: 14 additions & 11 deletions eventlet/wsgi.py
Expand Up @@ -92,8 +92,7 @@ def __init__(self,
sock,
wfile=None,
wfile_line=None,
chunked_input=False,
headers_sent=None):
chunked_input=False):

self.rfile = rfile
self._sock = sock
Expand All @@ -113,9 +112,10 @@ def __init__(self,
self.hundred_continue_headers = None
self.is_hundred_continue_response_sent = False

# Hold on to a ref to the response state so we know whether we can
# still send the 100 Continue
self.headers_sent = headers_sent
# handle_one_response should give us a ref to the response state so we
# know whether we can still send the 100 Continue; until then, though,
# we're flying blind
self.headers_sent = None

def send_hundred_continue_response(self):
if self.headers_sent:
Expand Down Expand Up @@ -458,23 +458,26 @@ def handle_one_request(self):
self.close_connection = 1
return

headers_sent = []
self.environ = self.get_environ(headers_sent)
self.environ = self.get_environ()
self.application = self.server.app
try:
self.server.outstanding_requests += 1
try:
self.handle_one_response(headers_sent)
self.handle_one_response()
except socket.error as e:
# Broken pipe, connection reset by peer
if support.get_errno(e) not in BROKEN_SOCK:
raise
finally:
self.server.outstanding_requests -= 1

def handle_one_response(self, headers_sent):
def handle_one_response(self):
start = time.time()
headers_set = []
headers_sent = []
# Push the headers-sent state into the Input so it won't send a
# 100 Continue response if we've already started a response.
self.environ['wsgi.input'].headers_sent = headers_sent

wfile = self.wfile
result = None
Expand Down Expand Up @@ -655,7 +658,7 @@ def get_client_address(self):
host = forward + ',' + host
return (host, port)

def get_environ(self, headers_sent):
def get_environ(self):
env = self.server.get_environ()
env['REQUEST_METHOD'] = self.command
env['SCRIPT_NAME'] = ''
Expand Down Expand Up @@ -719,7 +722,7 @@ def get_environ(self, headers_sent):
chunked = env.get('HTTP_TRANSFER_ENCODING', '').lower() == 'chunked'
env['wsgi.input'] = env['eventlet.input'] = Input(
self.rfile, length, self.connection, wfile=wfile, wfile_line=wfile_line,
chunked_input=chunked, headers_sent=headers_sent)
chunked_input=chunked)
env['eventlet.posthooks'] = []

return env
Expand Down

0 comments on commit 1df1fb1

Please sign in to comment.