summaryrefslogtreecommitdiff
path: root/paste/cgiserver.py
blob: 83d257ce05402775a3e65b54d10cc04877f72213 (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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
"""
cgi WSGI server
===============

Usage
-----

The CGI script is the configuration and glue for this server.
Typically you will write a CGI script like::

    #!/usr/bin/env python
    from paste.cgiserver import run_with_cgi
    # Assuming app is your WSGI application object...
    from myapplication import app
    run_with_cgi(app)

"""

import os, sys

def run_with_cgi(application,
                 use_cgitb=True,
                 redirect_stdout=False):
    stdout = sys.stdout

    if use_cgitb:
        import cgitb
        cgitb.enable()
    
    environ = dict(os.environ)
    environ['wsgi.input']        = sys.stdin
    environ['wsgi.errors']       = sys.stderr
    environ['wsgi.version']      = (1, 0)
    environ['wsgi.multithread']  = False
    environ['wsgi.multiprocess'] = True
    environ['wsgi.run_once']     = True

    if os.environ.get('HTTPS', 'off').lower() in ('on', '1'):
        environ['wsgi.url_scheme'] = 'https'
    else:
        environ['wsgi.url_scheme'] = 'http'

    if redirect_stdout:
        sys.stdout = sys.stderr

    headers_set = []
    headers_sent = []
    result = None

    def write(data):
        assert headers_set, "write() before start_response()"

        if not headers_sent:
             # Before the first output, send the stored headers
             status, response_headers = headers_sent[:] = headers_set

             # See if Content-Length is given.
             found = False
             for name, value in response_headers:
                 if name.lower() == 'content-length':
                     found = True
                     break

             # If not given, try to deduce it if the iterator implements
             # __len__ and is of length 1. (data will be result[0] in this
             # case.)
             if not found and result is not None:
                 try:
                     if len(result) == 1:
                         response_headers.append(('Content-Length',
                                                  str(len(data))))
                 except:
                     pass

             stdout.write('Status: %s\r\n' % status)
             for header in response_headers:
                 stdout.write('%s: %s\r\n' % header)
             stdout.write('\r\n')

        stdout.write(data)
        stdout.flush()

    def start_response(status, response_headers, exc_info=None):
        if exc_info:
            try:
                if headers_sent:
                    # Re-raise original exception if headers sent
                    raise exc_info[0], exc_info[1], exc_info[2]
            finally:
                exc_info = None     # avoid dangling circular ref
        else:
            assert not headers_set, "Headers already set!"
            
        headers_set[:] = [status, response_headers]
        return write

    result = application(environ, start_response)
    try:
        for data in result:
            if data:    # don't send headers until body appears
                write(data)
        if not headers_sent:
            write('')   # send headers now if body was empty
    finally:
        if hasattr(result, 'close'):
            result.close()

if __name__ == '__main__':
    def myapp(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/plain')])
        return ['Hello World!\n']

    run_with_cgi(myapp)