Skip to content

Commit 420a4d3

Browse files
author
Samuel
committed
add wsgi support
1 parent f67eb87 commit 420a4d3

File tree

7 files changed

+215
-21
lines changed

7 files changed

+215
-21
lines changed

nginx/http/http.pyx

Lines changed: 110 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,29 @@
11
from cpython cimport Py_INCREF, Py_DECREF
2-
from .nginx_core cimport ngx_log_error, NGX_LOG_CRIT, NGX_AGAIN, from_nginx_str
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
2+
from .nginx_core cimport (
3+
ngx_log_error,
4+
NGX_LOG_CRIT,
5+
NGX_AGAIN,
6+
from_nginx_str,
7+
ngx_calloc,
8+
ngx_free,
9+
ngx_memcpy,
10+
ngx_module_t,
11+
ngx_str_t,
12+
)
13+
from .ngx_http cimport (
14+
ngx_http_request_t,
15+
ngx_http_core_run_phases,
16+
ngx_http_get_module_ctx,
17+
ngx_http_set_ctx,
18+
ngx_http_send_header,
19+
ngx_list_push,
20+
ngx_table_elt_t,
21+
ngx_str_set,
22+
ngx_http_output_filter,
23+
ngx_chain_t,
24+
ngx_buf_t,
25+
ngx_calloc_buf,
26+
)
527

628
import traceback
729

@@ -17,6 +39,8 @@ cdef class Request:
1739
public str extension
1840
public str unparsed_uri
1941
public str method_name
42+
public str content_type
43+
public str content_length
2044
public str http_protocol
2145

2246
def __init__(self, *args):
@@ -37,17 +61,88 @@ cdef class Request:
3761
return self.future.result()
3862
return NGX_AGAIN
3963

64+
def send_header(self):
65+
return ngx_http_send_header(self.request)
66+
67+
def add_response_header(self, key, value):
68+
cdef:
69+
ngx_table_elt_t *h
70+
char *cstr
71+
char *csource
72+
bytes key_data, value_data
73+
h = ngx_list_push(&self.request.headers_out.headers)
74+
if h == NULL:
75+
raise MemoryError()
76+
h.hash = 1
77+
78+
key_data = str(key).encode('iso8859-1')
79+
cstr = <char *>ngx_calloc(sizeof(char) * len(key_data), self.request.connection.log)
80+
h.key.len = len(key_data)
81+
csource = key_data
82+
ngx_memcpy(cstr, csource, len(key_data))
83+
h.key.data = cstr
84+
85+
value_data = str(value).encode('iso8859-1')
86+
cstr = <char *>ngx_calloc(sizeof(char) * len(value_data), self.request.connection.log)
87+
h.value.len = len(value_data)
88+
csource = value_data
89+
ngx_memcpy(cstr, csource, len(value_data))
90+
h.value.data = cstr
91+
92+
def send_response(self, pos):
93+
cdef:
94+
ngx_chain_t out
95+
ngx_buf_t *b
96+
bytes data = pos
97+
char* cstr = data
98+
b = ngx_calloc_buf(self.request.pool)
99+
if b == NULL:
100+
raise MemoryError
101+
b.last_buf = 1
102+
b.last_in_chain = 1
103+
b.memory = 1
104+
b.pos = cstr
105+
b.last = b.pos + len(data)
106+
107+
out.buf = b
108+
out.next = NULL
109+
110+
return ngx_http_output_filter(self.request, &out)
111+
112+
def get_app_from_config(self):
113+
cdef ngx_wsgi_pass_conf_t *conf
114+
115+
conf = <ngx_wsgi_pass_conf_t *>self.request.loc_conf[ngx_python_module.ctx_index]
116+
return from_nginx_str(conf.wsgi_pass)
117+
118+
property response_status:
119+
def __get__(self):
120+
return self.request.headers_out.status
121+
122+
def __set__(self, value):
123+
self.request.headers_out.status = value
124+
125+
property response_content_length:
126+
def __get__(self):
127+
if self.request.headers_out.content_length:
128+
return self.request.headers_out.content_length.value
129+
130+
def __set__(self, value):
131+
self.request.headers_out.content_length.value = value
132+
40133
def __repr__(self):
41134
return f'Request({self.method_name} {self.uri})'
42135

