httpconnection.py
121 lines
| 4.0 KiB
| text/x-python
|
PythonLexer
/ mercurial / httpconnection.py
Augie Fackler
|
r14244 | # httpconnection.py - urllib2 handler for new http support | ||
# | ||||
# Copyright 2005, 2006, 2007, 2008 Matt Mackall <mpm@selenic.com> | ||||
# Copyright 2006, 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br> | ||||
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | ||||
# Copyright 2011 Google, Inc. | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
Gregory Szorc
|
r27521 | |||
from __future__ import absolute_import | ||||
import os | ||||
Augie Fackler
|
r14244 | |||
Gregory Szorc
|
r27521 | from .i18n import _ | ||
from . import ( | ||||
Augie Fackler
|
r36669 | pycompat, | ||
Gregory Szorc
|
r27521 | util, | ||
) | ||||
Augie Fackler
|
r14244 | |||
timeless
|
r28883 | urlerr = util.urlerr | ||
urlreq = util.urlreq | ||||
Augie Fackler
|
r14244 | # moved here from url.py to avoid a cycle | ||
class httpsendfile(object): | ||||
"""This is a wrapper around the objects returned by python's "open". | ||||
Mads Kiilerich
|
r15152 | Its purpose is to send file-like objects via HTTP. | ||
It do however not define a __len__ attribute because the length | ||||
might be more than Py_ssize_t can handle. | ||||
Augie Fackler
|
r14244 | """ | ||
def __init__(self, ui, *args, **kwargs): | ||||
self.ui = ui | ||||
self._data = open(*args, **kwargs) | ||||
self.seek = self._data.seek | ||||
self.close = self._data.close | ||||
self.write = self._data.write | ||||
Mads Kiilerich
|
r15152 | self.length = os.fstat(self._data.fileno()).st_size | ||
Augie Fackler
|
r14244 | self._pos = 0 | ||
# We pass double the max for total because we currently have | ||||
# to send the bundle twice in the case of a server that | ||||
# requires authentication. Since we can't know until we try | ||||
# once whether authentication will be required, just lie to | ||||
# the user and maybe the push succeeds suddenly at 50%. | ||||
Martin von Zweigbergk
|
r38412 | self._progress = ui.makeprogress(_('sending'), unit=_('kb'), | ||
total=(self.length // 1024 * 2)) | ||||
def read(self, *args, **kwargs): | ||||
ret = self._data.read(*args, **kwargs) | ||||
if not ret: | ||||
self._progress.complete() | ||||
return ret | ||||
self._pos += len(ret) | ||||
self._progress.update(self._pos // 1024) | ||||
Augie Fackler
|
r14244 | return ret | ||
Mads Kiilerich
|
r30142 | def __enter__(self): | ||
return self | ||||
def __exit__(self, exc_type, exc_val, exc_tb): | ||||
self.close() | ||||
Augie Fackler
|
r14244 | # moved here from url.py to avoid a cycle | ||
Patrick Mezard
|
r15025 | def readauthforuri(ui, uri, user): | ||
Augie Fackler
|
r36669 | uri = pycompat.bytesurl(uri) | ||
Augie Fackler
|
r14244 | # Read configuration | ||
Gregory Szorc
|
r31300 | groups = {} | ||
Augie Fackler
|
r14244 | for key, val in ui.configitems('auth'): | ||
Gregory Szorc
|
r31935 | if key in ('cookiefile',): | ||
continue | ||||
Augie Fackler
|
r14244 | if '.' not in key: | ||
ui.warn(_("ignoring invalid [auth] key '%s'\n") % key) | ||||
continue | ||||
group, setting = key.rsplit('.', 1) | ||||
Gregory Szorc
|
r31300 | gdict = groups.setdefault(group, {}) | ||
Augie Fackler
|
r14244 | if setting in ('username', 'cert', 'key'): | ||
val = util.expandpath(val) | ||||
gdict[setting] = val | ||||
# Find the best match | ||||
Pierre-Yves David
|
r25206 | scheme, hostpath = uri.split('://', 1) | ||
Patrick Mezard
|
r15005 | bestuser = None | ||
Augie Fackler
|
r14244 | bestlen = 0 | ||
bestauth = None | ||||
Gregory Szorc
|
r31300 | for group, auth in groups.iteritems(): | ||
Patrick Mezard
|
r15005 | if user and user != auth.get('username', user): | ||
# If a username was set in the URI, the entry username | ||||
# must either match it or be unset | ||||
continue | ||||
Augie Fackler
|
r14244 | prefix = auth.get('prefix') | ||
if not prefix: | ||||
continue | ||||
Matt Harbison
|
r40699 | |||
prefixurl = util.url(prefix) | ||||
if prefixurl.user and prefixurl.user != user: | ||||
# If a username was set in the prefix, it must match the username in | ||||
# the URI. | ||||
continue | ||||
# The URI passed in has been stripped of credentials, so erase the user | ||||
# here to allow simpler matching. | ||||
prefixurl.user = None | ||||
prefix = bytes(prefixurl) | ||||
Augie Fackler
|
r14244 | p = prefix.split('://', 1) | ||
if len(p) > 1: | ||||
schemes, prefix = [p[0]], p[1] | ||||
else: | ||||
schemes = (auth.get('schemes') or 'https').split() | ||||
if (prefix == '*' or hostpath.startswith(prefix)) and \ | ||||
Patrick Mezard
|
r15005 | (len(prefix) > bestlen or (len(prefix) == bestlen and \ | ||
not bestuser and 'username' in auth)) \ | ||||
and scheme in schemes: | ||||
Augie Fackler
|
r14244 | bestlen = len(prefix) | ||
bestauth = group, auth | ||||
Patrick Mezard
|
r15005 | bestuser = auth.get('username') | ||
if user and not bestuser: | ||||
auth['username'] = user | ||||
Augie Fackler
|
r14244 | return bestauth | ||