Skip to content

Commit 76c09a8

Browse files
committed
Added HTTP module, demonstrating delaying all responses by 1 second
1 parent b9ff70c commit 76c09a8

File tree

13 files changed

+164
-24
lines changed

13 files changed

+164
-24
lines changed

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ include HISTORY.rst
44
include LICENSE
55
include README.rst
66
include nginx/config
7+
include nginx/ngx_python_module.h
78

89
recursive-include nginx *.pyx
910
recursive-include nginx *.pxd

nginx/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
try:
1010
from ._nginx import (
11-
Cycle, Log, get_current_cycle,
11+
Cycle, Log, get_current_cycle, ReturnCode,
12+
Request,
1213
NginxEventLoop, NginxEventLoopPolicy, Event,
1314
)
1415
except ImportError:

nginx/hooks.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import asyncio
22
import logging
33

4+
from . import ReturnCode
45
from .module import load_modules, _modules
56

67
log = logging.Logger(__name__)
@@ -34,5 +35,10 @@ def exit_process():
3435
_modules.clear()
3536

3637

37-
def post_read():
38-
log.critical('post read hook!')
38+
def post_read(request):
39+
rv = ReturnCode.declined
40+
for mod in _modules:
41+
rv = mod.post_read(request)
42+
if rv != ReturnCode.declined:
43+
return rv
44+
return rv

nginx/http/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .module import HTTPModule

nginx/http/http.pyx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from cpython cimport Py_INCREF, Py_DECREF
2+
from .nginx_core cimport ngx_log_error, NGX_LOG_CRIT, NGX_AGAIN
3+
from .ngx_http cimport ngx_http_request_t, ngx_http_core_run_phases
4+
from .ngx_http cimport ngx_http_get_module_ctx, ngx_http_set_ctx
5+
6+
import traceback
7+
8+
9+
cdef class Request:
10+
cdef:
11+
ngx_http_request_t *request
12+
public Log log
13+
object future
14+
15+
def __init__(self, *args):
16+
raise NotImplementedError
17+
18+
def _started(self):
19+
return self.future is not None
20+
21+
def _start(self, fut):
22+
self.future = fut
23+
Py_INCREF(self)
24+
return NGX_AGAIN
25+
26+
def _result(self):
27+
if self.future.done():
28+
Py_DECREF(self)
29+
ngx_http_set_ctx(self.request, NULL, ngx_python_module)
30+
return self.future.result()
31+
return NGX_AGAIN
32+
33+
@staticmethod
34+
cdef Request from_ptr(ngx_http_request_t *request):
35+
cdef:
36+
void *rv
37+
Request new_req
38+
rv = ngx_http_get_module_ctx(request, ngx_python_module)
39+
if rv == NULL:
40+
new_req = Request.__new__(Request)
41+
new_req.request = request
42+
new_req.log = Log.from_ptr(request.connection.log)
43+
ngx_http_set_ctx(request, <void *>new_req, ngx_python_module)
44+
return new_req
45+
else:
46+
return <object>rv
47+
48+
49+
cdef public ngx_int_t nginxpy_post_read(ngx_http_request_t *request):
50+
try:
51+
from . import hooks
52+
return hooks.post_read(Request.from_ptr(request))
53+
except:
54+
ngx_log_error(NGX_LOG_CRIT, request.connection.log, 0,
55+
b'Error occured in post_read:\n' +
56+
traceback.format_exc().encode())
57+
return 500
58+
59+
60+
def run_phases(Request request):
61+
ngx_http_core_run_phases(request.request)

nginx/http/module.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import asyncio
2+
import logging
3+
4+
from .._nginx import run_phases
5+
from ..module import BaseModule, ReturnCode
6+
7+
log = logging.getLogger(__name__)
8+
9+
10+
class HTTPModule(BaseModule):
11+
def __init__(self):
12+
self.loop = None
13+
14+
def init_process(self):
15+
self.loop = asyncio.get_event_loop()
16+
17+
def post_read(self, request):
18+
if request._started():
19+
return request._result()
20+
else:
21+
return request._start(self.loop.create_task(self._handle(request)))
22+
23+
async def _handle(self, request):
24+
try:
25+
log.info('Handling request...')
26+
await asyncio.sleep(1)
27+
log.info('Done')
28+
return ReturnCode.declined
29+
finally:
30+
self.loop.call_soon(run_phases, request)

nginx/module.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import logging
22
import pkg_resources
33

4+
from . import ReturnCode
5+
46
log = logging.Logger(__name__)
57
_modules = []
68

