mercurial/httpclient/__init__.py
author Pierre-Yves David <pierre-yves.david@ens-lyon.org>
Mon, 10 Apr 2017 16:53:37 +0200
changeset 31969 face2b5493fb
parent 31411 a53f2d4c734f
permissions -rw-r--r--
obsolescence: add test case D-1 for obsolescence markers exchange About 3 years ago, in August 2014, the logic to select what markers to select on push was ported from the evolve extension to Mercurial core. However, for some unclear reasons, the tests for that logic were not ported alongside. I realised it a couple of weeks ago while working on another push related issue. I've made a clean up pass on the tests and they are now ready to integrate the core test suite. This series of changesets do not change any logic. I just adds test for logic that has been around for about 10 versions of Mercurial. They are a patch for each test case. It makes it easier to review and postpone one with documentation issues without rejecting the wholes series. This patch introduce case D-1: Pruned changeset based on missing precursor of something not present Each test case comes it in own test file. It help parallelism and does not introduce a significant overhead from having a single unified giant test file. Here are timing to support this claim. # Multiple test files version: # run-tests.py --local -j 1 test-exchange-*.t 53.40s user 6.82s system 85% cpu 1:10.76 total 52.79s user 6.97s system 85% cpu 1:09.97 total 52.94s user 6.82s system 85% cpu 1:09.69 total # Single test file version: # run-tests.py --local -j 1 test-exchange-obsmarkers.t 52.97s user 6.85s system 85% cpu 1:10.10 total 52.64s user 6.79s system 85% cpu 1:09.63 total 53.70s user 7.00s system 85% cpu 1:11.17 total
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
     1
# Copyright 2010, Google Inc.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
     2
# All rights reserved.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
     3
#
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
     4
# Redistribution and use in source and binary forms, with or without
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
     5
# modification, are permitted provided that the following conditions are
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
     6
# met:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
     7
#
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
     8
#     * Redistributions of source code must retain the above copyright
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
     9
# notice, this list of conditions and the following disclaimer.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    10
#     * Redistributions in binary form must reproduce the above
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    11
# copyright notice, this list of conditions and the following disclaimer
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    12
# in the documentation and/or other materials provided with the
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    13
# distribution.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    14
#     * Neither the name of Google Inc. nor the names of its
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    15
# contributors may be used to endorse or promote products derived from
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    16
# this software without specific prior written permission.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    17
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    18
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    19
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    20
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    21
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    22
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    23
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    24
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    25
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    26
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    27
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    28
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    29
"""Improved HTTP/1.1 client library
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    30
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    31
This library contains an HTTPConnection which is similar to the one in
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    32
httplib, but has several additional features:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    33
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    34
  * supports keepalives natively
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    35
  * uses select() to block for incoming data
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    36
  * notices when the server responds early to a request
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    37
  * implements ssl inline instead of in a different class
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    38
"""
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
    39
from __future__ import absolute_import
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    40
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
    41
# Many functions in this file have too many arguments.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
    42
# pylint: disable=R0913
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
    43
import email
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
    44
import email.message
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    45
import errno
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    46
import inspect
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    47
import logging
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    48
import select
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    49
import socket
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
    50
import ssl
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
    51
import sys
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    52
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    53
try:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    54
    import cStringIO as io
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    55
    io.StringIO
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    56
except ImportError:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    57
    import io
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    58
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    59
try:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    60
    import httplib
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    61
    httplib.HTTPException
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    62
except ImportError:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    63
    import http.client as httplib
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    64
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
    65
from . import (
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
    66
    _readers,
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
    67
)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    68
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    69
logger = logging.getLogger(__name__)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    70
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    71
__all__ = ['HTTPConnection', 'HTTPResponse']
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    72
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
    73
HTTP_VER_1_0 = b'HTTP/1.0'
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
    74
HTTP_VER_1_1 = b'HTTP/1.1'
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    75
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    76
OUTGOING_BUFFER_SIZE = 1 << 15
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    77
INCOMING_BUFFER_SIZE = 1 << 20
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    78
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    79
HDR_ACCEPT_ENCODING = 'accept-encoding'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    80
HDR_CONNECTION_CTRL = 'connection'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    81
HDR_CONTENT_LENGTH = 'content-length'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    82
HDR_XFER_ENCODING = 'transfer-encoding'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    83
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    84
XFER_ENCODING_CHUNKED = 'chunked'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    85
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    86
CONNECTION_CLOSE = 'close'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    87
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
    88
EOL = b'\r\n'
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    89
_END_HEADERS = EOL * 2
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    90
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    91
# Based on some searching around, 1 second seems like a reasonable
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    92
# default here.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    93
TIMEOUT_ASSUME_CONTINUE = 1
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    94
TIMEOUT_DEFAULT = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
    95
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
    96
if sys.version_info > (3, 0):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
    97
    _unicode = str
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
    98
