1
2
3
4 """
5 This file is part of the web2py Web Framework
6 Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
7 License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
8 """
9
10 import os
11 import stat
12 import time
13 import re
14 import errno
15 import rewrite
16 from http import HTTP
17 from contenttype import contenttype
18
19
20 regex_start_range = re.compile('\d+(?=\-)')
21 regex_stop_range = re.compile('(?<=\-)\d+')
22
23 DEFAULT_CHUNK_SIZE = 64*1024
24
26 offset = 0
27 while bytes == None or offset < bytes:
28 if bytes != None and bytes - offset < chunk_size:
29 chunk_size = bytes - offset
30 data = stream.read(chunk_size)
31 length = len(data)
32 if not length:
33 break
34 else:
35 yield data
36 if length < chunk_size:
37 break
38 offset += length
39 stream.close()
40
48 if error_message is None:
49 error_message = rewrite.thread.routes.error_message % 'invalid request'
50 try:
51 fp = open(static_file)
52 except IOError, e:
53 if e[0] == errno.EISDIR:
54 raise HTTP(403, error_message, web2py_error='file is a directory')
55 elif e[0] == errno.EACCES:
56 raise HTTP(403, error_message, web2py_error='inaccessible file')
57 else:
58 raise HTTP(404, error_message, web2py_error='invalid file')
59 else:
60 fp.close()
61 stat_file = os.stat(static_file)
62 fsize = stat_file[stat.ST_SIZE]
63 mtime = time.strftime('%a, %d %b %Y %H:%M:%S GMT',
64 time.gmtime(stat_file[stat.ST_MTIME]))
65 headers['Content-Type'] = contenttype(static_file)
66 headers['Last-Modified'] = mtime
67 headers['Pragma'] = 'cache'
68 headers['Cache-Control'] = 'private'
69
70 if request and request.env.http_if_modified_since == mtime:
71 raise HTTP(304, **{'Content-Type': headers['Content-Type']})
72
73 elif request and request.env.http_range:
74 start_items = regex_start_range.findall(request.env.http_range)
75 if not start_items:
76 start_items = [0]
77 stop_items = regex_stop_range.findall(request.env.http_range)
78 if not stop_items or int(stop_items[0]) > fsize - 1:
79 stop_items = [fsize - 1]
80 part = (int(start_items[0]), int(stop_items[0]), fsize)
81 bytes = part[1] - part[0] + 1
82 try:
83 stream = open(static_file, 'rb')
84 except IOError, e:
85 if e[0] in (errno.EISDIR, errno.EACCES):
86 raise HTTP(403)
87 else:
88 raise HTTP(404)
89 stream.seek(part[0])
90 headers['Content-Range'] = 'bytes %i-%i/%i' % part
91 headers['Content-Length'] = '%i' % bytes
92 status = 206
93 else:
94 try:
95 stream = open(static_file, 'rb')
96 except IOError, e:
97 if e[0] in (errno.EISDIR, errno.EACCES):
98 raise HTTP(403)
99 else:
100 raise HTTP(404)
101 headers['Content-Length'] = fsize
102 bytes = None
103 status = 200
104 if request and request.env.web2py_use_wsgi_file_wrapper:
105 wrapped = request.env.wsgi_file_wrapper(stream, chunk_size)
106 else:
107 wrapped = streamer(stream, chunk_size=chunk_size, bytes=bytes)
108 raise HTTP(status, wrapped, **headers)
109