~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/http/__init__.py

  • Committer: Martin Pool
  • Date: 2006-01-13 09:57:13 UTC
  • mto: This revision was merged to the branch mainline in revision 1611.
  • Revision ID: mbp@sourcefrog.net-20060113095713-1fa5912229a3898e
Review updates of pycurl transport

Split them out into 

  bzrlib.transport.http             common base
  bzrlib.transport.http._urllib     pure python
  bzrlib.transport.http._pycurl     calls pycurl

Update to work with robert's nice transport test multiplexer.

Add PyCurlTransport.has() which does just a HEAD request; should be faster.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
 
"""Implementation of Transport over http.
 
16
 
 
17
"""Base implementation of Transport over http.
 
18
 
 
19
There are separate implementation modules for each http client implementation.
17
20
"""
18
21
 
 
22
import errno
 
23
from cStringIO import StringIO
 
24
import urlparse
 
25
import urllib
 
26
 
19
27
from bzrlib.transport import Transport, register_transport
20
28
from bzrlib.errors import (TransportNotPossible, NoSuchFile, 
21
29
                           TransportError, ConnectionError)
22
 
import os, errno
23
 
from cStringIO import StringIO
24
 
import urllib, urllib2
25
 
import urlparse
26
 
 
27
30
from bzrlib.errors import BzrError, BzrCheckError
28
31
from bzrlib.branch import Branch
29
32
from bzrlib.trace import mutter
152
155
        # well, we could try DAV...
153
156
        return False
154
157
 
155
 
 
156
 
class HttpTransport(HttpTransportBase):
157
 
    """Python urllib transport for http and https.
158
 
    
159
 
    TODO: Implement pipelined versions of all of the *_multi() functions.
160
 
    """
161
 
 
162
 
    def __init__(self, base):
163
 
        """Set the base path where files will be stored."""
164
 
        super(HttpTransport, self).__init__(base)
165
 
 
166
 
    def _get_url(self, url):
167
 
        mutter("get_url %s" % url)
168
 
        manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
169
 
        url = extract_auth(url, manager)
170
 
        auth_handler = urllib2.HTTPBasicAuthHandler(manager)
171
 
        opener = urllib2.build_opener(auth_handler)
172
 
        url_f = opener.open(url)
173
 
        return url_f
174
 
 
175
 
    def should_cache(self):
176
 
        """Return True if the data pulled across should be cached locally.
177
 
        """
178
 
        return True
179
 
 
180
 
    def has(self, relpath):
181
 
        """Does the target location exist?
182
 
 
183
 
        TODO: HttpTransport.has() should use a HEAD request,
184
 
        not a full GET request.
185
 
 
186
 
        TODO: This should be changed so that we don't use
187
 
        urllib2 and get an exception, the code path would be
188
 
        cleaner if we just do an http HEAD request, and parse
189
 
        the return code.
190
 
        """
191
 
        path = relpath
192
 
        try:
193
 
            path = self.abspath(relpath)
194
 
            f = self._get_url(path)
195
 
            # Without the read and then close()
196
 
            # we tend to have busy sockets.
197
 
            f.read()
198
 
            f.close()
199
 
            return True
200
 
        except urllib2.URLError, e:
201
 
            mutter('url error code: %s for has url: %r', e.code, path)
202
 
            if e.code == 404:
203
 
                return False
204
 
            raise
205
 
        except IOError, e:
206
 
            mutter('io error: %s %s for has url: %r', 
207
 
                e.errno, errno.errorcode.get(e.errno), path)
208
 
            if e.errno == errno.ENOENT:
209
 
                return False
210
 
            raise TransportError(orig_error=e)
211
 
 
212
 
    def get(self, relpath):
213
 
        """Get the file at the given relative path.
214
 
 
215
 
        :param relpath: The relative path to the file
216
 
        """
217
 
        path = relpath
218
 
        try:
219
 
            path = self.abspath(relpath)
220
 
            return self._get_url(path)
221
 
        except urllib2.HTTPError, e:
222
 
            mutter('url error code: %s for has url: %r', e.code, path)
223
 
            if e.code == 404:
224
 
                raise NoSuchFile(path, extra=e)
225
 
            raise
226
 
        except (BzrError, IOError), e:
227
 
            if hasattr(e, 'errno'):
228
 
                mutter('io error: %s %s for has url: %r', 
229
 
                    e.errno, errno.errorcode.get(e.errno), path)
230
 
                if e.errno == errno.ENOENT:
231
 
                    raise NoSuchFile(path, extra=e)
232
 
            raise ConnectionError(msg = "Error retrieving %s: %s" 
233
 
                             % (self.abspath(relpath), str(e)),
234
 
                             orig_error=e)
235
 
 
236
158
    def put(self, relpath, f, mode=None):
237
159
        """Copy the file-like or string object into the location.
238
160
 
255
177
        """Copy the item at rel_from to the location at rel_to"""
256
178
        raise TransportNotPossible('http does not support copy()')
257
179
 
258
 
    def copy_to(self, relpaths, other, mode=None, pb=None):
259
 
        """Copy a set of entries from self into another Transport.
260
 
 
261
 
        :param relpaths: A list/generator of entries to be copied.
262
 
 
263
 
        TODO: if other is LocalTransport, is it possible to
264
 
              do better than put(get())?
265
 
        """
266
 
        # At this point HttpTransport might be able to check and see if
267
 
        # the remote location is the same, and rather than download, and
268
 
        # then upload, it could just issue a remote copy_this command.
269
 
        if isinstance(other, HttpTransport):
270
 
            raise TransportNotPossible('http cannot be the target of copy_to()')
271
 
        else:
272
 
            return super(HttpTransport, self).copy_to(relpaths, other, mode=mode, pb=pb)
273
 
 
274
 
    def move(self, rel_from, rel_to):
275
 
        """Move the item at rel_from to the location at rel_to"""
276
 
        raise TransportNotPossible('http does not support move()')
277
 
 
278
 
    def delete(self, relpath):
279
 
        """Delete the item at relpath"""
280
 
        raise TransportNotPossible('http does not support delete()')
281