Merge
This commit is contained in:
@@ -21,5 +21,41 @@ To launch a wsgi server, simply create a socket and call :func:`eventlet.wsgi.se
|
|||||||
You can find a slightly more elaborate version of this code in the file
|
You can find a slightly more elaborate version of this code in the file
|
||||||
``examples/wsgi.py``.
|
``examples/wsgi.py``.
|
||||||
|
|
||||||
|
Non-Standard Extension to Support Post Hooks
|
||||||
|
--------------------------------------------
|
||||||
|
Eventlet's WSGI server supports a non-standard extension to the WSGI
|
||||||
|
specification where :samp:`env['eventlet.posthooks']` contains an array of
|
||||||
|
`post hooks` that will be called after fully sending a response. Each post hook
|
||||||
|
is a tuple of :samp:`(func, args, kwargs)` and the `func` will be called with
|
||||||
|
the WSGI environment dictionary, followed by the `args` and then the `kwargs`
|
||||||
|
in the post hook.
|
||||||
|
|
||||||
|
For example::
|
||||||
|
|
||||||
|
from eventlet import wsgi
|
||||||
|
import eventlet
|
||||||
|
|
||||||
|
def hook(env, arg1, arg2, kwarg3=None, kwarg4=None):
|
||||||
|
print 'Hook called: %s %s %s %s %s' % (env, arg1, arg2, kwarg3, kwarg4)
|
||||||
|
|
||||||
|
def hello_world(env, start_response):
|
||||||
|
env['eventlet.posthooks'].append(
|
||||||
|
(hook, ('arg1', 'arg2'), {'kwarg3': 3, 'kwarg4': 4}))
|
||||||
|
start_response('200 OK', [('Content-Type', 'text/plain')])
|
||||||
|
return ['Hello, World!\r\n']
|
||||||
|
|
||||||
|
wsgi.server(eventlet.listen(('', 8090)), hello_world)
|
||||||
|
|
||||||
|
The above code will print the WSGI environment and the other passed function
|
||||||
|
arguments for every request processed.
|
||||||
|
|
||||||
|
Post hooks are useful when code needs to be executed after a response has been
|
||||||
|
fully sent to the client (or when the client disconnects early). One example is
|
||||||
|
for more accurate logging of bandwidth used, as client disconnects use less
|
||||||
|
bandwidth than the actual Content-Length.
|
||||||
|
|
||||||
|
API
|
||||||
|
---
|
||||||
|
|
||||||
.. automodule:: eventlet.wsgi
|
.. automodule:: eventlet.wsgi
|
||||||
:members:
|
:members:
|
||||||
|
@@ -376,6 +376,9 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
pass
|
pass
|
||||||
finish = time.time()
|
finish = time.time()
|
||||||
|
|
||||||
|
for hook, args, kwargs in self.environ['eventlet.posthooks']:
|
||||||
|
hook(self.environ, *args, **kwargs)
|
||||||
|
|
||||||
self.server.log_message(self.server.log_format % dict(
|
self.server.log_message(self.server.log_format % dict(
|
||||||
client_ip=self.get_client_ip(),
|
client_ip=self.get_client_ip(),
|
||||||
date_time=self.log_date_time_string(),
|
date_time=self.log_date_time_string(),
|
||||||
@@ -442,6 +445,7 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
env['wsgi.input'] = env['eventlet.input'] = Input(
|
env['wsgi.input'] = env['eventlet.input'] = Input(
|
||||||
self.rfile, length, wfile=wfile, wfile_line=wfile_line,
|
self.rfile, length, wfile=wfile, wfile_line=wfile_line,
|
||||||
chunked_input=chunked)
|
chunked_input=chunked)
|
||||||
|
env['eventlet.posthooks'] = []
|
||||||
|
|
||||||
return env
|
return env
|
||||||
|
|
||||||
|
@@ -818,6 +818,60 @@ class TestHttpd(_TestBase):
|
|||||||
pass # TODO: should test with OpenSSL
|
pass # TODO: should test with OpenSSL
|
||||||
greenthread.kill(g)
|
greenthread.kill(g)
|
||||||
|
|
||||||
|
def test_029_posthooks(self):
|
||||||
|
posthook1_count = [0]
|
||||||
|
posthook2_count = [0]
|
||||||
|
def posthook1(env, value, multiplier=1):
|
||||||
|
self.assertEquals(env['local.test'], 'test_029_posthooks')
|
||||||
|
posthook1_count[0] += value * multiplier
|
||||||
|
def posthook2(env, value, divisor=1):
|
||||||
|
self.assertEquals(env['local.test'], 'test_029_posthooks')
|
||||||
|
posthook2_count[0] += value / divisor
|
||||||
|
|
||||||
|
def one_posthook_app(env, start_response):
|
||||||
|
env['local.test'] = 'test_029_posthooks'
|
||||||
|
if 'eventlet.posthooks' not in env:
|
||||||
|
start_response('500 eventlet.posthooks not supported',
|
||||||
|
[('Content-Type', 'text/plain')])
|
||||||
|
else:
|
||||||
|
env['eventlet.posthooks'].append(
|
||||||
|
(posthook1, (2,), {'multiplier': 3}))
|
||||||
|
start_response('200 OK', [('Content-Type', 'text/plain')])
|
||||||
|
yield ''
|
||||||
|
self.site.application = one_posthook_app
|
||||||
|
sock = eventlet.connect(('localhost', self.port))
|
||||||
|
fp = sock.makefile('rw')
|
||||||
|
fp.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
|
fp.flush()
|
||||||
|
self.assertEquals(fp.readline(), 'HTTP/1.1 200 OK\r\n')
|
||||||
|
fp.close()
|
||||||
|
sock.close()
|
||||||
|
self.assertEquals(posthook1_count[0], 6)
|
||||||
|
self.assertEquals(posthook2_count[0], 0)
|
||||||
|
|
||||||
|
def two_posthook_app(env, start_response):
|
||||||
|
env['local.test'] = 'test_029_posthooks'
|
||||||
|
if 'eventlet.posthooks' not in env:
|
||||||
|
start_response('500 eventlet.posthooks not supported',
|
||||||
|
[('Content-Type', 'text/plain')])
|
||||||
|
else:
|
||||||
|
env['eventlet.posthooks'].append(
|
||||||
|
(posthook1, (4,), {'multiplier': 5}))
|
||||||
|
env['eventlet.posthooks'].append(
|
||||||
|
(posthook2, (100,), {'divisor': 4}))
|
||||||
|
start_response('200 OK', [('Content-Type', 'text/plain')])
|
||||||
|
yield ''
|
||||||
|
self.site.application = two_posthook_app
|
||||||
|
sock = eventlet.connect(('localhost', self.port))
|
||||||
|
fp = sock.makefile('rw')
|
||||||
|
fp.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
|
fp.flush()
|
||||||
|
self.assertEquals(fp.readline(), 'HTTP/1.1 200 OK\r\n')
|
||||||
|
fp.close()
|
||||||
|
sock.close()
|
||||||
|
self.assertEquals(posthook1_count[0], 26)
|
||||||
|
self.assertEquals(posthook2_count[0], 25)
|
||||||
|
|
||||||
def test_zero_length_chunked_response(self):
|
def test_zero_length_chunked_response(self):
|
||||||
def zero_chunked_app(env, start_response):
|
def zero_chunked_app(env, start_response):
|
||||||
start_response('200 OK', [('Content-type', 'text/plain')])
|
start_response('200 OK', [('Content-type', 'text/plain')])
|
||||||
|
Reference in New Issue
Block a user