annotate upmana/mercurial/byterange.py @ 135:dcf4fbe09b70 beta

Traipse Beta 'OpenRPG' {091010-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary (Beta) Added Bookmarks Fix to Remote Admin Commands Minor fix to text based Server Fix to Pretty Print, from Core Fix to Splitter Nodes not being created Fix to massive amounts of images loading, from Core Added 'boot' command to remote admin Added confirmation window for sent nodes Minor changes to allow for portability to an OpenSUSE linux OS Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG Zoom Mouse plugin added Images added to Plugin UI Switching to Element Tree Map efficiency, from FlexiRPG Added Status Bar to Update Manager default_manifest.xml renamed to default_upmana.xml Cleaner clode for saved repositories New TrueDebug Class in orpg_log (See documentation for usage) Mercurial's hgweb folder is ported to upmana **Pretty important update that can help remove thousands of dead children from your gametree. **Children, <forms />, <group_atts />, <horizontal />, <cols />, <rows />, <height />, etc... are all tags now. Check your gametree and look for dead children!! **New Gamtree Recusion method, mapping, and context sensitivity. !!Alpha - Watch out for infinite loops!!
author sirebral
date Tue, 10 Nov 2009 14:11:28 -0600
parents
children
rev   line source
135
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
1 # This library is free software; you can redistribute it and/or
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
2 # modify it under the terms of the GNU Lesser General Public
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
3 # License as published by the Free Software Foundation; either
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
4 # version 2.1 of the License, or (at your option) any later version.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
5 #
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
6 # This library is distributed in the hope that it will be useful,
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
9 # Lesser General Public License for more details.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
10 #
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
11 # You should have received a copy of the GNU Lesser General Public
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
12 # License along with this library; if not, write to the
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
13 # Free Software Foundation, Inc.,
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
14 # 59 Temple Place, Suite 330,
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
15 # Boston, MA 02111-1307 USA
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
16
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
17 # This file is part of urlgrabber, a high-level cross-protocol url-grabber
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
18 # Copyright 2002-2004 Michael D. Stenner, Ryan Tomayko
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
19
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
20 # $Id: byterange.py,v 1.9 2005/02/14 21:55:07 mstenner Exp $
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
21
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
22 import os
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
23 import stat
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
24 import urllib
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
25 import urllib2
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
26 import email.Utils
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
27
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
28 try:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
29 from cStringIO import StringIO
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
30 except ImportError, msg:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
31 from StringIO import StringIO
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
32
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
33 class RangeError(IOError):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
34 """Error raised when an unsatisfiable range is requested."""
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
35 pass
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
36
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
37 class HTTPRangeHandler(urllib2.BaseHandler):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
38 """Handler that enables HTTP Range headers.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
39
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
40 This was extremely simple. The Range header is a HTTP feature to
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
41 begin with so all this class does is tell urllib2 that the
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
42 "206 Partial Content" reponse from the HTTP server is what we
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
43 expected.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
44
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
45 Example:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
46 import urllib2
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
47 import byterange
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
48
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
49 range_handler = range.HTTPRangeHandler()
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
50 opener = urllib2.build_opener(range_handler)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
51
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
52 # install it
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
53 urllib2.install_opener(opener)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
54
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
55 # create Request and set Range header
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
56 req = urllib2.Request('http://www.python.org/')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
57 req.header['Range'] = 'bytes=30-50'
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
58 f = urllib2.urlopen(req)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
59 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
60
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
61 def http_error_206(self, req, fp, code, msg, hdrs):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
62 # 206 Partial Content Response
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
63 r = urllib.addinfourl(fp, hdrs, req.get_full_url())
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
64 r.code = code
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
65 r.msg = msg
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
66 return r
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
67
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
68 def http_error_416(self, req, fp, code, msg, hdrs):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
69 # HTTP's Range Not Satisfiable error
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
70 raise RangeError('Requested Range Not Satisfiable')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
71
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
72 class RangeableFileObject:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
73 """File object wrapper to enable raw range handling.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
74 This was implemented primarilary for handling range
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
75 specifications for file:// urls. This object effectively makes
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
76 a file object look like it consists only of a range of bytes in
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
77 the stream.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
78
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
79 Examples:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
80 # expose 10 bytes, starting at byte position 20, from
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
81 # /etc/aliases.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
82 >>> fo = RangeableFileObject(file('/etc/passwd', 'r'), (20,30))
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
83 # seek seeks within the range (to position 23 in this case)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
84 >>> fo.seek(3)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
85 # tell tells where your at _within the range_ (position 3 in
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
86 # this case)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
87 >>> fo.tell()
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
88 # read EOFs if an attempt is made to read past the last
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
89 # byte in the range. the following will return only 7 bytes.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
90 >>> fo.read(30)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
91 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
92
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
93 def __init__(self, fo, rangetup):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
94 """Create a RangeableFileObject.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
95 fo -- a file like object. only the read() method need be
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
96 supported but supporting an optimized seek() is
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
97 preferable.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
98 rangetup -- a (firstbyte,lastbyte) tuple specifying the range
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
99 to work over.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
100 The file object provided is assumed to be at byte offset 0.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
101 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
102 self.fo = fo
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
103 (self.firstbyte, self.lastbyte) = range_tuple_normalize(rangetup)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
104 self.realpos = 0
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
105 self._do_seek(self.firstbyte)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
106
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
107 def __getattr__(self, name):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
108 """This effectively allows us to wrap at the instance level.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
109 Any attribute not found in _this_ object will be searched for
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
110 in self.fo. This includes methods."""
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
111 if hasattr(self.fo, name):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
112 return getattr(self.fo, name)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
113 raise AttributeError(name)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
114
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
115 def tell(self):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
116 """Return the position within the range.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
117 This is different from fo.seek in that position 0 is the
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
118 first byte position of the range tuple. For example, if
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
119 this object was created with a range tuple of (500,899),
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
120 tell() will return 0 when at byte position 500 of the file.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
121 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
122 return (self.realpos - self.firstbyte)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
123
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
124 def seek(self, offset, whence=0):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
125 """Seek within the byte range.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
126 Positioning is identical to that described under tell().
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
127 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
128 assert whence in (0, 1, 2)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
129 if whence == 0: # absolute seek
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
130 realoffset = self.firstbyte + offset
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
131 elif whence == 1: # relative seek
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
132 realoffset = self.realpos + offset
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
133 elif whence == 2: # absolute from end of file
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
134 # XXX: are we raising the right Error here?
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
135 raise IOError('seek from end of file not supported.')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
136
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
137 # do not allow seek past lastbyte in range
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
138 if self.lastbyte and (realoffset >= self.lastbyte):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
139 realoffset = self.lastbyte
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
140
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
141 self._do_seek(realoffset - self.realpos)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
142
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
143 def read(self, size=-1):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
144 """Read within the range.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
145 This method will limit the size read based on the range.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
146 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
147 size = self._calc_read_size(size)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
148 rslt = self.fo.read(size)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
149 self.realpos += len(rslt)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
150 return rslt
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
151
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
152 def readline(self, size=-1):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
153 """Read lines within the range.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
154 This method will limit the size read based on the range.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
155 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
156 size = self._calc_read_size(size)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
157 rslt = self.fo.readline(size)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
158 self.realpos += len(rslt)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
159 return rslt
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
160
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
161 def _calc_read_size(self, size):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
162 """Handles calculating the amount of data to read based on
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
163 the range.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
164 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
165 if self.lastbyte:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
166 if size > -1:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
167 if ((self.realpos + size) >= self.lastbyte):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
168 size = (self.lastbyte - self.realpos)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
169 else:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
170 size = (self.lastbyte - self.realpos)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
171 return size
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
172
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
173 def _do_seek(self, offset):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
174 """Seek based on whether wrapped object supports seek().
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
175 offset is relative to the current position (self.realpos).
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
176 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
177 assert offset >= 0
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
178 if not hasattr(self.fo, 'seek'):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
179 self._poor_mans_seek(offset)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
180 else:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
181 self.fo.seek(self.realpos + offset)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
182 self.realpos += offset
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
183
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
184 def _poor_mans_seek(self, offset):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
185 """Seek by calling the wrapped file objects read() method.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
186 This is used for file like objects that do not have native
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
187 seek support. The wrapped objects read() method is called
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
188 to manually seek to the desired position.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
189 offset -- read this number of bytes from the wrapped
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
190 file object.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
191 raise RangeError if we encounter EOF before reaching the
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
192 specified offset.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
193 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
194 pos = 0
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
195 bufsize = 1024
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
196 while pos < offset:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
197 if (pos + bufsize) > offset:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
198 bufsize = offset - pos
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
199 buf = self.fo.read(bufsize)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
200 if len(buf) != bufsize:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
201 raise RangeError('Requested Range Not Satisfiable')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
202 pos += bufsize
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
203
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
204 class FileRangeHandler(urllib2.FileHandler):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
205 """FileHandler subclass that adds Range support.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
206 This class handles Range headers exactly like an HTTP
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
207 server would.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
208 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
209 def open_local_file(self, req):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
210 import mimetypes
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
211 import mimetools
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
212 host = req.get_host()
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
213 file = req.get_selector()
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
214 localfile = urllib.url2pathname(file)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
215 stats = os.stat(localfile)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
216 size = stats[stat.ST_SIZE]
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
217 modified = email.Utils.formatdate(stats[stat.ST_MTIME])
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
218 mtype = mimetypes.guess_type(file)[0]
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
219 if host:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
220 host, port = urllib.splitport(host)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
221 if port or socket.gethostbyname(host) not in self.get_names():
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
222 raise urllib2.URLError('file not on local host')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
223 fo = open(localfile,'rb')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
224 brange = req.headers.get('Range', None)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
225 brange = range_header_to_tuple(brange)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
226 assert brange != ()
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
227 if brange:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
228 (fb, lb) = brange
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
229 if lb == '':
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
230 lb = size
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
231 if fb < 0 or fb > size or lb > size:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
232 raise RangeError('Requested Range Not Satisfiable')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
233 size = (lb - fb)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
234 fo = RangeableFileObject(fo, (fb, lb))
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
235 headers = mimetools.Message(StringIO(
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
236 'Content-Type: %s\nContent-Length: %d\nLast-Modified: %s\n' %
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
237 (mtype or 'text/plain', size, modified)))
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
238 return urllib.addinfourl(fo, headers, 'file:'+file)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
239
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
240
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
241 # FTP Range Support
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
242 # Unfortunately, a large amount of base FTP code had to be copied
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
243 # from urllib and urllib2 in order to insert the FTP REST command.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
244 # Code modifications for range support have been commented as
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
245 # follows:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
246 # -- range support modifications start/end here
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
247
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
248 from urllib import splitport, splituser, splitpasswd, splitattr, \
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
249 unquote, addclosehook, addinfourl
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
250 import ftplib
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
251 import socket
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
252 import sys
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
253 import mimetypes
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
254 import mimetools
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
255
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
256 class FTPRangeHandler(urllib2.FTPHandler):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
257 def ftp_open(self, req):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
258 host = req.get_host()
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
259 if not host:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
260 raise IOError('ftp error', 'no host given')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
261 host, port = splitport(host)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
262 if port is None:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
263 port = ftplib.FTP_PORT
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
264
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
265 # username/password handling
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
266 user, host = splituser(host)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
267 if user:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
268 user, passwd = splitpasswd(user)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
269 else:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
270 passwd = None
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
271 host = unquote(host)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
272 user = unquote(user or '')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
273 passwd = unquote(passwd or '')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
274
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
275 try:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
276 host = socket.gethostbyname(host)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
277 except socket.error, msg:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
278 raise urllib2.URLError(msg)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
279 path, attrs = splitattr(req.get_selector())
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
280 dirs = path.split('/')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
281 dirs = map(unquote, dirs)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
282 dirs, file = dirs[:-1], dirs[-1]
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
283 if dirs and not dirs[0]:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
284 dirs = dirs[1:]
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
285 try:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
286 fw = self.connect_ftp(user, passwd, host, port, dirs)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
287 type = file and 'I' or 'D'
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
288 for attr in attrs:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
289 attr, value = splitattr(attr)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
290 if attr.lower() == 'type' and \
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
291 value in ('a', 'A', 'i', 'I', 'd', 'D'):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
292 type = value.upper()
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
293
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
294 # -- range support modifications start here
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
295 rest = None
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
296 range_tup = range_header_to_tuple(req.headers.get('Range', None))
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
297 assert range_tup != ()
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
298 if range_tup:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
299 (fb, lb) = range_tup
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
300 if fb > 0:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
301 rest = fb
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
302 # -- range support modifications end here
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
303
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
304 fp, retrlen = fw.retrfile(file, type, rest)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
305
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
306 # -- range support modifications start here
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
307 if range_tup:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
308 (fb, lb) = range_tup
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
309 if lb == '':
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
310 if retrlen is None or retrlen == 0:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
311 raise RangeError('Requested Range Not Satisfiable due to unobtainable file length.')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
312 lb = retrlen
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
313 retrlen = lb - fb
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
314 if retrlen < 0:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
315 # beginning of range is larger than file
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
316 raise RangeError('Requested Range Not Satisfiable')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
317 else:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
318 retrlen = lb - fb
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
319 fp = RangeableFileObject(fp, (0, retrlen))
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
320 # -- range support modifications end here
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
321
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
322 headers = ""
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
323 mtype = mimetypes.guess_type(req.get_full_url())[0]
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
324 if mtype:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
325 headers += "Content-Type: %s\n" % mtype
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
326 if retrlen is not None and retrlen >= 0:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
327 headers += "Content-Length: %d\n" % retrlen
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
328 sf = StringIO(headers)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
329 headers = mimetools.Message(sf)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
330 return addinfourl(fp, headers, req.get_full_url())
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
331 except ftplib.all_errors, msg:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
332 raise IOError('ftp error', msg), sys.exc_info()[2]
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
333
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
334 def connect_ftp(self, user, passwd, host, port, dirs):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
335 fw = ftpwrapper(user, passwd, host, port, dirs)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
336 return fw
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
337
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
338 class ftpwrapper(urllib.ftpwrapper):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
339 # range support note:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
340 # this ftpwrapper code is copied directly from
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
341 # urllib. The only enhancement is to add the rest
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
342 # argument and pass it on to ftp.ntransfercmd
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
343 def retrfile(self, file, type, rest=None):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
344 self.endtransfer()
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
345 if type in ('d', 'D'):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
346 cmd = 'TYPE A'
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
347 isdir = 1
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
348 else:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
349 cmd = 'TYPE ' + type
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
350 isdir = 0
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
351 try:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
352 self.ftp.voidcmd(cmd)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
353 except ftplib.all_errors:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
354 self.init()
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
355 self.ftp.voidcmd(cmd)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
356 conn = None
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
357 if file and not isdir:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
358 # Use nlst to see if the file exists at all
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
359 try:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
360 self.ftp.nlst(file)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
361 except ftplib.error_perm, reason:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
362 raise IOError('ftp error', reason), sys.exc_info()[2]
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
363 # Restore the transfer mode!
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
364 self.ftp.voidcmd(cmd)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
365 # Try to retrieve as a file
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
366 try:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
367 cmd = 'RETR ' + file
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
368 conn = self.ftp.ntransfercmd(cmd, rest)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
369 except ftplib.error_perm, reason:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
370 if str(reason).startswith('501'):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
371 # workaround for REST not supported error
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
372 fp, retrlen = self.retrfile(file, type)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
373 fp = RangeableFileObject(fp, (rest,''))
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
374 return (fp, retrlen)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
375 elif not str(reason).startswith('550'):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
376 raise IOError('ftp error', reason), sys.exc_info()[2]
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
377 if not conn:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
378 # Set transfer mode to ASCII!
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
379 self.ftp.voidcmd('TYPE A')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
380 # Try a directory listing
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
381 if file:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
382 cmd = 'LIST ' + file
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
383 else:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
384 cmd = 'LIST'
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
385 conn = self.ftp.ntransfercmd(cmd)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
386 self.busy = 1
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
387 # Pass back both a suitably decorated object and a retrieval length
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
388 return (addclosehook(conn[0].makefile('rb'),
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
389 self.endtransfer), conn[1])
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
390
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
391
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
392 ####################################################################
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
393 # Range Tuple Functions
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
394 # XXX: These range tuple functions might go better in a class.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
395
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
396 _rangere = None
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
397 def range_header_to_tuple(range_header):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
398 """Get a (firstbyte,lastbyte) tuple from a Range header value.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
399
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
400 Range headers have the form "bytes=<firstbyte>-<lastbyte>". This
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
401 function pulls the firstbyte and lastbyte values and returns
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
402 a (firstbyte,lastbyte) tuple. If lastbyte is not specified in
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
403 the header value, it is returned as an empty string in the
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
404 tuple.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
405
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
406 Return None if range_header is None
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
407 Return () if range_header does not conform to the range spec
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
408 pattern.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
409
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
410 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
411 global _rangere
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
412 if range_header is None:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
413 return None
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
414 if _rangere is None:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
415 import re
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
416 _rangere = re.compile(r'^bytes=(\d{1,})-(\d*)')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
417 match = _rangere.match(range_header)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
418 if match:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
419 tup = range_tuple_normalize(match.group(1, 2))
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
420 if tup and tup[1]:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
421 tup = (tup[0], tup[1]+1)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
422 return tup
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
423 return ()
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
424
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
425 def range_tuple_to_header(range_tup):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
426 """Convert a range tuple to a Range header value.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
427 Return a string of the form "bytes=<firstbyte>-<lastbyte>" or None
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
428 if no range is needed.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
429 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
430 if range_tup is None:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
431 return None
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
432 range_tup = range_tuple_normalize(range_tup)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
433 if range_tup:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
434 if range_tup[1]:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
435 range_tup = (range_tup[0], range_tup[1] - 1)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
436 return 'bytes=%s-%s' % range_tup
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
437
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
438 def range_tuple_normalize(range_tup):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
439 """Normalize a (first_byte,last_byte) range tuple.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
440 Return a tuple whose first element is guaranteed to be an int
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
441 and whose second element will be '' (meaning: the last byte) or
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
442 an int. Finally, return None if the normalized tuple == (0,'')
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
443 as that is equivelant to retrieving the entire file.
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
444 """
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
445 if range_tup is None:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
446 return None
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
447 # handle first byte
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
448 fb = range_tup[0]
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
449 if fb in (None, ''):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
450 fb = 0
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
451 else:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
452 fb = int(fb)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
453 # handle last byte
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
454 try:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
455 lb = range_tup[1]
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
456 except IndexError:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
457 lb = ''
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
458 else:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
459 if lb is None:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
460 lb = ''
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
461 elif lb != '':
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
462 lb = int(lb)
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
463 # check if range is over the entire file
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
464 if (fb, lb) == (0, ''):
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
465 return None
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
466 # check that the range is valid
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
467 if lb < fb:
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
468 raise RangeError('Invalid byte range: %s-%s' % (fb, lb))
dcf4fbe09b70 Traipse Beta 'OpenRPG' {091010-00}
sirebral
parents:
diff changeset
469 return (fb, lb)