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