43136
def __str__(self):
44137
return f''' request_line: {self.request_line}
45-
uri: {self.uri}
46-
args: {self.args}
47-
extension: {self.extension}
48-
unparsed_uri: {self.unparsed_uri}
49-
method_name: {self.method_name}
50-
http_protocol: {self.http_protocol}'''
138+
uri: {self.uri}
139+
args: {self.args}
140+
extension: {self.extension}
141+
unparsed_uri: {self.unparsed_uri}
142+
method_name: {self.method_name}
143+
content_type: {self.content_type}
144+
content_length: {self.content_length}
145+
http_protocol: {self.http_protocol}'''
51146

52147
@staticmethod
53148
cdef Request from_ptr(ngx_http_request_t *request):
@@ -67,6 +162,12 @@ http_protocol: {self.http_protocol}'''
67162
new_req.unparsed_uri = from_nginx_str(request.unparsed_uri)
68163
new_req.method_name = from_nginx_str(request.method_name)
69164
new_req.http_protocol = from_nginx_str(request.http_protocol)
165+
if request.headers_in.content_type:
166+
new_req.content_type = from_nginx_str(
167+
request.headers_in.content_type.value)
168+
if request.headers_in.content_length:
169+
new_req.content_length = from_nginx_str(
170+
request.headers_in.content_length.value)
70171

71172
ngx_http_set_ctx(request, <void *>new_req, ngx_python_module)
72173
return new_req

nginx/http/module.py

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import asyncio
2+
import io
3+
import sys
4+
import functools
25

36
from . import log
47
from .._nginx import run_phases
@@ -13,14 +16,50 @@ def __init__(self):
1316
def init_process(self):
1417
self.loop = asyncio.get_event_loop()
1518

19+
def start_response(self, request, status, response_headers, exc_info=None):
20+
request.response_status = int(status.split(maxsplit=1)[0])
21+
for key, value in response_headers:
22+
request.add_response_header(key, value)
23+
1624
def post_read(self, request):
17-
if request._started():
18-
log.debug('post_read end')
19-
return request._result()
25+
environ = {
26+
'REQUEST_METHOD': request.method_name,
27+
'SCRIPT_NAME': None,
28+
'PATH_INFO': request.uri,
29+
'QUERY_STRING': request.args,
30+
'CONTENT_TYPE': request.content_type,
31+
'CONTENT_LENGTH': request.content_length,
32+
'SERVER_NAME': 'localhost',
33+
'SERVER_PORT': '8080',
34+
'SERVER_PROTOCOL': request.http_protocol,
35+
'wsgi.input': io.BytesIO(),
36+
'wsgi.errors': sys.stderr,
37+
'wsgi.version': (1, 0),
38+
'wsgi.multithread': False,
39+
'wsgi.multiprocess': True,
40+
'wsgi.run_once': True,
41+
}
42+
if environ.get('HTTPS', 'off') in ('on', '1'):
43+
environ['wsgi.url_scheme'] = 'https'
2044
else:
21-
log.debug('post_read request:\n%s', request)
22-
return request._start(self.loop.create_task(
23-
self._post_read_async(request)))
45+
environ['wsgi.url_scheme'] = 'http'
46+
app_name = request.get_app_from_config()
47+
module_name, method_name = app_name.split(':')
48+
app = getattr(__import__(module_name), method_name)
49+
resp = app(environ, functools.partial(
50+
self.start_response, request))
51+
request.send_header()
52+
rv = 404
53+
for pos in resp:
54+
rv = request.send_response(pos)
55+
return rv
56+
# if request._started():
57+
# log.debug('post_read end')
58+
# return request._result()
59+
# else:
60+
# log.debug('post_read request:\n%s', request)
61+
# return request._start(self.loop.create_task(
62+
# self._post_read_async(request)))
2463

2564
async def _post_read_async(self, request):
2665
try:

nginx/nginx.pyx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ import traceback
44
from enum import IntEnum
55

66
from .nginx_config cimport ngx_int_t
7-
from .nginx_core cimport ngx_module_t, ngx_cycle_t
7+
from .nginx_core cimport ngx_module_t, ngx_cycle_t, ngx_str_t
88
from .nginx_core cimport NGX_OK, NGX_ERROR, NGX_DECLINED, NGX_AGAIN
99
from .nginx_core cimport NGX_LOG_DEBUG, NGX_LOG_CRIT
1010
from .nginx_core cimport ngx_log_error
1111

1212

1313
cdef extern from "ngx_python_module.h":
1414
ngx_module_t ngx_python_module
15+
ctypedef struct ngx_wsgi_pass_conf_t:
16+
ngx_str_t wsgi_pass
1517

1618

1719
class ReturnCode(IntEnum):

