1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
__all__ = []
try:
import sendfile
except ImportError:
have_sendfile = False
else:
have_sendfile = True
class FileWrapper:
"""
@ivar offset: Initially 0. Becomes -1 when reading using next and
becomes positive when reading using next. In the latter case it
counts the number of bytes sent. It also ensures that next and
transfer are never mixed.
"""
def __init__(self, filelike, blksize=8192):
self.filelike = filelike
self.blksize = blksize
self.offset = 0
if hasattr(filelike, "close"):
self.close = filelike.close
def can_transfer(self):
return have_sendfile and hasattr(self.filelike, "fileno") and \
self.offset >= 0
def transfer(self, sock, blksize=None):
assert self.offset >= 0
if blksize is None:
blksize = self.blksize
else:
blksize = min(self.blksize, blksize)
try:
sent = sendfile.sendfile(sock.fileno(), self.filelike.fileno(),
self.offset, blksize)
except OSError:
return -1
# There are two different sendfile libraries. Yeah!
if isinstance(sent, tuple):
sent = sent[1]
self.offset += sent
return sent
def __iter__(self):
return self
def __next__(self):
assert self.offset <= 0
self.offset = -1
data = self.filelike.read(self.blksize)
if data:
return data
raise StopIteration
def next(self):
return self.__next__()
def _convert_environ(environ, multithread=False, multiprocess=False,
run_once=False):
environ.update({
"wsgi.version": (1, 0),
"wsgi.url_scheme": "http",
"wsgi.multithread": multithread,
"wsgi.multiprocess": multiprocess,
"wsgi.run_once": run_once})
if environ.get("HTTPS", "no").lower() in ('yes', 'y', 'on', '1'):
environ["wsgi.url_scheme"] = "https"
try:
environ["CONTENT_TYPE"] = environ.pop("HTTP_CONTENT_TYPE")
except KeyError:
pass
environ.pop("HTTP_CONTENT_LENGTH", None) # TODO: better way?
if have_sendfile:
environ["wsgi.file_wrapper"] = FileWrapper
|