129
# _proto: "http" or "https"
130
# _qualified_proto: may have "+pycurl", etc
133
# _unqualified_scheme: "http" or "https"
134
# _scheme: may have "+pycurl", etc
132
def __init__(self, base, from_transport=None):
136
def __init__(self, base, _from_transport=None):
133
137
"""Set the base path where files will be stored."""
134
138
proto_match = re.match(r'^(https?)(\+\w+)?://', base)
135
139
if not proto_match:
136
140
raise AssertionError("not a http url: %r" % base)
137
self._proto = proto_match.group(1)
141
self._unqualified_scheme = proto_match.group(1)
138
142
impl_name = proto_match.group(2)
140
144
impl_name = impl_name[1:]
141
145
self._impl_name = impl_name
144
super(HttpTransportBase, self).__init__(base)
145
(apparent_proto, self._host,
146
self._path, self._parameters,
147
self._query, self._fragment) = urlparse.urlparse(self.base)
148
self._qualified_proto = apparent_proto
146
super(HttpTransportBase, self).__init__(base,
147
_from_transport=_from_transport)
149
148
# range hint is handled dynamically throughout the life
150
149
# of the transport object. We start by trying multi-range
151
150
# requests and if the server returns bogus results, we
153
152
# forget about range if the server really can't
154
153
# understand. Once acquired, this piece of info is
155
154
# propagated to clones.
156
if from_transport is not None:
157
self._range_hint = from_transport._range_hint
155
if _from_transport is not None:
156
self._range_hint = _from_transport._range_hint
159
158
self._range_hint = 'multi'
161
def abspath(self, relpath):
162
"""Return the full url to the given relative path.
164
This can be supplied with a string or a list.
166
The URL returned always has the protocol scheme originally used to
167
construct the transport, even if that includes an explicit
168
implementation qualifier.
170
assert isinstance(relpath, basestring)
171
if isinstance(relpath, unicode):
172
raise errors.InvalidURL(relpath, 'paths must not be unicode.')
173
if isinstance(relpath, basestring):
174
relpath_parts = relpath.split('/')
176
# TODO: Don't call this with an array - no magic interfaces
177
relpath_parts = relpath[:]
178
if relpath.startswith('/'):
181
# Except for the root, no trailing slashes are allowed
182
if len(relpath_parts) > 1 and relpath_parts[-1] == '':
184
"path %r within branch %r seems to be a directory"
185
% (relpath, self._path))
186
basepath = self._path.split('/')
187
if len(basepath) > 0 and basepath[-1] == '':
188
basepath = basepath[:-1]
190
for p in relpath_parts:
192
if len(basepath) == 0:
193
# In most filesystems, a request for the parent
194
# of root, just returns root.
197
elif p == '.' or p == '':
201
# Possibly, we could use urlparse.urljoin() here, but
202
# I'm concerned about when it chooses to strip the last
203
# portion of the path, and when it doesn't.
204
path = '/'.join(basepath)
207
result = urlparse.urlunparse((self._qualified_proto,
208
self._host, path, '', '', ''))
211
def _real_abspath(self, relpath):
212
"""Produce absolute path, adjusting protocol if needed"""
213
abspath = self.abspath(relpath)
214
qp = self._qualified_proto
216
if self._qualified_proto != self._proto:
217
abspath = rp + abspath[len(qp):]
218
if not isinstance(abspath, str):
219
# escaping must be done at a higher level
220
abspath = abspath.encode('ascii')
160
def _remote_path(self, relpath):
161
"""Produce absolute path, adjusting protocol."""
162
relative = urlutils.unescape(relpath).encode('utf-8')
163
path = self._combine_paths(self._path, relative)
164
return self._unsplit_url(self._unqualified_scheme,
165
self._user, self._password,
166
self._host, self._port,
223
169
def has(self, relpath):
224
170
raise NotImplementedError("has() is abstract on %r" % self)