else:
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
    99
    _unicode = unicode
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   100
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   101
def _ensurebytes(data):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   102
    if not isinstance(data, (_unicode, bytes)):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   103
        data = str(data)
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   104
    if not isinstance(data, bytes):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   105
        try:
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   106
            return data.encode('latin-1')
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   107
        except UnicodeEncodeError as err:
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   108
            raise UnicodeEncodeError(
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   109
                err.encoding,
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   110
                err.object,
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   111
                err.start,
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   112
                err.end,
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   113
                '%r is not valid Latin-1 Use .encode("utf-8") '
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   114
                'if sending as utf-8 is desired.' % (
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   115
                    data[err.start:err.end],))
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   116
    return data
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   117
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   118
class _CompatMessage(email.message.Message):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   119
    """Workaround for rfc822.Message and email.message.Message API diffs."""
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   120
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   121
    @classmethod
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   122
    def from_string(cls, s):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   123
        if sys.version_info > (3, 0):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   124
            # Python 3 can't decode headers from bytes, so we have to
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   125
            # trust RFC 2616 and decode the headers as iso-8859-1
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   126
            # bytes.
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   127
            s = s.decode('iso-8859-1')
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   128
        headers = email.message_from_string(s, _class=_CompatMessage)
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   129
        # Fix multi-line headers to match httplib's behavior from
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   130
        # Python 2.x, since email.message.Message handles them in
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   131
        # slightly different ways.
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   132
        if sys.version_info < (3, 0):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   133
            new = []
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   134
            for h, v in headers._headers:
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   135
                if '\r\n' in v:
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   136
                    v = '\n'.join([' ' + x.lstrip() for x in v.split('\r\n')])[1:]
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   137
                new.append((h, v))
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   138
            headers._headers = new
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   139
        return headers
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   140
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   141
    def getheaders(self, key):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   142
        return self.get_all(key)
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   143
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   144
    def getheader(self, key, default=None):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   145
        return self.get(key, failobj=default)
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   146
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   147
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   148
class HTTPResponse(object):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   149
    """Response from an HTTP server.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   150
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   151
    The response will continue to load as available. If you need the
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   152
    complete response before continuing, check the .complete() method.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   153
    """
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   154
    def __init__(self, sock, timeout, method):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   155
        self.sock = sock
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   156
        self.method = method
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   157
        self.raw_response = b''
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   158
        self._headers_len = 0
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   159
        self.headers = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   160
        self.will_close = False
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   161
        self.status_line = b''
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   162
        self.status = None
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   163
        self.continued = False
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   164
        self.http_version = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   165
        self.reason = None
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   166
        self._reader = None
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   167
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   168
        self._read_location = 0
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   169
        self._eol = EOL
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   170
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   171
        self._timeout = timeout
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   172
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   173
    @property
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   174
    def _end_headers(self):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   175
        return self._eol * 2
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   176
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   177
    def complete(self):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   178
        """Returns true if this response is completely loaded.
14376
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   179
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   180
        Note that if this is a connection where complete means the
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   181
        socket is closed, this will nearly always return False, even
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   182
        in cases where all the data has actually been loaded.
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   183
        """
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   184
        if self._reader:
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   185
            return self._reader.done()
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   186
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   187
    def _close(self):
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   188
        if self._reader is not None:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   189
            # We're a friend of the reader class here.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   190
            # pylint: disable=W0212
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   191
            self._reader._close()
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   192
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   193
    def getheader(self, header, default=None):
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   194
        return self.headers.getheader(header, default=default)
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   195
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   196
    def getheaders(self):
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   197
        if sys.version_info < (3, 0):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   198
            return [(k.lower(), v) for k, v in self.headers.items()]
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   199
        # Starting in Python 3, headers aren't lowercased before being
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   200
        # returned here.
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   201
        return self.headers.items()
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   202
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   203
    def readline(self):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   204
        """Read a single line from the response body.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   205
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   206
        This may block until either a line ending is found or the
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   207
        response is complete.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   208
        """
19038
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
   209
        blocks = []
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
   210
        while True:
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   211
            self._reader.readto(b'\n', blocks)
19038
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
   212
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   213
            if blocks and blocks[-1][-1:] == b'\n' or self.complete():
19038
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
   214
                break
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
   215
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   216
            self._select()
19038
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
   217
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   218
        return b''.join(blocks)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   219
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   220
    def read(self, length=None):
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   221
        """Read data from the response body."""
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   222
        # if length is None, unbounded read
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   223
        while (not self.complete()  # never select on a finished read
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   224
               and (not length  # unbounded, so we wait for complete()
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   225
                    or length > self._reader.available_data)):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   226
            self._select()
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   227
        if not length:
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   228
            length = self._reader.available_data
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   229
        r = self._reader.read(length)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   230
        if self.complete() and self.will_close:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   231
            self.sock.close()
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   232
        return r
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   233
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   234
    def _select(self):
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   235
        r, unused_write, unused_err = select.select(
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   236
            [self.sock], [], [], self._timeout)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   237
        if not r:
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   238
            # socket was not readable. If the response is not
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   239
            # complete, raise a timeout.
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   240
            if not self.complete():
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   241
                logger.info('timed out with timeout of %s', self._timeout)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   242
                raise HTTPTimeoutException('timeout reading data')
14341
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
   243
        try:
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
   244
            data = self.sock.recv(INCOMING_BUFFER_SIZE)
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   245
        except ssl.SSLError as e:
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   246
            if e.args[0] != ssl.SSL_ERROR_WANT_READ:
14341
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
   247
                raise
17428
72803c8edaa4 avoid using abbreviations that look like spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents: 17424
diff changeset
   248
            logger.debug('SSL_ERROR_WANT_READ in _select, should retry later')
