@@ -43,8 +43,8 @@ class HTTP11Connection(object):
43
43
:param host: The host to connect to. This may be an IP address or a
44
44
hostname, and optionally may include a port: for example,
45
45
``'twitter.com'``, ``'twitter.com:443'`` or ``'127.0.0.1'``.
46
- :param port: (optional) The port to connect to. If not provided and one also
47
- isn't provided in the ``host`` parameter, defaults to 80.
46
+ :param port: (optional) The port to connect to. If not provided and one
47
+ also isn't provided in the ``host`` parameter, defaults to 80.
48
48
:param secure: (optional) Whether the request should use TLS. Defaults to
49
49
``False`` for most requests, but to ``True`` for any request issued to
50
50
port 443.
@@ -82,7 +82,9 @@ def __init__(self, host, port=None, secure=None, ssl_context=None,
82
82
# Setup proxy details if applicable.
83
83
if proxy_host :
84
84
if proxy_port is None :
85
- self .proxy_host , self .proxy_port = to_host_port_tuple (proxy_host , default_port = 8080 )
85
+ self .proxy_host , self .proxy_port = to_host_port_tuple (
86
+ proxy_host , default_port = 8080
87
+ )
86
88
else :
87
89
self .proxy_host , self .proxy_port = proxy_host , proxy_port
88
90
else :
@@ -118,7 +120,7 @@ def connect(self):
118
120
proto = None
119
121
120
122
if self .secure :
121
- assert not self .proxy_host , "Using a proxy with HTTPS not yet supported."
123
+ assert not self .proxy_host , "Proxy with HTTPS not supported."
122
124
sock , proto = wrap_socket (sock , host , self .ssl_context )
123
125
124
126
log .debug ("Selected protocol: %s" , proto )
@@ -142,8 +144,8 @@ def request(self, method, url, body=None, headers=None):
142
144
143
145
:param method: The request method, e.g. ``'GET'``.
144
146
:param url: The URL to contact, e.g. ``'/path/segment'``.
145
- :param body: (optional) The request body to send. Must be a bytestring, an iterable of bytestring
146
- or a file-like object.
147
+ :param body: (optional) The request body to send. Must be a bytestring,
148
+ an iterable of bytestring, or a file-like object.
147
149
:param headers: (optional) The headers to send on the request.
148
150
:returns: Nothing.
149
151
"""
@@ -159,7 +161,9 @@ def request(self, method, url, body=None, headers=None):
159
161
elif isinstance (headers , Iterable ):
160
162
headers = HTTPHeaderMap (headers )
161
163
else :
162
- raise ValueError ('Header argument must be a dictionary or an iterable' )
164
+ raise ValueError (
165
+ 'Header argument must be a dictionary or an iterable'
166
+ )
163
167
164
168
if self ._sock is None :
165
169
self .connect ()
@@ -205,8 +209,8 @@ def get_response(self):
205
209
self ._sock .advance_buffer (response .consumed )
206
210
207
211
if (response .status == 101 and
208
- b'upgrade' in headers ['connection' ] and
209
- H2C_PROTOCOL .encode ('utf-8' ) in headers ['upgrade' ]):
212
+ b'upgrade' in headers ['connection' ] and
213
+ H2C_PROTOCOL .encode ('utf-8' ) in headers ['upgrade' ]):
210
214
raise HTTPUpgrade (H2C_PROTOCOL , self ._sock )
211
215
212
216
return HTTP11Response (
@@ -265,10 +269,13 @@ def _add_upgrade_headers(self, headers):
265
269
headers [b'connection' ] = b'Upgrade, HTTP2-Settings'
266
270
headers [b'upgrade' ] = H2C_PROTOCOL
267
271
268
- # Encode SETTINGS frame payload in Base64 and put into the HTTP-2 Settings header.
272
+ # Encode SETTINGS frame payload in Base64 and put into the HTTP-2
273
+ # Settings header.
269
274
http2_settings = SettingsFrame (0 )
270
275
http2_settings .settings [SettingsFrame .INITIAL_WINDOW_SIZE ] = 65535
271
- encoded_settings = base64 .urlsafe_b64encode (http2_settings .serialize_body ())
276
+ encoded_settings = base64 .urlsafe_b64encode (
277
+ http2_settings .serialize_body ()
278
+ )
272
279
headers [b'HTTP2-Settings' ] = encoded_settings .rstrip (b'=' )
273
280
274
281
def _send_body (self , body , body_type ):
@@ -279,17 +286,7 @@ def _send_body(self, body, body_type):
279
286
if body_type == BODY_FLAT :
280
287
# Special case for files and other 'readable' objects.
281
288
if hasattr (body , 'read' ):
282
- while True :
283
- block = body .read (16 * 1024 )
284
- if not block :
285
- break
286
-
287
- try :
288
- self ._sock .send (block )
289
- except TypeError :
290
- raise ValueError ("File-like bodies must return bytestrings. Got: {}" .format (type (block )))
291
-
292
- return
289
+ return self ._send_file_like_obj (body )
293
290
294
291
# Case for bytestrings.
295
292
elif isinstance (body , bytes ):
@@ -303,14 +300,26 @@ def _send_body(self, body, body_type):
303
300
try :
304
301
self ._sock .send (item )
305
302
except TypeError :
306
- raise ValueError ("Elements in iterable body must be bytestrings. "
307
- "Illegal element: {}" .format (item ))
303
+ raise ValueError (
304
+ "Elements in iterable body must be bytestrings. "
305
+ "Illegal element: {}" .format (item )
306
+ )
308
307
return
309
308
310
309
else :
311
- raise ValueError ('Request body must be a bytestring, a file-like object returning bytestrings '
312
- 'or an iterable of bytestrings. Got: {}' .format (type (body )))
310
+ raise ValueError (
311
+ 'Request body must be a bytestring, a file-like object '
312
+ 'returning bytestrings or an iterable of bytestrings. '
313
+ 'Got: {}' .format (type (body ))
314
+ )
315
+
316
+ # Chunked!
317
+ return self ._send_chunked (body )
313
318
319
+ def _send_chunked (self , body ):
320
+ """
321
+ Handles the HTTP/1.1 logic for sending a chunk-encoded body.
322
+ """
314
323
# Chunked! For chunked bodies we don't special-case, we just iterate
315
324
# over what we have and send stuff out.
316
325
for chunk in body :
@@ -324,11 +333,32 @@ def _send_body(self, body, body_type):
324
333
self ._sock .send (chunk )
325
334
self ._sock .send (b'\r \n ' )
326
335
except TypeError :
327
- raise ValueError ("Iterable bodies must always iterate in bytestrings" )
336
+ raise ValueError (
337
+ "Iterable bodies must always iterate in bytestrings"
338
+ )
328
339
329
340
self ._sock .send (b'0\r \n \r \n ' )
330
341
return
331
342
343
+ def _send_file_like_obj (self , fobj ):
344
+ """
345
+ Handles streaming a file-like object to the network.
346
+ """
347
+ while True :
348
+ block = fobj .read (16 * 1024 )
349
+ if not block :
350
+ break
351
+
352
+ try :
353
+ self ._sock .send (block )
354
+ except TypeError :
355
+ raise ValueError (
356
+ "File-like bodies must return bytestrings. Got: "
357
+ "{}" .format (type (block ))
358
+ )
359
+
360
+ return
361
+
332
362
def close (self ):
333
363
"""
334
364
Closes the connection. This closes the socket and then abandons the
0 commit comments