Rev 2526: Finish http refactoring. Test suite passing. in file:///v/home/vila/src/experimental/reuse.transports/
Vincent Ladeuil
v.ladeuil+lp at free.fr
Thu Jun 7 12:36:29 BST 2007
At file:///v/home/vila/src/experimental/reuse.transports/
------------------------------------------------------------
revno: 2526
revision-id: v.ladeuil+lp at free.fr-20070607113627-2fudc24suivry84k
parent: v.ladeuil+lp at free.fr-20070607112936-xkiqdgbkjibjjkh6
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: reuse.transports
timestamp: Thu 2007-06-07 13:36:27 +0200
message:
Finish http refactoring. Test suite passing.
* bzrlib/transport/http/_urllib.py:
(HttpTransport_urllib.__init__): Simplified.
(HttpTransport_urllib._remote_path): New method. Get rid of
authinfo only for urllib2 purposes.
(HttpTransport_urllib._perform): Rewrite the connection sync
between transport and request.
(HttpTransport_urllib._get, HttpTransport_urllib._get,
HttpTransport_urllib._post): Updated for the new connection handling.
* bzrlib/transport/http/_pycurl.py:
(PyCurlTransport.__init__): Simplified.
(PyCurlTransport._get_curl): New method.
(PyCurlTransport.has, PyCurlTransport._get_full)
(PyCurlTransport._get_ranged, PyCurlTransport._post): Use _get_curl().
modified:
bzrlib/transport/http/_pycurl.py pycurlhttp.py-20060110060940-4e2a705911af77a6
bzrlib/transport/http/_urllib.py _urlgrabber.py-20060113083826-0bbf7d992fbf090c
-------------- next part --------------
=== modified file 'bzrlib/transport/http/_pycurl.py'
--- a/bzrlib/transport/http/_pycurl.py 2007-06-01 20:26:46 +0000
+++ b/bzrlib/transport/http/_pycurl.py 2007-06-07 11:36:27 +0000
@@ -88,7 +88,7 @@
"""
def __init__(self, base, from_transport=None):
- super(PyCurlTransport, self).__init__(base)
+ super(PyCurlTransport, self).__init__(base, from_transport)
if base.startswith('https'):
# Check availability of https into pycurl supported
# protocols
@@ -96,11 +96,17 @@
if 'https' not in supported:
raise DependencyNotPresent('pycurl', 'no https support')
self.cabundle = ca_bundle.get_ca_path()
- if from_transport is not None:
- self._curl = from_transport._curl
- else:
- mutter('using pycurl %s' % pycurl.version)
- self._curl = pycurl.Curl()
+
+ def _get_curl(self):
+ connection = self._get_connection()
+ if connection is None:
+ # First connection ever. There is no credentials for pycurl, either
+ # the password was embedded in the URL or it's not needed. The
+ # connection for pycurl is just the Curl object, it will not
+ # connect until the first request
+ connection = pycurl.Curl()
+ self._set_connection(connection, None)
+ return connection
def should_cache(self):
"""Return True if the data pulled across should be cached locally.
@@ -111,7 +117,7 @@
"""See Transport.has()"""
# We set NO BODY=0 in _get_full, so it should be safe
# to re-use the non-range curl object
- curl = self._curl
+ curl = self._get_curl()
abspath = self._remote_path(relpath)
curl.setopt(pycurl.URL, abspath)
self._set_curl_options(curl)
@@ -174,7 +180,7 @@
def _get_full(self, relpath):
"""Make a request for the entire file"""
- curl = self._curl
+ curl = self._get_curl()
abspath, data, header = self._setup_get_request(curl, relpath)
self._curl_perform(curl, header)
@@ -191,7 +197,7 @@
def _get_ranged(self, relpath, ranges, tail_amount):
"""Make a request for just part of the file."""
- curl = self._curl
+ curl = self._get_curl()
abspath, data, header = self._setup_get_request(curl, relpath)
range_header = self.attempted_range_header(ranges, tail_amount)
@@ -212,10 +218,10 @@
def _post(self, body_bytes):
fake_file = StringIO(body_bytes)
- curl = self._curl
- # Other places that use _base_curl for GET requests explicitly set
- # HTTPGET, so it should be safe to re-use the same object for both GETs
- # and POSTs.
+ curl = self._get_curl()
+ # Other places that use the Curl object (returned by _get_curl)
+ # for GET requests explicitly set HTTPGET, so it should be safe to
+ # re-use the same object for both GETs and POSTs.
curl.setopt(pycurl.POST, 1)
curl.setopt(pycurl.POSTFIELDSIZE, len(body_bytes))
curl.setopt(pycurl.READFUNCTION, fake_file.read)
=== modified file 'bzrlib/transport/http/_urllib.py'
--- a/bzrlib/transport/http/_urllib.py 2007-06-01 20:26:46 +0000
+++ b/bzrlib/transport/http/_urllib.py 2007-06-07 11:36:27 +0000
@@ -18,7 +18,10 @@
import urllib
import urlparse
-from bzrlib import errors
+from bzrlib import (
+ errors,
+ urlutils,
+ )
from bzrlib.trace import mutter
from bzrlib.transport import register_urlparse_netloc_protocol
from bzrlib.transport.http import HttpTransportBase
@@ -45,59 +48,61 @@
_opener_class = Opener
def __init__(self, base, from_transport=None):
- """Set the base path where files will be stored."""
+ super(HttpTransport_urllib, self).__init__(base, from_transport)
if from_transport is not None:
- super(HttpTransport_urllib, self).__init__(base, from_transport)
- self._connection = from_transport._connection
- self._auth = from_transport._auth
- self._proxy_auth = from_transport._proxy_auth
-
self._opener = from_transport._opener
else:
- # urllib2 will be confused if it find authentication
- # info in the urls. So we handle them separatly.
- # Note: we don't need to when cloning because it was
- # already done.
- clean_base, user, password = extract_credentials(base)
- super(HttpTransport_urllib, self).__init__(clean_base,
- from_transport)
- self._connection = None
self._opener = self._opener_class()
- authuri = extract_authentication_uri(self._remote_path(self._path))
- self._auth = {'user': user, 'password': password,
- 'authuri': authuri}
+ def _remote_path(self, relpath):
+ """Produce absolute path, adjusting protocol."""
+ relative = urlutils.unescape(relpath).encode('utf-8')
+ path = self._combine_paths(self._path, relative)
+ # urllib2 will be confused if it find authentication
+ # info (user, password) in the urls. So we handle them separatly.
+ return self._unsplit_url(self._unqualified_scheme,
+ None, None, self._host, self._port, path)
+
+ def _perform(self, request):
+ """Send the request to the server and handles common errors.
+
+ :returns: urllib2 Response object
+ """
+ connection = self._get_connection()
+ if connection is not None:
+ # Give back shared info
+ request.connection = connection
+ (auth, proxy_auth) = self._get_credentials()
+ else:
+ # First request, intialize credentials
+ user = self._user
+ password = self._password
+ authuri = self._remote_path('.')
+ auth = {'user': user, 'password': password, 'authuri': authuri}
+
if user and password is not None: # '' is a valid password
# Make the (user, password) available to urllib2
# We default to a realm of None to catch them all.
self._opener.password_manager.add_password(None, authuri,
user, password)
- self._proxy_auth = {}
-
- def _perform(self, request):
- """Send the request to the server and handles common errors.
-
- :returns: urllib2 Response object
- """
- if self._connection is not None:
- # Give back shared info
- request.connection = self._connection
+ proxy_auth = {}
# Ensure authentication info is provided
- request.auth = self._auth
- request.proxy_auth = self._proxy_auth
+ request.auth = auth
+ request.proxy_auth = proxy_auth
mutter('%s: [%s]' % (request.method, request.get_full_url()))
if self._debuglevel > 0:
print 'perform: %s base: %s, url: %s' % (request.method, self.base,
request.get_full_url())
response = self._opener.open(request)
- if self._connection is None:
- # Acquire connection when the first request is able
- # to connect to the server
- self._connection = request.connection
- # Always get auth parameters, they may change
- self._auth = request.auth
- self._proxy_auth = request.proxy_auth
+ if self._get_connection() is not request.connection:
+ # First connection or reconnection
+ self._set_connection(request.connection,
+ (request.auth, request.proxy_auth))
+ else:
+ # http may change the credentials while keeping the
+ # connection opened
+ self._update_credentials((request.auth, request.proxy_auth))
code = response.code
if request.follow_redirections is False \
@@ -129,12 +134,12 @@
code = response.code
if code == 404: # not found
- self._connection.fake_close()
+ self._get_connection().fake_close()
raise errors.NoSuchFile(abspath)
data = handle_response(abspath, code, response.headers, response)
# Close response to free the httplib.HTTPConnection pipeline
- self._connection.fake_close()
+ self._get_connection().fake_close()
return code, data
def _post(self, body_bytes):
@@ -143,7 +148,7 @@
code = response.code
data = handle_response(abspath, code, response.headers, response)
# Close response to free the httplib.HTTPConnection pipeline
- self._connection.fake_close()
+ self._get_connection().fake_close()
return code, data
def should_cache(self):
@@ -160,7 +165,7 @@
request = Request('HEAD', abspath)
response = self._perform(request)
- self._connection.fake_close()
+ self._get_connection().fake_close()
return response
def has(self, relpath):
More information about the bazaar-commits
mailing list