Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Commit 49a15ee

Browse files
committed
Move _start_http_response out of class
This is possible because it no longer depends on self.
1 parent b5566f3 commit 49a15ee

File tree

1 file changed

+75
-72
lines changed

1 file changed

+75
-72
lines changed

urllib3/sync_connection.py

Lines changed: 75 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,76 @@ def _build_tunnel_request(host, port, headers):
179179
return tunnel_request
180180

181181

182+
async def _start_http_request(request, state_machine, conn):
183+
"""
184+
Send the request using the given state machine and connection, wait
185+
for the response headers, and return them.
186+
187+
If we get response headers early, then we stop sending and return
188+
immediately, poisoning the state machine along the way so that we know
189+
it can't be re-used.
190+
191+
This is a standalone function because we use it both to set up both
192+
CONNECT requests and real requests.
193+
"""
194+
# Before we begin, confirm that the state machine is ok.
195+
if (state_machine.our_state is not h11.IDLE or
196+
state_machine.their_state is not h11.IDLE):
197+
raise ProtocolError("Invalid internal state transition")
198+
199+
request_bytes_iterable = _request_bytes_iterable(request, state_machine)
200+
201+
send_aborted = True
202+
203+
async def next_bytes_to_send():
204+
nonlocal send_aborted
205+
try:
206+
return next(request_bytes_iterable)
207+
except StopIteration:
208+
# We successfully sent the whole body!
209+
send_aborted = False
210+
return None
211+
212+
h11_response = None
213+
214+
def consume_bytes(data):
215+
nonlocal h11_response
216+
217+
state_machine.receive_data(data)
218+
while True:
219+
event = state_machine.next_event()
220+
if event is h11.NEED_DATA:
221+
break
222+
elif isinstance(event, h11.InformationalResponse):
223+
# Ignore 1xx responses
224+
continue
225+
elif isinstance(event, h11.Response):
226+
# We have our response! Save it and get out of here.
227+
h11_response = event
228+
raise LoopAbort
229+
else:
230+
# Can't happen
231+
raise RuntimeError("Unexpected h11 event {}".format(event))
232+
233+
await conn.send_and_receive_for_a_while(
234+
next_bytes_to_send, consume_bytes)
235+
assert h11_response is not None
236+
237+
if send_aborted:
238+
# Our state machine thinks we sent a bunch of data... but maybe we
239+
# didn't! Maybe our send got cancelled while we were only half-way
240+
# through sending the last chunk, and then h11 thinks we sent a
241+
# complete request and we actually didn't. Then h11 might think we can
242+
# re-use this connection, even though we can't. So record this in
243+
# h11's state machine.
244+
# XX need to implement this in h11
245+
# state_machine.poison()
246+
# XX kluge for now
247+
state_machine._cstate.process_error(state_machine.our_role)
248+
249+
return h11_response
250+
251+
182252
async def _read_until_event(state_machine, conn):
183253
"""
184254
A loop that keeps issuing reads and feeding the data into h11 and
@@ -279,9 +349,10 @@ async def send_request(self, request, read_timeout):
279349
"""
280350
Given a Request object, performs the logic required to get a response.
281351
"""
282-
return await self._start_http_request(
352+
h11_response = await _start_http_request(
283353
request, self._state_machine, self._sock
284354
)
355+
return _response_from_h11(h11_response, self)
285356

286357
async def _tunnel(self, conn):
287358
"""
@@ -296,11 +367,12 @@ async def _tunnel(self, conn):
296367

297368
tunnel_state_machine = h11.Connection(our_role=h11.CLIENT)
298369

299-
tunnel_response = await self._start_http_request(
370+
h11_response = await _start_http_request(
300371
tunnel_request, tunnel_state_machine, conn
301372
)
373+
tunnel_response = _response_from_h11(h11_response, self)
302374

303-
if tunnel_response.status_code != 200:
375+
if h11_response.status_code != 200:
304376
conn.forceful_close()
305377
raise FailedTunnelError(
306378
"Unable to establish CONNECT tunnel", tunnel_response
@@ -354,75 +426,6 @@ async def connect(self, ssl_context=None,
354426
# XX We should pick one of these names and use it consistently...
355427
self._sock = conn
356428

357-
async def _start_http_request(self, request, state_machine, conn):
358-
"""
359-
Send the request using the given state machine and connection, wait
360-
for the response headers, and return them.
361-
362-
If we get response headers early, then we stop sending and return
363-
immediately, poisoning the state machine along the way so that we know
364-
it can't be re-used.
365-
366-
This is a standalone function because we use it both to set up both
367-
CONNECT requests and real requests.
368-
"""
369-
# Before we begin, confirm that the state machine is ok.
370-
if (state_machine.our_state is not h11.IDLE or
371-
state_machine.their_state is not h11.IDLE):
372-
raise ProtocolError("Invalid internal state transition")
373-
374-
request_bytes_iterable = _request_bytes_iterable(request, state_machine)
375-
376-
send_aborted = True
377-
378-
async def next_bytes_to_send():
379-
nonlocal send_aborted
380-
try:
381-
return next(request_bytes_iterable)
382-
except StopIteration:
383-
# We successfully sent the whole body!
384-
send_aborted = False
385-
return None
386-
387-
h11_response = None
388-
389-
def consume_bytes(data):
390-
nonlocal h11_response
391-
392-
state_machine.receive_data(data)
393-
while True:
394-
event = state_machine.next_event()
395-
if event is h11.NEED_DATA:
396-
break
397-
elif isinstance(event, h11.InformationalResponse):
398-
# Ignore 1xx responses
399-
continue
400-
elif isinstance(event, h11.Response):
401-
# We have our response! Save it and get out of here.
402-
h11_response = event
403-
raise LoopAbort
404-
else:
405-
# Can't happen
406-
raise RuntimeError("Unexpected h11 event {}".format(event))
407-
408-
await conn.send_and_receive_for_a_while(
409-
next_bytes_to_send, consume_bytes)
410-
assert h11_response is not None
411-
412-
if send_aborted:
413-
# Our state machine thinks we sent a bunch of data... but maybe we
414-
# didn't! Maybe our send got cancelled while we were only half-way
415-
# through sending the last chunk, and then h11 thinks we sent a
416-
# complete request and we actually didn't. Then h11 might think we can
417-
# re-use this connection, even though we can't. So record this in
418-
# h11's state machine.
419-
# XX need to implement this in h11
420-
# state_machine.poison()
421-
# XX kluge for now
422-
state_machine._cstate.process_error(state_machine.our_role)
423-
424-
return _response_from_h11(h11_response, self)
425-
426429
async def close(self):
427430
"""
428431
Close this connection.

0 commit comments

Comments
 (0)