##// END OF EJS Templates
httpclient: update to 938f2107d6e2 of httpplus...
Augie Fackler -
r27601:1ad9da96 default
parent child Browse files
Show More
@@ -36,6 +36,7 b' httplib, but has several additional feat'
36 36 * notices when the server responds early to a request
37 37 * implements ssl inline instead of in a different class
38 38 """
39 from __future__ import absolute_import
39 40
40 41 # Many functions in this file have too many arguments.
41 42 # pylint: disable=R0913
@@ -48,8 +49,10 b' import rfc822'
48 49 import select
49 50 import socket
50 51
51 import _readers
52 import socketutil
52 from . import (
53 _readers,
54 socketutil,
55 )
53 56
54 57 logger = logging.getLogger(__name__)
55 58
@@ -124,6 +127,12 b' class HTTPResponse(object):'
124 127 # pylint: disable=W0212
125 128 self._reader._close()
126 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()
135
127 136 def readline(self):
128 137 """Read a single line from the response body.
129 138
@@ -279,6 +288,14 b' class HTTPResponse(object):'
279 288 # pylint: disable=W0212
280 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 300 class HTTPConnection(object):
284 301 """Connection to a single http server.
@@ -292,7 +309,8 b' class HTTPConnection(object):'
292 309 def __init__(self, host, port=None, use_ssl=None, ssl_validator=None,
293 310 timeout=TIMEOUT_DEFAULT,
294 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 314 """Create a new HTTPConnection.
297 315
298 316 Args:
@@ -307,6 +325,13 b' class HTTPConnection(object):'
307 325 "100 Continue" response. Default is TIMEOUT_ASSUME_CONTINUE.
308 326 proxy_hostport: Optional. Tuple of (host, port) to use as an http
309 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 335 ssl_wrap_socket: Optional function to use for wrapping
311 336 sockets. If unspecified, the one from the ssl module will
312 337 be used if available, or something that's compatible with
@@ -330,10 +355,7 b' class HTTPConnection(object):'
330 355 elif use_ssl is None:
331 356 use_ssl = (port == 443)
332 357 elif port is None:
333 if use_ssl:
334 port = 443
335 else:
336 port = 80
358 port = (use_ssl and 443 or 80)
337 359 self.port = port
338 360 if use_ssl and not socketutil.have_ssl:
339 361 raise Exception('ssl requested but unavailable on this Python')
@@ -346,13 +368,20 b' class HTTPConnection(object):'
346 368 self._current_response_taken = False
347 369 if proxy_hostport is None:
348 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 377 else:
350 378 self._proxy_host, self._proxy_port = proxy_hostport
379 self._proxy_headers = _foldheaders(proxy_headers or {})
351 380
352 381 self.timeout = timeout
353 382 self.continue_timeout = continue_timeout
354 383
355 def _connect(self):
384 def _connect(self, proxy_headers):
356 385 """Connect to the host and port specified in __init__."""
357 386 if self.sock:
358 387 return
@@ -362,10 +391,9 b' class HTTPConnection(object):'
362 391 sock = socketutil.create_connection((self._proxy_host,
363 392 self._proxy_port))
364 393 if self.ssl:
365 # TODO proxy header support
366 394 data = self._buildheaders('CONNECT', '%s:%d' % (self.host,
367 395 self.port),
368 {}, HTTP_VER_1_0)
396 proxy_headers, HTTP_VER_1_0)
369 397 sock.send(data)
370 398 sock.setblocking(0)
371 399 r = self.response_class(sock, self.timeout, 'CONNECT')
@@ -468,10 +496,10 b' class HTTPConnection(object):'
468 496 return True
469 497 return False
470 498
471 def _reconnect(self, where):
499 def _reconnect(self, where, pheaders):
472 500 logger.info('reconnecting during %s', where)
473 501 self.close()
474 self._connect()
502 self._connect(pheaders)
475 503
476 504 def request(self, method, path, body=None, headers={},
477 505 expect_continue=False):
@@ -492,11 +520,20 b' class HTTPConnection(object):'
492 520
493 521 logger.info('sending %s request for %s to %s on port %s',
494 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 524 if hdrs.get('expect', ('', ''))[1].lower() == '100-continue':
497 525 expect_continue = True
498 526 elif expect_continue:
499 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 538 chunked = False
502 539 if body and HDR_CONTENT_LENGTH not in hdrs:
@@ -513,7 +550,7 b' class HTTPConnection(object):'
513 550 # conditions where we'll want to retry, so make a note of the
514 551 # state of self.sock
515 552 fresh_socket = self.sock is None
516 self._connect()
553 self._connect(pheaders)
517 554 outgoing_headers = self._buildheaders(
518 555 method, path, hdrs, self.http_version)
519 556 response = None
@@ -588,7 +625,7 b' class HTTPConnection(object):'
588 625 logger.info(
589 626 'Connection appeared closed in read on first'
590 627 ' request loop iteration, will retry.')
591 self._reconnect('read')
628 self._reconnect('read', pheaders)
592 629 continue
593 630 else:
594 631 # We didn't just send the first data hunk,
@@ -645,7 +682,7 b' class HTTPConnection(object):'
645 682 elif (e[0] not in (errno.ECONNRESET, errno.EPIPE)
646 683 and not first):
647 684 raise
648 self._reconnect('write')
685 self._reconnect('write', pheaders)
649 686 amt = self.sock.send(out)
650 687 logger.debug('sent %d', amt)
651 688 first = False
@@ -664,8 +701,8 b' class HTTPConnection(object):'
664 701 # data at all, and in all probability the socket was
665 702 # closed before the server even saw our request. Try
666 703 # the request again on a fresh socket.
667 logging.debug('response._select() failed during request().'
668 ' Assuming request needs to be retried.')
704 logger.debug('response._select() failed during request().'
705 ' Assuming request needs to be retried.')
669 706 self.sock = None
670 707 # Call this method explicitly to re-try the
671 708 # request. We don't use self.request() because
@@ -31,6 +31,7 b''
31 31 This module is package-private. It is not expected that these will
32 32 have any clients outside of httpplus.
33 33 """
34 from __future__ import absolute_import
34 35
35 36 import httplib
36 37 import logging
@@ -98,11 +99,12 b' class AbstractReader(object):'
98 99 return result
99 100
100 101 def readto(self, delimstr, blocks = None):
101 """return available data chunks up to the first one in which delimstr
102 occurs. No data will be returned after delimstr -- the chunk in which
103 it occurs will be split and the remainder pushed back onto the available
104 data queue. If blocks is supplied chunks will be added to blocks, otherwise
105 a new list will be allocated.
102 """return available data chunks up to the first one in which
103 delimstr occurs. No data will be returned after delimstr --
104 the chunk in which it occurs will be split and the remainder
105 pushed back onto the available data queue. If blocks is
106 supplied chunks will be added to blocks, otherwise a new list
107 will be allocated.
106 108 """
107 109 if blocks is None:
108 110 blocks = []
@@ -32,6 +32,8 b' This will attempt to use the ssl module '
32 32 socket.create_connection method, but fall back to the old
33 33 methods if those are unavailable.
34 34 """
35 from __future__ import absolute_import
36
35 37 import logging
36 38 import socket
37 39
@@ -101,9 +101,6 b''
101 101 mercurial/cmdutil.py not using absolute_import
102 102 mercurial/commands.py not using absolute_import
103 103 mercurial/dispatch.py requires print_function
104 mercurial/httpclient/__init__.py not using absolute_import
105 mercurial/httpclient/_readers.py not using absolute_import
106 mercurial/httpclient/socketutil.py not using absolute_import
107 104 mercurial/keepalive.py requires print_function
108 105 mercurial/lsprof.py requires print_function
109 106 mercurial/lsprofcalltree.py requires print_function
General Comments 0
You need to be logged in to leave comments. Login now