3
An implementation of the Transport object for http access.
6
from bzrlib.transport import Transport, register_transport, \
7
TransportNotPossible, NoSuchFile, NonRelativePath, \
10
from cStringIO import StringIO
14
from bzrlib.errors import BzrError, BzrCheckError
15
from bzrlib.branch import Branch, BZR_BRANCH_FORMAT
16
from bzrlib.trace import mutter
18
# velocitynet.com.au transparently proxies connections and thereby
19
# breaks keep-alive -- sucks!
24
mutter("get_url %s" % url)
25
url_f = urllib2.urlopen(url)
28
class HttpTransportError(TransportError):
31
class HttpTransport(Transport):
32
"""This is the transport agent for http:// access.
34
TODO: Implement pipelined versions of all of the *_multi() functions.
37
def __init__(self, base):
38
"""Set the base path where files will be stored."""
39
assert base.startswith('http://') or base.startswith('https://')
40
super(HttpTransport, self).__init__(base)
41
# In the future we might actually connect to the remote host
42
# rather than using get_url
43
# self._connection = None
44
(self._proto, self._host,
45
self._path, self._parameters,
46
self._query, self._fragment) = urlparse.urlparse(self.base)
48
def should_cache(self):
49
"""Return True if the data pulled across should be cached locally.
53
def clone(self, offset=None):
54
"""Return a new HttpTransport with root at self.base + offset
55
For now HttpTransport does not actually connect, so just return
56
a new HttpTransport object.
59
return HttpTransport(self.base)
61
return HttpTransport(self.abspath(offset))
63
def abspath(self, relpath):
64
"""Return the full url to the given relative path.
65
This can be supplied with a string or a list
67
if isinstance(relpath, basestring):
69
basepath = self._path.split('/')
70
if len(basepath) > 0 and basepath[-1] == '':
71
basepath = basepath[:-1]
76
# In most filesystems, a request for the parent
77
# of root, just returns root.
85
# Possibly, we could use urlparse.urljoin() here, but
86
# I'm concerned about when it chooses to strip the last
87
# portion of the path, and when it doesn't.
88
path = '/'.join(basepath)
89
return urlparse.urlunparse((self._proto,
90
self._host, path, '', '', ''))
92
def relpath(self, abspath):
93
if not abspath.startswith(self.base):
94
raise NonRelativePath('path %r is not under base URL %r'
95
% (abspath, self.base))
97
return abspath[pl:].lstrip('/')
99
def has(self, relpath):
100
"""Does the target location exist?
102
TODO: HttpTransport.has() should use a HEAD request,
103
not a full GET request.
105
TODO: This should be changed so that we don't use
106
urllib2 and get an exception, the code path would be
107
cleaner if we just do an http HEAD request, and parse
111
f = get_url(self.abspath(relpath))
112
# Without the read and then close()
113
# we tend to have busy sockets.
119
except urllib2.URLError:
122
if e.errno == errno.ENOENT:
124
raise HttpTransportError(orig_error=e)
126
def get(self, relpath, decode=False):
127
"""Get the file at the given relative path.
129
:param relpath: The relative path to the file
132
return get_url(self.abspath(relpath))
134
raise NoSuchFile(orig_error=e)
135
except urllib2.URLError, e:
136
raise NoSuchFile(orig_error=e)
138
raise NoSuchFile(orig_error=e)
140
raise HttpTransportError(orig_error=e)
142
def put(self, relpath, f):
143
"""Copy the file-like or string object into the location.
145
:param relpath: Location to put the contents, relative to base.
146
:param f: File-like or string object.
148
raise TransportNotPossible('http PUT not supported')
150
def mkdir(self, relpath):
151
"""Create a directory at the given path."""
152
raise TransportNotPossible('http does not support mkdir()')
154
def append(self, relpath, f):
155
"""Append the text in the file-like object into the final
158
raise TransportNotPossible('http does not support append()')
160
def copy(self, rel_from, rel_to):
161
"""Copy the item at rel_from to the location at rel_to"""
162
raise TransportNotPossible('http does not support copy()')
164
def copy_to(self, relpaths, other, pb=None):
165
"""Copy a set of entries from self into another Transport.
167
:param relpaths: A list/generator of entries to be copied.
169
TODO: if other is LocalTransport, is it possible to
170
do better than put(get())?
172
# At this point HttpTransport might be able to check and see if
173
# the remote location is the same, and rather than download, and
174
# then upload, it could just issue a remote copy_this command.
175
if isinstance(other, HttpTransport):
176
raise TransportNotPossible('http cannot be the target of copy_to()')
178
return super(HttpTransport, self).copy_to(relpaths, other, pb=pb)
180
def move(self, rel_from, rel_to):
181
"""Move the item at rel_from to the location at rel_to"""
182
raise TransportNotPossible('http does not support move()')
184
def delete(self, relpath):
185
"""Delete the item at relpath"""
186
raise TransportNotPossible('http does not support delete()')
188
def async_get(self, relpath):
189
"""Make a request for an file at the given location, but
190
don't worry about actually getting it yet.
194
raise NotImplementedError
196
def list_dir(self, relpath):
197
"""Return a list of all files at the given location.
198
WARNING: many transports do not support this, so trying avoid using
199
it if at all possible.
201
raise TransportNotPossible('http does not support list_dir()')
203
def stat(self, relpath):
204
"""Return the stat information for a file.
206
raise TransportNotPossible('http does not support stat()')
208
def lock_read(self, relpath):
209
"""Lock the given file for shared (read) access.
210
:return: A lock object, which should be passed to Transport.unlock()
212
# The old RemoteBranch ignore lock for reading, so we will
213
# continue that tradition and return a bogus lock object.
214
class BogusLock(object):
215
def __init__(self, path):
219
return BogusLock(relpath)
221
def lock_write(self, relpath):
222
"""Lock the given file for exclusive (write) access.
223
WARNING: many transports do not support this, so trying avoid using it
225
:return: A lock object, which should be passed to Transport.unlock()
227
raise TransportNotPossible('http does not support lock_write()')
229
register_transport('http://', HttpTransport)
230
register_transport('https://', HttpTransport)