1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
# Copyright (C) 2005, 2006 Canonical Ltd
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import urllib, urllib2
from bzrlib.errors import BzrError
from bzrlib.trace import mutter
from bzrlib.transport.http import HttpTransportBase, extract_auth
from bzrlib.errors import (TransportNotPossible, NoSuchFile,
TransportError, ConnectionError)
class HttpTransport(HttpTransportBase):
"""Python urllib transport for http and https.
"""
# TODO: Implement pipelined versions of all of the *_multi() functions.
def __init__(self, base):
"""Set the base path where files will be stored."""
super(HttpTransport, self).__init__(base)
def _get_url(self, url):
mutter("get_url %s" % url)
manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
url = extract_auth(url, manager)
auth_handler = urllib2.HTTPBasicAuthHandler(manager)
opener = urllib2.build_opener(auth_handler)
url_f = opener.open(url)
return url_f
def should_cache(self):
"""Return True if the data pulled across should be cached locally.
"""
return True
def has(self, relpath):
"""Does the target location exist?
TODO: HttpTransport.has() should use a HEAD request,
not a full GET request.
TODO: This should be changed so that we don't use
urllib2 and get an exception, the code path would be
cleaner if we just do an http HEAD request, and parse
the return code.
"""
path = relpath
try:
path = self.abspath(relpath)
f = self._get_url(path)
# Without the read and then close()
# we tend to have busy sockets.
f.read()
f.close()
return True
except urllib2.URLError, e:
mutter('url error code: %s for has url: %r', e.code, path)
if e.code == 404:
return False
raise
except IOError, e:
mutter('io error: %s %s for has url: %r',
e.errno, errno.errorcode.get(e.errno), path)
if e.errno == errno.ENOENT:
return False
raise TransportError(orig_error=e)
def get(self, relpath):
"""Get the file at the given relative path.
:param relpath: The relative path to the file
"""
path = relpath
try:
path = self.abspath(relpath)
return self._get_url(path)
except urllib2.HTTPError, e:
mutter('url error code: %s for has url: %r', e.code, path)
if e.code == 404:
raise NoSuchFile(path, extra=e)
raise
except (BzrError, IOError), e:
if hasattr(e, 'errno'):
mutter('io error: %s %s for has url: %r',
e.errno, errno.errorcode.get(e.errno), path)
if e.errno == errno.ENOENT:
raise NoSuchFile(path, extra=e)
raise ConnectionError(msg = "Error retrieving %s: %s"
% (self.abspath(relpath), str(e)),
orig_error=e)
def copy_to(self, relpaths, other, mode=None, pb=None):
"""Copy a set of entries from self into another Transport.
:param relpaths: A list/generator of entries to be copied.
TODO: if other is LocalTransport, is it possible to
do better than put(get())?
"""
# At this point HttpTransport might be able to check and see if
# the remote location is the same, and rather than download, and
# then upload, it could just issue a remote copy_this command.
if isinstance(other, HttpTransport):
raise TransportNotPossible('http cannot be the target of copy_to()')
else:
return super(HttpTransport, self).copy_to(relpaths, other, mode=mode, pb=pb)
def move(self, rel_from, rel_to):
"""Move the item at rel_from to the location at rel_to"""
raise TransportNotPossible('http does not support move()')
def delete(self, relpath):
"""Delete the item at relpath"""
raise TransportNotPossible('http does not support delete()')
|