14341
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
   249
            return True
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   250
        logger.debug('response read %d data during _select', len(data))
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   251
        # If the socket was readable and no data was read, that means
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   252
        # the socket was closed. Inform the reader (if any) so it can
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   253
        # raise an exception if this is an invalid situation.
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   254
        if not data:
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   255
            if self._reader:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   256
                # We're a friend of the reader class here.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   257
                # pylint: disable=W0212
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   258
                self._reader._close()
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   259
            return False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   260
        else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   261
            self._load_response(data)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   262
            return True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   263
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   264
    # This method gets replaced by _load later, which confuses pylint.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   265
    def _load_response(self, data): # pylint: disable=E0202
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   266
        # Being here implies we're not at the end of the headers yet,
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   267
        # since at the end of this method if headers were completely
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   268
        # loaded we replace this method with the load() method of the
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   269
        # reader we created.
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   270
        self.raw_response += data
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   271
        # This is a bogus server with bad line endings
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   272
        if self._eol not in self.raw_response:
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   273
            for bad_eol in (b'\n', b'\r'):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   274
                if (bad_eol in self.raw_response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   275
                    # verify that bad_eol is not the end of the incoming data
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   276
                    # as this could be a response line that just got
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   277
                    # split between \r and \n.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   278
                    and (self.raw_response.index(bad_eol) <
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   279
                         (len(self.raw_response) - 1))):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   280
                    logger.info('bogus line endings detected, '
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   281
                                'using %r for EOL', bad_eol)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   282
                    self._eol = bad_eol
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   283
                    break
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   284
        # exit early if not at end of headers
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   285
        if self._end_headers not in self.raw_response or self.headers:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   286
            return
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   287
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   288
        # handle 100-continue response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   289
        hdrs, body = self.raw_response.split(self._end_headers, 1)
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   290
        unused_http_ver, status = hdrs.split(b' ', 1)
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   291
        if status.startswith(b'100'):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   292
            self.raw_response = body
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   293
            self.continued = True
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   294
            logger.debug('continue seen, setting body to %r', body)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   295
            return
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   296
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   297
        # arriving here means we should parse response headers
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   298
        # as all headers have arrived completely
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   299
        hdrs, body = self.raw_response.split(self._end_headers, 1)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   300
        del self.raw_response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   301
        if self._eol in hdrs:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   302
            self.status_line, hdrs = hdrs.split(self._eol, 1)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   303
        else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   304
            self.status_line = hdrs
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   305
            hdrs = b''
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   306
        # TODO HTTP < 1.0 support
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   307
        (self.http_version, self.status,
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   308
         self.reason) = self.status_line.split(b' ', 2)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   309
        self.status = int(self.status)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   310
        if self._eol != EOL:
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   311
            hdrs = hdrs.replace(self._eol, b'\r\n')
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   312
        headers = _CompatMessage.from_string(hdrs)
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   313
        content_len = None
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   314
        if HDR_CONTENT_LENGTH in headers:
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   315
            content_len = int(headers[HDR_CONTENT_LENGTH])
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   316
        if self.http_version == HTTP_VER_1_0:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   317
            self.will_close = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   318
        elif HDR_CONNECTION_CTRL in headers:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   319
            self.will_close = (
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   320
                headers[HDR_CONNECTION_CTRL].lower() == CONNECTION_CLOSE)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   321
        if (HDR_XFER_ENCODING in headers
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   322
            and headers[HDR_XFER_ENCODING].lower() == XFER_ENCODING_CHUNKED):
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   323
            self._reader = _readers.ChunkedReader(self._eol)
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   324
            logger.debug('using a chunked reader')
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   325
        else:
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   326
            # HEAD responses are forbidden from returning a body, and
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   327
            # it's implausible for a CONNECT response to use
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   328
            # close-is-end logic for an OK response.
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   329
            if (self.method == b'HEAD' or
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   330
                (self.method == b'CONNECT' and content_len is None)):
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   331
                content_len = 0
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   332
            if content_len is not None:
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   333
                logger.debug('using a content-length reader with length %d',
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   334
                             content_len)
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   335
                self._reader = _readers.ContentLengthReader(content_len)
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   336
            else:
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   337
                # Response body had no length specified and is not
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   338
                # chunked, so the end of the body will only be
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   339
                # identifiable by the termination of the socket by the
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   340
                # server. My interpretation of the spec means that we
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   341
                # are correct in hitting this case if
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   342
                # transfer-encoding, content-length, and
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   343
                # connection-control were left unspecified.
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   344
                self._reader = _readers.CloseIsEndReader()
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   345
                logger.debug('using a close-is-end reader')
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   346
                self.will_close = True
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   347
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   348
        if body:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   349
            # We're a friend of the reader class here.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   350
            # pylint: disable=W0212
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   351
            self._reader._load(body)
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   352
        logger.debug('headers complete')
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   353
        self.headers = headers
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   354
        # We're a friend of the reader class here.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   355
        # pylint: disable=W0212
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   356
        self._load_response = self._reader._load
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   357
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   358
def _foldheaders(headers):
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   359
    """Given some headers, rework them so we can safely overwrite values.
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   360
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   361
    >>> _foldheaders({'Accept-Encoding': 'wat'})
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   362
    {'accept-encoding': ('Accept-Encoding', 'wat')}
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   363
    """
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   364
    return dict((k.lower(), (k, v)) for k, v in headers.items())
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   365
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   366
try:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   367
    inspect.signature
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   368
    def _handlesarg(func, arg):
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   369
        """ Try to determine if func accepts arg
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   370
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   371
        If it takes arg, return True
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   372
        If it happens to take **args, then it could do anything:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   373
            * It could throw a different TypeError, just for fun
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   374
            * It could throw an ArgumentError or anything else
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   375
            * It could choose not to throw an Exception at all
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   376
        ... return 'unknown'
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   377
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   378
        Otherwise, return False
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   379
        """
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   380
        params = inspect.signature(func).parameters
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   381
        if arg in params:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   382
            return True
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   383
        for p in params:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   384
            if params[p].kind == inspect._ParameterKind.VAR_KEYWORD:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   385
                return 'unknown'
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   386
        return False
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   387
except AttributeError:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   388
    def _handlesarg(func, arg):
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   389
        """ Try to determine if func accepts arg
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   390
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   391
        If it takes arg, return True
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   392
        If it happens to take **args, then it could do anything:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   393
            * It could throw a different TypeError, just for fun
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   394
            * It could throw an ArgumentError or anything else
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   395
            * It could choose not to throw an Exception at all
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   396
        ... return 'unknown'
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   397
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   398
        Otherwise, return False
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   399
        """
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   400
        spec = inspect.getargspec(func)
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   401
        if arg in spec.args:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   402
            return True
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   403
        if spec.keywords:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   404
            return 'unknown'
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   405
        return False
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   406
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   407
class HTTPConnection(object):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   408
    """Connection to a single http server.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   409
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   410
    Supports 100-continue and keepalives natively. Uses select() for
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   411
    non-blocking socket operations.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   412
    """
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   413
    http_version = HTTP_VER_1_1
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   414
    response_class = HTTPResponse
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   415
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   416
    def __init__(self, host, port=None, use_ssl=None, ssl_validator=None,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   417
                 timeout=TIMEOUT_DEFAULT,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   418
                 continue_timeout=TIMEOUT_ASSUME_CONTINUE,
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   419
                 proxy_hostport=None, proxy_headers=None,
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   420
                 ssl_wrap_socket=None, **ssl_opts):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   421
        """Create a new HTTPConnection.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   422
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   423
        Args:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   424
          host: The host to which we'll connect.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   425
          port: Optional. The port over which we'll connect. Default 80 for
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   426
                non-ssl, 443 for ssl.
17424
e7cfe3587ea4 fix trivial spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents: 16774
diff changeset
   427
          use_ssl: Optional. Whether to use ssl. Defaults to False if port is
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   428
                   not 443, true if port is 443.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   429
          ssl_validator: a function(socket) to validate the ssl cert
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   430
          timeout: Optional. Connection timeout, default is TIMEOUT_DEFAULT.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   431
          continue_timeout: Optional. Timeout for waiting on an expected
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   432
                   "100 Continue" response. Default is TIMEOUT_ASSUME_CONTINUE.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   433
          proxy_hostport: Optional. Tuple of (host, port) to use as an http
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   434
                       proxy for the connection. Default is to not use a proxy.
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   435
          proxy_headers: Optional dict of header keys and values to send to
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   436
                         a proxy when using CONNECT. For compatibility with
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   437
                         httplib, the Proxy-Authorization header may be
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   438
                         specified in headers for request(), which will clobber
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   439
                         any such header specified here if specified. Providing
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   440
                         this option and not proxy_hostport will raise an
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   441
                         ValueError.
19807
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
   442
          ssl_wrap_socket: Optional function to use for wrapping
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
   443
            sockets. If unspecified, the one from the ssl module will
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
   444
            be used if available, or something that's compatible with
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
   445
            it if on a Python older than 2.6.
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
   446
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
   447
        Any extra keyword arguments to this function will be provided
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
   448
        to the ssl_wrap_socket method. If no ssl
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   449
        """
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   450
        host = _ensurebytes(host)
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   451
        if port is None and host.count(b':') == 1 or b']:' in host:
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   452
            host, port = host.rsplit(b':', 1)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   453
            port = int(port)
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   454
            if b'[' in host:
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   455
                host = host[1:-1]
