1 import os.path
2
3 __all__ = []
4
5 try:
6 basestring
7 except NameError:
8 basestring = str
9
10 __all__.append("StaticContent")
11 -class StaticContent(object):
12 """
13 This wsgi application provides static content on whatever request it
14 receives with method GET or HEAD (content stripped). If not present, a
15 content-length header is computed.
16 """
17 - def __init__(self, status, headers, content, anymethod=False):
18 """
19 @type status: str
20 @param status: is the HTTP status returned to the browser (ex: "200 OK")
21 @type headers: list
22 @param headers: is a list of C{(header, value)} pairs being delivered as
23 HTTP headers
24 @type content: bytes
25 @param content: contains the data to be delivered to the client. It is
26 either a string or some kind of iterable yielding strings.
27 @type anymethod: boolean
28 @param anymethod: determines whether any request method should be
29 answered with this response instead of a 501
30 """
31 assert isinstance(status, str)
32 assert isinstance(headers, list)
33 assert isinstance(content, bytes) or hasattr(content, "__iter__")
34 self.status = status
35 self.headers = headers
36 self.anymethod = anymethod
37 length = -1
38 if isinstance(content, bytes):
39 self.content = [content]
40 length = len(content)
41 else:
42 self.content = content
43 if isinstance(self.content, list):
44 length = sum(map(len, self.content))
45 if length >= 0:
46 if not [v for h, v in headers if h.lower() == "content-length"]:
47 headers.append(("Content-length", str(length)))
48 - def __call__(self, environ, start_response):
49 """wsgi interface"""
50 assert isinstance(environ, dict)
51 if environ["REQUEST_METHOD"].upper() not in ["GET", "HEAD"] and \
52 not self.anymethod:
53 resp = b"Request method not implemented"
54 start_response("501 Not Implemented",
55 [("Content-length", str(len(resp)))])
56 return [resp]
57 start_response(self.status, list(self.headers))
58 if environ["REQUEST_METHOD"].upper() == "HEAD":
59 return []
60 return self.content
61
62 __all__.append("StaticFile")
64 """
65 This wsgi application provides the content of a static file on whatever
66 request it receives with method GET or HEAD (content stripped). If not
67 present, a content-length header is computed.
68 """
69 - def __init__(self, filelike, status="200 OK", headers=list(),
70 blocksize=4096):
71 """
72 @type status: str
73 @param status: is the HTTP status returned to the browser
74 @type headers: [(str, str)]
75 @param headers: is a list of C{(header, value)} pairs being delivered as
76 HTTP headers
77 @type filelike: str or file-like
78 @param filelike: may either be an path in the local file system or a
79 file-like that must support C{read(size)} and C{seek(0)}. If
80 C{tell()} is present, C{seek(0, 2)} and C{tell()} will be used
81 to compute the content-length.
82 @type blocksize: int
83 @param blocksize: the content is provided in chunks of this size
84 """
85 self.filelike = filelike
86 self.status = status
87 self.headers = headers
88 self.blocksize = blocksize
89
91 """internal method yielding data from the given stream"""
92 while True:
93 data = stream.read(self.blocksize)
94 if not data:
95 break
96 yield data
97 if isinstance(self.filelike, basestring):
98 stream.close()
99
100 - def __call__(self, environ, start_response):
101 """wsgi interface"""
102 assert isinstance(environ, dict)
103
104 if environ["REQUEST_METHOD"].upper() not in ["GET", "HEAD"]:
105 resp = b"Request method not implemented"
106 start_response("501 Not Implemented",
107 [("Content-length", str(len(resp)))])
108 return [resp]
109
110 stream = None
111 size = -1
112 try:
113 if isinstance(self.filelike, basestring):
114
115 stream = open(self.filelike, "rb")
116 size = os.path.getsize(self.filelike)
117 else:
118 stream = self.filelike
119 if hasattr(stream, "tell"):
120 stream.seek(0, 2)
121 size = stream.tell()
122 stream.seek(0)
123 except IOError:
124 resp = b"File not found"
125 start_response("404 File not found",
126 [("Content-length", str(len(resp)))])
127 return [resp]
128
129 headers = list(self.headers)
130 if size >= 0:
131 if not [v for h, v in headers if h.lower() == "content-length"]:
132 headers.append(("Content-length", str(size)))
133
134 start_response(self.status, headers)
135 if environ["REQUEST_METHOD"].upper() == "HEAD":
136 if isinstance(self.filelike, basestring):
137 stream.close()
138 return []
139
140 if isinstance(self.filelike, basestring) and 'wsgi.file_wrapper' in environ:
141 return environ['wsgi.file_wrapper'](stream, self.blocksize)
142
143 if 0 <= size <= self.blocksize:
144 data = stream.read(size)
145 if isinstance(self.filelike, basestring):
146 stream.close()
147 return [data]
148 return self._serve_in_chunks(stream)
149