summaryrefslogtreecommitdiff
path: root/wsgitools/scgi/__init__.py
blob: 4e60b74b0e3350845d8651d4a1caefa7e9623e55 (plain)
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