@@ -15,11 +17,17 @@ async def after_init_process(self):
1517
def exit_process(self):
1618
pass
1719

20+
def post_read(self, request):
21+
return ReturnCode.declined
22+
1823

1924
def load_modules():
2025
log.debug('loading modules')
21-
for ep in pkg_resources.iter_entry_points('nginx', 'module'):
22-
log.debug('loading %s', ep.module_name)
26+
endpoints = [ep for d in pkg_resources.working_set for ep in
27+
d.get_entry_map('nginx.modules').values()]
28+
endpoints.sort(key=lambda ep: ep.name)
29+
for ep in endpoints:
30+
log.info('loading %s', ep.module_name)
2331
mod = ep.load()
24-
log.debug('installing %s', mod)
32+
log.info('installing %s', mod)
2533
_modules.append(mod())

nginx/nginx.pyx

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
# cython: language_level=3
22

33
import traceback
4+
from enum import IntEnum
45

56
from .nginx_config cimport ngx_int_t
6-
from .nginx_core cimport ngx_cycle_t
7-
from .nginx_core cimport NGX_OK, NGX_ERROR
7+
from .nginx_core cimport ngx_module_t, ngx_cycle_t
8+
from .nginx_core cimport NGX_OK, NGX_ERROR, NGX_DECLINED, NGX_AGAIN
89
from .nginx_core cimport NGX_LOG_DEBUG, NGX_LOG_CRIT
910
from .nginx_core cimport ngx_log_error
1011

11-
from . import hooks
12+
13+
cdef extern from "ngx_python_module.h":
14+
ngx_module_t ngx_python_module
15+
16+
17+
class ReturnCode(IntEnum):
18+
ok = NGX_OK
19+
error = NGX_ERROR
20+
declined = NGX_DECLINED
21+
again = NGX_AGAIN
1222

1323

1424
cdef public ngx_int_t nginxpy_init_process(ngx_cycle_t *cycle):
1525
ngx_log_error(NGX_LOG_DEBUG, cycle.log, 0,
1626
b'Starting init_process.')
1727
# noinspection PyBroadException
1828
try:
29+
from . import hooks
1930
global current_cycle
2031
current_cycle = Cycle.from_ptr(cycle)
2132
set_last_resort(current_cycle.log)
@@ -36,6 +47,7 @@ cdef public void nginxpy_exit_process(ngx_cycle_t *cycle):
3647
b'Starting exit_process.')
3748
# noinspection PyBroadException
3849
try:
50+
from . import hooks
3951
global current_cycle
4052
hooks.exit_process()
4153
unset_last_resort()
@@ -49,10 +61,7 @@ cdef public void nginxpy_exit_process(ngx_cycle_t *cycle):
4961
b'Finished exit_process.')
5062

5163

52-
cdef public void nginxpy_post_read():
53-
hooks.post_read()
54-
55-
5664
include "log.pyx"
5765
include "cycle.pyx"
66+
include "http/http.pyx"
5867
include "asyncio/loop.pyx"

nginx/nginx_core.pxd

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ from .nginx_config cimport ngx_int_t, ngx_uint_t
33
cdef extern from "ngx_core.h":
44
const ngx_int_t NGX_OK
55
const ngx_int_t NGX_ERROR
6+
const ngx_int_t NGX_DECLINED
7+
const ngx_int_t NGX_AGAIN
68

79
const int NGX_LOG_EMERG
810
const int NGX_LOG_ALERT
@@ -16,6 +18,9 @@ cdef extern from "ngx_core.h":
1618
ctypedef int ngx_err_t
1719
ctypedef int ngx_msec_t
1820

21+
ctypedef struct ngx_module_t:
22+
pass
23+
1924
ctypedef struct ngx_log_t:
2025
pass
2126

nginx/ngx_http.pxd

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from .nginx_core cimport ngx_module_t, ngx_log_t
2+
3+
4+
cdef extern from "ngx_http.h":
5+
ctypedef struct ngx_connection_t:
6+
ngx_log_t *log
7+
8+
ctypedef struct ngx_http_request_t:
9+
ngx_connection_t *connection
10+
11+
void ngx_http_core_run_phases(ngx_http_request_t *request)
12+
void *ngx_http_get_module_ctx(ngx_http_request_t *request,
13+
ngx_module_t module)
14+
void ngx_http_set_ctx(ngx_http_request_t *request, void *ctx,
15+
ngx_module_t module)

0 commit comments

Comments
 (0)