equal
deleted
inserted
replaced
15 # This file is part of urlgrabber, a high-level cross-protocol url-grabber |
15 # This file is part of urlgrabber, a high-level cross-protocol url-grabber |
16 # Copyright 2002-2004 Michael D. Stenner, Ryan Tomayko |
16 # Copyright 2002-2004 Michael D. Stenner, Ryan Tomayko |
17 |
17 |
18 # $Id: byterange.py,v 1.9 2005/02/14 21:55:07 mstenner Exp $ |
18 # $Id: byterange.py,v 1.9 2005/02/14 21:55:07 mstenner Exp $ |
19 |
19 |
|
20 from __future__ import absolute_import |
|
21 |
|
22 import email |
|
23 import ftplib |
|
24 import mimetypes |
20 import os |
25 import os |
|
26 import re |
|
27 import socket |
21 import stat |
28 import stat |
22 import urllib |
29 import urllib |
23 import urllib2 |
30 import urllib2 |
24 import email.Utils |
31 |
|
32 addclosehook = urllib.addclosehook |
|
33 addinfourl = urllib.addinfourl |
|
34 splitattr = urllib.splitattr |
|
35 splitpasswd = urllib.splitpasswd |
|
36 splitport = urllib.splitport |
|
37 splituser = urllib.splituser |
|
38 unquote = urllib.unquote |
25 |
39 |
26 class RangeError(IOError): |
40 class RangeError(IOError): |
27 """Error raised when an unsatisfiable range is requested.""" |
41 """Error raised when an unsatisfiable range is requested.""" |
28 pass |
42 pass |
29 |
43 |
194 """FileHandler subclass that adds Range support. |
208 """FileHandler subclass that adds Range support. |
195 This class handles Range headers exactly like an HTTP |
209 This class handles Range headers exactly like an HTTP |
196 server would. |
210 server would. |
197 """ |
211 """ |
198 def open_local_file(self, req): |
212 def open_local_file(self, req): |
199 import mimetypes |
|
200 import email |
|
201 host = req.get_host() |
213 host = req.get_host() |
202 file = req.get_selector() |
214 file = req.get_selector() |
203 localfile = urllib.url2pathname(file) |
215 localfile = urllib.url2pathname(file) |
204 stats = os.stat(localfile) |
216 stats = os.stat(localfile) |
205 size = stats[stat.ST_SIZE] |
217 size = stats[stat.ST_SIZE] |
231 # Unfortunately, a large amount of base FTP code had to be copied |
243 # Unfortunately, a large amount of base FTP code had to be copied |
232 # from urllib and urllib2 in order to insert the FTP REST command. |
244 # from urllib and urllib2 in order to insert the FTP REST command. |
233 # Code modifications for range support have been commented as |
245 # Code modifications for range support have been commented as |
234 # follows: |
246 # follows: |
235 # -- range support modifications start/end here |
247 # -- range support modifications start/end here |
236 |
|
237 from urllib import splitport, splituser, splitpasswd, splitattr, \ |
|
238 unquote, addclosehook, addinfourl |
|
239 import ftplib |
|
240 import socket |
|
241 import mimetypes |
|
242 import email |
|
243 |
248 |
244 class FTPRangeHandler(urllib2.FTPHandler): |
249 class FTPRangeHandler(urllib2.FTPHandler): |
245 def ftp_open(self, req): |
250 def ftp_open(self, req): |
246 host = req.get_host() |
251 host = req.get_host() |
247 if not host: |
252 if not host: |
404 """ |
409 """ |
405 global _rangere |
410 global _rangere |
406 if range_header is None: |
411 if range_header is None: |
407 return None |
412 return None |
408 if _rangere is None: |
413 if _rangere is None: |
409 import re |
|
410 _rangere = re.compile(r'^bytes=(\d{1,})-(\d*)') |
414 _rangere = re.compile(r'^bytes=(\d{1,})-(\d*)') |
411 match = _rangere.match(range_header) |
415 match = _rangere.match(range_header) |
412 if match: |
416 if match: |
413 tup = range_tuple_normalize(match.group(1, 2)) |
417 tup = range_tuple_normalize(match.group(1, 2)) |
414 if tup and tup[1]: |
418 if tup and tup[1]: |