19807
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
   456
        if ssl_wrap_socket is not None:
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   457
            _wrap_socket = ssl_wrap_socket
19807
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
   458
        else:
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   459
            _wrap_socket = ssl.wrap_socket
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   460
        call_wrap_socket = None
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   461
        handlesubar = _handlesarg(_wrap_socket, 'server_hostname')
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   462
        if handlesubar is True:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   463
            # supports server_hostname
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   464
            call_wrap_socket = _wrap_socket
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   465
        handlesnobar = _handlesarg(_wrap_socket, 'serverhostname')
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   466
        if handlesnobar is True and handlesubar is not True:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   467
            # supports serverhostname
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   468
            def call_wrap_socket(sock, server_hostname=None, **ssl_opts):
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   469
                return _wrap_socket(sock, serverhostname=server_hostname,
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   470
                                    **ssl_opts)
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   471
        if handlesubar is False and handlesnobar is False:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   472
            # does not support either
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   473
            def call_wrap_socket(sock, server_hostname=None, **ssl_opts):
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   474
                return _wrap_socket(sock, **ssl_opts)
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   475
        if call_wrap_socket is None:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   476
            # we assume it takes **args
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   477
            def call_wrap_socket(sock, **ssl_opts):
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   478
                if 'server_hostname' in ssl_opts:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   479
                    ssl_opts['serverhostname'] = ssl_opts['server_hostname']
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   480
                return _wrap_socket(sock, **ssl_opts)
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   481
        self._ssl_wrap_socket = call_wrap_socket
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   482
        if use_ssl is None and port is None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   483
            use_ssl = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   484
            port = 80
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   485
        elif use_ssl is None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   486
            use_ssl = (port == 443)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   487
        elif port is None:
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   488
            port = (use_ssl and 443 or 80)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   489
        self.port = port
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   490
        self.ssl = use_ssl
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   491
        self.ssl_opts = ssl_opts
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   492
        self._ssl_validator = ssl_validator
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   493
        self.host = host
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   494
        self.sock = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   495
        self._current_response = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   496
        self._current_response_taken = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   497
        if proxy_hostport is None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   498
            self._proxy_host = self._proxy_port = None
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   499
            if proxy_headers:
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   500
                raise ValueError(
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   501
                    'proxy_headers may not be specified unless '
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   502
                    'proxy_hostport is also specified.')
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   503
            else:
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   504
                self._proxy_headers = {}
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   505
        else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   506
            self._proxy_host, self._proxy_port = proxy_hostport
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   507
            self._proxy_headers = _foldheaders(proxy_headers or {})
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   508
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   509
        self.timeout = timeout
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   510
        self.continue_timeout = continue_timeout
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   511
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   512
    def _connect(self, proxy_headers):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   513
        """Connect to the host and port specified in __init__."""
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   514
        if self.sock:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   515
            return
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   516
        if self._proxy_host is not None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   517
            logger.info('Connecting to http proxy %s:%s',
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   518
                        self._proxy_host, self._proxy_port)
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   519
            sock = socket.create_connection((self._proxy_host,
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   520
                                             self._proxy_port))
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   521
            if self.ssl:
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   522
                data = self._buildheaders(b'CONNECT', b'%s:%d' % (self.host,
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   523
                                                                  self.port),
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   524
                                          proxy_headers, HTTP_VER_1_0)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   525
                sock.send(data)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   526
                sock.setblocking(0)
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   527
                r = self.response_class(sock, self.timeout, b'CONNECT')
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   528
                timeout_exc = HTTPTimeoutException(
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   529
                    'Timed out waiting for CONNECT response from proxy')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   530
                while not r.complete():
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   531
                    try:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   532
                        # We're a friend of the response class, so let
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   533
                        # us use the private attribute.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   534
                        # pylint: disable=W0212
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   535
                        if not r._select():
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   536
                            if not r.complete():
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   537
                                raise timeout_exc
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   538
                    except HTTPTimeoutException:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   539
                        # This raise/except pattern looks goofy, but
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   540
                        # _select can raise the timeout as well as the
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   541
                        # loop body. I wish it wasn't this convoluted,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   542
                        # but I don't have a better solution
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   543
                        # immediately handy.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   544
                        raise timeout_exc
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   545
                if r.status != 200:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   546
                    raise HTTPProxyConnectFailedException(
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   547
                        'Proxy connection failed: %d %s' % (r.status,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   548
                                                            r.read()))
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   549
                logger.info('CONNECT (for SSL) to %s:%s via proxy succeeded.',
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   550
                            self.host, self.port)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   551
        else:
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   552
            sock = socket.create_connection((self.host, self.port))
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   553
        if self.ssl:
