##// 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 1026 coreconfigitem('ui', 'graphnodetemplate',
1027 1027 default=None,
1028 1028 )
1029 coreconfigitem('ui', 'http2debuglevel',
1030 default=None,
1031 )
1032 1029 coreconfigitem('ui', 'interactive',
1033 1030 default=None,
1034 1031 )
@@ -1127,9 +1124,6 b" coreconfigitem('ui', 'traceback',"
1127 1124 coreconfigitem('ui', 'tweakdefaults',
1128 1125 default=False,
1129 1126 )
1130 coreconfigitem('ui', 'usehttp2',
1131 default=False,
1132 )
1133 1127 coreconfigitem('ui', 'username',
1134 1128 alias=[('ui', 'user')]
1135 1129 )
@@ -10,15 +10,10 b''
10 10
11 11 from __future__ import absolute_import
12 12
13 import logging
14 13 import os
15 import socket
16 14
17 15 from .i18n import _
18 16 from . import (
19 httpclient,
20 sslutil,
21 urllibcompat,
22 17 util,
23 18 )
24 19
@@ -110,190 +105,3 b' def readauthforuri(ui, uri, user):'
110 105 if user and not bestuser:
111 106 auth['username'] = user
112 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 291 size = data.length
292 292 elif data is not None:
293 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 294 if data is not None and r'Content-Type' not in headers:
298 295 headers[r'Content-Type'] = r'application/mercurial-0.1'
299 296
@@ -470,14 +470,6 b' def opener(ui, authinfo=None, useragent='
470 470 construct an opener suitable for urllib2
471 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 473 handlers = [httphandler()]
482 474 if has_https:
483 475 handlers.append(httpshandler(ui))
@@ -806,7 +806,6 b" packages = ['mercurial',"
806 806 'mercurial.cext',
807 807 'mercurial.cffi',
808 808 'mercurial.hgweb',
809 'mercurial.httpclient',
810 809 'mercurial.pure',
811 810 'mercurial.thirdparty',
812 811 'mercurial.thirdparty.attr',
@@ -13,8 +13,6 b' New errors are not allowed. Warnings are'
13 13 > -X mercurial/thirdparty \
14 14 > | sed 's-\\-/-g' | "$check_code" --warnings --per-file=0 - || false
15 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 16 Skipping mercurial/statprof.py it has no-che?k-code (glob)
19 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 211 ui.slash=True
212 212 ui.interactive=False
213 213 ui.mergemarkers=detailed
214 ui.usehttp2=true (?)
215 214 ui.foo=bar
216 215 ui.nontty=true
217 216 web.address=localhost
@@ -221,7 +220,6 b' check that local configs for the cached '
221 220 ui.slash=True
222 221 ui.interactive=False
223 222 ui.mergemarkers=detailed
224 ui.usehttp2=true (?)
225 223 ui.nontty=true
226 224
227 225 $ rm -R foo
1 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
General Comments 0
You need to be logged in to leave comments. Login now