annotate mercurial/byterange.py @ 33766:4c706037adef

wireproto: overhaul iterating batcher code (API) The remote batching code is difficult to read. Let's improve it. As part of the refactor, the future returned by method calls on batchiter() instances is now populated. However, you still need to consume the results() generator for the future to be set. But at least now we can stuff the future somewhere and not have to worry about aligning method call order with result order since you can use a future to hold the result. Also as part of the change, we now verify that @batchable generators yield exactly 2 values. In other words, we enforce their API. The non-iter batcher has been unused since b6e71f8af5b8. And to my surprise we had no explicit unit test coverage of it! test-batching.py has been overhauled to use the iterating batcher. Since the iterating batcher doesn't allow non-batchable method calls nor local calls, tests have been updated to reflect reality. The iterating batcher has been used for multiple releases apparently without major issue. So this shouldn't cause alarm. .. api:: @peer.batchable functions must now yield exactly 2 values Differential Revision: https://phab.mercurial-scm.org/D319
author Gregory Szorc <gregory.szorc@gmail.com>
date Wed, 09 Aug 2017 23:29:30 -0700
parents 032c4c2f802a
children 0fa781320203
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
1 # This library is free software; you can redistribute it and/or
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
2 # modify it under the terms of the GNU Lesser General Public
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
3 # License as published by the Free Software Foundation; either
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
4 # version 2.1 of the License, or (at your option) any later version.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
5 #
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
6 # This library is distributed in the hope that it will be useful,
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
9 # Lesser General Public License for more details.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
10 #
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
11 # You should have received a copy of the GNU Lesser General Public
15782
7de7630053cb Remove FSF mailing address from GPL headers
Martin Geisler <mg@aragost.com>
parents: 14947
diff changeset
12 # License along with this library; if not, see
7de7630053cb Remove FSF mailing address from GPL headers
Martin Geisler <mg@aragost.com>
parents: 14947
diff changeset
13 # <http://www.gnu.org/licenses/>.
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
14
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
15 # This file is part of urlgrabber, a high-level cross-protocol url-grabber
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
16 # Copyright 2002-2004 Michael D. Stenner, Ryan Tomayko
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
17
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
18 # $Id: byterange.py,v 1.9 2005/02/14 21:55:07 mstenner Exp $
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
19
27504
ce3ae9ccd800 byterange: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
20 from __future__ import absolute_import
ce3ae9ccd800 byterange: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
21
ce3ae9ccd800 byterange: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
22 import email
ce3ae9ccd800 byterange: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
23 import ftplib
ce3ae9ccd800 byterange: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
24 import mimetypes
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
25 import os
27504
ce3ae9ccd800 byterange: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
26 import re
ce3ae9ccd800 byterange: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
27 import socket
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
28 import stat
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
29
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
30 from . import (
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
31 util,
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
32 )
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
33
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
34 urlerr = util.urlerr
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
35 urlreq = util.urlreq
27504
ce3ae9ccd800 byterange: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
36
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
37 addclosehook = urlreq.addclosehook
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
38 addinfourl = urlreq.addinfourl
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
39 splitattr = urlreq.splitattr
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
40 splitpasswd = urlreq.splitpasswd
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
41 splitport = urlreq.splitport
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
42 splituser = urlreq.splituser
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
43 unquote = urlreq.unquote
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
44
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
45 class RangeError(IOError):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
46 """Error raised when an unsatisfiable range is requested."""
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
47 pass
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
48
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
49 class HTTPRangeHandler(urlreq.basehandler):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
50 """Handler that enables HTTP Range headers.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
51
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
52 This was extremely simple. The Range header is a HTTP feature to
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
53 begin with so all this class does is tell urllib2 that the
17424
e7cfe3587ea4 fix trivial spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents: 15782
diff changeset
54 "206 Partial Content" response from the HTTP server is what we
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
55 expected.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
56
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
57 Example:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
58 import urllib2
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
59 import byterange
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
60
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
61 range_handler = range.HTTPRangeHandler()
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
62 opener = urlreq.buildopener(range_handler)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
63
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
64 # install it
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
65 urlreq.installopener(opener)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
66
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
67 # create Request and set Range header
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
68 req = urlreq.request('http://www.python.org/')
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
69 req.header['Range'] = 'bytes=30-50'
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
70 f = urlreq.urlopen(req)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
71 """
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
72
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
73 def http_error_206(self, req, fp, code, msg, hdrs):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
74 # 206 Partial Content Response
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
75 r = urlreq.addinfourl(fp, hdrs, req.get_full_url())
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
76 r.code = code
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
77 r.msg = msg
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
78 return r
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
79
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
80 def http_error_416(self, req, fp, code, msg, hdrs):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
81 # HTTP's Range Not Satisfiable error
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
82 raise RangeError('Requested Range Not Satisfiable')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
83
14764
a7d5816087a9 classes: fix class style problems found by b071cd58af50
Thomas Arendsen Hein <thomas@intevation.de>
parents: 10905
diff changeset
84 class RangeableFileObject(object):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
85 """File object wrapper to enable raw range handling.
17507
f25613683e52 spelling: primarily
timeless@mozdev.org
parents: 17489
diff changeset
86 This was implemented primarily for handling range
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
87 specifications for file:// urls. This object effectively makes
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
88 a file object look like it consists only of a range of bytes in
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
89 the stream.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
90
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
91 Examples:
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
92 # expose 10 bytes, starting at byte position 20, from
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
93 # /etc/aliases.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
94 >>> fo = RangeableFileObject(file('/etc/passwd', 'r'), (20,30))
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
95 # seek seeks within the range (to position 23 in this case)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
96 >>> fo.seek(3)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
97 # tell tells where your at _within the range_ (position 3 in
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
98 # this case)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
99 >>> fo.tell()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
100 # read EOFs if an attempt is made to read past the last
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
101 # byte in the range. the following will return only 7 bytes.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
102 >>> fo.read(30)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
103 """
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
104
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
105 def __init__(self, fo, rangetup):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
106 """Create a RangeableFileObject.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
107 fo -- a file like object. only the read() method need be
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
108 supported but supporting an optimized seek() is
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
109 preferable.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
110 rangetup -- a (firstbyte,lastbyte) tuple specifying the range
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
111 to work over.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
112 The file object provided is assumed to be at byte offset 0.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
113 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
114 self.fo = fo
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
115 (self.firstbyte, self.lastbyte) = range_tuple_normalize(rangetup)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
116 self.realpos = 0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
117 self._do_seek(self.firstbyte)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
118
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
119 def __getattr__(self, name):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
120 """This effectively allows us to wrap at the instance level.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
121 Any attribute not found in _this_ object will be searched for
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
122 in self.fo. This includes methods."""
14947
3aa34005a73d byterange: replace uses of hasattr with getattr
Augie Fackler <durin42@gmail.com>
parents: 14764
diff changeset
123 return getattr(self.fo, name)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
124
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
125 def tell(self):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
126 """Return the position within the range.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
127 This is different from fo.seek in that position 0 is the
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
128 first byte position of the range tuple. For example, if
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
129 this object was created with a range tuple of (500,899),
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
130 tell() will return 0 when at byte position 500 of the file.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
131 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
132 return (self.realpos - self.firstbyte)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
133
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
134 def seek(self, offset, whence=0):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
135 """Seek within the byte range.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
136 Positioning is identical to that described under tell().
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
137 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
138 assert whence in (0, 1, 2)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
139 if whence == 0: # absolute seek
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
140 realoffset = self.firstbyte + offset
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
141 elif whence == 1: # relative seek
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
142 realoffset = self.realpos + offset
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
143 elif whence == 2: # absolute from end of file
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
144 # XXX: are we raising the right Error here?
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
145 raise IOError('seek from end of file not supported.')
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
146
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
147 # do not allow seek past lastbyte in range
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
148 if self.lastbyte and (realoffset >= self.lastbyte):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
149 realoffset = self.lastbyte
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
150
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
151 self._do_seek(realoffset - self.realpos)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
152
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
153 def read(self, size=-1):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
154 """Read within the range.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
155 This method will limit the size read based on the range.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
156 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
157 size = self._calc_read_size(size)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
158 rslt = self.fo.read(size)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
159 self.realpos += len(rslt)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
160 return rslt
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
161
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
162 def readline(self, size=-1):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
163 """Read lines within the range.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
164 This method will limit the size read based on the range.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
165 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
166 size = self._calc_read_size(size)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
167 rslt = self.fo.readline(size)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
168 self.realpos += len(rslt)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
169 return rslt
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
170
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
171 def _calc_read_size(self, size):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
172 """Handles calculating the amount of data to read based on
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
173 the range.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
174 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
175 if self.lastbyte:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
176 if size > -1:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
177 if ((self.realpos + size) >= self.lastbyte):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
178 size = (self.lastbyte - self.realpos)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
179 else:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
180 size = (self.lastbyte - self.realpos)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
181 return size
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
182
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
183 def _do_seek(self, offset):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
184 """Seek based on whether wrapped object supports seek().
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
185 offset is relative to the current position (self.realpos).
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
186 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
187 assert offset >= 0
14947
3aa34005a73d byterange: replace uses of hasattr with getattr
Augie Fackler <durin42@gmail.com>
parents: 14764
diff changeset
188 seek = getattr(self.fo, 'seek', self._poor_mans_seek)
3aa34005a73d byterange: replace uses of hasattr with getattr
Augie Fackler <durin42@gmail.com>
parents: 14764
diff changeset
189 seek(self.realpos + offset)
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
190 self.realpos += offset
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
191
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
192 def _poor_mans_seek(self, offset):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
193 """Seek by calling the wrapped file objects read() method.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
194 This is used for file like objects that do not have native
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
195 seek support. The wrapped objects read() method is called
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
196 to manually seek to the desired position.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
197 offset -- read this number of bytes from the wrapped
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
198 file object.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
199 raise RangeError if we encounter EOF before reaching the
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
200 specified offset.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
201 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
202 pos = 0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
203 bufsize = 1024
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
204 while pos < offset:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
205 if (pos + bufsize) > offset:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
206 bufsize = offset - pos
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
207 buf = self.fo.read(bufsize)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
208 if len(buf) != bufsize:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
209 raise RangeError('Requested Range Not Satisfiable')
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
210 pos += bufsize
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
211
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
212 class FileRangeHandler(urlreq.filehandler):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
213 """FileHandler subclass that adds Range support.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
214 This class handles Range headers exactly like an HTTP
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
215 server would.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
216 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
217 def open_local_file(self, req):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
218 host = req.get_host()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
219 file = req.get_selector()
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
220 localfile = urlreq.url2pathname(file)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
221 stats = os.stat(localfile)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
222 size = stats[stat.ST_SIZE]
8378
59acf64995d2 byterange: fix import error
Martin Geisler <mg@lazybytes.net>
parents: 8366
diff changeset
223 modified = email.Utils.formatdate(stats[stat.ST_MTIME])
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
224 mtype = mimetypes.guess_type(file)[0]
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
225 if host:
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
226 host, port = urlreq.splitport(host)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
227 if port or socket.gethostbyname(host) not in self.get_names():
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
228 raise urlerr.urlerror('file not on local host')
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
229 fo = open(localfile,'rb')
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
230 brange = req.headers.get('Range', None)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
231 brange = range_header_to_tuple(brange)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
232 assert brange != ()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
233 if brange:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
234 (fb, lb) = brange
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
235 if lb == '':
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
236 lb = size
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
237 if fb < 0 or fb > size or lb > size:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
238 raise RangeError('Requested Range Not Satisfiable')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
239 size = (lb - fb)
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
240 fo = RangeableFileObject(fo, (fb, lb))
9034
8429062de8d3 compat: use email in favor of mimetools
Alejandro Santos <alejolp@alejolp.com>
parents: 8378
diff changeset
241 headers = email.message_from_string(
5930
c301f15c965a send conservatively capitalized HTTP headers
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 3673
diff changeset
242 'Content-Type: %s\nContent-Length: %d\nLast-Modified: %s\n' %
9034
8429062de8d3 compat: use email in favor of mimetools
Alejandro Santos <alejolp@alejolp.com>
parents: 8378
diff changeset
243 (mtype or 'text/plain', size, modified))
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
244 return urlreq.addinfourl(fo, headers, 'file:'+file)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
245
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
246
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
247 # FTP Range Support
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
248 # Unfortunately, a large amount of base FTP code had to be copied
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
249 # from urllib and urllib2 in order to insert the FTP REST command.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
250 # Code modifications for range support have been commented as
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
251 # follows:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
252 # -- range support modifications start/end here
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
253
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
254 class FTPRangeHandler(urlreq.ftphandler):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
255 def ftp_open(self, req):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
256 host = req.get_host()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
257 if not host:
7008
8fee8ff13d37 use Exception(args)-style raising consistently (py3k compatibility)
Peter Ruibal <peter.ruibal@intel.com>
parents: 5930
diff changeset
258 raise IOError('ftp error', 'no host given')
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
259 host, port = splitport(host)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
260 if port is None:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
261 port = ftplib.FTP_PORT
9695
e4211db457c0 byterange: backport fix from upstream
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9034
diff changeset
262 else:
e4211db457c0 byterange: backport fix from upstream
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 9034
diff changeset
263 port = int(port)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
264
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
265 # username/password handling
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
266 user, host = splituser(host)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
267 if user:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
268 user, passwd = splitpasswd(user)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
269 else:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
270 passwd = None
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
271 host = unquote(host)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
272 user = unquote(user or '')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
273 passwd = unquote(passwd or '')
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
274
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
275 try:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
276 host = socket.gethostbyname(host)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24306
diff changeset
277 except socket.error as msg:
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
278 raise urlerr.urlerror(msg)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
279 path, attrs = splitattr(req.get_selector())
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
280 dirs = path.split('/')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
281 dirs = map(unquote, dirs)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
282 dirs, file = dirs[:-1], dirs[-1]
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
283 if dirs and not dirs[0]:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
284 dirs = dirs[1:]
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
285 try:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
286 fw = self.connect_ftp(user, passwd, host, port, dirs)
24306
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 18597
diff changeset
287 if file:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 18597
diff changeset
288 type = 'I'
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 18597
diff changeset
289 else:
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 18597
diff changeset
290 type = 'D'
6ddc86eedc3b style: kill ersatz if-else ternary operators
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 18597
diff changeset
291
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
292 for attr in attrs:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
293 attr, value = splitattr(attr)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
294 if attr.lower() == 'type' and \
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
295 value in ('a', 'A', 'i', 'I', 'd', 'D'):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
296 type = value.upper()
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
297
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
298 # -- range support modifications start here
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
299 rest = None
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
300 range_tup = range_header_to_tuple(req.headers.get('Range', None))
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
301 assert range_tup != ()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
302 if range_tup:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
303 (fb, lb) = range_tup
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
304 if fb > 0:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
305 rest = fb
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
306 # -- range support modifications end here
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
307
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
308 fp, retrlen = fw.retrfile(file, type, rest)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
309
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
310 # -- range support modifications start here
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
311 if range_tup:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
312 (fb, lb) = range_tup
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
313 if lb == '':
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
314 if retrlen is None or retrlen == 0:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 9695
diff changeset
315 raise RangeError('Requested Range Not Satisfiable due'
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 9695
diff changeset
316 ' to unobtainable file length.')
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
317 lb = retrlen
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
318 retrlen = lb - fb
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
319 if retrlen < 0:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
320 # beginning of range is larger than file
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
321 raise RangeError('Requested Range Not Satisfiable')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
322 else:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
323 retrlen = lb - fb
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
324 fp = RangeableFileObject(fp, (0, retrlen))
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
325 # -- range support modifications end here
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
326
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
327 headers = ""
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
328 mtype = mimetypes.guess_type(req.get_full_url())[0]
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
329 if mtype:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
330 headers += "Content-Type: %s\n" % mtype
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
331 if retrlen is not None and retrlen >= 0:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
332 headers += "Content-Length: %d\n" % retrlen
9034
8429062de8d3 compat: use email in favor of mimetools
Alejandro Santos <alejolp@alejolp.com>
parents: 8378
diff changeset
333 headers = email.message_from_string(headers)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
334 return addinfourl(fp, headers, req.get_full_url())
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24306
diff changeset
335 except ftplib.all_errors as msg:
18586
40f9472f5737 byterange: remove old two-arg raise trick
Augie Fackler <raf@durin42.com>
parents: 17537
diff changeset
336 raise IOError('ftp error', msg)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
337
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
338 def connect_ftp(self, user, passwd, host, port, dirs):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
339 fw = ftpwrapper(user, passwd, host, port, dirs)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
340 return fw
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
341
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 27504
diff changeset
342 class ftpwrapper(urlreq.ftpwrapper):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
343 # range support note:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
344 # this ftpwrapper code is copied directly from
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
345 # urllib. The only enhancement is to add the rest
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
346 # argument and pass it on to ftp.ntransfercmd
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
347 def retrfile(self, file, type, rest=None):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
348 self.endtransfer()
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
349 if type in ('d', 'D'):
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
350 cmd = 'TYPE A'
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
351 isdir = 1
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
352 else:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
353 cmd = 'TYPE ' + type
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
354 isdir = 0
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
355 try:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
356 self.ftp.voidcmd(cmd)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
357 except ftplib.all_errors:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
358 self.init()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
359 self.ftp.voidcmd(cmd)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
360 conn = None
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
361 if file and not isdir:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
362 # Use nlst to see if the file exists at all
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
363 try:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
364 self.ftp.nlst(file)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24306
diff changeset
365 except ftplib.error_perm as reason:
18586
40f9472f5737 byterange: remove old two-arg raise trick
Augie Fackler <raf@durin42.com>
parents: 17537
diff changeset
366 raise IOError('ftp error', reason)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
367 # Restore the transfer mode!
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
368 self.ftp.voidcmd(cmd)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
369 # Try to retrieve as a file
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
370 try:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
371 cmd = 'RETR ' + file
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
372 conn = self.ftp.ntransfercmd(cmd, rest)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24306
diff changeset
373 except ftplib.error_perm as reason:
674
6513ba7d858a Make consistent use of str.startswith() in conditionals.
chad.netzer@gmail.com
parents: 667
diff changeset
374 if str(reason).startswith('501'):
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
375 # workaround for REST not supported error
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
376 fp, retrlen = self.retrfile(file, type)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
377 fp = RangeableFileObject(fp, (rest,''))
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
378 return (fp, retrlen)
674
6513ba7d858a Make consistent use of str.startswith() in conditionals.
chad.netzer@gmail.com
parents: 667
diff changeset
379 elif not str(reason).startswith('550'):
18586
40f9472f5737 byterange: remove old two-arg raise trick
Augie Fackler <raf@durin42.com>
parents: 17537
diff changeset
380 raise IOError('ftp error', reason)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
381 if not conn:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
382 # Set transfer mode to ASCII!
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
383 self.ftp.voidcmd('TYPE A')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
384 # Try a directory listing
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
385 if file:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
386 cmd = 'LIST ' + file
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
387 else:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
388 cmd = 'LIST'
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
389 conn = self.ftp.ntransfercmd(cmd)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
390 self.busy = 1
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
391 # Pass back both a suitably decorated object and a retrieval length
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
392 return (addclosehook(conn[0].makefile('rb'),
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
393 self.endtransfer), conn[1])
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
394
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
395
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
396 ####################################################################
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
397 # Range Tuple Functions
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
398 # XXX: These range tuple functions might go better in a class.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
399
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
400 _rangere = None
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
401 def range_header_to_tuple(range_header):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
402 """Get a (firstbyte,lastbyte) tuple from a Range header value.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
403
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
404 Range headers have the form "bytes=<firstbyte>-<lastbyte>". This
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
405 function pulls the firstbyte and lastbyte values and returns
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
406 a (firstbyte,lastbyte) tuple. If lastbyte is not specified in
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
407 the header value, it is returned as an empty string in the
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
408 tuple.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
409
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
410 Return None if range_header is None
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
411 Return () if range_header does not conform to the range spec
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
412 pattern.
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
413
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
414 """
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
415 global _rangere
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
416 if range_header is None:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
417 return None
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
418 if _rangere is None:
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
419 _rangere = re.compile(r'^bytes=(\d{1,})-(\d*)')
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
420 match = _rangere.match(range_header)
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
421 if match:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
422 tup = range_tuple_normalize(match.group(1, 2))
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
423 if tup and tup[1]:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
424 tup = (tup[0], tup[1]+1)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
425 return tup
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
426 return ()
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
427
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
428 def range_tuple_to_header(range_tup):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
429 """Convert a range tuple to a Range header value.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
430 Return a string of the form "bytes=<firstbyte>-<lastbyte>" or None
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
431 if no range is needed.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
432 """
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
433 if range_tup is None:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
434 return None
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
435 range_tup = range_tuple_normalize(range_tup)
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
436 if range_tup:
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
437 if range_tup[1]:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
438 range_tup = (range_tup[0], range_tup[1] - 1)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
439 return 'bytes=%s-%s' % range_tup
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
440
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
441 def range_tuple_normalize(range_tup):
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
442 """Normalize a (first_byte,last_byte) range tuple.
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
443 Return a tuple whose first element is guaranteed to be an int
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
444 and whose second element will be '' (meaning: the last byte) or
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
445 an int. Finally, return None if the normalized tuple == (0,'')
17489
fddf769677f5 spelling: equivalent
timeless@mozdev.org
parents: 15782
diff changeset
446 as that is equivalent to retrieving the entire file.
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
447 """
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
448 if range_tup is None:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
449 return None
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
450 # handle first byte
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
451 fb = range_tup[0]
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
452 if fb in (None, ''):
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
453 fb = 0
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
454 else:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
455 fb = int(fb)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
456 # handle last byte
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
457 try:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
458 lb = range_tup[1]
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
459 except IndexError:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
460 lb = ''
575
7f5ce4bbdd7b More whitespace cleanups
mpm@selenic.com
parents: 0
diff changeset
461 else:
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
462 if lb is None:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
463 lb = ''
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
464 elif lb != '':
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
465 lb = int(lb)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
466 # check if range is over the entire file
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
467 if (fb, lb) == (0, ''):
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
468 return None
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
469 # check that the range is valid
3673
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
470 if lb < fb:
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
471 raise RangeError('Invalid byte range: %s-%s' % (fb, lb))
eb0b4a2d70a9 white space and line break cleanups
Thomas Arendsen Hein <thomas@intevation.de>
parents: 674
diff changeset
472 return (fb, lb)