16774
69af967b6d6f httpclient: update to c5abd358e543 of httpplus
Augie Fackler <raf@durin42.com>
parents: 16643
diff changeset
   554
            # This is the default, but in the case of proxied SSL
69af967b6d6f httpclient: update to c5abd358e543 of httpplus
Augie Fackler <raf@durin42.com>
parents: 16643
diff changeset
   555
            # requests the proxy logic above will have cleared
17424
e7cfe3587ea4 fix trivial spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents: 16774
diff changeset
   556
            # blocking mode, so re-enable it just to be safe.
16774
69af967b6d6f httpclient: update to c5abd358e543 of httpplus
Augie Fackler <raf@durin42.com>
parents: 16643
diff changeset
   557
            sock.setblocking(1)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   558
            logger.debug('wrapping socket for ssl with options %r',
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   559
                         self.ssl_opts)
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   560
            sock = self._ssl_wrap_socket(sock, server_hostname=self.host,
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
   561
                                         **self.ssl_opts)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   562
            if self._ssl_validator:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   563
                self._ssl_validator(sock)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   564
        sock.setblocking(0)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   565
        self.sock = sock
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   566
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   567
    def _buildheaders(self, method, path, headers, http_ver):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   568
        if self.ssl and self.port == 443 or self.port == 80:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   569
            # default port for protocol, so leave it out
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   570
            hdrhost = self.host
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   571
        else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   572
            # include nonstandard port in header
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   573
            if b':' in self.host:  # must be IPv6
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   574
                hdrhost = b'[%s]:%d' % (self.host, self.port)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   575
            else:
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   576
                hdrhost = b'%s:%d' % (self.host, self.port)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   577
        if self._proxy_host and not self.ssl:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   578
            # When talking to a regular http proxy we must send the
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   579
            # full URI, but in all other cases we must not (although
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   580
            # technically RFC 2616 says servers must accept our
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   581
            # request if we screw up, experimentally few do that
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   582
            # correctly.)
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   583
            assert path[0:1] == b'/', 'path must start with a /'
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   584
            path = b'http://%s%s' % (hdrhost, path)
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   585
        outgoing = [b'%s %s %s%s' % (method, path, http_ver, EOL)]
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   586
        headers[b'host'] = (b'Host', hdrhost)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   587
        headers[HDR_ACCEPT_ENCODING] = (HDR_ACCEPT_ENCODING, 'identity')
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   588
        for hdr, val in sorted((_ensurebytes(h), _ensurebytes(v))
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   589
                               for h, v in headers.values()):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   590
            outgoing.append(b'%s: %s%s' % (hdr, val, EOL))
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   591
        outgoing.append(EOL)
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   592
        return b''.join(outgoing)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   593
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   594
    def close(self):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   595
        """Close the connection to the server.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   596
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   597
        This is a no-op if the connection is already closed. The
17536
dc6364a81e42 spelling: requested
timeless@mozdev.org
parents: 16774
diff changeset
   598
        connection may automatically close if requested by the server
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   599
        or required by the nature of a response.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   600
        """
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   601
        if self.sock is None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   602
            return
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   603
        self.sock.close()
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   604
        self.sock = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   605
        logger.info('closed connection to %s on %s', self.host, self.port)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   606
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   607
    def busy(self):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   608
        """Returns True if this connection object is currently in use.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   609
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   610
        If a response is still pending, this will return True, even if
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   611
        the request has finished sending. In the future,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   612
        HTTPConnection may transparently juggle multiple connections
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   613
        to the server, in which case this will be useful to detect if
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   614
        any of those connections is ready for use.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   615
        """
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   616
        cr = self._current_response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   617
        if cr is not None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   618
            if self._current_response_taken:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   619
                if cr.will_close:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   620
                    self.sock = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   621
                    self._current_response = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   622
                    return False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   623
                elif cr.complete():
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   624
                    self._current_response = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   625
                    return False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   626
            return True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   627
        return False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   628
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   629
    def _reconnect(self, where, pheaders):
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   630
        logger.info('reconnecting during %s', where)
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   631
        self.close()
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   632
        self._connect(pheaders)
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   633
31411
a53f2d4c734f httpclient: don't use mutable default argument value
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 29442
diff changeset
   634
    def request(self, method, path, body=None, headers=None,
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   635
                expect_continue=False):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   636
        """Send a request to the server.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   637
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   638
        For increased flexibility, this does not return the response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   639
        object. Future versions of HTTPConnection that juggle multiple
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   640
        sockets will be able to send (for example) 5 requests all at
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   641
        once, and then let the requests arrive as data is
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   642
        available. Use the `getresponse()` method to retrieve the
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   643
        response.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   644
        """
