forked from stattrak-dragonlore/scgiwsgi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscgiwsgi.py
142 lines (113 loc) · 4.33 KB
/
scgiwsgi.py
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# https://github.com/dengzhp/scgiwsgi
import os
import socket
import sys
from scgi import scgi_server
from scgi import passfd
__all__ = ['WSGIServer']
__version__ = "0.1"
_application = None
_logger = None
def build_wsgi_environ(scgi_env, scgi_input):
environ = {}
environ['wsgi.input'] = scgi_input
environ['wsgi.errors'] = sys.stderr
environ['wsgi.version'] = (1, 0)
environ['wsgi.multithread'] = False
environ['wsgi.multiprocess'] = True
environ['wsgi.run_once'] = False
environ['wsgi.url_scheme'] = 'http'
for k in scgi_env:
if k != "SCGI":
if k == 'DOCUMENT_URI':
environ['PATH_INFO'] = scgi_env[k]
else:
environ[k] = scgi_env[k]
environ['SCRIPT_NAME'] = ''
return environ
class WsgiHandler(scgi_server.SCGIHandler):
def serve(self):
while 1:
try:
os.write(self.parent_fd, "1") # indicates that child is ready
fd = passfd.recvfd(self.parent_fd)
except (IOError, OSError):
if _logger:
_logger.exception('exiting')
# parent probably exited (EPIPE comes thru as OSError)
raise SystemExit
conn = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
# Make sure the socket is blocking. Apparently, on FreeBSD the
# socket is non-blocking. I think that's an OS bug but I don't
# have the resources to track it down.
conn.setblocking(1)
os.close(fd)
try:
self.handle_connection(conn)
except Exception:
if _logger:
_logger.exception('exception occured')
else:
raise
def handle_connection(self, conn):
input = conn.makefile("r")
output = conn.makefile("w")
env = self.read_env(input)
environ = build_wsgi_environ(env, input)
headers_set = []
headers_sent = []
def wsgi_write(data):
if not isinstance(data, str):
raise TypeError("application must return an iterable yielding zero or more strings")
if not headers_set:
raise AssertionError("write() before start_response()")
elif not headers_sent:
# Before the first output, send the stored headers
status, headers = headers_sent[:] = headers_set
output.write("HTTP/1.1 %s\r\n" % status)
for h in headers:
output.write("%s: %s\r\n" % (h[0], h[1]))
output.write("\r\n")
output.write(data)
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
elif headers_set:
raise AssertionError("Headers already set!")
headers_set[:] = [status, response_headers]
return wsgi_write
try:
result = _application(environ, start_response)
try:
for data in result:
if data: # don't send headers until body appears
wsgi_write(data)
if not headers_sent:
wsgi_write('') # send headers now if body was empty
finally:
if hasattr(result, 'close'):
result.close()
finally:
output.close()
input.close()
conn.close()
class WSGIServer:
def __init__(self, app, logger=None):
global _application, _logger
_application = app
_logger = logger
def run(self, host='', port=4000, max_children=5):
scgi_server.SCGIServer(handler_class=WsgiHandler,
host=host,
port=port,
max_children=max_children).serve()
if __name__ == "__main__":
from app import application
import logging
logger = logging.getLogger()
WSGIServer(application, logger).run(port=4000)