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 |
40 |
40 # Many functions in this file have too many arguments. |
41 # Many functions in this file have too many arguments. |
41 # pylint: disable=R0913 |
42 # pylint: disable=R0913 |
42 |
43 |
43 import cStringIO |
44 import cStringIO |
121 def _close(self): |
124 def _close(self): |
122 if self._reader is not None: |
125 if self._reader is not None: |
123 # We're a friend of the reader class here. |
126 # We're a friend of the reader class here. |
124 # pylint: disable=W0212 |
127 # pylint: disable=W0212 |
125 self._reader._close() |
128 self._reader._close() |
|
129 |
|
130 def getheader(self, header, default=None): |
|
131 return self.headers.getheader(header, default=default) |
|
132 |
|
133 def getheaders(self): |
|
134 return self.headers.items() |
126 |
135 |
127 def readline(self): |
136 def readline(self): |
128 """Read a single line from the response body. |
137 """Read a single line from the response body. |
129 |
138 |
130 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 |
277 self.headers = headers |
286 self.headers = headers |
278 # We're a friend of the reader class here. |
287 # We're a friend of the reader class here. |
279 # pylint: disable=W0212 |
288 # pylint: disable=W0212 |
280 self._load_response = self._reader._load |
289 self._load_response = self._reader._load |
281 |
290 |
|
291 def _foldheaders(headers): |
|
292 """Given some headers, rework them so we can safely overwrite values. |
|
293 |
|
294 >>> _foldheaders({'Accept-Encoding': 'wat'}) |
|
295 {'accept-encoding': ('Accept-Encoding', 'wat')} |
|
296 """ |
|
297 return dict((k.lower(), (k, v)) for k, v in headers.iteritems()) |
|
298 |
282 |
299 |
283 class HTTPConnection(object): |
300 class HTTPConnection(object): |
284 """Connection to a single http server. |
301 """Connection to a single http server. |
285 |
302 |
286 Supports 100-continue and keepalives natively. Uses select() for |
303 Supports 100-continue and keepalives natively. Uses select() for |
290 response_class = HTTPResponse |
307 response_class = HTTPResponse |
291 |
308 |
292 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, |
293 timeout=TIMEOUT_DEFAULT, |
310 timeout=TIMEOUT_DEFAULT, |
294 continue_timeout=TIMEOUT_ASSUME_CONTINUE, |
311 continue_timeout=TIMEOUT_ASSUME_CONTINUE, |
295 proxy_hostport=None, ssl_wrap_socket=None, **ssl_opts): |
312 proxy_hostport=None, proxy_headers=None, |
|
313 ssl_wrap_socket=None, **ssl_opts): |
296 """Create a new HTTPConnection. |
314 """Create a new HTTPConnection. |
297 |
315 |
298 Args: |
316 Args: |
299 host: The host to which we'll connect. |
317 host: The host to which we'll connect. |
300 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 |
305 timeout: Optional. Connection timeout, default is TIMEOUT_DEFAULT. |
323 timeout: Optional. Connection timeout, default is TIMEOUT_DEFAULT. |
306 continue_timeout: Optional. Timeout for waiting on an expected |
324 continue_timeout: Optional. Timeout for waiting on an expected |
307 "100 Continue" response. Default is TIMEOUT_ASSUME_CONTINUE. |
325 "100 Continue" response. Default is TIMEOUT_ASSUME_CONTINUE. |
308 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 |
309 proxy for the connection. Default is to not use a proxy. |
327 proxy for the connection. Default is to not use a proxy. |
|
328 proxy_headers: Optional dict of header keys and values to send to |
|
329 a proxy when using CONNECT. For compatibility with |
|
330 httplib, the Proxy-Authorization header may be |
|
331 specified in headers for request(), which will clobber |
|
332 any such header specified here if specified. Providing |
|
333 this option and not proxy_hostport will raise an |
|
334 ValueError. |
310 ssl_wrap_socket: Optional function to use for wrapping |
335 ssl_wrap_socket: Optional function to use for wrapping |
311 sockets. If unspecified, the one from the ssl module will |
336 sockets. If unspecified, the one from the ssl module will |
312 be used if available, or something that's compatible with |
337 be used if available, or something that's compatible with |
313 it if on a Python older than 2.6. |
338 it if on a Python older than 2.6. |
314 |
339 |
328 use_ssl = False |
353 use_ssl = False |
329 port = 80 |
354 port = 80 |
330 elif use_ssl is None: |
355 elif use_ssl is None: |
331 use_ssl = (port == 443) |
356 use_ssl = (port == 443) |
332 elif port is None: |
357 elif port is None: |
333 if use_ssl: |
358 port = (use_ssl and 443 or 80) |
334 port = 443 |
|
335 else: |
|
336 port = 80 |
|
337 self.port = port |
359 self.port = port |
338 if use_ssl and not socketutil.have_ssl: |
360 if use_ssl and not socketutil.have_ssl: |
339 raise Exception('ssl requested but unavailable on this Python') |
361 raise Exception('ssl requested but unavailable on this Python') |
340 self.ssl = use_ssl |
362 self.ssl = use_ssl |
341 self.ssl_opts = ssl_opts |
363 self.ssl_opts = ssl_opts |
344 self.sock = None |
366 self.sock = None |
345 self._current_response = None |
367 self._current_response = None |
346 self._current_response_taken = False |
368 self._current_response_taken = False |
347 if proxy_hostport is None: |
369 if proxy_hostport is None: |
348 self._proxy_host = self._proxy_port = None |
370 self._proxy_host = self._proxy_port = None |
|
371 if proxy_headers: |
|
372 raise ValueError( |
|
373 'proxy_headers may not be specified unless ' |
|
374 'proxy_hostport is also specified.') |
|
375 else: |
|
376 self._proxy_headers = {} |
349 else: |
377 else: |
350 self._proxy_host, self._proxy_port = proxy_hostport |
378 self._proxy_host, self._proxy_port = proxy_hostport |
|
379 self._proxy_headers = _foldheaders(proxy_headers or {}) |
351 |
380 |
352 self.timeout = timeout |
381 self.timeout = timeout |
353 self.continue_timeout = continue_timeout |
382 self.continue_timeout = continue_timeout |
354 |
383 |
355 def _connect(self): |
384 def _connect(self, proxy_headers): |
356 """Connect to the host and port specified in __init__.""" |
385 """Connect to the host and port specified in __init__.""" |
357 if self.sock: |
386 if self.sock: |
358 return |
387 return |
359 if self._proxy_host is not None: |
388 if self._proxy_host is not None: |
360 logger.info('Connecting to http proxy %s:%s', |
389 logger.info('Connecting to http proxy %s:%s', |
361 self._proxy_host, self._proxy_port) |
390 self._proxy_host, self._proxy_port) |
362 sock = socketutil.create_connection((self._proxy_host, |
391 sock = socketutil.create_connection((self._proxy_host, |
363 self._proxy_port)) |
392 self._proxy_port)) |
364 if self.ssl: |
393 if self.ssl: |
365 # TODO proxy header support |
|
366 data = self._buildheaders('CONNECT', '%s:%d' % (self.host, |
394 data = self._buildheaders('CONNECT', '%s:%d' % (self.host, |
367 self.port), |
395 self.port), |
368 {}, HTTP_VER_1_0) |
396 proxy_headers, HTTP_VER_1_0) |
369 sock.send(data) |
397 sock.send(data) |
370 sock.setblocking(0) |
398 sock.setblocking(0) |
371 r = self.response_class(sock, self.timeout, 'CONNECT') |
399 r = self.response_class(sock, self.timeout, 'CONNECT') |
372 timeout_exc = HTTPTimeoutException( |
400 timeout_exc = HTTPTimeoutException( |
373 'Timed out waiting for CONNECT response from proxy') |
401 'Timed out waiting for CONNECT response from proxy') |
466 self._current_response = None |
494 self._current_response = None |
467 return False |
495 return False |
468 return True |
496 return True |
469 return False |
497 return False |
470 |
498 |
471 def _reconnect(self, where): |
499 def _reconnect(self, where, pheaders): |
472 logger.info('reconnecting during %s', where) |
500 logger.info('reconnecting during %s', where) |
473 self.close() |
501 self.close() |
474 self._connect() |
502 self._connect(pheaders) |
475 |
503 |
476 def request(self, method, path, body=None, headers={}, |
504 def request(self, method, path, body=None, headers={}, |
477 expect_continue=False): |
505 expect_continue=False): |
478 """Send a request to the server. |
506 """Send a request to the server. |
479 |
507 |
490 'current response is read!') |
518 'current response is read!') |
491 self._current_response_taken = False |
519 self._current_response_taken = False |
492 |
520 |
493 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', |
494 method, path, self.host, self.port) |
522 method, path, self.host, self.port) |
495 hdrs = dict((k.lower(), (k, v)) for k, v in headers.iteritems()) |
523 hdrs = _foldheaders(headers) |
496 if hdrs.get('expect', ('', ''))[1].lower() == '100-continue': |
524 if hdrs.get('expect', ('', ''))[1].lower() == '100-continue': |
497 expect_continue = True |
525 expect_continue = True |
498 elif expect_continue: |
526 elif expect_continue: |
499 hdrs['expect'] = ('Expect', '100-Continue') |
527 hdrs['expect'] = ('Expect', '100-Continue') |
|
528 # httplib compatibility: if the user specified a |
|
529 # proxy-authorization header, that's actually intended for a |
|
530 # proxy CONNECT action, not the real request, but only if |
|
531 # we're going to use a proxy. |
|
532 pheaders = dict(self._proxy_headers) |
|
533 if self._proxy_host and self.ssl: |
|
534 pa = hdrs.pop('proxy-authorization', None) |
|
535 if pa is not None: |
|
536 pheaders['proxy-authorization'] = pa |
500 |
537 |
501 chunked = False |
538 chunked = False |
502 if body and HDR_CONTENT_LENGTH not in hdrs: |
539 if body and HDR_CONTENT_LENGTH not in hdrs: |
503 if getattr(body, '__len__', False): |
540 if getattr(body, '__len__', False): |
504 hdrs[HDR_CONTENT_LENGTH] = (HDR_CONTENT_LENGTH, len(body)) |
541 hdrs[HDR_CONTENT_LENGTH] = (HDR_CONTENT_LENGTH, len(body)) |
511 |
548 |
512 # If we're reusing the underlying socket, there are some |
549 # If we're reusing the underlying socket, there are some |
513 # 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 |
514 # state of self.sock |
551 # state of self.sock |
515 fresh_socket = self.sock is None |
552 fresh_socket = self.sock is None |
516 self._connect() |
553 self._connect(pheaders) |
517 outgoing_headers = self._buildheaders( |
554 outgoing_headers = self._buildheaders( |
518 method, path, hdrs, self.http_version) |
555 method, path, hdrs, self.http_version) |
519 response = None |
556 response = None |
520 first = True |
557 first = True |
521 |
558 |
586 # after getting a really large response |
623 # after getting a really large response |
587 # from the server. |
624 # from the server. |
588 logger.info( |
625 logger.info( |
589 'Connection appeared closed in read on first' |
626 'Connection appeared closed in read on first' |
590 ' request loop iteration, will retry.') |
627 ' request loop iteration, will retry.') |
591 self._reconnect('read') |
628 self._reconnect('read', pheaders) |
592 continue |
629 continue |
593 else: |
630 else: |
594 # We didn't just send the first data hunk, |
631 # We didn't just send the first data hunk, |
595 # and either have a partial response or no |
632 # and either have a partial response or no |
596 # response at all. There's really nothing |
633 # response at all. There's really nothing |
643 if e[0] == errno.EWOULDBLOCK or e[0] == errno.EAGAIN: |
680 if e[0] == errno.EWOULDBLOCK or e[0] == errno.EAGAIN: |
644 continue |
681 continue |
645 elif (e[0] not in (errno.ECONNRESET, errno.EPIPE) |
682 elif (e[0] not in (errno.ECONNRESET, errno.EPIPE) |
646 and not first): |
683 and not first): |
647 raise |
684 raise |
648 self._reconnect('write') |
685 self._reconnect('write', pheaders) |
649 amt = self.sock.send(out) |
686 amt = self.sock.send(out) |
650 logger.debug('sent %d', amt) |
687 logger.debug('sent %d', amt) |
651 first = False |
688 first = False |
652 if out is body: |
689 if out is body: |
653 body = out[amt:] |
690 body = out[amt:] |
662 if not response._select(): |
699 if not response._select(): |
663 # This means the response failed to get any response |
700 # This means the response failed to get any response |
664 # data at all, and in all probability the socket was |
701 # data at all, and in all probability the socket was |
665 # closed before the server even saw our request. Try |
702 # closed before the server even saw our request. Try |
666 # the request again on a fresh socket. |
703 # the request again on a fresh socket. |
667 logging.debug('response._select() failed during request().' |
704 logger.debug('response._select() failed during request().' |
668 ' Assuming request needs to be retried.') |
705 ' Assuming request needs to be retried.') |
669 self.sock = None |
706 self.sock = None |
670 # Call this method explicitly to re-try the |
707 # Call this method explicitly to re-try the |
671 # request. We don't use self.request() because |
708 # request. We don't use self.request() because |
672 # some tools (notably Mercurial) expect to be able |
709 # some tools (notably Mercurial) expect to be able |
673 # to subclass and redefine request(), and they |
710 # to subclass and redefine request(), and they |