31411
a53f2d4c734f httpclient: don't use mutable default argument value
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 29442
diff changeset
   645
        if headers is None:
a53f2d4c734f httpclient: don't use mutable default argument value
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 29442
diff changeset
   646
            headers = {}
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   647
        method = _ensurebytes(method)
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   648
        path = _ensurebytes(path)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   649
        if self.busy():
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   650
            raise httplib.CannotSendRequest(
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   651
                'Can not send another request before '
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   652
                'current response is read!')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   653
        self._current_response_taken = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   654
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   655
        logger.info('sending %s request for %s to %s on port %s',
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   656
                    method, path, self.host, self.port)
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   657
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   658
        hdrs = _foldheaders(headers)
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   659
        # Figure out headers that have to be computed from the request
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   660
        # body.
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   661
        chunked = False
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   662
        if body and HDR_CONTENT_LENGTH not in hdrs:
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   663
            if getattr(body, '__len__', False):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   664
                hdrs[HDR_CONTENT_LENGTH] = (HDR_CONTENT_LENGTH,
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   665
                                            b'%d' % len(body))
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   666
            elif getattr(body, 'read', False):
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   667
                hdrs[HDR_XFER_ENCODING] = (HDR_XFER_ENCODING,
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   668
                                           XFER_ENCODING_CHUNKED)
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   669
                chunked = True
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   670
            else:
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   671
                raise BadRequestData('body has no __len__() nor read()')
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   672
        # Figure out expect-continue header
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   673
        if hdrs.get('expect', ('', ''))[1].lower() == b'100-continue':
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   674
            expect_continue = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   675
        elif expect_continue:
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   676
            hdrs['expect'] = (b'Expect', b'100-Continue')
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   677
        # httplib compatibility: if the user specified a
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   678
        # proxy-authorization header, that's actually intended for a
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   679
        # proxy CONNECT action, not the real request, but only if
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   680
        # we're going to use a proxy.
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   681
        pheaders = dict(self._proxy_headers)
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   682
        if self._proxy_host and self.ssl:
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   683
            pa = hdrs.pop('proxy-authorization', None)
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   684
            if pa is not None:
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   685
                pheaders['proxy-authorization'] = pa
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   686
        # Build header data
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   687
        outgoing_headers = self._buildheaders(
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   688
            method, path, hdrs, self.http_version)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   689
