##// END OF EJS Templates
http: drop custom http client logic...
Augie Fackler -
r36444:23d12524 default
parent child Browse files
Show More
@@ -1026,9 +1026,6 b" coreconfigitem('ui', 'formatted',"
1026 coreconfigitem('ui', 'graphnodetemplate',
1026 coreconfigitem('ui', 'graphnodetemplate',
1027 default=None,
1027 default=None,
1028 )
1028 )
1029 coreconfigitem('ui', 'http2debuglevel',
1030 default=None,
1031 )
1032 coreconfigitem('ui', 'interactive',
1029 coreconfigitem('ui', 'interactive',
1033 default=None,
1030 default=None,
1034 )
1031 )
@@ -1127,9 +1124,6 b" coreconfigitem('ui', 'traceback',"
1127 coreconfigitem('ui', 'tweakdefaults',
1124 coreconfigitem('ui', 'tweakdefaults',
1128 default=False,
1125 default=False,
1129 )
1126 )
1130 coreconfigitem('ui', 'usehttp2',
1131 default=False,
1132 )
1133 coreconfigitem('ui', 'username',
1127 coreconfigitem('ui', 'username',
1134 alias=[('ui', 'user')]
1128 alias=[('ui', 'user')]
1135 )
1129 )
@@ -10,15 +10,10 b''
10
10
11 from __future__ import absolute_import
11 from __future__ import absolute_import
12
12
13 import logging
14 import os
13 import os
15 import socket
16
14
17 from .i18n import _
15 from .i18n import _
18 from . import (
16 from . import (
19 httpclient,
20 sslutil,
21 urllibcompat,
22 util,
17 util,
23 )
18 )
24
19
@@ -110,190 +105,3 b' def readauthforuri(ui, uri, user):'
110 if user and not bestuser:
105 if user and not bestuser:
111 auth['username'] = user
106 auth['username'] = user
112 return bestauth
107 return bestauth
113
114 # Mercurial (at least until we can remove the old codepath) requires
115 # that the http response object be sufficiently file-like, so we
116 # provide a close() method here.
117 class HTTPResponse(httpclient.HTTPResponse):
118 def close(self):
119 pass
120
121 class HTTPConnection(httpclient.HTTPConnection):
122 response_class = HTTPResponse
123 def request(self, method, uri, body=None, headers=None):
124 if headers is None:
125 headers = {}
126 if isinstance(body, httpsendfile):
127 body.seek(0)
128 httpclient.HTTPConnection.request(self, method, uri, body=body,
129 headers=headers)
130
131
132 _configuredlogging = False
133 LOGFMT = '%(levelname)s:%(name)s:%(lineno)d:%(message)s'
134 # Subclass BOTH of these because otherwise urllib2 "helpfully"
135 # reinserts them since it notices we don't include any subclasses of
136 # them.
137 class http2handler(urlreq.httphandler, urlreq.httpshandler):
138 def __init__(self, ui, pwmgr):
139 global _configuredlogging
140 urlreq.abstracthttphandler.__init__(self)
141 self.ui = ui
142 self.pwmgr = pwmgr
143 self._connections = {}
144 # developer config: ui.http2debuglevel
145 loglevel = ui.config('ui', 'http2debuglevel')
146 if loglevel and not _configuredlogging:
147 _configuredlogging = True
148 logger = logging.getLogger('mercurial.httpclient')
149 logger.setLevel(getattr(logging, loglevel.upper()))
150 handler = logging.StreamHandler()
151 handler.setFormatter(logging.Formatter(LOGFMT))
152 logger.addHandler(handler)
153
154 def close_all(self):
155 """Close and remove all connection objects being kept for reuse."""
156 for openconns in self._connections.values():
157 for conn in openconns:
158 conn.close()
159 self._connections = {}
160
161 # shamelessly borrowed from urllib2.AbstractHTTPHandler
162 def do_open(self, http_class, req, use_ssl):
163 """Return an addinfourl object for the request, using http_class.
164
165 http_class must implement the HTTPConnection API from httplib.
166 The addinfourl return value is a file-like object. It also
167 has methods and attributes including:
168 - info(): return a mimetools.Message object for the headers
169 - geturl(): return the original request URL
170 - code: HTTP status code
171 """
172 # If using a proxy, the host returned by get_host() is
173 # actually the proxy. On Python 2.6.1, the real destination
174 # hostname is encoded in the URI in the urllib2 request
175 # object. On Python 2.6.5, it's stored in the _tunnel_host
176 # attribute which has no accessor.
177 tunhost = getattr(req, '_tunnel_host', None)
178 host = urllibcompat.gethost(req)
179 if tunhost:
180 proxyhost = host
181 host = tunhost
182 elif req.has_proxy():
183 proxyhost = urllibcompat.gethost(req)
184 host = urllibcompat.getselector(
185 req).split('://', 1)[1].split('/', 1)[0]
186 else:
187 proxyhost = None
188
189 if proxyhost:
190 if ':' in proxyhost:
191 # Note: this means we'll explode if we try and use an
192 # IPv6 http proxy. This isn't a regression, so we
193 # won't worry about it for now.
194 proxyhost, proxyport = proxyhost.rsplit(':', 1)
195 else:
196 proxyport = 3128 # squid default
197 proxy = (proxyhost, proxyport)
198 else:
199 proxy = None
200
201 if not host:
202 raise urlerr.urlerror('no host given')
203
204 connkey = use_ssl, host, proxy
205 allconns = self._connections.get(connkey, [])
206 conns = [c for c in allconns if not c.busy()]
207 if conns:
208 h = conns[0]
209 else:
210 if allconns:
211 self.ui.debug('all connections for %s busy, making a new '
212 'one\n' % host)
213 timeout = None
214 if req.timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
215 timeout = req.timeout
216 h = http_class(host, timeout=timeout, proxy_hostport=proxy)
217 self._connections.setdefault(connkey, []).append(h)
218
219 headers = dict(req.headers)
220 headers.update(req.unredirected_hdrs)
221 headers = dict(
222 (name.title(), val) for name, val in headers.items())
223 try:
224 path = urllibcompat.getselector(req)
225 if '://' in path:
226 path = path.split('://', 1)[1].split('/', 1)[1]
227 if path[0] != '/':
228 path = '/' + path
229 h.request(req.get_method(), path, req.data, headers)
230 r = h.getresponse()
231 except socket.error as err: # XXX what error?
232 raise urlerr.urlerror(err)
233
234 # Pick apart the HTTPResponse object to get the addinfourl
235 # object initialized properly.
236 r.recv = r.read
237
238 resp = urlreq.addinfourl(r, r.headers, urllibcompat.getfullurl(req))
239 resp.code = r.status
240 resp.msg = r.reason
241 return resp
242
243 # httplib always uses the given host/port as the socket connect
244 # target, and then allows full URIs in the request path, which it
245 # then observes and treats as a signal to do proxying instead.
246 def http_open(self, req):
247 if urllibcompat.getfullurl(req).startswith('https'):
248 return self.https_open(req)
249 def makehttpcon(*args, **kwargs):
250 k2 = dict(kwargs)
251 k2[r'use_ssl'] = False
252 return HTTPConnection(*args, **k2)
253 return self.do_open(makehttpcon, req, False)
254
255 def https_open(self, req):
256 # urllibcompat.getfullurl(req) does not contain credentials and we may
257 # need them to match the certificates.
258 url = urllibcompat.getfullurl(req)
259 user, password = self.pwmgr.find_stored_password(url)
260 res = readauthforuri(self.ui, url, user)
261 if res:
262 group, auth = res
263 self.auth = auth
264 self.ui.debug("using auth.%s.* for authentication\n" % group)
265 else:
266 self.auth = None
267 return self.do_open(self._makesslconnection, req, True)
268
269 def _makesslconnection(self, host, port=443, *args, **kwargs):
270 keyfile = None
271 certfile = None
272
273 if args: # key_file
274 keyfile = args.pop(0)
275 if args: # cert_file
276 certfile = args.pop(0)
277
278 # if the user has specified different key/cert files in
279 # hgrc, we prefer these
280 if self.auth and 'key' in self.auth and 'cert' in self.auth:
281 keyfile = self.auth['key']
282 certfile = self.auth['cert']
283
284 # let host port take precedence
285 if ':' in host and '[' not in host or ']:' in host:
286 host, port = host.rsplit(':', 1)
287 port = int(port)
288 if '[' in host:
289 host = host[1:-1]
290
291 kwargs[r'keyfile'] = keyfile
292 kwargs[r'certfile'] = certfile
293
294 con = HTTPConnection(host, port, use_ssl=True,
295 ssl_wrap_socket=sslutil.wrapsocket,
296 ssl_validator=sslutil.validatesocket,
297 ui=self.ui,
298 **kwargs)
299 return con
@@ -291,9 +291,6 b' class httppeer(wireproto.wirepeer):'
291 size = data.length
291 size = data.length
292 elif data is not None:
292 elif data is not None:
293 size = len(data)
293 size = len(data)
294 if size and self.ui.configbool('ui', 'usehttp2'):
295 headers[r'Expect'] = r'100-Continue'
296 headers[r'X-HgHttp2'] = r'1'
297 if data is not None and r'Content-Type' not in headers:
294 if data is not None and r'Content-Type' not in headers:
298 headers[r'Content-Type'] = r'application/mercurial-0.1'
295 headers[r'Content-Type'] = r'application/mercurial-0.1'
299
296
@@ -470,14 +470,6 b' def opener(ui, authinfo=None, useragent='
470 construct an opener suitable for urllib2
470 construct an opener suitable for urllib2
471 authinfo will be added to the password manager
471 authinfo will be added to the password manager
472 '''
472 '''
473 # experimental config: ui.usehttp2
474 if ui.configbool('ui', 'usehttp2'):
475 handlers = [
476 httpconnectionmod.http2handler(
477 ui,
478 passwordmgr(ui, ui.httppasswordmgrdb))
479 ]
480 else:
481 handlers = [httphandler()]
473 handlers = [httphandler()]
482 if has_https:
474 if has_https:
483 handlers.append(httpshandler(ui))
475 handlers.append(httpshandler(ui))
@@ -806,7 +806,6 b" packages = ['mercurial',"
806 'mercurial.cext',
806 'mercurial.cext',
807 'mercurial.cffi',
807 'mercurial.cffi',
808 'mercurial.hgweb',
808 'mercurial.hgweb',
809 'mercurial.httpclient',
810 'mercurial.pure',
809 'mercurial.pure',
811 'mercurial.thirdparty',
810 'mercurial.thirdparty',
812 'mercurial.thirdparty.attr',
811 'mercurial.thirdparty.attr',
@@ -13,8 +13,6 b' New errors are not allowed. Warnings are'
13 > -X mercurial/thirdparty \
13 > -X mercurial/thirdparty \
14 > | sed 's-\\-/-g' | "$check_code" --warnings --per-file=0 - || false
14 > | sed 's-\\-/-g' | "$check_code" --warnings --per-file=0 - || false
15 Skipping i18n/polib.py it has no-che?k-code (glob)
15 Skipping i18n/polib.py it has no-che?k-code (glob)
16 Skipping mercurial/httpclient/__init__.py it has no-che?k-code (glob)
17 Skipping mercurial/httpclient/_readers.py it has no-che?k-code (glob)
18 Skipping mercurial/statprof.py it has no-che?k-code (glob)
16 Skipping mercurial/statprof.py it has no-che?k-code (glob)
19 Skipping tests/badserverext.py it has no-che?k-code (glob)
17 Skipping tests/badserverext.py it has no-che?k-code (glob)
20
18
@@ -211,7 +211,6 b' check that local configs for the cached '
211 ui.slash=True
211 ui.slash=True
212 ui.interactive=False
212 ui.interactive=False
213 ui.mergemarkers=detailed
213 ui.mergemarkers=detailed
214 ui.usehttp2=true (?)
215 ui.foo=bar
214 ui.foo=bar
216 ui.nontty=true
215 ui.nontty=true
217 web.address=localhost
216 web.address=localhost
@@ -221,7 +220,6 b' check that local configs for the cached '
221 ui.slash=True
220 ui.slash=True
222 ui.interactive=False
221 ui.interactive=False
223 ui.mergemarkers=detailed
222 ui.mergemarkers=detailed
224 ui.usehttp2=true (?)
225 ui.nontty=true
223 ui.nontty=true
226
224
227 $ rm -R foo
225 $ rm -R foo
1 NO CONTENT: file was removed
NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (912 lines changed) Show them Hide them
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now