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.
17
"""Base implementation of Transport over http.
19
There are separate implementation modules for each http client implementation.
23
from cStringIO import StringIO
19
27
from bzrlib.transport import Transport, register_transport
20
28
from bzrlib.errors import (TransportNotPossible, NoSuchFile,
21
29
TransportError, ConnectionError)
23
from cStringIO import StringIO
24
import urllib, urllib2
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...
156
class HttpTransport(HttpTransportBase):
157
"""Python urllib transport for http and https.
159
TODO: Implement pipelined versions of all of the *_multi() functions.
162
def __init__(self, base):
163
"""Set the base path where files will be stored."""
164
super(HttpTransport, self).__init__(base)
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)
175
def should_cache(self):
176
"""Return True if the data pulled across should be cached locally.
180
def has(self, relpath):
181
"""Does the target location exist?
183
TODO: HttpTransport.has() should use a HEAD request,
184
not a full GET request.
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
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.
200
except urllib2.URLError, e:
201
mutter('url error code: %s for has url: %r', e.code, path)
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:
210
raise TransportError(orig_error=e)
212
def get(self, relpath):
213
"""Get the file at the given relative path.
215
:param relpath: The relative path to the file
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)
224
raise NoSuchFile(path, extra=e)
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)),
236
158
def put(self, relpath, f, mode=None):
237
159
"""Copy the file-like or string object into the location.
255
177
"""Copy the item at rel_from to the location at rel_to"""
256
178
raise TransportNotPossible('http does not support copy()')
258
def copy_to(self, relpaths, other, mode=None, pb=None):
259
"""Copy a set of entries from self into another Transport.
261
:param relpaths: A list/generator of entries to be copied.
263
TODO: if other is LocalTransport, is it possible to
264
do better than put(get())?
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()')
272
return super(HttpTransport, self).copy_to(relpaths, other, mode=mode, pb=pb)
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()')
278
def delete(self, relpath):
279
"""Delete the item at relpath"""
280
raise TransportNotPossible('http does not support delete()')