19620
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   690
        # If we're reusing the underlying socket, there are some
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   691
        # conditions where we'll want to retry, so make a note of the
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   692
        # state of self.sock
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   693
        fresh_socket = self.sock is None
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   694
        self._connect(pheaders)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   695
        response = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   696
        first = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   697
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   698
        while ((outgoing_headers or body)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   699
               and not (response and response.complete())):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   700
            select_timeout = self.timeout
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   701
            out = outgoing_headers or body
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   702
            blocking_on_continue = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   703
            if expect_continue and not outgoing_headers and not (
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   704
                response and (response.headers or response.continued)):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   705
                logger.info(
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   706
                    'waiting up to %s seconds for'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   707
                    ' continue response from server',
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   708
                    self.continue_timeout)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   709
                select_timeout = self.continue_timeout
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   710
                blocking_on_continue = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   711
                out = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   712
            if out:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   713
                w = [self.sock]
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   714
            else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   715
                w = []
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   716
            r, w, x = select.select([self.sock], w, [], select_timeout)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   717
            # if we were expecting a 100 continue and it's been long
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   718
            # enough, just go ahead and assume it's ok. This is the
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   719
            # recommended behavior from the RFC.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   720
            if r == w == x == []:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   721
                if blocking_on_continue:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   722
                    expect_continue = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   723
                    logger.info('no response to continue expectation from '
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   724
                                'server, optimistically sending request body')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   725
                else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   726
                    raise HTTPTimeoutException('timeout sending data')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   727
            was_first = first
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   728
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   729
            # incoming data
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   730
            if r:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   731
                try:
14341
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
   732
                    try:
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
   733
                        data = r[0].recv(INCOMING_BUFFER_SIZE)
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   734
                    except ssl.SSLError as e:
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   735
                        if e.args[0] != ssl.SSL_ERROR_WANT_READ:
14341
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
   736
                            raise
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   737
                        logger.debug('SSL_ERROR_WANT_READ while sending '
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   738
                                     'data, retrying...')
14341
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
   739
                        continue
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   740
                    if not data:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   741
                        logger.info('socket appears closed in read')
14376
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   742
                        self.sock = None
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   743
                        self._current_response = None
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   744
                        if response is not None:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   745
                            # We're a friend of the response class, so let
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   746
                            # us use the private attribute.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   747
                            # pylint: disable=W0212
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   748
                            response._close()
14376
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   749
                        # This if/elif ladder is a bit subtle,
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   750
                        # comments in each branch should help.
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   751
                        if response is not None and response.complete():
14376
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   752
                            # Server responded completely and then
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   753
                            # closed the socket. We should just shut
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   754
                            # things down and let the caller get their
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   755
                            # response.
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   756
                            logger.info('Got an early response, '
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   757
                                        'aborting remaining request.')
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   758
                            break
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   759
                        elif was_first and response is None:
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   760
                            # Most likely a keepalive that got killed
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   761
                            # on the server's end. Commonly happens
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   762
                            # after getting a really large response
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   763
                            # from the server.
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   764
                            logger.info(
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   765
                                'Connection appeared closed in read on first'
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   766
                                ' request loop iteration, will retry.')
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   767
                            self._reconnect('read', pheaders)
14376
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   768
                            continue
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   769
                        else:
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   770
                            # We didn't just send the first data hunk,
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   771
                            # and either have a partial response or no
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   772
                            # response at all. There's really nothing
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   773
                            # meaningful we can do here.
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   774
                            raise HTTPStateError(
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   775
                                'Connection appears closed after '
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   776
                                'some request data was written, but the '
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   777
                                'response was missing or incomplete!')
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   778
                    logger.debug('read %d bytes in request()', len(data))
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   779
                    if response is None:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   780
                        response = self.response_class(
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   781
                            r[0], self.timeout, method)
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   782
                    # We're a friend of the response class, so let us
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   783
                    # use the private attribute.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   784
                    # pylint: disable=W0212
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   785
                    response._load_response(data)
14376
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   786
                    # Jump to the next select() call so we load more
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   787
                    # data if the server is still sending us content.
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   788
                    continue
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24306
diff changeset
   789
                except socket.error as e:
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   790
                    if e[0] != errno.EPIPE and not was_first:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   791
                        raise
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   792
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   793
            # outgoing data
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   794
            if w and out:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   795
                try:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   796
                    if getattr(out, 'read', False):
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   797
                        # pylint guesses the type of out incorrectly here
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   798
                        # pylint: disable=E1103
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   799
                        data = out.read(OUTGOING_BUFFER_SIZE)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   800
                        if not data:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   801
                            continue
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   802
                        if len(data) < OUTGOING_BUFFER_SIZE:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   803
                            if chunked:
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   804
                                body = b'0' + EOL + EOL
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   805
                            else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   806
                                body = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   807
                        if chunked:
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   808
                            # This encode is okay because we know
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   809
                            # hex() is building us only 0-9 and a-f
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   810
                            # digits.
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   811
                            asciilen = hex(len(data))[2:].encode('ascii')
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   812
                            out = asciilen + EOL + data + EOL
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   813
                        else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   814
                            out = data
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   815
                    amt = w[0].send(out)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24306
