|
@@
-40,13
+40,15
b' from __future__ import absolute_import'
|
|
40
|
40
|
|
|
41
|
41
|
# Many functions in this file have too many arguments.
|
|
42
|
42
|
# pylint: disable=R0913
|
|
43
|
|
|
|
|
43
|
import email
|
|
|
44
|
import email.message
|
|
44
|
45
|
import errno
|
|
45
|
46
|
import inspect
|
|
46
|
47
|
import logging
|
|
47
|
|
import rfc822
|
|
48
|
48
|
import select
|
|
49
|
49
|
import socket
|
|
|
50
|
import ssl
|
|
|
51
|
import sys
|
|
50
|
52
|
|
|
51
|
53
|
try:
|
|
52
|
54
|
import cStringIO as io
|
|
@@
-62,15
+64,14
b' except ImportError:'
|
|
62
|
64
|
|
|
63
|
65
|
from . import (
|
|
64
|
66
|
_readers,
|
|
65
|
|
socketutil,
|
|
66
|
67
|
)
|
|
67
|
68
|
|
|
68
|
69
|
logger = logging.getLogger(__name__)
|
|
69
|
70
|
|
|
70
|
71
|
__all__ = ['HTTPConnection', 'HTTPResponse']
|
|
71
|
72
|
|
|
72
|
|
HTTP_VER_1_0 = 'HTTP/1.0'
|
|
73
|
|
HTTP_VER_1_1 = 'HTTP/1.1'
|
|
|
73
|
HTTP_VER_1_0 = b'HTTP/1.0'
|
|
|
74
|
HTTP_VER_1_1 = b'HTTP/1.1'
|
|
74
|
75
|
|
|
75
|
76
|
OUTGOING_BUFFER_SIZE = 1 << 15
|
|
76
|
77
|
INCOMING_BUFFER_SIZE = 1 << 20
|
|
@@
-84,7
+85,7
b" XFER_ENCODING_CHUNKED = 'chunked'"
|
|
84
|
85
|
|
|
85
|
86
|
CONNECTION_CLOSE = 'close'
|
|
86
|
87
|
|
|
87
|
|
EOL = '\r\n'
|
|
|
88
|
EOL = b'\r\n'
|
|
88
|
89
|
_END_HEADERS = EOL * 2
|
|
89
|
90
|
|
|
90
|
91
|
# Based on some searching around, 1 second seems like a reasonable
|
|
@@
-92,6
+93,57
b" EOL = '\\r\\n'"
|
|
92
|
93
|
TIMEOUT_ASSUME_CONTINUE = 1
|
|
93
|
94
|
TIMEOUT_DEFAULT = None
|
|
94
|
95
|
|
|
|
96
|
if sys.version_info > (3, 0):
|
|
|
97
|
_unicode = str
|
|
|
98
|
else:
|
|
|
99
|
_unicode = unicode
|
|
|
100
|
|
|
|
101
|
def _ensurebytes(data):
|
|
|
102
|
if not isinstance(data, (_unicode, bytes)):
|
|
|
103
|
data = str(data)
|
|
|
104
|
if not isinstance(data, bytes):
|
|
|
105
|
try:
|
|
|
106
|
return data.encode('latin-1')
|
|
|
107
|
except UnicodeEncodeError as err:
|
|
|
108
|
raise UnicodeEncodeError(
|
|
|
109
|
err.encoding,
|
|
|
110
|
err.object,
|
|
|
111
|
err.start,
|
|
|
112
|
err.end,
|
|
|
113
|
'%r is not valid Latin-1 Use .encode("utf-8") '
|
|
|
114
|
'if sending as utf-8 is desired.' % (
|
|
|
115
|
data[err.start:err.end],))
|
|
|
116
|
return data
|
|
|
117
|
|
|
|
118
|
class _CompatMessage(email.message.Message):
|
|
|
119
|
"""Workaround for rfc822.Message and email.message.Message API diffs."""
|
|
|
120
|
|
|
|
121
|
@classmethod
|
|
|
122
|
def from_string(cls, s):
|
|
|
123
|
if sys.version_info > (3, 0):
|
|
|
124
|
# Python 3 can't decode headers from bytes, so we have to
|
|
|
125
|
# trust RFC 2616 and decode the headers as iso-8859-1
|
|
|
126
|
# bytes.
|
|
|
127
|
s = s.decode('iso-8859-1')
|
|
|
128
|
headers = email.message_from_string(s, _class=_CompatMessage)
|
|
|
129
|
# Fix multi-line headers to match httplib's behavior from
|
|
|
130
|
# Python 2.x, since email.message.Message handles them in
|
|
|
131
|
# slightly different ways.
|
|
|
132
|
if sys.version_info < (3, 0):
|
|
|
133
|
new = []
|
|
|
134
|
for h, v in headers._headers:
|
|
|
135
|
if '\r\n' in v:
|
|
|
136
|
v = '\n'.join([' ' + x.lstrip() for x in v.split('\r\n')])[1:]
|
|
|
137
|
new.append((h, v))
|
|
|
138
|
headers._headers = new
|
|
|
139
|
return headers
|
|
|
140
|
|
|
|
141
|
def getheaders(self, key):
|
|
|
142
|
return self.get_all(key)
|
|
|
143
|
|
|
|
144
|
def getheader(self, key, default=None):
|
|
|
145
|
return self.get(key, failobj=default)
|
|
|
146
|
|
|
95
|
147
|
|
|
96
|
148
|
class HTTPResponse(object):
|
|
97
|
149
|
"""Response from an HTTP server.
|
|
@@
-102,11
+154,11
b' class HTTPResponse(object):'
|
|
102
|
154
|
def __init__(self, sock, timeout, method):
|
|
103
|
155
|
self.sock = sock
|
|
104
|
156
|
self.method = method
|
|
105
|
|
self.raw_response = ''
|
|
|
157
|
self.raw_response = b''
|
|
106
|
158
|
self._headers_len = 0
|
|
107
|
159
|
self.headers = None
|
|
108
|
160
|
self.will_close = False
|
|
109
|
|
self.status_line = ''
|
|
|
161
|
self.status_line = b''
|
|
110
|
162
|
self.status = None
|
|
111
|
163
|
self.continued = False
|
|
112
|
164
|
self.http_version = None
|
|
@@
-142,6
+194,10
b' class HTTPResponse(object):'
|
|
142
|
194
|
return self.headers.getheader(header, default=default)
|
|
143
|
195
|
|
|
144
|
196
|
def getheaders(self):
|
|
|
197
|
if sys.version_info < (3, 0):
|
|
|
198
|
return [(k.lower(), v) for k, v in self.headers.items()]
|
|
|
199
|
# Starting in Python 3, headers aren't lowercased before being
|
|
|
200
|
# returned here.
|
|
145
|
201
|
return self.headers.items()
|
|
146
|
202
|
|
|
147
|
203
|
def readline(self):
|
|
@@
-152,14
+208,14
b' class HTTPResponse(object):'
|
|
152
|
208
|
"""
|
|
153
|
209
|
blocks = []
|
|
154
|
210
|
while True:
|
|
155
|
|
self._reader.readto('\n', blocks)
|
|
|
211
|
self._reader.readto(b'\n', blocks)
|
|
156
|
212
|
|
|
157
|
|
if blocks and blocks[-1][-1] == '\n' or self.complete():
|
|
|
213
|
if blocks and blocks[-1][-1:] == b'\n' or self.complete():
|
|
158
|
214
|
break
|
|
159
|
215
|
|
|
160
|
216
|
self._select()
|
|
161
|
217
|
|
|
162
|
|
return ''.join(blocks)
|
|
|
218
|
return b''.join(blocks)
|
|
163
|
219
|
|
|
164
|
220
|
def read(self, length=None):
|
|
165
|
221
|
"""Read data from the response body."""
|
|
@@
-186,8
+242,8
b' class HTTPResponse(object):'
|
|
186
|
242
|
raise HTTPTimeoutException('timeout reading data')
|
|
187
|
243
|
try:
|
|
188
|
244
|
data = self.sock.recv(INCOMING_BUFFER_SIZE)
|
|
189
|
|
except socket.sslerror as e:
|
|
190
|
|
if e.args[0] != socket.SSL_ERROR_WANT_READ:
|
|
|
245
|
except ssl.SSLError as e:
|
|
|
246
|
if e.args[0] != ssl.SSL_ERROR_WANT_READ:
|
|
191
|
247
|
raise
|
|
192
|
248
|
logger.debug('SSL_ERROR_WANT_READ in _select, should retry later')
|
|
193
|
249
|
return True
|
|
@@
-214,7
+270,7
b' class HTTPResponse(object):'
|
|
214
|
270
|
self.raw_response += data
|
|
215
|
271
|
# This is a bogus server with bad line endings
|
|
216
|
272
|
if self._eol not in self.raw_response:
|
|
217
|
|
for bad_eol in ('\n', '\r'):
|
|
|
273
|
for bad_eol in (b'\n', b'\r'):
|
|
218
|
274
|
if (bad_eol in self.raw_response
|
|
219
|
275
|
# verify that bad_eol is not the end of the incoming data
|
|
220
|
276
|
# as this could be a response line that just got
|
|
@@
-231,8
+287,8
b' class HTTPResponse(object):'
|
|
231
|
287
|
|
|
232
|
288
|
# handle 100-continue response
|
|
233
|
289
|
hdrs, body = self.raw_response.split(self._end_headers, 1)
|
|
234
|
|
unused_http_ver, status = hdrs.split(' ', 1)
|
|
235
|
|
if status.startswith('100'):
|
|
|
290
|
unused_http_ver, status = hdrs.split(b' ', 1)
|
|
|
291
|
if status.startswith(b'100'):
|
|
236
|
292
|
self.raw_response = body
|
|
237
|
293
|
self.continued = True
|
|
238
|
294
|
logger.debug('continue seen, setting body to %r', body)
|
|
@@
-246,14
+302,14
b' class HTTPResponse(object):'
|
|
246
|
302
|
self.status_line, hdrs = hdrs.split(self._eol, 1)
|
|
247
|
303
|
else:
|
|
248
|
304
|
self.status_line = hdrs
|
|
249
|
|
hdrs = ''
|
|
|
305
|
hdrs = b''
|
|
250
|
306
|
# TODO HTTP < 1.0 support
|
|
251
|
307
|
(self.http_version, self.status,
|
|
252
|
|
self.reason) = self.status_line.split(' ', 2)
|
|
|
308
|
self.reason) = self.status_line.split(b' ', 2)
|
|
253
|
309
|
self.status = int(self.status)
|
|
254
|
310
|
if self._eol != EOL:
|
|
255
|
|
hdrs = hdrs.replace(self._eol, '\r\n')
|
|
256
|
|
headers = rfc822.Message(io.StringIO(hdrs))
|
|
|
311
|
hdrs = hdrs.replace(self._eol, b'\r\n')
|
|
|
312
|
headers = _CompatMessage.from_string(hdrs)
|
|
257
|
313
|
content_len = None
|
|
258
|
314
|
if HDR_CONTENT_LENGTH in headers:
|
|
259
|
315
|
content_len = int(headers[HDR_CONTENT_LENGTH])
|
|
@@
-270,8
+326,8
b' class HTTPResponse(object):'
|
|
270
|
326
|
# HEAD responses are forbidden from returning a body, and
|
|
271
|
327
|
# it's implausible for a CONNECT response to use
|
|
272
|
328
|
# close-is-end logic for an OK response.
|
|
273
|
|
if (self.method == 'HEAD' or
|
|
274
|
|
(self.method == 'CONNECT' and content_len is None)):
|
|
|
329
|
if (self.method == b'HEAD' or
|
|
|
330
|
(self.method == b'CONNECT' and content_len is None)):
|
|
275
|
331
|
content_len = 0
|
|
276
|
332
|
if content_len is not None:
|
|
277
|
333
|
logger.debug('using a content-length reader with length %d',
|
|
@@
-305,7
+361,7
b' def _foldheaders(headers):'
|
|
305
|
361
|
>>> _foldheaders({'Accept-Encoding': 'wat'})
|
|
306
|
362
|
{'accept-encoding': ('Accept-Encoding', 'wat')}
|
|
307
|
363
|
"""
|
|
308
|
|
return dict((k.lower(), (k, v)) for k, v in headers.iteritems())
|
|
|
364
|
return dict((k.lower(), (k, v)) for k, v in headers.items())
|
|
309
|
365
|
|
|
310
|
366
|
try:
|
|
311
|
367
|
inspect.signature
|
|
@@
-391,15
+447,16
b' class HTTPConnection(object):'
|
|
391
|
447
|
Any extra keyword arguments to this function will be provided
|
|
392
|
448
|
to the ssl_wrap_socket method. If no ssl
|
|
393
|
449
|
"""
|
|
394
|
|
if port is None and host.count(':') == 1 or ']:' in host:
|
|
395
|
|
host, port = host.rsplit(':', 1)
|
|
|
450
|
host = _ensurebytes(host)
|
|
|
451
|
if port is None and host.count(b':') == 1 or b']:' in host:
|
|
|
452
|
host, port = host.rsplit(b':', 1)
|
|
396
|
453
|
port = int(port)
|
|
397
|
|
if '[' in host:
|
|
|
454
|
if b'[' in host:
|
|
398
|
455
|
host = host[1:-1]
|
|
399
|
456
|
if ssl_wrap_socket is not None:
|
|
400
|
457
|
_wrap_socket = ssl_wrap_socket
|
|
401
|
458
|
else:
|
|
402
|
|
_wrap_socket = socketutil.wrap_socket
|
|
|
459
|
_wrap_socket = ssl.wrap_socket
|
|
403
|
460
|
call_wrap_socket = None
|
|
404
|
461
|
handlesubar = _handlesarg(_wrap_socket, 'server_hostname')
|
|
405
|
462
|
if handlesubar is True:
|
|
@@
-430,8
+487,6
b' class HTTPConnection(object):'
|
|
430
|
487
|
elif port is None:
|
|
431
|
488
|
port = (use_ssl and 443 or 80)
|
|
432
|
489
|
self.port = port
|
|
433
|
|
if use_ssl and not socketutil.have_ssl:
|
|
434
|
|
raise Exception('ssl requested but unavailable on this Python')
|
|
435
|
490
|
self.ssl = use_ssl
|
|
436
|
491
|
self.ssl_opts = ssl_opts
|
|
437
|
492
|
self._ssl_validator = ssl_validator
|
|
@@
-461,15
+516,15
b' class HTTPConnection(object):'
|
|
461
|
516
|
if self._proxy_host is not None:
|
|
462
|
517
|
logger.info('Connecting to http proxy %s:%s',
|
|
463
|
518
|
self._proxy_host, self._proxy_port)
|
|
464
|
|
sock = socketutil.create_connection((self._proxy_host,
|
|
465
|
|
self._proxy_port))
|
|
|
519
|
sock = socket.create_connection((self._proxy_host,
|
|
|
520
|
self._proxy_port))
|
|
466
|
521
|
if self.ssl:
|
|
467
|
|
data = self._buildheaders('CONNECT', '%s:%d' % (self.host,
|
|
468
|
|
self.port),
|
|
|
522
|
data = self._buildheaders(b'CONNECT', b'%s:%d' % (self.host,
|
|
|
523
|
self.port),
|
|
469
|
524
|
proxy_headers, HTTP_VER_1_0)
|
|
470
|
525
|
sock.send(data)
|
|
471
|
526
|
sock.setblocking(0)
|
|
472
|
|
r = self.response_class(sock, self.timeout, 'CONNECT')
|
|
|
527
|
r = self.response_class(sock, self.timeout, b'CONNECT')
|
|
473
|
528
|
timeout_exc = HTTPTimeoutException(
|
|
474
|
529
|
'Timed out waiting for CONNECT response from proxy')
|
|
475
|
530
|
while not r.complete():
|
|
@@
-494,7
+549,7
b' class HTTPConnection(object):'
|
|
494
|
549
|
logger.info('CONNECT (for SSL) to %s:%s via proxy succeeded.',
|
|
495
|
550
|
self.host, self.port)
|
|
496
|
551
|
else:
|
|
497
|
|
sock = socketutil.create_connection((self.host, self.port))
|
|
|
552
|
sock = socket.create_connection((self.host, self.port))
|
|
498
|
553
|
if self.ssl:
|
|
499
|
554
|
# This is the default, but in the case of proxied SSL
|
|
500
|
555
|
# requests the proxy logic above will have cleared
|
|
@@
-515,25
+570,26
b' class HTTPConnection(object):'
|
|
515
|
570
|
hdrhost = self.host
|
|
516
|
571
|
else:
|
|
517
|
572
|
# include nonstandard port in header
|
|
518
|
|
if ':' in self.host: # must be IPv6
|
|
519
|
|
hdrhost = '[%s]:%d' % (self.host, self.port)
|
|
|
573
|
if b':' in self.host: # must be IPv6
|
|
|
574
|
hdrhost = b'[%s]:%d' % (self.host, self.port)
|
|
520
|
575
|
else:
|
|
521
|
|
hdrhost = '%s:%d' % (self.host, self.port)
|
|
|
576
|
hdrhost = b'%s:%d' % (self.host, self.port)
|
|
522
|
577
|
if self._proxy_host and not self.ssl:
|
|
523
|
578
|
# When talking to a regular http proxy we must send the
|
|
524
|
579
|
# full URI, but in all other cases we must not (although
|
|
525
|
580
|
# technically RFC 2616 says servers must accept our
|
|
526
|
581
|
# request if we screw up, experimentally few do that
|
|
527
|
582
|
# correctly.)
|
|
528
|
|
assert path[0] == '/', 'path must start with a /'
|
|
529
|
|
path = 'http://%s%s' % (hdrhost, path)
|
|
530
|
|
outgoing = ['%s %s %s%s' % (method, path, http_ver, EOL)]
|
|
531
|
|
headers['host'] = ('Host', hdrhost)
|
|
|
583
|
assert path[0:1] == b'/', 'path must start with a /'
|
|
|
584
|
path = b'http://%s%s' % (hdrhost, path)
|
|
|
585
|
outgoing = [b'%s %s %s%s' % (method, path, http_ver, EOL)]
|
|
|
586
|
headers[b'host'] = (b'Host', hdrhost)
|
|
532
|
587
|
headers[HDR_ACCEPT_ENCODING] = (HDR_ACCEPT_ENCODING, 'identity')
|
|
533
|
|
for hdr, val in headers.itervalues():
|
|
534
|
|
outgoing.append('%s: %s%s' % (hdr, val, EOL))
|
|
|
588
|
for hdr, val in sorted((_ensurebytes(h), _ensurebytes(v))
|
|
|
589
|
for h, v in headers.values()):
|
|
|
590
|
outgoing.append(b'%s: %s%s' % (hdr, val, EOL))
|
|
535
|
591
|
outgoing.append(EOL)
|
|
536
|
|
return ''.join(outgoing)
|
|
|
592
|
return b''.join(outgoing)
|
|
537
|
593
|
|
|
538
|
594
|
def close(self):
|
|
539
|
595
|
"""Close the connection to the server.
|
|
@@
-586,6
+642,8
b' class HTTPConnection(object):'
|
|
586
|
642
|
available. Use the `getresponse()` method to retrieve the
|
|
587
|
643
|
response.
|
|
588
|
644
|
"""
|
|
|
645
|
method = _ensurebytes(method)
|
|
|
646
|
path = _ensurebytes(path)
|
|
589
|
647
|
if self.busy():
|
|
590
|
648
|
raise httplib.CannotSendRequest(
|
|
591
|
649
|
'Can not send another request before '
|
|
@@
-594,11
+652,26
b' class HTTPConnection(object):'
|
|
594
|
652
|
|
|
595
|
653
|
logger.info('sending %s request for %s to %s on port %s',
|
|
596
|
654
|
method, path, self.host, self.port)
|
|
|
655
|
|
|
597
|
656
|
hdrs = _foldheaders(headers)
|
|
598
|
|
if hdrs.get('expect', ('', ''))[1].lower() == '100-continue':
|
|
|
657
|
# Figure out headers that have to be computed from the request
|
|
|
658
|
# body.
|
|
|
659
|
chunked = False
|
|
|
660
|
if body and HDR_CONTENT_LENGTH not in hdrs:
|
|
|
661
|
if getattr(body, '__len__', False):
|
|
|
662
|
hdrs[HDR_CONTENT_LENGTH] = (HDR_CONTENT_LENGTH,
|
|
|
663
|
b'%d' % len(body))
|
|
|
664
|
elif getattr(body, 'read', False):
|
|
|
665
|
hdrs[HDR_XFER_ENCODING] = (HDR_XFER_ENCODING,
|
|
|
666
|
XFER_ENCODING_CHUNKED)
|
|
|
667
|
chunked = True
|
|
|
668
|
else:
|
|
|
669
|
raise BadRequestData('body has no __len__() nor read()')
|
|
|
670
|
# Figure out expect-continue header
|
|
|
671
|
if hdrs.get('expect', ('', ''))[1].lower() == b'100-continue':
|
|
599
|
672
|
expect_continue = True
|
|
600
|
673
|
elif expect_continue:
|
|
601
|
|
hdrs['expect'] = ('Expect', '100-Continue')
|
|
|
674
|
hdrs['expect'] = (b'Expect', b'100-Continue')
|
|
602
|
675
|
# httplib compatibility: if the user specified a
|
|
603
|
676
|
# proxy-authorization header, that's actually intended for a
|
|
604
|
677
|
# proxy CONNECT action, not the real request, but only if
|
|
@@
-608,25
+681,15
b' class HTTPConnection(object):'
|
|
608
|
681
|
pa = hdrs.pop('proxy-authorization', None)
|
|
609
|
682
|
if pa is not None:
|
|
610
|
683
|
pheaders['proxy-authorization'] = pa
|
|
611
|
|
|
|
612
|
|
chunked = False
|
|
613
|
|
if body and HDR_CONTENT_LENGTH not in hdrs:
|
|
614
|
|
if getattr(body, '__len__', False):
|
|
615
|
|
hdrs[HDR_CONTENT_LENGTH] = (HDR_CONTENT_LENGTH, len(body))
|
|
616
|
|
elif getattr(body, 'read', False):
|
|
617
|
|
hdrs[HDR_XFER_ENCODING] = (HDR_XFER_ENCODING,
|
|
618
|
|
XFER_ENCODING_CHUNKED)
|
|
619
|
|
chunked = True
|
|
620
|
|
else:
|
|
621
|
|
raise BadRequestData('body has no __len__() nor read()')
|
|
|
684
|
# Build header data
|
|
|
685
|
outgoing_headers = self._buildheaders(
|
|
|
686
|
method, path, hdrs, self.http_version)
|
|
622
|
687
|
|
|
623
|
688
|
# If we're reusing the underlying socket, there are some
|
|
624
|
689
|
# conditions where we'll want to retry, so make a note of the
|
|
625
|
690
|
# state of self.sock
|
|
626
|
691
|
fresh_socket = self.sock is None
|
|
627
|
692
|
self._connect(pheaders)
|
|
628
|
|
outgoing_headers = self._buildheaders(
|
|
629
|
|
method, path, hdrs, self.http_version)
|
|
630
|
693
|
response = None
|
|
631
|
694
|
first = True
|
|
632
|
695
|
|
|
@@
-666,8
+729,8
b' class HTTPConnection(object):'
|
|
666
|
729
|
try:
|
|
667
|
730
|
try:
|
|
668
|
731
|
data = r[0].recv(INCOMING_BUFFER_SIZE)
|
|
669
|
|
except socket.sslerror as e:
|
|
670
|
|
if e.args[0] != socket.SSL_ERROR_WANT_READ:
|
|
|
732
|
except ssl.SSLError as e:
|
|
|
733
|
if e.args[0] != ssl.SSL_ERROR_WANT_READ:
|
|
671
|
734
|
raise
|
|
672
|
735
|
logger.debug('SSL_ERROR_WANT_READ while sending '
|
|
673
|
736
|
'data, retrying...')
|
|
@@
-736,16
+799,20
b' class HTTPConnection(object):'
|
|
736
|
799
|
continue
|
|
737
|
800
|
if len(data) < OUTGOING_BUFFER_SIZE:
|
|
738
|
801
|
if chunked:
|
|
739
|
|
body = '0' + EOL + EOL
|
|
|
802
|
body = b'0' + EOL + EOL
|
|
740
|
803
|
else:
|
|
741
|
804
|
body = None
|
|
742
|
805
|
if chunked:
|
|
743
|
|
out = hex(len(data))[2:] + EOL + data + EOL
|
|
|
806
|
# This encode is okay because we know
|
|
|
807
|
# hex() is building us only 0-9 and a-f
|
|
|
808
|
# digits.
|
|
|
809
|
asciilen = hex(len(data))[2:].encode('ascii')
|
|
|
810
|
out = asciilen + EOL + data + EOL
|
|
744
|
811
|
else:
|
|
745
|
812
|
out = data
|
|
746
|
813
|
amt = w[0].send(out)
|
|
747
|
814
|
except socket.error as e:
|
|
748
|
|
if e[0] == socket.SSL_ERROR_WANT_WRITE and self.ssl:
|
|
|
815
|
if e[0] == ssl.SSL_ERROR_WANT_WRITE and self.ssl:
|
|
749
|
816
|
# This means that SSL hasn't flushed its buffer into
|
|
750
|
817
|
# the socket yet.
|
|
751
|
818
|
# TODO: find a way to block on ssl flushing its buffer
|
|
@@
-764,6
+831,7
b' class HTTPConnection(object):'
|
|
764
|
831
|
body = out[amt:]
|
|
765
|
832
|
else:
|
|
766
|
833
|
outgoing_headers = out[amt:]
|
|
|
834
|
# End of request-sending loop.
|
|
767
|
835
|
|
|
768
|
836
|
# close if the server response said to or responded before eating
|
|
769
|
837
|
# the whole request
|