##// END OF EJS Templates
httpclient: reverse accidental damage from 86db5cb55d46
timeless -
r28997:25d93c61 stable
parent child Browse files
Show More
@@ -1,767 +1,768 b''
1 # Copyright 2010, Google Inc.
1 # Copyright 2010, Google Inc.
2 # All rights reserved.
2 # All rights reserved.
3 #
3 #
4 # Redistribution and use in source and binary forms, with or without
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
5 # modification, are permitted provided that the following conditions are
6 # met:
6 # met:
7 #
7 #
8 # * Redistributions of source code must retain the above copyright
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
12 # in the documentation and/or other materials provided with the
13 # distribution.
13 # distribution.
14 # * Neither the name of Google Inc. nor the names of its
14 # * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
16 # this software without specific prior written permission.
17
17
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 """Improved HTTP/1.1 client library
29 """Improved HTTP/1.1 client library
30
30
31 This library contains an HTTPConnection which is similar to the one in
31 This library contains an HTTPConnection which is similar to the one in
32 httplib, but has several additional features:
32 httplib, but has several additional features:
33
33
34 * supports keepalives natively
34 * supports keepalives natively
35 * uses select() to block for incoming data
35 * uses select() to block for incoming data
36 * notices when the server responds early to a request
36 * notices when the server responds early to a request
37 * implements ssl inline instead of in a different class
37 * implements ssl inline instead of in a different class
38 """
38 """
39 from __future__ import absolute_import
39 from __future__ import absolute_import
40
40
41 # Many functions in this file have too many arguments.
41 # Many functions in this file have too many arguments.
42 # pylint: disable=R0913
42 # pylint: disable=R0913
43
43
44 import cStringIO
44 import errno
45 import errno
45 import httplib
46 import httplib
46 import logging
47 import logging
47 import rfc822
48 import rfc822
48 import select
49 import select
49 import socket
50 import socket
50
51
51 from . import (
52 from . import (
52 _readers,
53 _readers,
53 socketutil,
54 socketutil,
54 )
55 )
55
56
56 logger = logging.getLogger(__name__)
57 logger = logging.getLogger(__name__)
57
58
58 __all__ = ['HTTPConnection', 'HTTPResponse']
59 __all__ = ['HTTPConnection', 'HTTPResponse']
59
60
60 HTTP_VER_1_0 = 'HTTP/1.0'
61 HTTP_VER_1_0 = 'HTTP/1.0'
61 HTTP_VER_1_1 = 'HTTP/1.1'
62 HTTP_VER_1_1 = 'HTTP/1.1'
62
63
63 OUTGOING_BUFFER_SIZE = 1 << 15
64 OUTGOING_BUFFER_SIZE = 1 << 15
64 INCOMING_BUFFER_SIZE = 1 << 20
65 INCOMING_BUFFER_SIZE = 1 << 20
65
66
66 HDR_ACCEPT_ENCODING = 'accept-encoding'
67 HDR_ACCEPT_ENCODING = 'accept-encoding'
67 HDR_CONNECTION_CTRL = 'connection'
68 HDR_CONNECTION_CTRL = 'connection'
68 HDR_CONTENT_LENGTH = 'content-length'
69 HDR_CONTENT_LENGTH = 'content-length'
69 HDR_XFER_ENCODING = 'transfer-encoding'
70 HDR_XFER_ENCODING = 'transfer-encoding'
70
71
71 XFER_ENCODING_CHUNKED = 'chunked'
72 XFER_ENCODING_CHUNKED = 'chunked'
72
73
73 CONNECTION_CLOSE = 'close'
74 CONNECTION_CLOSE = 'close'
74
75
75 EOL = '\r\n'
76 EOL = '\r\n'
76 _END_HEADERS = EOL * 2
77 _END_HEADERS = EOL * 2
77
78
78 # Based on some searching around, 1 second seems like a reasonable
79 # Based on some searching around, 1 second seems like a reasonable
79 # default here.
80 # default here.
80 TIMEOUT_ASSUME_CONTINUE = 1
81 TIMEOUT_ASSUME_CONTINUE = 1
81 TIMEOUT_DEFAULT = None
82 TIMEOUT_DEFAULT = None
82
83
83
84
84 class HTTPResponse(object):
85 class HTTPResponse(object):
85 """Response from an HTTP server.
86 """Response from an HTTP server.
86
87
87 The response will continue to load as available. If you need the
88 The response will continue to load as available. If you need the
88 complete response before continuing, check the .complete() method.
89 complete response before continuing, check the .complete() method.
89 """
90 """
90 def __init__(self, sock, timeout, method):
91 def __init__(self, sock, timeout, method):
91 self.sock = sock
92 self.sock = sock
92 self.method = method
93 self.method = method
93 self.raw_response = ''
94 self.raw_response = ''
94 self._headers_len = 0
95 self._headers_len = 0
95 self.headers = None
96 self.headers = None
96 self.will_close = False
97 self.will_close = False
97 self.status_line = ''
98 self.status_line = ''
98 self.status = None
99 self.status = None
99 self.continued = False
100 self.continued = False
100 self.http_version = None
101 self.http_version = None
101 self.reason = None
102 self.reason = None
102 self._reader = None
103 self._reader = None
103
104
104 self._read_location = 0
105 self._read_location = 0
105 self._eol = EOL
106 self._eol = EOL
106
107
107 self._timeout = timeout
108 self._timeout = timeout
108
109
109 @property
110 @property
110 def _end_headers(self):
111 def _end_headers(self):
111 return self._eol * 2
112 return self._eol * 2
112
113
113 def complete(self):
114 def complete(self):
114 """Returns true if this response is completely loaded.
115 """Returns true if this response is completely loaded.
115
116
116 Note that if this is a connection where complete means the
117 Note that if this is a connection where complete means the
117 socket is closed, this will nearly always return False, even
118 socket is closed, this will nearly always return False, even
118 in cases where all the data has actually been loaded.
119 in cases where all the data has actually been loaded.
119 """
120 """
120 if self._reader:
121 if self._reader:
121 return self._reader.done()
122 return self._reader.done()
122
123
123 def _close(self):
124 def _close(self):
124 if self._reader is not None:
125 if self._reader is not None:
125 # We're a friend of the reader class here.
126 # We're a friend of the reader class here.
126 # pylint: disable=W0212
127 # pylint: disable=W0212
127 self._reader._close()
128 self._reader._close()
128
129
129 def getheader(self, header, default=None):
130 def getheader(self, header, default=None):
130 return self.headers.getheader(header, default=default)
131 return self.headers.getheader(header, default=default)
131
132
132 def getheaders(self):
133 def getheaders(self):
133 return self.headers.items()
134 return self.headers.items()
134
135
135 def readline(self):
136 def readline(self):
136 """Read a single line from the response body.
137 """Read a single line from the response body.
137
138
138 This may block until either a line ending is found or the
139 This may block until either a line ending is found or the
139 response is complete.
140 response is complete.
140 """
141 """
141 blocks = []
142 blocks = []
142 while True:
143 while True:
143 self._reader.readto('\n', blocks)
144 self._reader.readto('\n', blocks)
144
145
145 if blocks and blocks[-1][-1] == '\n' or self.complete():
146 if blocks and blocks[-1][-1] == '\n' or self.complete():
146 break
147 break
147
148
148 self._select()
149 self._select()
149
150
150 return ''.join(blocks)
151 return ''.join(blocks)
151
152
152 def read(self, length=None):
153 def read(self, length=None):
153 """Read data from the response body."""
154 """Read data from the response body."""
154 # if length is None, unbounded read
155 # if length is None, unbounded read
155 while (not self.complete() # never select on a finished read
156 while (not self.complete() # never select on a finished read
156 and (not length # unbounded, so we wait for complete()
157 and (not length # unbounded, so we wait for complete()
157 or length > self._reader.available_data)):
158 or length > self._reader.available_data)):
158 self._select()
159 self._select()
159 if not length:
160 if not length:
160 length = self._reader.available_data
161 length = self._reader.available_data
161 r = self._reader.read(length)
162 r = self._reader.read(length)
162 if self.complete() and self.will_close:
163 if self.complete() and self.will_close:
163 self.sock.close()
164 self.sock.close()
164 return r
165 return r
165
166
166 def _select(self):
167 def _select(self):
167 r, unused_write, unused_err = select.select(
168 r, unused_write, unused_err = select.select(
168 [self.sock], [], [], self._timeout)
169 [self.sock], [], [], self._timeout)
169 if not r:
170 if not r:
170 # socket was not readable. If the response is not
171 # socket was not readable. If the response is not
171 # complete, raise a timeout.
172 # complete, raise a timeout.
172 if not self.complete():
173 if not self.complete():
173 logger.info('timed out with timeout of %s', self._timeout)
174 logger.info('timed out with timeout of %s', self._timeout)
174 raise HTTPTimeoutException('timeout reading data')
175 raise HTTPTimeoutException('timeout reading data')
175 try:
176 try:
176 data = self.sock.recv(INCOMING_BUFFER_SIZE)
177 data = self.sock.recv(INCOMING_BUFFER_SIZE)
177 except socket.sslerror as e:
178 except socket.sslerror as e:
178 if e.args[0] != socket.SSL_ERROR_WANT_READ:
179 if e.args[0] != socket.SSL_ERROR_WANT_READ:
179 raise
180 raise
180 logger.debug('SSL_ERROR_WANT_READ in _select, should retry later')
181 logger.debug('SSL_ERROR_WANT_READ in _select, should retry later')
181 return True
182 return True
182 logger.debug('response read %d data during _select', len(data))
183 logger.debug('response read %d data during _select', len(data))
183 # If the socket was readable and no data was read, that means
184 # If the socket was readable and no data was read, that means
184 # the socket was closed. Inform the reader (if any) so it can
185 # the socket was closed. Inform the reader (if any) so it can
185 # raise an exception if this is an invalid situation.
186 # raise an exception if this is an invalid situation.
186 if not data:
187 if not data:
187 if self._reader:
188 if self._reader:
188 # We're a friend of the reader class here.
189 # We're a friend of the reader class here.
189 # pylint: disable=W0212
190 # pylint: disable=W0212
190 self._reader._close()
191 self._reader._close()
191 return False
192 return False
192 else:
193 else:
193 self._load_response(data)
194 self._load_response(data)
194 return True
195 return True
195
196
196 # This method gets replaced by _load later, which confuses pylint.
197 # This method gets replaced by _load later, which confuses pylint.
197 def _load_response(self, data): # pylint: disable=E0202
198 def _load_response(self, data): # pylint: disable=E0202
198 # Being here implies we're not at the end of the headers yet,
199 # Being here implies we're not at the end of the headers yet,
199 # since at the end of this method if headers were completely
200 # since at the end of this method if headers were completely
200 # loaded we replace this method with the load() method of the
201 # loaded we replace this method with the load() method of the
201 # reader we created.
202 # reader we created.
202 self.raw_response += data
203 self.raw_response += data
203 # This is a bogus server with bad line endings
204 # This is a bogus server with bad line endings
204 if self._eol not in self.raw_response:
205 if self._eol not in self.raw_response:
205 for bad_eol in ('\n', '\r'):
206 for bad_eol in ('\n', '\r'):
206 if (bad_eol in self.raw_response
207 if (bad_eol in self.raw_response
207 # verify that bad_eol is not the end of the incoming data
208 # verify that bad_eol is not the end of the incoming data
208 # as this could be a response line that just got
209 # as this could be a response line that just got
209 # split between \r and \n.
210 # split between \r and \n.
210 and (self.raw_response.index(bad_eol) <
211 and (self.raw_response.index(bad_eol) <
211 (len(self.raw_response) - 1))):
212 (len(self.raw_response) - 1))):
212 logger.info('bogus line endings detected, '
213 logger.info('bogus line endings detected, '
213 'using %r for EOL', bad_eol)
214 'using %r for EOL', bad_eol)
214 self._eol = bad_eol
215 self._eol = bad_eol
215 break
216 break
216 # exit early if not at end of headers
217 # exit early if not at end of headers
217 if self._end_headers not in self.raw_response or self.headers:
218 if self._end_headers not in self.raw_response or self.headers:
218 return
219 return
219
220
220 # handle 100-continue response
221 # handle 100-continue response
221 hdrs, body = self.raw_response.split(self._end_headers, 1)
222 hdrs, body = self.raw_response.split(self._end_headers, 1)
222 unused_http_ver, status = hdrs.split(' ', 1)
223 unused_http_ver, status = hdrs.split(' ', 1)
223 if status.startswith('100'):
224 if status.startswith('100'):
224 self.raw_response = body
225 self.raw_response = body
225 self.continued = True
226 self.continued = True
226 logger.debug('continue seen, setting body to %r', body)
227 logger.debug('continue seen, setting body to %r', body)
227 return
228 return
228
229
229 # arriving here means we should parse response headers
230 # arriving here means we should parse response headers
230 # as all headers have arrived completely
231 # as all headers have arrived completely
231 hdrs, body = self.raw_response.split(self._end_headers, 1)
232 hdrs, body = self.raw_response.split(self._end_headers, 1)
232 del self.raw_response
233 del self.raw_response
233 if self._eol in hdrs:
234 if self._eol in hdrs:
234 self.status_line, hdrs = hdrs.split(self._eol, 1)
235 self.status_line, hdrs = hdrs.split(self._eol, 1)
235 else:
236 else:
236 self.status_line = hdrs
237 self.status_line = hdrs
237 hdrs = ''
238 hdrs = ''
238 # TODO HTTP < 1.0 support
239 # TODO HTTP < 1.0 support
239 (self.http_version, self.status,
240 (self.http_version, self.status,
240 self.reason) = self.status_line.split(' ', 2)
241 self.reason) = self.status_line.split(' ', 2)
241 self.status = int(self.status)
242 self.status = int(self.status)
242 if self._eol != EOL:
243 if self._eol != EOL:
243 hdrs = hdrs.replace(self._eol, '\r\n')
244 hdrs = hdrs.replace(self._eol, '\r\n')
244 headers = rfc822.Message(cStringIO.StringIO(hdrs))
245 headers = rfc822.Message(cStringIO.StringIO(hdrs))
245 content_len = None
246 content_len = None
246 if HDR_CONTENT_LENGTH in headers:
247 if HDR_CONTENT_LENGTH in headers:
247 content_len = int(headers[HDR_CONTENT_LENGTH])
248 content_len = int(headers[HDR_CONTENT_LENGTH])
248 if self.http_version == HTTP_VER_1_0:
249 if self.http_version == HTTP_VER_1_0:
249 self.will_close = True
250 self.will_close = True
250 elif HDR_CONNECTION_CTRL in headers:
251 elif HDR_CONNECTION_CTRL in headers:
251 self.will_close = (
252 self.will_close = (
252 headers[HDR_CONNECTION_CTRL].lower() == CONNECTION_CLOSE)
253 headers[HDR_CONNECTION_CTRL].lower() == CONNECTION_CLOSE)
253 if (HDR_XFER_ENCODING in headers
254 if (HDR_XFER_ENCODING in headers
254 and headers[HDR_XFER_ENCODING].lower() == XFER_ENCODING_CHUNKED):
255 and headers[HDR_XFER_ENCODING].lower() == XFER_ENCODING_CHUNKED):
255 self._reader = _readers.ChunkedReader(self._eol)
256 self._reader = _readers.ChunkedReader(self._eol)
256 logger.debug('using a chunked reader')
257 logger.debug('using a chunked reader')
257 else:
258 else:
258 # HEAD responses are forbidden from returning a body, and
259 # HEAD responses are forbidden from returning a body, and
259 # it's implausible for a CONNECT response to use
260 # it's implausible for a CONNECT response to use
260 # close-is-end logic for an OK response.
261 # close-is-end logic for an OK response.
261 if (self.method == 'HEAD' or
262 if (self.method == 'HEAD' or
262 (self.method == 'CONNECT' and content_len is None)):
263 (self.method == 'CONNECT' and content_len is None)):
263 content_len = 0
264 content_len = 0
264 if content_len is not None:
265 if content_len is not None:
265 logger.debug('using a content-length reader with length %d',
266 logger.debug('using a content-length reader with length %d',
266 content_len)
267 content_len)
267 self._reader = _readers.ContentLengthReader(content_len)
268 self._reader = _readers.ContentLengthReader(content_len)
268 else:
269 else:
269 # Response body had no length specified and is not
270 # Response body had no length specified and is not
270 # chunked, so the end of the body will only be
271 # chunked, so the end of the body will only be
271 # identifiable by the termination of the socket by the
272 # identifiable by the termination of the socket by the
272 # server. My interpretation of the spec means that we
273 # server. My interpretation of the spec means that we
273 # are correct in hitting this case if
274 # are correct in hitting this case if
274 # transfer-encoding, content-length, and
275 # transfer-encoding, content-length, and
275 # connection-control were left unspecified.
276 # connection-control were left unspecified.
276 self._reader = _readers.CloseIsEndReader()
277 self._reader = _readers.CloseIsEndReader()
277 logger.debug('using a close-is-end reader')
278 logger.debug('using a close-is-end reader')
278 self.will_close = True
279 self.will_close = True
279
280
280 if body:
281 if body:
281 # We're a friend of the reader class here.
282 # We're a friend of the reader class here.
282 # pylint: disable=W0212
283 # pylint: disable=W0212
283 self._reader._load(body)
284 self._reader._load(body)
284 logger.debug('headers complete')
285 logger.debug('headers complete')
285 self.headers = headers
286 self.headers = headers
286 # We're a friend of the reader class here.
287 # We're a friend of the reader class here.
287 # pylint: disable=W0212
288 # pylint: disable=W0212
288 self._load_response = self._reader._load
289 self._load_response = self._reader._load
289
290
290 def _foldheaders(headers):
291 def _foldheaders(headers):
291 """Given some headers, rework them so we can safely overwrite values.
292 """Given some headers, rework them so we can safely overwrite values.
292
293
293 >>> _foldheaders({'Accept-Encoding': 'wat'})
294 >>> _foldheaders({'Accept-Encoding': 'wat'})
294 {'accept-encoding': ('Accept-Encoding', 'wat')}
295 {'accept-encoding': ('Accept-Encoding', 'wat')}
295 """
296 """
296 return dict((k.lower(), (k, v)) for k, v in headers.iteritems())
297 return dict((k.lower(), (k, v)) for k, v in headers.iteritems())
297
298
298
299
299 class HTTPConnection(object):
300 class HTTPConnection(object):
300 """Connection to a single http server.
301 """Connection to a single http server.
301
302
302 Supports 100-continue and keepalives natively. Uses select() for
303 Supports 100-continue and keepalives natively. Uses select() for
303 non-blocking socket operations.
304 non-blocking socket operations.
304 """
305 """
305 http_version = HTTP_VER_1_1
306 http_version = HTTP_VER_1_1
306 response_class = HTTPResponse
307 response_class = HTTPResponse
307
308
308 def __init__(self, host, port=None, use_ssl=None, ssl_validator=None,
309 def __init__(self, host, port=None, use_ssl=None, ssl_validator=None,
309 timeout=TIMEOUT_DEFAULT,
310 timeout=TIMEOUT_DEFAULT,
310 continue_timeout=TIMEOUT_ASSUME_CONTINUE,
311 continue_timeout=TIMEOUT_ASSUME_CONTINUE,
311 proxy_hostport=None, proxy_headers=None,
312 proxy_hostport=None, proxy_headers=None,
312 ssl_wrap_socket=None, **ssl_opts):
313 ssl_wrap_socket=None, **ssl_opts):
313 """Create a new HTTPConnection.
314 """Create a new HTTPConnection.
314
315
315 Args:
316 Args:
316 host: The host to which we'll connect.
317 host: The host to which we'll connect.
317 port: Optional. The port over which we'll connect. Default 80 for
318 port: Optional. The port over which we'll connect. Default 80 for
318 non-ssl, 443 for ssl.
319 non-ssl, 443 for ssl.
319 use_ssl: Optional. Whether to use ssl. Defaults to False if port is
320 use_ssl: Optional. Whether to use ssl. Defaults to False if port is
320 not 443, true if port is 443.
321 not 443, true if port is 443.
321 ssl_validator: a function(socket) to validate the ssl cert
322 ssl_validator: a function(socket) to validate the ssl cert
322 timeout: Optional. Connection timeout, default is TIMEOUT_DEFAULT.
323 timeout: Optional. Connection timeout, default is TIMEOUT_DEFAULT.
323 continue_timeout: Optional. Timeout for waiting on an expected
324 continue_timeout: Optional. Timeout for waiting on an expected
324 "100 Continue" response. Default is TIMEOUT_ASSUME_CONTINUE.
325 "100 Continue" response. Default is TIMEOUT_ASSUME_CONTINUE.
325 proxy_hostport: Optional. Tuple of (host, port) to use as an http
326 proxy_hostport: Optional. Tuple of (host, port) to use as an http
326 proxy for the connection. Default is to not use a proxy.
327 proxy for the connection. Default is to not use a proxy.
327 proxy_headers: Optional dict of header keys and values to send to
328 proxy_headers: Optional dict of header keys and values to send to
328 a proxy when using CONNECT. For compatibility with
329 a proxy when using CONNECT. For compatibility with
329 httplib, the Proxy-Authorization header may be
330 httplib, the Proxy-Authorization header may be
330 specified in headers for request(), which will clobber
331 specified in headers for request(), which will clobber
331 any such header specified here if specified. Providing
332 any such header specified here if specified. Providing
332 this option and not proxy_hostport will raise an
333 this option and not proxy_hostport will raise an
333 ValueError.
334 ValueError.
334 ssl_wrap_socket: Optional function to use for wrapping
335 ssl_wrap_socket: Optional function to use for wrapping
335 sockets. If unspecified, the one from the ssl module will
336 sockets. If unspecified, the one from the ssl module will
336 be used if available, or something that's compatible with
337 be used if available, or something that's compatible with
337 it if on a Python older than 2.6.
338 it if on a Python older than 2.6.
338
339
339 Any extra keyword arguments to this function will be provided
340 Any extra keyword arguments to this function will be provided
340 to the ssl_wrap_socket method. If no ssl
341 to the ssl_wrap_socket method. If no ssl
341 """
342 """
342 if port is None and host.count(':') == 1 or ']:' in host:
343 if port is None and host.count(':') == 1 or ']:' in host:
343 host, port = host.rsplit(':', 1)
344 host, port = host.rsplit(':', 1)
344 port = int(port)
345 port = int(port)
345 if '[' in host:
346 if '[' in host:
346 host = host[1:-1]
347 host = host[1:-1]
347 if ssl_wrap_socket is not None:
348 if ssl_wrap_socket is not None:
348 self._ssl_wrap_socket = ssl_wrap_socket
349 self._ssl_wrap_socket = ssl_wrap_socket
349 else:
350 else:
350 self._ssl_wrap_socket = socketutil.wrap_socket
351 self._ssl_wrap_socket = socketutil.wrap_socket
351 if use_ssl is None and port is None:
352 if use_ssl is None and port is None:
352 use_ssl = False
353 use_ssl = False
353 port = 80
354 port = 80
354 elif use_ssl is None:
355 elif use_ssl is None:
355 use_ssl = (port == 443)
356 use_ssl = (port == 443)
356 elif port is None:
357 elif port is None:
357 port = (use_ssl and 443 or 80)
358 port = (use_ssl and 443 or 80)
358 self.port = port
359 self.port = port
359 if use_ssl and not socketutil.have_ssl:
360 if use_ssl and not socketutil.have_ssl:
360 raise Exception('ssl requested but unavailable on this Python')
361 raise Exception('ssl requested but unavailable on this Python')
361 self.ssl = use_ssl
362 self.ssl = use_ssl
362 self.ssl_opts = ssl_opts
363 self.ssl_opts = ssl_opts
363 self._ssl_validator = ssl_validator
364 self._ssl_validator = ssl_validator
364 self.host = host
365 self.host = host
365 self.sock = None
366 self.sock = None
366 self._current_response = None
367 self._current_response = None
367 self._current_response_taken = False
368 self._current_response_taken = False
368 if proxy_hostport is None:
369 if proxy_hostport is None:
369 self._proxy_host = self._proxy_port = None
370 self._proxy_host = self._proxy_port = None
370 if proxy_headers:
371 if proxy_headers:
371 raise ValueError(
372 raise ValueError(
372 'proxy_headers may not be specified unless '
373 'proxy_headers may not be specified unless '
373 'proxy_hostport is also specified.')
374 'proxy_hostport is also specified.')
374 else:
375 else:
375 self._proxy_headers = {}
376 self._proxy_headers = {}
376 else:
377 else:
377 self._proxy_host, self._proxy_port = proxy_hostport
378 self._proxy_host, self._proxy_port = proxy_hostport
378 self._proxy_headers = _foldheaders(proxy_headers or {})
379 self._proxy_headers = _foldheaders(proxy_headers or {})
379
380
380 self.timeout = timeout
381 self.timeout = timeout
381 self.continue_timeout = continue_timeout
382 self.continue_timeout = continue_timeout
382
383
383 def _connect(self, proxy_headers):
384 def _connect(self, proxy_headers):
384 """Connect to the host and port specified in __init__."""
385 """Connect to the host and port specified in __init__."""
385 if self.sock:
386 if self.sock:
386 return
387 return
387 if self._proxy_host is not None:
388 if self._proxy_host is not None:
388 logger.info('Connecting to http proxy %s:%s',
389 logger.info('Connecting to http proxy %s:%s',
389 self._proxy_host, self._proxy_port)
390 self._proxy_host, self._proxy_port)
390 sock = socketutil.create_connection((self._proxy_host,
391 sock = socketutil.create_connection((self._proxy_host,
391 self._proxy_port))
392 self._proxy_port))
392 if self.ssl:
393 if self.ssl:
393 data = self._buildheaders('CONNECT', '%s:%d' % (self.host,
394 data = self._buildheaders('CONNECT', '%s:%d' % (self.host,
394 self.port),
395 self.port),
395 proxy_headers, HTTP_VER_1_0)
396 proxy_headers, HTTP_VER_1_0)
396 sock.send(data)
397 sock.send(data)
397 sock.setblocking(0)
398 sock.setblocking(0)
398 r = self.response_class(sock, self.timeout, 'CONNECT')
399 r = self.response_class(sock, self.timeout, 'CONNECT')
399 timeout_exc = HTTPTimeoutException(
400 timeout_exc = HTTPTimeoutException(
400 'Timed out waiting for CONNECT response from proxy')
401 'Timed out waiting for CONNECT response from proxy')
401 while not r.complete():
402 while not r.complete():
402 try:
403 try:
403 # We're a friend of the response class, so let
404 # We're a friend of the response class, so let
404 # us use the private attribute.
405 # us use the private attribute.
405 # pylint: disable=W0212
406 # pylint: disable=W0212
406 if not r._select():
407 if not r._select():
407 if not r.complete():
408 if not r.complete():
408 raise timeout_exc
409 raise timeout_exc
409 except HTTPTimeoutException:
410 except HTTPTimeoutException:
410 # This raise/except pattern looks goofy, but
411 # This raise/except pattern looks goofy, but
411 # _select can raise the timeout as well as the
412 # _select can raise the timeout as well as the
412 # loop body. I wish it wasn't this convoluted,
413 # loop body. I wish it wasn't this convoluted,
413 # but I don't have a better solution
414 # but I don't have a better solution
414 # immediately handy.
415 # immediately handy.
415 raise timeout_exc
416 raise timeout_exc
416 if r.status != 200:
417 if r.status != 200:
417 raise HTTPProxyConnectFailedException(
418 raise HTTPProxyConnectFailedException(
418 'Proxy connection failed: %d %s' % (r.status,
419 'Proxy connection failed: %d %s' % (r.status,
419 r.read()))
420 r.read()))
420 logger.info('CONNECT (for SSL) to %s:%s via proxy succeeded.',
421 logger.info('CONNECT (for SSL) to %s:%s via proxy succeeded.',
421 self.host, self.port)
422 self.host, self.port)
422 else:
423 else:
423 sock = socketutil.create_connection((self.host, self.port))
424 sock = socketutil.create_connection((self.host, self.port))
424 if self.ssl:
425 if self.ssl:
425 # This is the default, but in the case of proxied SSL
426 # This is the default, but in the case of proxied SSL
426 # requests the proxy logic above will have cleared
427 # requests the proxy logic above will have cleared
427 # blocking mode, so re-enable it just to be safe.
428 # blocking mode, so re-enable it just to be safe.
428 sock.setblocking(1)
429 sock.setblocking(1)
429 logger.debug('wrapping socket for ssl with options %r',
430 logger.debug('wrapping socket for ssl with options %r',
430 self.ssl_opts)
431 self.ssl_opts)
431 sock = self._ssl_wrap_socket(sock, **self.ssl_opts)
432 sock = self._ssl_wrap_socket(sock, **self.ssl_opts)
432 if self._ssl_validator:
433 if self._ssl_validator:
433 self._ssl_validator(sock)
434 self._ssl_validator(sock)
434 sock.setblocking(0)
435 sock.setblocking(0)
435 self.sock = sock
436 self.sock = sock
436
437
437 def _buildheaders(self, method, path, headers, http_ver):
438 def _buildheaders(self, method, path, headers, http_ver):
438 if self.ssl and self.port == 443 or self.port == 80:
439 if self.ssl and self.port == 443 or self.port == 80:
439 # default port for protocol, so leave it out
440 # default port for protocol, so leave it out
440 hdrhost = self.host
441 hdrhost = self.host
441 else:
442 else:
442 # include nonstandard port in header
443 # include nonstandard port in header
443 if ':' in self.host: # must be IPv6
444 if ':' in self.host: # must be IPv6
444 hdrhost = '[%s]:%d' % (self.host, self.port)
445 hdrhost = '[%s]:%d' % (self.host, self.port)
445 else:
446 else:
446 hdrhost = '%s:%d' % (self.host, self.port)
447 hdrhost = '%s:%d' % (self.host, self.port)
447 if self._proxy_host and not self.ssl:
448 if self._proxy_host and not self.ssl:
448 # When talking to a regular http proxy we must send the
449 # When talking to a regular http proxy we must send the
449 # full URI, but in all other cases we must not (although
450 # full URI, but in all other cases we must not (although
450 # technically RFC 2616 says servers must accept our
451 # technically RFC 2616 says servers must accept our
451 # request if we screw up, experimentally few do that
452 # request if we screw up, experimentally few do that
452 # correctly.)
453 # correctly.)
453 assert path[0] == '/', 'path must start with a /'
454 assert path[0] == '/', 'path must start with a /'
454 path = 'http://%s%s' % (hdrhost, path)
455 path = 'http://%s%s' % (hdrhost, path)
455 outgoing = ['%s %s %s%s' % (method, path, http_ver, EOL)]
456 outgoing = ['%s %s %s%s' % (method, path, http_ver, EOL)]
456 headers['host'] = ('Host', hdrhost)
457 headers['host'] = ('Host', hdrhost)
457 headers[HDR_ACCEPT_ENCODING] = (HDR_ACCEPT_ENCODING, 'identity')
458 headers[HDR_ACCEPT_ENCODING] = (HDR_ACCEPT_ENCODING, 'identity')
458 for hdr, val in headers.itervalues():
459 for hdr, val in headers.itervalues():
459 outgoing.append('%s: %s%s' % (hdr, val, EOL))
460 outgoing.append('%s: %s%s' % (hdr, val, EOL))
460 outgoing.append(EOL)
461 outgoing.append(EOL)
461 return ''.join(outgoing)
462 return ''.join(outgoing)
462
463
463 def close(self):
464 def close(self):
464 """Close the connection to the server.
465 """Close the connection to the server.
465
466
466 This is a no-op if the connection is already closed. The
467 This is a no-op if the connection is already closed. The
467 connection may automatically close if requested by the server
468 connection may automatically close if requested by the server
468 or required by the nature of a response.
469 or required by the nature of a response.
469 """
470 """
470 if self.sock is None:
471 if self.sock is None:
471 return
472 return
472 self.sock.close()
473 self.sock.close()
473 self.sock = None
474 self.sock = None
474 logger.info('closed connection to %s on %s', self.host, self.port)
475 logger.info('closed connection to %s on %s', self.host, self.port)
475
476
476 def busy(self):
477 def busy(self):
477 """Returns True if this connection object is currently in use.
478 """Returns True if this connection object is currently in use.
478
479
479 If a response is still pending, this will return True, even if
480 If a response is still pending, this will return True, even if
480 the request has finished sending. In the future,
481 the request has finished sending. In the future,
481 HTTPConnection may transparently juggle multiple connections
482 HTTPConnection may transparently juggle multiple connections
482 to the server, in which case this will be useful to detect if
483 to the server, in which case this will be useful to detect if
483 any of those connections is ready for use.
484 any of those connections is ready for use.
484 """
485 """
485 cr = self._current_response
486 cr = self._current_response
486 if cr is not None:
487 if cr is not None:
487 if self._current_response_taken:
488 if self._current_response_taken:
488 if cr.will_close:
489 if cr.will_close:
489 self.sock = None
490 self.sock = None
490 self._current_response = None
491 self._current_response = None
491 return False
492 return False
492 elif cr.complete():
493 elif cr.complete():
493 self._current_response = None
494 self._current_response = None
494 return False
495 return False
495 return True
496 return True
496 return False
497 return False
497
498
498 def _reconnect(self, where, pheaders):
499 def _reconnect(self, where, pheaders):
499 logger.info('reconnecting during %s', where)
500 logger.info('reconnecting during %s', where)
500 self.close()
501 self.close()
501 self._connect(pheaders)
502 self._connect(pheaders)
502
503
503 def request(self, method, path, body=None, headers={},
504 def request(self, method, path, body=None, headers={},
504 expect_continue=False):
505 expect_continue=False):
505 """Send a request to the server.
506 """Send a request to the server.
506
507
507 For increased flexibility, this does not return the response
508 For increased flexibility, this does not return the response
508 object. Future versions of HTTPConnection that juggle multiple
509 object. Future versions of HTTPConnection that juggle multiple
509 sockets will be able to send (for example) 5 requests all at
510 sockets will be able to send (for example) 5 requests all at
510 once, and then let the requests arrive as data is
511 once, and then let the requests arrive as data is
511 available. Use the `getresponse()` method to retrieve the
512 available. Use the `getresponse()` method to retrieve the
512 response.
513 response.
513 """
514 """
514 if self.busy():
515 if self.busy():
515 raise httplib.CannotSendRequest(
516 raise httplib.CannotSendRequest(
516 'Can not send another request before '
517 'Can not send another request before '
517 'current response is read!')
518 'current response is read!')
518 self._current_response_taken = False
519 self._current_response_taken = False
519
520
520 logger.info('sending %s request for %s to %s on port %s',
521 logger.info('sending %s request for %s to %s on port %s',
521 method, path, self.host, self.port)
522 method, path, self.host, self.port)
522 hdrs = _foldheaders(headers)
523 hdrs = _foldheaders(headers)
523 if hdrs.get('expect', ('', ''))[1].lower() == '100-continue':
524 if hdrs.get('expect', ('', ''))[1].lower() == '100-continue':
524 expect_continue = True
525 expect_continue = True
525 elif expect_continue:
526 elif expect_continue:
526 hdrs['expect'] = ('Expect', '100-Continue')
527 hdrs['expect'] = ('Expect', '100-Continue')
527 # httplib compatibility: if the user specified a
528 # httplib compatibility: if the user specified a
528 # proxy-authorization header, that's actually intended for a
529 # proxy-authorization header, that's actually intended for a
529 # proxy CONNECT action, not the real request, but only if
530 # proxy CONNECT action, not the real request, but only if
530 # we're going to use a proxy.
531 # we're going to use a proxy.
531 pheaders = dict(self._proxy_headers)
532 pheaders = dict(self._proxy_headers)
532 if self._proxy_host and self.ssl:
533 if self._proxy_host and self.ssl:
533 pa = hdrs.pop('proxy-authorization', None)
534 pa = hdrs.pop('proxy-authorization', None)
534 if pa is not None:
535 if pa is not None:
535 pheaders['proxy-authorization'] = pa
536 pheaders['proxy-authorization'] = pa
536
537
537 chunked = False
538 chunked = False
538 if body and HDR_CONTENT_LENGTH not in hdrs:
539 if body and HDR_CONTENT_LENGTH not in hdrs:
539 if getattr(body, '__len__', False):
540 if getattr(body, '__len__', False):
540 hdrs[HDR_CONTENT_LENGTH] = (HDR_CONTENT_LENGTH, len(body))
541 hdrs[HDR_CONTENT_LENGTH] = (HDR_CONTENT_LENGTH, len(body))
541 elif getattr(body, 'read', False):
542 elif getattr(body, 'read', False):
542 hdrs[HDR_XFER_ENCODING] = (HDR_XFER_ENCODING,
543 hdrs[HDR_XFER_ENCODING] = (HDR_XFER_ENCODING,
543 XFER_ENCODING_CHUNKED)
544 XFER_ENCODING_CHUNKED)
544 chunked = True
545 chunked = True
545 else:
546 else:
546 raise BadRequestData('body has no __len__() nor read()')
547 raise BadRequestData('body has no __len__() nor read()')
547
548
548 # If we're reusing the underlying socket, there are some
549 # If we're reusing the underlying socket, there are some
549 # conditions where we'll want to retry, so make a note of the
550 # conditions where we'll want to retry, so make a note of the
550 # state of self.sock
551 # state of self.sock
551 fresh_socket = self.sock is None
552 fresh_socket = self.sock is None
552 self._connect(pheaders)
553 self._connect(pheaders)
553 outgoing_headers = self._buildheaders(
554 outgoing_headers = self._buildheaders(
554 method, path, hdrs, self.http_version)
555 method, path, hdrs, self.http_version)
555 response = None
556 response = None
556 first = True
557 first = True
557
558
558 while ((outgoing_headers or body)
559 while ((outgoing_headers or body)
559 and not (response and response.complete())):
560 and not (response and response.complete())):
560 select_timeout = self.timeout
561 select_timeout = self.timeout
561 out = outgoing_headers or body
562 out = outgoing_headers or body
562 blocking_on_continue = False
563 blocking_on_continue = False
563 if expect_continue and not outgoing_headers and not (
564 if expect_continue and not outgoing_headers and not (
564 response and (response.headers or response.continued)):
565 response and (response.headers or response.continued)):
565 logger.info(
566 logger.info(
566 'waiting up to %s seconds for'
567 'waiting up to %s seconds for'
567 ' continue response from server',
568 ' continue response from server',
568 self.continue_timeout)
569 self.continue_timeout)
569 select_timeout = self.continue_timeout
570 select_timeout = self.continue_timeout
570 blocking_on_continue = True
571 blocking_on_continue = True
571 out = False
572 out = False
572 if out:
573 if out:
573 w = [self.sock]
574 w = [self.sock]
574 else:
575 else:
575 w = []
576 w = []
576 r, w, x = select.select([self.sock], w, [], select_timeout)
577 r, w, x = select.select([self.sock], w, [], select_timeout)
577 # if we were expecting a 100 continue and it's been long
578 # if we were expecting a 100 continue and it's been long
578 # enough, just go ahead and assume it's ok. This is the
579 # enough, just go ahead and assume it's ok. This is the
579 # recommended behavior from the RFC.
580 # recommended behavior from the RFC.
580 if r == w == x == []:
581 if r == w == x == []:
581 if blocking_on_continue:
582 if blocking_on_continue:
582 expect_continue = False
583 expect_continue = False
583 logger.info('no response to continue expectation from '
584 logger.info('no response to continue expectation from '
584 'server, optimistically sending request body')
585 'server, optimistically sending request body')
585 else:
586 else:
586 raise HTTPTimeoutException('timeout sending data')
587 raise HTTPTimeoutException('timeout sending data')
587 was_first = first
588 was_first = first
588
589
589 # incoming data
590 # incoming data
590 if r:
591 if r:
591 try:
592 try:
592 try:
593 try:
593 data = r[0].recv(INCOMING_BUFFER_SIZE)
594 data = r[0].recv(INCOMING_BUFFER_SIZE)
594 except socket.sslerror as e:
595 except socket.sslerror as e:
595 if e.args[0] != socket.SSL_ERROR_WANT_READ:
596 if e.args[0] != socket.SSL_ERROR_WANT_READ:
596 raise
597 raise
597 logger.debug('SSL_ERROR_WANT_READ while sending '
598 logger.debug('SSL_ERROR_WANT_READ while sending '
598 'data, retrying...')
599 'data, retrying...')
599 continue
600 continue
600 if not data:
601 if not data:
601 logger.info('socket appears closed in read')
602 logger.info('socket appears closed in read')
602 self.sock = None
603 self.sock = None
603 self._current_response = None
604 self._current_response = None
604 if response is not None:
605 if response is not None:
605 # We're a friend of the response class, so let
606 # We're a friend of the response class, so let
606 # us use the private attribute.
607 # us use the private attribute.
607 # pylint: disable=W0212
608 # pylint: disable=W0212
608 response._close()
609 response._close()
609 # This if/elif ladder is a bit subtle,
610 # This if/elif ladder is a bit subtle,
610 # comments in each branch should help.
611 # comments in each branch should help.
611 if response is not None and response.complete():
612 if response is not None and response.complete():
612 # Server responded completely and then
613 # Server responded completely and then
613 # closed the socket. We should just shut
614 # closed the socket. We should just shut
614 # things down and let the caller get their
615 # things down and let the caller get their
615 # response.
616 # response.
616 logger.info('Got an early response, '
617 logger.info('Got an early response, '
617 'aborting remaining request.')
618 'aborting remaining request.')
618 break
619 break
619 elif was_first and response is None:
620 elif was_first and response is None:
620 # Most likely a keepalive that got killed
621 # Most likely a keepalive that got killed
621 # on the server's end. Commonly happens
622 # on the server's end. Commonly happens
622 # after getting a really large response
623 # after getting a really large response
623 # from the server.
624 # from the server.
624 logger.info(
625 logger.info(
625 'Connection appeared closed in read on first'
626 'Connection appeared closed in read on first'
626 ' request loop iteration, will retry.')
627 ' request loop iteration, will retry.')
627 self._reconnect('read', pheaders)
628 self._reconnect('read', pheaders)
628 continue
629 continue
629 else:
630 else:
630 # We didn't just send the first data hunk,
631 # We didn't just send the first data hunk,
631 # and either have a partial response or no
632 # and either have a partial response or no
632 # response at all. There's really nothing
633 # response at all. There's really nothing
633 # meaningful we can do here.
634 # meaningful we can do here.
634 raise HTTPStateError(
635 raise HTTPStateError(
635 'Connection appears closed after '
636 'Connection appears closed after '
636 'some request data was written, but the '
637 'some request data was written, but the '
637 'response was missing or incomplete!')
638 'response was missing or incomplete!')
638 logger.debug('read %d bytes in request()', len(data))
639 logger.debug('read %d bytes in request()', len(data))
639 if response is None:
640 if response is None:
640 response = self.response_class(
641 response = self.response_class(
641 r[0], self.timeout, method)
642 r[0], self.timeout, method)
642 # We're a friend of the response class, so let us
643 # We're a friend of the response class, so let us
643 # use the private attribute.
644 # use the private attribute.
644 # pylint: disable=W0212
645 # pylint: disable=W0212
645 response._load_response(data)
646 response._load_response(data)
646 # Jump to the next select() call so we load more
647 # Jump to the next select() call so we load more
647 # data if the server is still sending us content.
648 # data if the server is still sending us content.
648 continue
649 continue
649 except socket.error as e:
650 except socket.error as e:
650 if e[0] != errno.EPIPE and not was_first:
651 if e[0] != errno.EPIPE and not was_first:
651 raise
652 raise
652
653
653 # outgoing data
654 # outgoing data
654 if w and out:
655 if w and out:
655 try:
656 try:
656 if getattr(out, 'read', False):
657 if getattr(out, 'read', False):
657 # pylint guesses the type of out incorrectly here
658 # pylint guesses the type of out incorrectly here
658 # pylint: disable=E1103
659 # pylint: disable=E1103
659 data = out.read(OUTGOING_BUFFER_SIZE)
660 data = out.read(OUTGOING_BUFFER_SIZE)
660 if not data:
661 if not data:
661 continue
662 continue
662 if len(data) < OUTGOING_BUFFER_SIZE:
663 if len(data) < OUTGOING_BUFFER_SIZE:
663 if chunked:
664 if chunked:
664 body = '0' + EOL + EOL
665 body = '0' + EOL + EOL
665 else:
666 else:
666 body = None
667 body = None
667 if chunked:
668 if chunked:
668 out = hex(len(data))[2:] + EOL + data + EOL
669 out = hex(len(data))[2:] + EOL + data + EOL
669 else:
670 else:
670 out = data
671 out = data
671 amt = w[0].send(out)
672 amt = w[0].send(out)
672 except socket.error as e:
673 except socket.error as e:
673 if e[0] == socket.SSL_ERROR_WANT_WRITE and self.ssl:
674 if e[0] == socket.SSL_ERROR_WANT_WRITE and self.ssl:
674 # This means that SSL hasn't flushed its buffer into
675 # This means that SSL hasn't flushed its buffer into
675 # the socket yet.
676 # the socket yet.
676 # TODO: find a way to block on ssl flushing its buffer
677 # TODO: find a way to block on ssl flushing its buffer
677 # similar to selecting on a raw socket.
678 # similar to selecting on a raw socket.
678 continue
679 continue
679 if e[0] == errno.EWOULDBLOCK or e[0] == errno.EAGAIN:
680 if e[0] == errno.EWOULDBLOCK or e[0] == errno.EAGAIN:
680 continue
681 continue
681 elif (e[0] not in (errno.ECONNRESET, errno.EPIPE)
682 elif (e[0] not in (errno.ECONNRESET, errno.EPIPE)
682 and not first):
683 and not first):
683 raise
684 raise
684 self._reconnect('write', pheaders)
685 self._reconnect('write', pheaders)
685 amt = self.sock.send(out)
686 amt = self.sock.send(out)
686 logger.debug('sent %d', amt)
687 logger.debug('sent %d', amt)
687 first = False
688 first = False
688 if out is body:
689 if out is body:
689 body = out[amt:]
690 body = out[amt:]
690 else:
691 else:
691 outgoing_headers = out[amt:]
692 outgoing_headers = out[amt:]
692
693
693 # close if the server response said to or responded before eating
694 # close if the server response said to or responded before eating
694 # the whole request
695 # the whole request
695 if response is None:
696 if response is None:
696 response = self.response_class(self.sock, self.timeout, method)
697 response = self.response_class(self.sock, self.timeout, method)
697 if not fresh_socket:
698 if not fresh_socket:
698 if not response._select():
699 if not response._select():
699 # This means the response failed to get any response
700 # This means the response failed to get any response
700 # data at all, and in all probability the socket was
701 # data at all, and in all probability the socket was
701 # closed before the server even saw our request. Try
702 # closed before the server even saw our request. Try
702 # the request again on a fresh socket.
703 # the request again on a fresh socket.
703 logger.debug('response._select() failed during request().'
704 logger.debug('response._select() failed during request().'
704 ' Assuming request needs to be retried.')
705 ' Assuming request needs to be retried.')
705 self.sock = None
706 self.sock = None
706 # Call this method explicitly to re-try the
707 # Call this method explicitly to re-try the
707 # request. We don't use self.request() because
708 # request. We don't use self.request() because
708 # some tools (notably Mercurial) expect to be able
709 # some tools (notably Mercurial) expect to be able
709 # to subclass and redefine request(), and they
710 # to subclass and redefine request(), and they
710 # don't have the same argspec as we do.
711 # don't have the same argspec as we do.
711 #
712 #
712 # TODO restructure sending of requests to avoid
713 # TODO restructure sending of requests to avoid
713 # this recursion
714 # this recursion
714 return HTTPConnection.request(
715 return HTTPConnection.request(
715 self, method, path, body=body, headers=headers,
716 self, method, path, body=body, headers=headers,
716 expect_continue=expect_continue)
717 expect_continue=expect_continue)
717 data_left = bool(outgoing_headers or body)
718 data_left = bool(outgoing_headers or body)
718 if data_left:
719 if data_left:
719 logger.info('stopped sending request early, '
720 logger.info('stopped sending request early, '
720 'will close the socket to be safe.')
721 'will close the socket to be safe.')
721 response.will_close = True
722 response.will_close = True
722 if response.will_close:
723 if response.will_close:
723 # The socket will be closed by the response, so we disown
724 # The socket will be closed by the response, so we disown
724 # the socket
725 # the socket
725 self.sock = None
726 self.sock = None
726 self._current_response = response
727 self._current_response = response
727
728
728 def getresponse(self):
729 def getresponse(self):
729 """Returns the response to the most recent request."""
730 """Returns the response to the most recent request."""
730 if self._current_response is None:
731 if self._current_response is None:
731 raise httplib.ResponseNotReady()
732 raise httplib.ResponseNotReady()
732 r = self._current_response
733 r = self._current_response
733 while r.headers is None:
734 while r.headers is None:
734 # We're a friend of the response class, so let us use the
735 # We're a friend of the response class, so let us use the
735 # private attribute.
736 # private attribute.
736 # pylint: disable=W0212
737 # pylint: disable=W0212
737 if not r._select() and not r.complete():
738 if not r._select() and not r.complete():
738 raise _readers.HTTPRemoteClosedError()
739 raise _readers.HTTPRemoteClosedError()
739 if r.will_close:
740 if r.will_close:
740 self.sock = None
741 self.sock = None
741 self._current_response = None
742 self._current_response = None
742 elif r.complete():
743 elif r.complete():
743 self._current_response = None
744 self._current_response = None
744 else:
745 else:
745 self._current_response_taken = True
746 self._current_response_taken = True
746 return r
747 return r
747
748
748
749
749 class HTTPTimeoutException(httplib.HTTPException):
750 class HTTPTimeoutException(httplib.HTTPException):
750 """A timeout occurred while waiting on the server."""
751 """A timeout occurred while waiting on the server."""
751
752
752
753
753 class BadRequestData(httplib.HTTPException):
754 class BadRequestData(httplib.HTTPException):
754 """Request body object has neither __len__ nor read."""
755 """Request body object has neither __len__ nor read."""
755
756
756
757
757 class HTTPProxyConnectFailedException(httplib.HTTPException):
758 class HTTPProxyConnectFailedException(httplib.HTTPException):
758 """Connecting to the HTTP proxy failed."""
759 """Connecting to the HTTP proxy failed."""
759
760
760
761
761 class HTTPStateError(httplib.HTTPException):
762 class HTTPStateError(httplib.HTTPException):
762 """Invalid internal state encountered."""
763 """Invalid internal state encountered."""
763
764
764 # Forward this exception type from _readers since it needs to be part
765 # Forward this exception type from _readers since it needs to be part
765 # of the public API.
766 # of the public API.
766 HTTPRemoteClosedError = _readers.HTTPRemoteClosedError
767 HTTPRemoteClosedError = _readers.HTTPRemoteClosedError
767 # no-check-code
768 # no-check-code
General Comments 0
You need to be logged in to leave comments. Login now