diff changeset
   816
                except socket.error as e:
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   817
                    if e[0] == ssl.SSL_ERROR_WANT_WRITE and self.ssl:
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   818
                        # This means that SSL hasn't flushed its buffer into
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   819
                        # the socket yet.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   820
                        # TODO: find a way to block on ssl flushing its buffer
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   821
                        # similar to selecting on a raw socket.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   822
                        continue
19489
42fcb2f7787d httpclient: update to revision 9517a2b56fe9 of httpplus (issue3905)
Augie Fackler <raf@durin42.com>
parents: 19182
diff changeset
   823
                    if e[0] == errno.EWOULDBLOCK or e[0] == errno.EAGAIN:
42fcb2f7787d httpclient: update to revision 9517a2b56fe9 of httpplus (issue3905)
Augie Fackler <raf@durin42.com>
parents: 19182
diff changeset
   824
                        continue
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   825
                    elif (e[0] not in (errno.ECONNRESET, errno.EPIPE)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   826
                          and not first):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   827
                        raise
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   828
                    self._reconnect('write', pheaders)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   829
                    amt = self.sock.send(out)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   830
                logger.debug('sent %d', amt)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   831
                first = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   832
                if out is body:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   833
                    body = out[amt:]
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   834
                else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   835
                    outgoing_headers = out[amt:]
29442
456609cbd840 httpclient: update to 54868ef054d2 of httpplus
Augie Fackler <raf@durin42.com>
parents: 29131
diff changeset
   836
        # End of request-sending loop.
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   837
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   838
        # close if the server response said to or responded before eating
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   839
        # the whole request
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   840
        if response is None:
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   841
            response = self.response_class(self.sock, self.timeout, method)
19620
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   842
            if not fresh_socket:
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   843
                if not response._select():
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   844
                    # This means the response failed to get any response
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   845
                    # data at all, and in all probability the socket was
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   846
                    # closed before the server even saw our request. Try
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   847
                    # the request again on a fresh socket.
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   848
                    logger.debug('response._select() failed during request().'
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
   849
                                 ' Assuming request needs to be retried.')
19620
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   850
                    self.sock = None
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   851
                    # Call this method explicitly to re-try the
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   852
                    # request. We don't use self.request() because
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   853
                    # some tools (notably Mercurial) expect to be able
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   854
                    # to subclass and redefine request(), and they
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   855
                    # don't have the same argspec as we do.
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   856
                    #
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   857
                    # TODO restructure sending of requests to avoid
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   858
                    # this recursion
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   859
                    return HTTPConnection.request(
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   860
                        self, method, path, body=body, headers=headers,
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
   861
                        expect_continue=expect_continue)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   862
        data_left = bool(outgoing_headers or body)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   863
        if data_left:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   864
            logger.info('stopped sending request early, '
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   865
                         'will close the socket to be safe.')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   866
            response.will_close = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   867
        if response.will_close:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   868
            # The socket will be closed by the response, so we disown
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   869
            # the socket
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   870
            self.sock = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   871
        self._current_response = response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   872
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   873
    def getresponse(self):
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   874
        """Returns the response to the most recent request."""
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   875
        if self._current_response is None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   876
            raise httplib.ResponseNotReady()
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   877
        r = self._current_response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   878
        while r.headers is None:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   879
            # We're a friend of the response class, so let us use the
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   880
            # private attribute.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
   881
            # pylint: disable=W0212
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   882
            if not r._select() and not r.complete():
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   883
                raise _readers.HTTPRemoteClosedError()
14293
9adbb5ef0964 httpclient: import f4c380237fd5 to fix keepalive not working
Augie Fackler <durin42@gmail.com>
parents: 14243
diff changeset
   884
        if r.will_close:
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   885
            self.sock = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   886
            self._current_response = None
14293
9adbb5ef0964 httpclient: import f4c380237fd5 to fix keepalive not working
Augie Fackler <durin42@gmail.com>
parents: 14243
diff changeset
   887
        elif r.complete():
9adbb5ef0964 httpclient: import f4c380237fd5 to fix keepalive not working
Augie Fackler <durin42@gmail.com>
parents: 14243
diff changeset
   888
            self._current_response = None
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   889
        else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   890
            self._current_response_taken = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   891
        return r
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   892
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   893
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   894
class HTTPTimeoutException(httplib.HTTPException):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   895
    """A timeout occurred while waiting on the server."""
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   896
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   897
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   898
class BadRequestData(httplib.HTTPException):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   899
    """Request body object has neither __len__ nor read."""
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   900
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   901
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   902
class HTTPProxyConnectFailedException(httplib.HTTPException):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   903
    """Connecting to the HTTP proxy failed."""
14376
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   904
15218
c81dce8a7bb6 httpclient: update to 07d8c356f4d1 of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14376
diff changeset
   905
14376
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   906
class HTTPStateError(httplib.HTTPException):
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
   907
    """Invalid internal state encountered."""
15218
c81dce8a7bb6 httpclient: update to 07d8c356f4d1 of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14376
diff changeset
   908
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   909
# Forward this exception type from _readers since it needs to be part
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   910
# of the public API.
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
   911
HTTPRemoteClosedError = _readers.HTTPRemoteClosedError
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
   912
# no-check-code