annotate mercurial/httpclient/__init__.py @ 29131:8a66eda46c98

httpclient: update to upstream revision 2995635573d2 This is mostly Python 3 compat work thanks to timeless.
author Augie Fackler <augie@google.com>
date Mon, 09 May 2016 21:13:50 -0400
parents 25d93c61cef4
children 456609cbd840
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
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
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
43
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
44 import errno
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
45 import inspect
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
46 import logging
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
47 import rfc822
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
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
50
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
51 try:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
52 import cStringIO as io
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
53 io.StringIO
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
54 except ImportError:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
55 import io
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
56
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
57 try:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
58 import httplib
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
59 httplib.HTTPException
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
60 except ImportError:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
61 import http.client as httplib
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
62
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
63 from . import (
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
64 _readers,
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
65 socketutil,
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
66 )
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
67
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
68 logger = logging.getLogger(__name__)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
69
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
70 __all__ = ['HTTPConnection', 'HTTPResponse']
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
71
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
72 HTTP_VER_1_0 = 'HTTP/1.0'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
73 HTTP_VER_1_1 = 'HTTP/1.1'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
74
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
75 OUTGOING_BUFFER_SIZE = 1 << 15
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
76 INCOMING_BUFFER_SIZE = 1 << 20
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
77
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
78 HDR_ACCEPT_ENCODING = 'accept-encoding'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
79 HDR_CONNECTION_CTRL = 'connection'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
80 HDR_CONTENT_LENGTH = 'content-length'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
81 HDR_XFER_ENCODING = 'transfer-encoding'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
82
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
83 XFER_ENCODING_CHUNKED = 'chunked'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
84
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
85 CONNECTION_CLOSE = 'close'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
86
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
87 EOL = '\r\n'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
88 _END_HEADERS = EOL * 2
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
89
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
90 # 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
91 # default here.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
92 TIMEOUT_ASSUME_CONTINUE = 1
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
93 TIMEOUT_DEFAULT = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
94
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
95
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
96 class HTTPResponse(object):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
97 """Response from an HTTP server.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
98
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
99 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
100 complete response before continuing, check the .complete() method.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
101 """
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
102 def __init__(self, sock, timeout, method):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
103 self.sock = sock
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
104 self.method = method
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
105 self.raw_response = ''
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
106 self._headers_len = 0
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
107 self.headers = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
108 self.will_close = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
109 self.status_line = ''
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
110 self.status = None
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
111 self.continued = False
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
112 self.http_version = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
113 self.reason = None
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
114 self._reader = None
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
115
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
116 self._read_location = 0
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
117 self._eol = EOL
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
118
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
119 self._timeout = timeout
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
120
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
121 @property
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
122 def _end_headers(self):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
123 return self._eol * 2
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
124
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
125 def complete(self):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
126 """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
127
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
128 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
129 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
130 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
131 """
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
132 if self._reader:
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
133 return self._reader.done()
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
134
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
135 def _close(self):
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
136 if self._reader is not None:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
137 # 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
138 # pylint: disable=W0212
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
139 self._reader._close()
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
140
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
141 def getheader(self, header, default=None):
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
142 return self.headers.getheader(header, default=default)
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
143
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
144 def getheaders(self):
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
145 return self.headers.items()
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
146
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
147 def readline(self):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
148 """Read a single line from the response body.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
149
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
150 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
151 response is complete.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
152 """
19038
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
153 blocks = []
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
154 while True:
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
155 self._reader.readto('\n', blocks)
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
156
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
157 if blocks and blocks[-1][-1] == '\n' or self.complete():
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
158 break
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
159
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
160 self._select()
19038
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
161
36733ab7fa05 http2: sane readline
Brendan Cully <brendan@kublai.com>
parents: 17537
diff changeset
162 return ''.join(blocks)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
163
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
164 def read(self, length=None):
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
165 """Read data from the response body."""
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
166 # if length is None, unbounded read
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
167 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
168 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
169 or length > self._reader.available_data)):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
170 self._select()
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
171 if not length:
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
172 length = self._reader.available_data
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
173 r = self._reader.read(length)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
174 if self.complete() and self.will_close:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
175 self.sock.close()
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
176 return r
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
177
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
178 def _select(self):
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
179 r, unused_write, unused_err = select.select(
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
180 [self.sock], [], [], self._timeout)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
181 if not r:
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
182 # 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
183 # complete, raise a timeout.
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
184 if not self.complete():
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
185 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
186 raise HTTPTimeoutException('timeout reading data')
14341
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
187 try:
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
188 data = self.sock.recv(INCOMING_BUFFER_SIZE)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24306
diff changeset
189 except socket.sslerror as e:
14341
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
190 if e.args[0] != socket.SSL_ERROR_WANT_READ:
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
191 raise
17428
72803c8edaa4 avoid using abbreviations that look like spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents: 17424
diff changeset
192 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
193 return True
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
194 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
195 # 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
196 # 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
197 # 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
198 if not data:
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
199 if self._reader:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
200 # 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
201 # pylint: disable=W0212
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
202 self._reader._close()
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
203 return False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
204 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
205 self._load_response(data)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
206 return True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
207
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
208 # 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
209 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
210 # 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
211 # 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
212 # 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
213 # reader we created.
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
214 self.raw_response += data
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
215 # 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
216 if self._eol not in self.raw_response:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
217 for bad_eol in ('\n', '\r'):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
218 if (bad_eol in self.raw_response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
219 # 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
220 # 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
221 # split between \r and \n.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
222 and (self.raw_response.index(bad_eol) <
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
223 (len(self.raw_response) - 1))):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
224 logger.info('bogus line endings detected, '
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
225 'using %r for EOL', bad_eol)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
226 self._eol = bad_eol
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
227 break
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
228 # exit early if not at end of headers
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
229 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
230 return
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
231
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
232 # handle 100-continue response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
233 hdrs, body = self.raw_response.split(self._end_headers, 1)
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
234 unused_http_ver, status = hdrs.split(' ', 1)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
235 if status.startswith('100'):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
236 self.raw_response = body
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
237 self.continued = True
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
238 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
239 return
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
240
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
241 # arriving here means we should parse response headers
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
242 # as all headers have arrived completely
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
243 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
244 del self.raw_response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
245 if self._eol in hdrs:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
246 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
247 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
248 self.status_line = hdrs
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
249 hdrs = ''
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
250 # TODO HTTP < 1.0 support
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
251 (self.http_version, self.status,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
252 self.reason) = self.status_line.split(' ', 2)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
253 self.status = int(self.status)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
254 if self._eol != EOL:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
255 hdrs = hdrs.replace(self._eol, '\r\n')
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
256 headers = rfc822.Message(io.StringIO(hdrs))
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
257 content_len = None
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
258 if HDR_CONTENT_LENGTH in headers:
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
259 content_len = int(headers[HDR_CONTENT_LENGTH])
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
260 if self.http_version == HTTP_VER_1_0:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
261 self.will_close = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
262 elif HDR_CONNECTION_CTRL in headers:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
263 self.will_close = (
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
264 headers[HDR_CONNECTION_CTRL].lower() == CONNECTION_CLOSE)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
265 if (HDR_XFER_ENCODING in headers
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
266 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
267 self._reader = _readers.ChunkedReader(self._eol)
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
268 logger.debug('using a chunked reader')
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
269 else:
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
270 # 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
271 # 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
272 # close-is-end logic for an OK response.
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
273 if (self.method == 'HEAD' or
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
274 (self.method == 'CONNECT' and content_len is None)):
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
275 content_len = 0
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
276 if content_len is not None:
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
277 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
278 content_len)
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
279 self._reader = _readers.ContentLengthReader(content_len)
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
280 else:
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
281 # 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
282 # 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
283 # 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
284 # 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
285 # are correct in hitting this case if
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
286 # transfer-encoding, content-length, and
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
287 # connection-control were left unspecified.
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
288 self._reader = _readers.CloseIsEndReader()
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
289 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
290 self.will_close = True
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
291
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
292 if body:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
293 # 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
294 # pylint: disable=W0212
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
295 self._reader._load(body)
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
296 logger.debug('headers complete')
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
297 self.headers = headers
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
298 # 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
299 # pylint: disable=W0212
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
300 self._load_response = self._reader._load
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
301
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
302 def _foldheaders(headers):
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
303 """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
304
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
305 >>> _foldheaders({'Accept-Encoding': 'wat'})
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
306 {'accept-encoding': ('Accept-Encoding', 'wat')}
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
307 """
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
308 return dict((k.lower(), (k, v)) for k, v in headers.iteritems())
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
309
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
310 try:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
311 inspect.signature
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
312 def _handlesarg(func, arg):
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
313 """ Try to determine if func accepts arg
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
314
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
315 If it takes arg, return True
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
316 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
317 * 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
318 * It could throw an ArgumentError or anything else
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
319 * 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
320 ... return 'unknown'
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
321
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
322 Otherwise, return False
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
323 """
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
324 params = inspect.signature(func).parameters
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
325 if arg in params:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
326 return True
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
327 for p in params:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
328 if params[p].kind == inspect._ParameterKind.VAR_KEYWORD:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
329 return 'unknown'
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
330 return False
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
331 except AttributeError:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
332 def _handlesarg(func, arg):
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
333 """ Try to determine if func accepts arg
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
334
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
335 If it takes arg, return True
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
336 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
337 * 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
338 * It could throw an ArgumentError or anything else
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
339 * 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
340 ... return 'unknown'
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
341
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
342 Otherwise, return False
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
343 """
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
344 spec = inspect.getargspec(func)
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
345 if arg in spec.args:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
346 return True
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
347 if spec.keywords:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
348 return 'unknown'
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
349 return False
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
350
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
351 class HTTPConnection(object):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
352 """Connection to a single http server.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
353
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
354 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
355 non-blocking socket operations.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
356 """
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
357 http_version = HTTP_VER_1_1
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
358 response_class = HTTPResponse
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
359
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
360 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
361 timeout=TIMEOUT_DEFAULT,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
362 continue_timeout=TIMEOUT_ASSUME_CONTINUE,
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
363 proxy_hostport=None, proxy_headers=None,
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
364 ssl_wrap_socket=None, **ssl_opts):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
365 """Create a new HTTPConnection.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
366
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
367 Args:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
368 host: The host to which we'll connect.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
369 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
370 non-ssl, 443 for ssl.
17424
e7cfe3587ea4 fix trivial spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents: 16774
diff changeset
371 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
372 not 443, true if port is 443.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
373 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
374 timeout: Optional. Connection timeout, default is TIMEOUT_DEFAULT.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
375 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
376 "100 Continue" response. Default is TIMEOUT_ASSUME_CONTINUE.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
377 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
378 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
379 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
380 a proxy when using CONNECT. For compatibility with
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
381 httplib, the Proxy-Authorization header may be
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
382 specified in headers for request(), which will clobber
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
383 any such header specified here if specified. Providing
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
384 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
385 ValueError.
19807
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
386 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
387 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
388 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
389 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
390
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
391 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
392 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
393 """
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
394 if port is None and host.count(':') == 1 or ']:' in host:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
395 host, port = host.rsplit(':', 1)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
396 port = int(port)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
397 if '[' in host:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
398 host = host[1:-1]
19807
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
399 if ssl_wrap_socket is not None:
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
400 _wrap_socket = ssl_wrap_socket
19807
c48df403caae httpclient: import 4bb625347d4a to provide SSL wrapper injection
Augie Fackler <raf@durin42.com>
parents: 19620
diff changeset
401 else:
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
402 _wrap_socket = socketutil.wrap_socket
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
403 call_wrap_socket = None
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
404 handlesubar = _handlesarg(_wrap_socket, 'server_hostname')
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
405 if handlesubar is True:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
406 # supports server_hostname
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
407 call_wrap_socket = _wrap_socket
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
408 handlesnobar = _handlesarg(_wrap_socket, 'serverhostname')
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
409 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
410 # supports serverhostname
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
411 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
412 return _wrap_socket(sock, serverhostname=server_hostname,
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
413 **ssl_opts)
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
414 if handlesubar is False and handlesnobar is False:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
415 # does not support either
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
416 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
417 return _wrap_socket(sock, **ssl_opts)
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
418 if call_wrap_socket is None:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
419 # we assume it takes **args
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
420 def call_wrap_socket(sock, **ssl_opts):
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
421 if 'server_hostname' in ssl_opts:
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
422 ssl_opts['serverhostname'] = ssl_opts['server_hostname']
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
423 return _wrap_socket(sock, **ssl_opts)
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
424 self._ssl_wrap_socket = call_wrap_socket
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
425 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
426 use_ssl = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
427 port = 80
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
428 elif use_ssl is None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
429 use_ssl = (port == 443)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
430 elif port is None:
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
431 port = (use_ssl and 443 or 80)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
432 self.port = port
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
433 if use_ssl and not socketutil.have_ssl:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
434 raise Exception('ssl requested but unavailable on this Python')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
435 self.ssl = use_ssl
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
436 self.ssl_opts = ssl_opts
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
437 self._ssl_validator = ssl_validator
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
438 self.host = host
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
439 self.sock = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
440 self._current_response = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
441 self._current_response_taken = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
442 if proxy_hostport is None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
443 self._proxy_host = self._proxy_port = None
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
444 if proxy_headers:
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
445 raise ValueError(
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
446 'proxy_headers may not be specified unless '
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
447 'proxy_hostport is also specified.')
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
448 else:
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
449 self._proxy_headers = {}
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
450 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
451 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
452 self._proxy_headers = _foldheaders(proxy_headers or {})
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
453
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
454 self.timeout = timeout
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
455 self.continue_timeout = continue_timeout
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
456
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
457 def _connect(self, proxy_headers):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
458 """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
459 if self.sock:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
460 return
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
461 if self._proxy_host is not None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
462 logger.info('Connecting to http proxy %s:%s',
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
463 self._proxy_host, self._proxy_port)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
464 sock = socketutil.create_connection((self._proxy_host,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
465 self._proxy_port))
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
466 if self.ssl:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
467 data = self._buildheaders('CONNECT', '%s:%d' % (self.host,
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
468 self.port),
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
469 proxy_headers, HTTP_VER_1_0)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
470 sock.send(data)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
471 sock.setblocking(0)
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
472 r = self.response_class(sock, self.timeout, 'CONNECT')
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
473 timeout_exc = HTTPTimeoutException(
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
474 'Timed out waiting for CONNECT response from proxy')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
475 while not r.complete():
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
476 try:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
477 # 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
478 # us use the private attribute.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
479 # pylint: disable=W0212
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
480 if not r._select():
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
481 if not r.complete():
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
482 raise timeout_exc
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
483 except HTTPTimeoutException:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
484 # This raise/except pattern looks goofy, but
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
485 # _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
486 # 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
487 # but I don't have a better solution
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
488 # immediately handy.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
489 raise timeout_exc
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
490 if r.status != 200:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
491 raise HTTPProxyConnectFailedException(
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
492 'Proxy connection failed: %d %s' % (r.status,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
493 r.read()))
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
494 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
495 self.host, self.port)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
496 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
497 sock = socketutil.create_connection((self.host, self.port))
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
498 if self.ssl:
16774
69af967b6d6f httpclient: update to c5abd358e543 of httpplus
Augie Fackler <raf@durin42.com>
parents: 16643
diff changeset
499 # 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
500 # requests the proxy logic above will have cleared
17424
e7cfe3587ea4 fix trivial spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents: 16774
diff changeset
501 # 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
502 sock.setblocking(1)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
503 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
504 self.ssl_opts)
29131
8a66eda46c98 httpclient: update to upstream revision 2995635573d2
Augie Fackler <augie@google.com>
parents: 28997
diff changeset
505 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
506 **self.ssl_opts)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
507 if self._ssl_validator:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
508 self._ssl_validator(sock)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
509 sock.setblocking(0)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
510 self.sock = sock
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
511
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
512 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
513 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
514 # default port for protocol, so leave it out
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
515 hdrhost = self.host
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
516 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
517 # include nonstandard port in header
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
518 if ':' in self.host: # must be IPv6
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
519 hdrhost = '[%s]:%d' % (self.host, self.port)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
520 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
521 hdrhost = '%s:%d' % (self.host, self.port)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
522 if self._proxy_host and not self.ssl:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
523 # 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
524 # 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
525 # technically RFC 2616 says servers must accept our
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
526 # 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
527 # correctly.)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
528 assert path[0] == '/', 'path must start with a /'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
529 path = 'http://%s%s' % (hdrhost, path)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
530 outgoing = ['%s %s %s%s' % (method, path, http_ver, EOL)]
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
531 headers['host'] = ('Host', hdrhost)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
532 headers[HDR_ACCEPT_ENCODING] = (HDR_ACCEPT_ENCODING, 'identity')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
533 for hdr, val in headers.itervalues():
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
534 outgoing.append('%s: %s%s' % (hdr, val, EOL))
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
535 outgoing.append(EOL)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
536 return ''.join(outgoing)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
537
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
538 def close(self):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
539 """Close the connection to the server.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
540
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
541 This is a no-op if the connection is already closed. The
17536
dc6364a81e42 spelling: requested
timeless@mozdev.org
parents: 16774
diff changeset
542 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
543 or required by the nature of a response.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
544 """
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
545 if self.sock is None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
546 return
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
547 self.sock.close()
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
548 self.sock = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
549 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
550
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
551 def busy(self):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
552 """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
553
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
554 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
555 the request has finished sending. In the future,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
556 HTTPConnection may transparently juggle multiple connections
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
557 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
558 any of those connections is ready for use.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
559 """
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
560 cr = self._current_response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
561 if cr is not None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
562 if self._current_response_taken:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
563 if cr.will_close:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
564 self.sock = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
565 self._current_response = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
566 return False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
567 elif cr.complete():
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
568 self._current_response = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
569 return False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
570 return True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
571 return False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
572
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
573 def _reconnect(self, where, pheaders):
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
574 logger.info('reconnecting during %s', where)
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
575 self.close()
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
576 self._connect(pheaders)
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
577
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
578 def request(self, method, path, body=None, headers={},
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
579 expect_continue=False):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
580 """Send a request to the server.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
581
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
582 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
583 object. Future versions of HTTPConnection that juggle multiple
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
584 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
585 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
586 available. Use the `getresponse()` method to retrieve the
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
587 response.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
588 """
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
589 if self.busy():
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
590 raise httplib.CannotSendRequest(
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
591 'Can not send another request before '
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
592 'current response is read!')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
593 self._current_response_taken = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
594
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
595 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
596 method, path, self.host, self.port)
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
597 hdrs = _foldheaders(headers)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
598 if hdrs.get('expect', ('', ''))[1].lower() == '100-continue':
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
599 expect_continue = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
600 elif expect_continue:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
601 hdrs['expect'] = ('Expect', '100-Continue')
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
602 # httplib compatibility: if the user specified a
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
603 # 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
604 # 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
605 # we're going to use a proxy.
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
606 pheaders = dict(self._proxy_headers)
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
607 if self._proxy_host and self.ssl:
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
608 pa = hdrs.pop('proxy-authorization', None)
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
609 if pa is not None:
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
610 pheaders['proxy-authorization'] = pa
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
611
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
612 chunked = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
613 if body and HDR_CONTENT_LENGTH not in hdrs:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
614 if getattr(body, '__len__', False):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
615 hdrs[HDR_CONTENT_LENGTH] = (HDR_CONTENT_LENGTH, len(body))
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
616 elif getattr(body, 'read', False):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
617 hdrs[HDR_XFER_ENCODING] = (HDR_XFER_ENCODING,
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
618 XFER_ENCODING_CHUNKED)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
619 chunked = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
620 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
621 raise BadRequestData('body has no __len__() nor read()')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
622
19620
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
623 # 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
624 # 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
625 # 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
626 fresh_socket = self.sock is None
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
627 self._connect(pheaders)
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
628 outgoing_headers = self._buildheaders(
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
629 method, path, hdrs, self.http_version)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
630 response = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
631 first = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
632
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
633 while ((outgoing_headers or body)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
634 and not (response and response.complete())):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
635 select_timeout = self.timeout
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
636 out = outgoing_headers or body
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
637 blocking_on_continue = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
638 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
639 response and (response.headers or response.continued)):
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
640 logger.info(
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
641 'waiting up to %s seconds for'
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
642 ' continue response from server',
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
643 self.continue_timeout)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
644 select_timeout = self.continue_timeout
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
645 blocking_on_continue = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
646 out = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
647 if out:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
648 w = [self.sock]
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
649 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
650 w = []
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
651 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
652 # 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
653 # 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
654 # recommended behavior from the RFC.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
655 if r == w == x == []:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
656 if blocking_on_continue:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
657 expect_continue = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
658 logger.info('no response to continue expectation from '
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
659 'server, optimistically sending request body')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
660 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
661 raise HTTPTimeoutException('timeout sending data')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
662 was_first = first
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
663
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
664 # incoming data
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
665 if r:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
666 try:
14341
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
667 try:
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
668 data = r[0].recv(INCOMING_BUFFER_SIZE)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24306
diff changeset
669 except socket.sslerror as e:
14341
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
670 if e.args[0] != socket.SSL_ERROR_WANT_READ:
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
671 raise
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
672 logger.debug('SSL_ERROR_WANT_READ while sending '
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
673 'data, retrying...')
14341
5c3de67e7402 httpclient: import revision b8c3511a8cae from py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14293
diff changeset
674 continue
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
675 if not data:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
676 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
677 self.sock = None
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
678 self._current_response = None
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
679 if response is not None:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
680 # 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
681 # us use the private attribute.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
682 # pylint: disable=W0212
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
683 response._close()
14376
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
684 # 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
685 # comments in each branch should help.
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
686 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
687 # Server responded completely and then
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
688 # 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
689 # 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
690 # response.
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
691 logger.info('Got an early response, '
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
692 'aborting remaining request.')
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
693 break
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
694 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
695 # 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
696 # 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
697 # after getting a really large response
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
698 # from the server.
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
699 logger.info(
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
700 '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
701 ' request loop iteration, will retry.')
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
702 self._reconnect('read', pheaders)
14376
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
703 continue
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
704 else:
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
705 # 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
706 # 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
707 # 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
708 # meaningful we can do here.
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
709 raise HTTPStateError(
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
710 'Connection appears closed after '
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
711 '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
712 'response was missing or incomplete!')
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
713 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
714 if response is None:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
715 response = self.response_class(
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
716 r[0], self.timeout, method)
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
717 # 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
718 # use the private attribute.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
719 # pylint: disable=W0212
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
720 response._load_response(data)
14376
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
721 # 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
722 # 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
723 continue
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24306
diff changeset
724 except socket.error as e:
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
725 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
726 raise
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
727
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
728 # outgoing data
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
729 if w and out:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
730 try:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
731 if getattr(out, 'read', False):
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
732 # pylint guesses the type of out incorrectly here
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
733 # pylint: disable=E1103
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
734 data = out.read(OUTGOING_BUFFER_SIZE)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
735 if not data:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
736 continue
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
737 if len(data) < OUTGOING_BUFFER_SIZE:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
738 if chunked:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
739 body = '0' + EOL + EOL
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
740 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
741 body = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
742 if chunked:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
743 out = hex(len(data))[2:] + EOL + data + EOL
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
744 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
745 out = data
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
746 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
747 except socket.error as e:
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
748 if e[0] == socket.SSL_ERROR_WANT_WRITE and self.ssl:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
749 # 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
750 # the socket yet.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
751 # 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
752 # similar to selecting on a raw socket.
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
753 continue
19489
42fcb2f7787d httpclient: update to revision 9517a2b56fe9 of httpplus (issue3905)
Augie Fackler <raf@durin42.com>
parents: 19182
diff changeset
754 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
755 continue
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
756 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
757 and not first):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
758 raise
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
759 self._reconnect('write', pheaders)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
760 amt = self.sock.send(out)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
761 logger.debug('sent %d', amt)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
762 first = False
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
763 if out is body:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
764 body = out[amt:]
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
765 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
766 outgoing_headers = out[amt:]
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
767
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
768 # 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
769 # the whole request
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
770 if response is None:
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
771 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
772 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
773 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
774 # 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
775 # 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
776 # 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
777 # the request again on a fresh socket.
27601
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
778 logger.debug('response._select() failed during request().'
1ad9da968a2e httpclient: update to 938f2107d6e2 of httpplus
Augie Fackler <augie@google.com>
parents: 25660
diff changeset
779 ' 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
780 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
781 # 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
782 # 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
783 # 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
784 # 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
785 # 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
786 #
d4a0055af149 httpclient: import 0d1b0a8bc549 to fix bug involving late-arriving RST after a response
Augie Fackler <raf@durin42.com>
parents: 19489
diff changeset
787 # 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
788 # 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
789 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
790 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
791 expect_continue=expect_continue)
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
792 data_left = bool(outgoing_headers or body)
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
793 if data_left:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
794 logger.info('stopped sending request early, '
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
795 'will close the socket to be safe.')
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
796 response.will_close = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
797 if response.will_close:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
798 # 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
799 # the socket
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
800 self.sock = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
801 self._current_response = response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
802
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
803 def getresponse(self):
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
804 """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
805 if self._current_response is None:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
806 raise httplib.ResponseNotReady()
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
807 r = self._current_response
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
808 while r.headers is None:
19182
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
809 # 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
810 # private attribute.
fae47ecaa952 httpclient: upgrade to fe8c09e4db64 of httpplus
Augie Fackler <raf@durin42.com>
parents: 19038
diff changeset
811 # pylint: disable=W0212
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
812 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
813 raise _readers.HTTPRemoteClosedError()
14293
9adbb5ef0964 httpclient: import f4c380237fd5 to fix keepalive not working
Augie Fackler <durin42@gmail.com>
parents: 14243
diff changeset
814 if r.will_close:
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
815 self.sock = None
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
816 self._current_response = None
14293
9adbb5ef0964 httpclient: import f4c380237fd5 to fix keepalive not working
Augie Fackler <durin42@gmail.com>
parents: 14243
diff changeset
817 elif r.complete():
9adbb5ef0964 httpclient: import f4c380237fd5 to fix keepalive not working
Augie Fackler <durin42@gmail.com>
parents: 14243
diff changeset
818 self._current_response = None
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
819 else:
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
820 self._current_response_taken = True
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
821 return r
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
822
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
823
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
824 class HTTPTimeoutException(httplib.HTTPException):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
825 """A timeout occurred while waiting on the server."""
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
826
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
827
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
828 class BadRequestData(httplib.HTTPException):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
829 """Request body object has neither __len__ nor read."""
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
830
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
831
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
832 class HTTPProxyConnectFailedException(httplib.HTTPException):
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
833 """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
834
15218
c81dce8a7bb6 httpclient: update to 07d8c356f4d1 of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14376
diff changeset
835
14376
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
836 class HTTPStateError(httplib.HTTPException):
a75e0f4ba0ab httpclient: import revision fc731618702a of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14341
diff changeset
837 """Invalid internal state encountered."""
15218
c81dce8a7bb6 httpclient: update to 07d8c356f4d1 of py-nonblocking-http
Augie Fackler <durin42@gmail.com>
parents: 14376
diff changeset
838
16643
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
839 # 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
840 # of the public API.
24dbef11f477 httpclient: update to revision 892730fe7f46 of httpplus
Augie Fackler <raf@durin42.com>
parents: 15218
diff changeset
841 HTTPRemoteClosedError = _readers.HTTPRemoteClosedError
14243
861f28212398 Import new http library as mercurial.httpclient.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
842 # no-check-code