nginx/nginx_core.pxd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ cdef extern from "ngx_core.h":
2626
char *data
2727

2828
ctypedef struct ngx_module_t:
29+
ngx_uint_t ctx_index
2930
pass
3031

3132
ctypedef struct ngx_log_t:
@@ -40,6 +41,7 @@ cdef extern from "ngx_core.h":
4041

4142
void *ngx_calloc(size_t size, ngx_log_t *log)
4243
void ngx_free(void *p)
44+
void *ngx_memcpy(void *dst, const void *src, size_t n)
4345
void ngx_log_error(ngx_uint_t level,
4446
ngx_log_t *log,
4547
ngx_err_t err,

nginx/ngx_http.pxd

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,39 @@
1-
from .nginx_core cimport ngx_str_t, ngx_module_t, ngx_log_t
1+
from .nginx_core cimport ngx_str_t, ngx_module_t, ngx_log_t, ngx_uint_t, ngx_int_t
22

33

44
cdef extern from "ngx_http.h":
5+
6+
ctypedef struct ngx_table_elt_t:
7+
ngx_uint_t hash
8+
ngx_str_t key
9+
ngx_str_t value
10+
11+
ctypedef struct ngx_list_t:
12+
pass
13+
14+
ctypedef struct ngx_http_headers_in_t:
15+
ngx_table_elt_t *content_type
16+
ngx_table_elt_t *content_length
17+
18+
ctypedef struct ngx_http_headers_out_t:
19+
ngx_uint_t status
20+
ngx_table_elt_t *content_length
21+
ngx_list_t headers
22+
23+
ctypedef struct ngx_chain_t:
24+
ngx_buf_t *buf
25+
ngx_chain_t *next
26+
27+
ctypedef struct ngx_buf_t:
28+
unsigned last_buf
29+
unsigned last_in_chain
30+
unsigned memory
31+
char *pos
32+
char *last
33+
34+
ctypedef struct ngx_pool_t:
35+
pass
36+
537
ctypedef struct ngx_connection_t:
638
ngx_log_t *log
739

@@ -14,9 +46,25 @@ cdef extern from "ngx_http.h":
1446
ngx_str_t unparsed_uri
1547
ngx_str_t method_name
1648
ngx_str_t http_protocol
49+
ngx_pool_t *pool
50+
ngx_http_headers_in_t headers_in
51+
ngx_http_headers_out_t headers_out
52+
void **loc_conf
1753

1854
void ngx_http_core_run_phases(ngx_http_request_t *request)
1955
void *ngx_http_get_module_ctx(ngx_http_request_t *request,
2056
ngx_module_t module)
2157
void ngx_http_set_ctx(ngx_http_request_t *request, void *ctx,
2258
ngx_module_t module)
59+
60+
void ngx_http_send_header(ngx_http_request_t *r)
61+
62+
ngx_table_elt_t *ngx_list_push(ngx_list_t *list)
63+
64+
void ngx_str_set(ngx_str_t *str, char *text)
65+
66+
ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *input)
67+
68+
ngx_buf_t *ngx_calloc_buf(ngx_pool_t *pool)
69+
70+

nginx/ngx_python_module.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <ngx_http.h>
44
#include <Python.h>
55
#include "nginx.h"
6+
#include "ngx_python_module.h"
67

78

89
static ngx_int_t ngx_python_init_process(ngx_cycle_t *cycle);
@@ -16,9 +17,6 @@ static void *ngx_http_wsgi_create_loc_conf(ngx_conf_t *cf);
1617
static char *ngx_handle_app(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
1718
static ngx_conf_post_t ngx_wsgi_pass_post = { ngx_handle_app };
1819

19-
typedef struct {
20-
ngx_str_t wsgi_pass;
21-
} ngx_wsgi_pass_conf_t;
2220

2321
static ngx_command_t ngx_wsgi_commands[] = {
2422
{ ngx_string("wsgi_pass"),
@@ -109,7 +107,7 @@ ngx_python_postconfiguration(ngx_conf_t *cf) {
109107

110108
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
111109

112-
h = ngx_array_push(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers);
110+
h = ngx_array_push(&cmcf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers);
113111
if (h == NULL) {
114112
return NGX_ERROR;
115113
}

nginx/ngx_python_module.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
extern ngx_module_t ngx_python_module;
2+
3+
typedef struct {
4+
ngx_str_t wsgi_pass;
5+
} ngx_wsgi_pass_conf_t;

0 commit comments

Comments
 (0)