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, |
|
|
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 |
|
|
|
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 |
|
|
|
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 |
logg |
|
|
668 |
|
|
|
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 |
|
|
102 |
occurs. No data will be returned after delimstr -- |
|
|
103 |
it occurs will be split and the remainder |
|
|
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