~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/http.py

Merge from integration.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
from bzrlib.transport import Transport, register_transport
20
20
from bzrlib.errors import (TransportNotPossible, NoSuchFile, 
21
 
                           NonRelativePath, TransportError, ConnectionError)
 
21
                           TransportError, ConnectionError)
22
22
import os, errno
23
23
from cStringIO import StringIO
24
 
import urllib2
 
24
import urllib, urllib2
25
25
import urlparse
26
26
 
27
27
from bzrlib.errors import BzrError, BzrCheckError
29
29
from bzrlib.trace import mutter
30
30
 
31
31
 
 
32
def extract_auth(url, password_manager):
 
33
    """
 
34
    Extract auth parameters from am HTTP/HTTPS url and add them to the given
 
35
    password manager.  Return the url, minus those auth parameters (which
 
36
    confuse urllib2).
 
37
    """
 
38
    assert url.startswith('http://') or url.startswith('https://')
 
39
    scheme, host = url.split('//', 1)
 
40
    if '/' in host:
 
41
        host, path = host.split('/', 1)
 
42
        path = '/' + path
 
43
    else:
 
44
        path = ''
 
45
    port = ''
 
46
    if '@' in host:
 
47
        auth, host = host.split('@', 1)
 
48
        if ':' in auth:
 
49
            username, password = auth.split(':', 1)
 
50
        else:
 
51
            username, password = auth, None
 
52
        if ':' in host:
 
53
            host, port = host.split(':', 1)
 
54
            port = ':' + port
 
55
        # FIXME: if password isn't given, should we ask for it?
 
56
        if password is not None:
 
57
            username = urllib.unquote(username)
 
58
            password = urllib.unquote(password)
 
59
            password_manager.add_password(None, host, username, password)
 
60
    url = scheme + '//' + host + port + path
 
61
    return url
 
62
    
32
63
def get_url(url):
33
64
    import urllib2
34
 
    mutter("get_url %s", url)
35
 
    url_f = urllib2.urlopen(url)
 
65
    mutter("get_url %s" % url)
 
66
    manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
 
67
    url = extract_auth(url, manager)
 
68
    auth_handler = urllib2.HTTPBasicAuthHandler(manager)
 
69
    opener = urllib2.build_opener(auth_handler)
 
70
    url_f = opener.open(url)
36
71
    return url_f
37
72
 
38
 
class HttpTransportError(TransportError):
39
 
    pass
40
 
 
41
73
class HttpTransport(Transport):
42
74
    """This is the transport agent for http:// access.
43
75
    
119
151
        cleaner if we just do an http HEAD request, and parse
120
152
        the return code.
121
153
        """
 
154
        path = relpath
122
155
        try:
123
 
            f = get_url(self.abspath(relpath))
 
156
            path = self.abspath(relpath)
 
157
            f = get_url(path)
124
158
            # Without the read and then close()
125
159
            # we tend to have busy sockets.
126
160
            f.read()
127
161
            f.close()
128
162
            return True
129
163
        except urllib2.URLError, e:
 
164
            mutter('url error code: %s for has url: %r', e.code, path)
130
165
            if e.code == 404:
131
166
                return False
132
167
            raise
133
168
        except IOError, e:
 
169
            mutter('io error: %s %s for has url: %r', 
 
170
                e.errno, errno.errorcode.get(e.errno), path)
134
171
            if e.errno == errno.ENOENT:
135
172
                return False
136
 
            raise HttpTransportError(orig_error=e)
 
173
            raise TransportError(orig_error=e)
137
174
 
138
175
    def get(self, relpath, decode=False):
139
176
        """Get the file at the given relative path.
140
177
 
141
178
        :param relpath: The relative path to the file
142
179
        """
 
180
        path = relpath
143
181
        try:
144
 
            return get_url(self.abspath(relpath))
 
182
            path = self.abspath(relpath)
 
183
            return get_url(path)
145
184
        except urllib2.HTTPError, e:
 
185
            mutter('url error code: %s for has url: %r', e.code, path)
146
186
            if e.code == 404:
147
 
                raise NoSuchFile(msg = "Error retrieving %s: %s" 
148
 
                                 % (self.abspath(relpath), str(e)),
149
 
                                 orig_error=e)
 
187
                raise NoSuchFile(path, extra=e)
150
188
            raise
151
189
        except (BzrError, IOError), e:
 
190
            if hasattr(e, 'errno'):
 
191
                mutter('io error: %s %s for has url: %r', 
 
192
                    e.errno, errno.errorcode.get(e.errno), path)
 
193
                if e.errno == errno.ENOENT:
 
194
                    raise NoSuchFile(path, extra=e)
152
195
            raise ConnectionError(msg = "Error retrieving %s: %s" 
153
196
                             % (self.abspath(relpath), str(e)),
154
197
                             orig_error=e)