nxt_python_wsgi.c (1648:551e0dbba1da) nxt_python_wsgi.c (1681:542b5b8c0647)
1
2/*
3 * Copyright (C) Max Romanov
4 * Copyright (C) Valentin V. Bartenev
5 * Copyright (C) NGINX, Inc.
6 */
7
8

--- 24 unchanged lines hidden (view full) ---

33 * - "Bytestrings" (which are implemented using the bytes type in Python 3, and
34 * str elsewhere), that are used for the bodies of requests and responses
35 * (e.g. POST/PUT input data and HTML page outputs).
36 *
37 * will use PyString_* or corresponding PyBytes_* functions
38 */
39
40
1
2/*
3 * Copyright (C) Max Romanov
4 * Copyright (C) Valentin V. Bartenev
5 * Copyright (C) NGINX, Inc.
6 */
7
8

--- 24 unchanged lines hidden (view full) ---

33 * - "Bytestrings" (which are implemented using the bytes type in Python 3, and
34 * str elsewhere), that are used for the bodies of requests and responses
35 * (e.g. POST/PUT input data and HTML page outputs).
36 *
37 * will use PyString_* or corresponding PyBytes_* functions
38 */
39
40
41typedef struct nxt_python_run_ctx_s nxt_python_run_ctx_t;
42
43typedef struct {
44 PyObject_HEAD
41typedef struct {
42 PyObject_HEAD
45} nxt_py_input_t;
46
43
44 uint64_t content_length;
45 uint64_t bytes_sent;
46 PyObject *environ;
47 PyObject *start_resp;
48 PyObject *write;
49 nxt_unit_request_info_t *req;
50 PyThreadState *thread_state;
51} nxt_python_ctx_t;
47
52
48typedef struct {
49 PyObject_HEAD
50} nxt_py_error_t;
51
53
54static int nxt_python_wsgi_ctx_data_alloc(void **pdata);
55static void nxt_python_wsgi_ctx_data_free(void *data);
56static int nxt_python_wsgi_run(nxt_unit_ctx_t *ctx);
57static void nxt_python_wsgi_done(void);
58
52static void nxt_python_request_handler(nxt_unit_request_info_t *req);
53
59static void nxt_python_request_handler(nxt_unit_request_info_t *req);
60
54static PyObject *nxt_python_create_environ(nxt_task_t *task);
55static PyObject *nxt_python_get_environ(nxt_python_run_ctx_t *ctx);
56static int nxt_python_add_sptr(nxt_python_run_ctx_t *ctx, PyObject *name,
61static PyObject *nxt_python_create_environ(nxt_python_app_conf_t *c);
62static PyObject *nxt_python_get_environ(nxt_python_ctx_t *pctx);
63static int nxt_python_add_sptr(nxt_python_ctx_t *pctx, PyObject *name,
57 nxt_unit_sptr_t *sptr, uint32_t size);
64 nxt_unit_sptr_t *sptr, uint32_t size);
58static int nxt_python_add_field(nxt_python_run_ctx_t *ctx,
65static int nxt_python_add_field(nxt_python_ctx_t *pctx,
59 nxt_unit_field_t *field, int n, uint32_t vl);
60static PyObject *nxt_python_field_name(const char *name, uint8_t len);
61static PyObject *nxt_python_field_value(nxt_unit_field_t *f, int n,
62 uint32_t vl);
66 nxt_unit_field_t *field, int n, uint32_t vl);
67static PyObject *nxt_python_field_name(const char *name, uint8_t len);
68static PyObject *nxt_python_field_value(nxt_unit_field_t *f, int n,
69 uint32_t vl);
63static int nxt_python_add_obj(nxt_python_run_ctx_t *ctx, PyObject *name,
70static int nxt_python_add_obj(nxt_python_ctx_t *pctx, PyObject *name,
64 PyObject *value);
65
66static PyObject *nxt_py_start_resp(PyObject *self, PyObject *args);
71 PyObject *value);
72
73static PyObject *nxt_py_start_resp(PyObject *self, PyObject *args);
67static int nxt_python_response_add_field(nxt_python_run_ctx_t *ctx,
74static int nxt_python_response_add_field(nxt_python_ctx_t *pctx,
68 PyObject *name, PyObject *value, int i);
69static int nxt_python_str_buf(PyObject *str, char **buf, uint32_t *len,
70 PyObject **bytes);
71static PyObject *nxt_py_write(PyObject *self, PyObject *args);
72
75 PyObject *name, PyObject *value, int i);
76static int nxt_python_str_buf(PyObject *str, char **buf, uint32_t *len,
77 PyObject **bytes);
78static PyObject *nxt_py_write(PyObject *self, PyObject *args);
79
73static void nxt_py_input_dealloc(nxt_py_input_t *self);
74static PyObject *nxt_py_input_read(nxt_py_input_t *self, PyObject *args);
75static PyObject *nxt_py_input_readline(nxt_py_input_t *self, PyObject *args);
76static PyObject *nxt_py_input_getline(nxt_python_run_ctx_t *ctx, size_t size);
77static PyObject *nxt_py_input_readlines(nxt_py_input_t *self, PyObject *args);
80static void nxt_py_input_dealloc(nxt_python_ctx_t *pctx);
81static PyObject *nxt_py_input_read(nxt_python_ctx_t *pctx, PyObject *args);
82static PyObject *nxt_py_input_readline(nxt_python_ctx_t *pctx,
83 PyObject *args);
84static PyObject *nxt_py_input_getline(nxt_python_ctx_t *pctx, size_t size);
85static PyObject *nxt_py_input_readlines(nxt_python_ctx_t *self,
86 PyObject *args);
78
87
79static PyObject *nxt_py_input_iter(PyObject *self);
80static PyObject *nxt_py_input_next(PyObject *self);
88static PyObject *nxt_py_input_iter(PyObject *pctx);
89static PyObject *nxt_py_input_next(PyObject *pctx);
81
90
82static int nxt_python_write(nxt_python_run_ctx_t *ctx, PyObject *bytes);
91static int nxt_python_write(nxt_python_ctx_t *pctx, PyObject *bytes);
83
92
84struct nxt_python_run_ctx_s {
85 uint64_t content_length;
86 uint64_t bytes_sent;
87 PyObject *environ;
88 nxt_unit_request_info_t *req;
89};
90
93
91
92static PyMethodDef nxt_py_start_resp_method[] = {
93 {"unit_start_response", nxt_py_start_resp, METH_VARARGS, ""}
94};
95
96
97static PyMethodDef nxt_py_write_method[] = {
98 {"unit_write", nxt_py_write, METH_O, ""}
99};

--- 6 unchanged lines hidden (view full) ---

106 { NULL, NULL, 0, 0 }
107};
108
109
110static PyTypeObject nxt_py_input_type = {
111 PyVarObject_HEAD_INIT(NULL, 0)
112
113 .tp_name = "unit._input",
94static PyMethodDef nxt_py_start_resp_method[] = {
95 {"unit_start_response", nxt_py_start_resp, METH_VARARGS, ""}
96};
97
98
99static PyMethodDef nxt_py_write_method[] = {
100 {"unit_write", nxt_py_write, METH_O, ""}
101};

--- 6 unchanged lines hidden (view full) ---

108 { NULL, NULL, 0, 0 }
109};
110
111
112static PyTypeObject nxt_py_input_type = {
113 PyVarObject_HEAD_INIT(NULL, 0)
114
115 .tp_name = "unit._input",
114 .tp_basicsize = sizeof(nxt_py_input_t),
116 .tp_basicsize = sizeof(nxt_python_ctx_t),
115 .tp_dealloc = (destructor) nxt_py_input_dealloc,
116 .tp_flags = Py_TPFLAGS_DEFAULT,
117 .tp_doc = "unit input object.",
118 .tp_iter = nxt_py_input_iter,
119 .tp_iternext = nxt_py_input_next,
120 .tp_methods = nxt_py_input_methods,
121};
122
123
117 .tp_dealloc = (destructor) nxt_py_input_dealloc,
118 .tp_flags = Py_TPFLAGS_DEFAULT,
119 .tp_doc = "unit input object.",
120 .tp_iter = nxt_py_input_iter,
121 .tp_iternext = nxt_py_input_next,
122 .tp_methods = nxt_py_input_methods,
123};
124
125
124static PyObject *nxt_py_start_resp_obj;
125static PyObject *nxt_py_write_obj;
126static PyObject *nxt_py_environ_ptyp;
126static PyObject *nxt_py_environ_ptyp;
127
127
128static PyThreadState *nxt_python_thread_state;
129static nxt_python_run_ctx_t *nxt_python_run_ctx;
130
131static PyObject *nxt_py_80_str;
132static PyObject *nxt_py_close_str;
133static PyObject *nxt_py_content_length_str;
134static PyObject *nxt_py_content_type_str;
135static PyObject *nxt_py_http_str;
136static PyObject *nxt_py_https_str;
137static PyObject *nxt_py_path_info_str;
138static PyObject *nxt_py_query_string_str;
139static PyObject *nxt_py_remote_addr_str;
140static PyObject *nxt_py_request_method_str;
141static PyObject *nxt_py_request_uri_str;
142static PyObject *nxt_py_server_addr_str;
143static PyObject *nxt_py_server_name_str;
144static PyObject *nxt_py_server_port_str;
145static PyObject *nxt_py_server_protocol_str;
128static PyObject *nxt_py_80_str;
129static PyObject *nxt_py_close_str;
130static PyObject *nxt_py_content_length_str;
131static PyObject *nxt_py_content_type_str;
132static PyObject *nxt_py_http_str;
133static PyObject *nxt_py_https_str;
134static PyObject *nxt_py_path_info_str;
135static PyObject *nxt_py_query_string_str;
136static PyObject *nxt_py_remote_addr_str;
137static PyObject *nxt_py_request_method_str;
138static PyObject *nxt_py_request_uri_str;
139static PyObject *nxt_py_server_addr_str;
140static PyObject *nxt_py_server_name_str;
141static PyObject *nxt_py_server_port_str;
142static PyObject *nxt_py_server_protocol_str;
143static PyObject *nxt_py_wsgi_input_str;
146static PyObject *nxt_py_wsgi_uri_scheme_str;
147
148static nxt_python_string_t nxt_python_strings[] = {
149 { nxt_string("80"), &nxt_py_80_str },
150 { nxt_string("close"), &nxt_py_close_str },
151 { nxt_string("CONTENT_LENGTH"), &nxt_py_content_length_str },
152 { nxt_string("CONTENT_TYPE"), &nxt_py_content_type_str },
153 { nxt_string("http"), &nxt_py_http_str },
154 { nxt_string("https"), &nxt_py_https_str },
155 { nxt_string("PATH_INFO"), &nxt_py_path_info_str },
156 { nxt_string("QUERY_STRING"), &nxt_py_query_string_str },
157 { nxt_string("REMOTE_ADDR"), &nxt_py_remote_addr_str },
158 { nxt_string("REQUEST_METHOD"), &nxt_py_request_method_str },
159 { nxt_string("REQUEST_URI"), &nxt_py_request_uri_str },
160 { nxt_string("SERVER_ADDR"), &nxt_py_server_addr_str },
161 { nxt_string("SERVER_NAME"), &nxt_py_server_name_str },
162 { nxt_string("SERVER_PORT"), &nxt_py_server_port_str },
163 { nxt_string("SERVER_PROTOCOL"), &nxt_py_server_protocol_str },
144static PyObject *nxt_py_wsgi_uri_scheme_str;
145
146static nxt_python_string_t nxt_python_strings[] = {
147 { nxt_string("80"), &nxt_py_80_str },
148 { nxt_string("close"), &nxt_py_close_str },
149 { nxt_string("CONTENT_LENGTH"), &nxt_py_content_length_str },
150 { nxt_string("CONTENT_TYPE"), &nxt_py_content_type_str },
151 { nxt_string("http"), &nxt_py_http_str },
152 { nxt_string("https"), &nxt_py_https_str },
153 { nxt_string("PATH_INFO"), &nxt_py_path_info_str },
154 { nxt_string("QUERY_STRING"), &nxt_py_query_string_str },
155 { nxt_string("REMOTE_ADDR"), &nxt_py_remote_addr_str },
156 { nxt_string("REQUEST_METHOD"), &nxt_py_request_method_str },
157 { nxt_string("REQUEST_URI"), &nxt_py_request_uri_str },
158 { nxt_string("SERVER_ADDR"), &nxt_py_server_addr_str },
159 { nxt_string("SERVER_NAME"), &nxt_py_server_name_str },
160 { nxt_string("SERVER_PORT"), &nxt_py_server_port_str },
161 { nxt_string("SERVER_PROTOCOL"), &nxt_py_server_protocol_str },
162 { nxt_string("wsgi.input"), &nxt_py_wsgi_input_str },
164 { nxt_string("wsgi.url_scheme"), &nxt_py_wsgi_uri_scheme_str },
165 { nxt_null_string, NULL },
166};
167
163 { nxt_string("wsgi.url_scheme"), &nxt_py_wsgi_uri_scheme_str },
164 { nxt_null_string, NULL },
165};
166
167static nxt_python_proto_t nxt_py_wsgi_proto = {
168 .ctx_data_alloc = nxt_python_wsgi_ctx_data_alloc,
169 .ctx_data_free = nxt_python_wsgi_ctx_data_free,
170 .run = nxt_python_wsgi_run,
171 .done = nxt_python_wsgi_done,
172};
168
173
169nxt_int_t
170nxt_python_wsgi_init(nxt_task_t *task, nxt_unit_init_t *init)
174
175int
176nxt_python_wsgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto)
171{
172 PyObject *obj;
173
174 obj = NULL;
175
177{
178 PyObject *obj;
179
180 obj = NULL;
181
176 if (nxt_slow_path(nxt_python_init_strings(nxt_python_strings) != NXT_OK)) {
177 nxt_alert(task, "Python failed to init string objects");
182 if (nxt_slow_path(nxt_python_init_strings(nxt_python_strings)
183 != NXT_UNIT_OK))
184 {
185 nxt_unit_alert(NULL, "Python failed to init string objects");
178 goto fail;
179 }
180
186 goto fail;
187 }
188
181 obj = PyCFunction_New(nxt_py_start_resp_method, NULL);
189 obj = nxt_python_create_environ(init->data);
182 if (nxt_slow_path(obj == NULL)) {
190 if (nxt_slow_path(obj == NULL)) {
183 nxt_alert(task,
184 "Python failed to initialize the \"start_response\" function");
185 goto fail;
186 }
187
191 goto fail;
192 }
193
188 nxt_py_start_resp_obj = obj;
194 nxt_py_environ_ptyp = obj;
195 obj = NULL;
189
196
190 obj = PyCFunction_New(nxt_py_write_method, NULL);
191 if (nxt_slow_path(obj == NULL)) {
192 nxt_alert(task, "Python failed to initialize the \"write\" function");
193 goto fail;
197 init->callbacks.request_handler = nxt_python_request_handler;
198
199 *proto = nxt_py_wsgi_proto;
200
201 return NXT_UNIT_OK;
202
203fail:
204
205 Py_XDECREF(obj);
206
207 return NXT_UNIT_ERROR;
208}
209
210
211static int
212nxt_python_wsgi_ctx_data_alloc(void **pdata)
213{
214 nxt_python_ctx_t *pctx;
215
216 pctx = PyObject_New(nxt_python_ctx_t, &nxt_py_input_type);
217 if (nxt_slow_path(pctx == NULL)) {
218 nxt_unit_alert(NULL,
219 "Python failed to create the \"wsgi.input\" object");
220 return NXT_UNIT_ERROR;
194 }
195
221 }
222
196 nxt_py_write_obj = obj;
223 pctx->write = NULL;
197
224
198 obj = nxt_python_create_environ(task);
199 if (nxt_slow_path(obj == NULL)) {
225 pctx->start_resp = PyCFunction_New(nxt_py_start_resp_method,
226 (PyObject *) pctx);
227 if (nxt_slow_path(pctx->start_resp == NULL)) {
228 nxt_unit_alert(NULL,
229 "Python failed to initialize the \"start_response\" function");
200 goto fail;
201 }
202
230 goto fail;
231 }
232
203 nxt_py_environ_ptyp = obj;
204 obj = NULL;
233 pctx->write = PyCFunction_New(nxt_py_write_method, (PyObject *) pctx);
234 if (nxt_slow_path(pctx->write == NULL)) {
235 nxt_unit_alert(NULL,
236 "Python failed to initialize the \"write\" function");
237 goto fail;
238 }
205
239
206 init->callbacks.request_handler = nxt_python_request_handler;
240 *pdata = pctx;
207
241
208 return NXT_OK;
242 return NXT_UNIT_OK;
209
210fail:
211
243
244fail:
245
212 Py_XDECREF(obj);
246 nxt_python_wsgi_ctx_data_free(pctx);
213
247
214 return NXT_ERROR;
248 return NXT_UNIT_ERROR;
215}
216
217
249}
250
251
218int
252static void
253nxt_python_wsgi_ctx_data_free(void *data)
254{
255 nxt_python_ctx_t *pctx;
256
257 pctx = data;
258
259 Py_XDECREF(pctx->start_resp);
260 Py_XDECREF(pctx->write);
261 Py_XDECREF(pctx);
262}
263
264
265static int
219nxt_python_wsgi_run(nxt_unit_ctx_t *ctx)
220{
266nxt_python_wsgi_run(nxt_unit_ctx_t *ctx)
267{
221 int rc;
268 int rc;
269 nxt_python_ctx_t *pctx;
222
270
223 nxt_python_thread_state = PyEval_SaveThread();
271 pctx = ctx->data;
224
272
273 pctx->thread_state = PyEval_SaveThread();
274
225 rc = nxt_unit_run(ctx);
226
275 rc = nxt_unit_run(ctx);
276
227 PyEval_RestoreThread(nxt_python_thread_state);
277 PyEval_RestoreThread(pctx->thread_state);
228
229 return rc;
230}
231
232
278
279 return rc;
280}
281
282
233void
283static void
234nxt_python_wsgi_done(void)
235{
236 nxt_python_done_strings(nxt_python_strings);
237
284nxt_python_wsgi_done(void)
285{
286 nxt_python_done_strings(nxt_python_strings);
287
238 Py_XDECREF(nxt_py_start_resp_obj);
239 Py_XDECREF(nxt_py_write_obj);
240 Py_XDECREF(nxt_py_environ_ptyp);
241}
242
243
244static void
245nxt_python_request_handler(nxt_unit_request_info_t *req)
246{
288 Py_XDECREF(nxt_py_environ_ptyp);
289}
290
291
292static void
293nxt_python_request_handler(nxt_unit_request_info_t *req)
294{
247 int rc;
248 PyObject *environ, *args, *response, *iterator, *item;
249 PyObject *close, *result;
250 nxt_python_run_ctx_t run_ctx = {-1, 0, NULL, req};
295 int rc;
296 PyObject *environ, *args, *response, *iterator, *item;
297 PyObject *close, *result;
298 nxt_python_ctx_t *pctx;
251
299
252 PyEval_RestoreThread(nxt_python_thread_state);
300 pctx = req->ctx->data;
253
301
254 environ = nxt_python_get_environ(&run_ctx);
302 pctx->content_length = -1;
303 pctx->bytes_sent = 0;
304 pctx->req = req;
305
306 PyEval_RestoreThread(pctx->thread_state);
307
308 environ = nxt_python_get_environ(pctx);
255 if (nxt_slow_path(environ == NULL)) {
256 rc = NXT_UNIT_ERROR;
257 goto done;
258 }
259
260 args = PyTuple_New(2);
261 if (nxt_slow_path(args == NULL)) {
262 Py_DECREF(environ);
263
264 nxt_unit_req_error(req, "Python failed to create arguments tuple");
265
266 rc = NXT_UNIT_ERROR;
267 goto done;
268 }
269
270 PyTuple_SET_ITEM(args, 0, environ);
271
309 if (nxt_slow_path(environ == NULL)) {
310 rc = NXT_UNIT_ERROR;
311 goto done;
312 }
313
314 args = PyTuple_New(2);
315 if (nxt_slow_path(args == NULL)) {
316 Py_DECREF(environ);
317
318 nxt_unit_req_error(req, "Python failed to create arguments tuple");
319
320 rc = NXT_UNIT_ERROR;
321 goto done;
322 }
323
324 PyTuple_SET_ITEM(args, 0, environ);
325
272 Py_INCREF(nxt_py_start_resp_obj);
273 PyTuple_SET_ITEM(args, 1, nxt_py_start_resp_obj);
326 Py_INCREF(pctx->start_resp);
327 PyTuple_SET_ITEM(args, 1, pctx->start_resp);
274
328
275 nxt_python_run_ctx = &run_ctx;
276
277 response = PyObject_CallObject(nxt_py_application, args);
278
279 Py_DECREF(args);
280
281 if (nxt_slow_path(response == NULL)) {
282 nxt_unit_req_error(req, "Python failed to call the application");
283 nxt_python_print_exception();
284
285 rc = NXT_UNIT_ERROR;
286 goto done;
287 }
288
289 /* Shortcut: avoid iterate over response string symbols. */
290 if (PyBytes_Check(response)) {
329 response = PyObject_CallObject(nxt_py_application, args);
330
331 Py_DECREF(args);
332
333 if (nxt_slow_path(response == NULL)) {
334 nxt_unit_req_error(req, "Python failed to call the application");
335 nxt_python_print_exception();
336
337 rc = NXT_UNIT_ERROR;
338 goto done;
339 }
340
341 /* Shortcut: avoid iterate over response string symbols. */
342 if (PyBytes_Check(response)) {
291 rc = nxt_python_write(&run_ctx, response);
343 rc = nxt_python_write(pctx, response);
292
293 } else {
294 iterator = PyObject_GetIter(response);
295
296 if (nxt_fast_path(iterator != NULL)) {
297 rc = NXT_UNIT_OK;
298
344
345 } else {
346 iterator = PyObject_GetIter(response);
347
348 if (nxt_fast_path(iterator != NULL)) {
349 rc = NXT_UNIT_OK;
350
299 while (run_ctx.bytes_sent < run_ctx.content_length) {
351 while (pctx->bytes_sent < pctx->content_length) {
300 item = PyIter_Next(iterator);
301
302 if (item == NULL) {
303 if (nxt_slow_path(PyErr_Occurred() != NULL)) {
304 nxt_unit_req_error(req, "Python failed to iterate over "
305 "the application response object");
306 nxt_python_print_exception();
307
308 rc = NXT_UNIT_ERROR;
309 }
310
311 break;
312 }
313
314 if (nxt_fast_path(PyBytes_Check(item))) {
352 item = PyIter_Next(iterator);
353
354 if (item == NULL) {
355 if (nxt_slow_path(PyErr_Occurred() != NULL)) {
356 nxt_unit_req_error(req, "Python failed to iterate over "
357 "the application response object");
358 nxt_python_print_exception();
359
360 rc = NXT_UNIT_ERROR;
361 }
362
363 break;
364 }
365
366 if (nxt_fast_path(PyBytes_Check(item))) {
315 rc = nxt_python_write(&run_ctx, item);
367 rc = nxt_python_write(pctx, item);
316
317 } else {
318 nxt_unit_req_error(req, "the application returned "
319 "not a bytestring object");
320 rc = NXT_UNIT_ERROR;
321 }
322
323 Py_DECREF(item);

--- 32 unchanged lines hidden (view full) ---

356 PyErr_Clear();
357 }
358 }
359
360 Py_DECREF(response);
361
362done:
363
368
369 } else {
370 nxt_unit_req_error(req, "the application returned "
371 "not a bytestring object");
372 rc = NXT_UNIT_ERROR;
373 }
374
375 Py_DECREF(item);

--- 32 unchanged lines hidden (view full) ---

408 PyErr_Clear();
409 }
410 }
411
412 Py_DECREF(response);
413
414done:
415
364 nxt_python_thread_state = PyEval_SaveThread();
416 pctx->thread_state = PyEval_SaveThread();
365
417
366 nxt_python_run_ctx = NULL;
418 pctx->req = NULL;
419
367 nxt_unit_request_done(req, rc);
368}
369
370
371static PyObject *
420 nxt_unit_request_done(req, rc);
421}
422
423
424static PyObject *
372nxt_python_create_environ(nxt_task_t *task)
425nxt_python_create_environ(nxt_python_app_conf_t *c)
373{
374 PyObject *obj, *err, *environ;
375
376 environ = PyDict_New();
377
378 if (nxt_slow_path(environ == NULL)) {
426{
427 PyObject *obj, *err, *environ;
428
429 environ = PyDict_New();
430
431 if (nxt_slow_path(environ == NULL)) {
379 nxt_alert(task, "Python failed to create the \"environ\" dictionary");
432 nxt_unit_alert(NULL,
433 "Python failed to create the \"environ\" dictionary");
380 return NULL;
381 }
382
383 obj = PyString_FromStringAndSize((char *) nxt_server.start,
384 nxt_server.length);
385 if (nxt_slow_path(obj == NULL)) {
434 return NULL;
435 }
436
437 obj = PyString_FromStringAndSize((char *) nxt_server.start,
438 nxt_server.length);
439 if (nxt_slow_path(obj == NULL)) {
386 nxt_alert(task,
440 nxt_unit_alert(NULL,
387 "Python failed to create the \"SERVER_SOFTWARE\" environ value");
388 goto fail;
389 }
390
391 if (nxt_slow_path(PyDict_SetItemString(environ, "SERVER_SOFTWARE", obj)
392 != 0))
393 {
441 "Python failed to create the \"SERVER_SOFTWARE\" environ value");
442 goto fail;
443 }
444
445 if (nxt_slow_path(PyDict_SetItemString(environ, "SERVER_SOFTWARE", obj)
446 != 0))
447 {
394 nxt_alert(task,
448 nxt_unit_alert(NULL,
395 "Python failed to set the \"SERVER_SOFTWARE\" environ value");
396 goto fail;
397 }
398
399 Py_DECREF(obj);
400
401 obj = Py_BuildValue("(ii)", 1, 0);
402
403 if (nxt_slow_path(obj == NULL)) {
449 "Python failed to set the \"SERVER_SOFTWARE\" environ value");
450 goto fail;
451 }
452
453 Py_DECREF(obj);
454
455 obj = Py_BuildValue("(ii)", 1, 0);
456
457 if (nxt_slow_path(obj == NULL)) {
404 nxt_alert(task,
458 nxt_unit_alert(NULL,
405 "Python failed to build the \"wsgi.version\" environ value");
406 goto fail;
407 }
408
409 if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.version", obj) != 0))
410 {
459 "Python failed to build the \"wsgi.version\" environ value");
460 goto fail;
461 }
462
463 if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.version", obj) != 0))
464 {
411 nxt_alert(task,
412 "Python failed to set the \"wsgi.version\" environ value");
465 nxt_unit_alert(NULL,
466 "Python failed to set the \"wsgi.version\" environ value");
413 goto fail;
414 }
415
416 Py_DECREF(obj);
417 obj = NULL;
418
419
420 if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.multithread",
467 goto fail;
468 }
469
470 Py_DECREF(obj);
471 obj = NULL;
472
473
474 if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.multithread",
421 Py_False)
475 c->threads > 1 ? Py_True : Py_False)
422 != 0))
423 {
476 != 0))
477 {
424 nxt_alert(task,
478 nxt_unit_alert(NULL,
425 "Python failed to set the \"wsgi.multithread\" environ value");
426 goto fail;
427 }
428
429 if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.multiprocess",
430 Py_True)
431 != 0))
432 {
479 "Python failed to set the \"wsgi.multithread\" environ value");
480 goto fail;
481 }
482
483 if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.multiprocess",
484 Py_True)
485 != 0))
486 {
433 nxt_alert(task,
487 nxt_unit_alert(NULL,
434 "Python failed to set the \"wsgi.multiprocess\" environ value");
435 goto fail;
436 }
437
438 if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.run_once",
439 Py_False)
440 != 0))
441 {
488 "Python failed to set the \"wsgi.multiprocess\" environ value");
489 goto fail;
490 }
491
492 if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.run_once",
493 Py_False)
494 != 0))
495 {
442 nxt_alert(task,
496 nxt_unit_alert(NULL,
443 "Python failed to set the \"wsgi.run_once\" environ value");
444 goto fail;
445 }
446
447
448 if (nxt_slow_path(PyType_Ready(&nxt_py_input_type) != 0)) {
497 "Python failed to set the \"wsgi.run_once\" environ value");
498 goto fail;
499 }
500
501
502 if (nxt_slow_path(PyType_Ready(&nxt_py_input_type) != 0)) {
449 nxt_alert(task,
503 nxt_unit_alert(NULL,
450 "Python failed to initialize the \"wsgi.input\" type object");
451 goto fail;
452 }
453
504 "Python failed to initialize the \"wsgi.input\" type object");
505 goto fail;
506 }
507
454 obj = (PyObject *) PyObject_New(nxt_py_input_t, &nxt_py_input_type);
455
508
456 if (nxt_slow_path(obj == NULL)) {
457 nxt_alert(task, "Python failed to create the \"wsgi.input\" object");
458 goto fail;
459 }
460
461 if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.input", obj) != 0)) {
462 nxt_alert(task,
463 "Python failed to set the \"wsgi.input\" environ value");
464 goto fail;
465 }
466
467 Py_DECREF(obj);
468 obj = NULL;
469
470
471 err = PySys_GetObject((char *) "stderr");
472
473 if (nxt_slow_path(err == NULL)) {
509 err = PySys_GetObject((char *) "stderr");
510
511 if (nxt_slow_path(err == NULL)) {
474 nxt_alert(task, "Python failed to get \"sys.stderr\" object");
512 nxt_unit_alert(NULL, "Python failed to get \"sys.stderr\" object");
475 goto fail;
476 }
477
478 if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.errors", err) != 0))
479 {
513 goto fail;
514 }
515
516 if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.errors", err) != 0))
517 {
480 nxt_alert(task,
481 "Python failed to set the \"wsgi.errors\" environ value");
518 nxt_unit_alert(NULL,
519 "Python failed to set the \"wsgi.errors\" environ value");
482 goto fail;
483 }
484
485 return environ;
486
487fail:
488
489 Py_XDECREF(obj);
490 Py_DECREF(environ);
491
492 return NULL;
493}
494
495
496static PyObject *
520 goto fail;
521 }
522
523 return environ;
524
525fail:
526
527 Py_XDECREF(obj);
528 Py_DECREF(environ);
529
530 return NULL;
531}
532
533
534static PyObject *
497nxt_python_get_environ(nxt_python_run_ctx_t *ctx)
535nxt_python_get_environ(nxt_python_ctx_t *pctx)
498{
499 int rc;
500 uint32_t i, j, vl;
501 PyObject *environ;
502 nxt_unit_field_t *f, *f2;
503 nxt_unit_request_t *r;
504
505 environ = PyDict_Copy(nxt_py_environ_ptyp);
506 if (nxt_slow_path(environ == NULL)) {
536{
537 int rc;
538 uint32_t i, j, vl;
539 PyObject *environ;
540 nxt_unit_field_t *f, *f2;
541 nxt_unit_request_t *r;
542
543 environ = PyDict_Copy(nxt_py_environ_ptyp);
544 if (nxt_slow_path(environ == NULL)) {
507 nxt_unit_req_error(ctx->req,
545 nxt_unit_req_error(pctx->req,
508 "Python failed to copy the \"environ\" dictionary");
509
510 return NULL;
511 }
512
546 "Python failed to copy the \"environ\" dictionary");
547
548 return NULL;
549 }
550
513 ctx->environ = environ;
551 pctx->environ = environ;
514
552
515 r = ctx->req->request;
553 r = pctx->req->request;
516
517#define RC(S) \
518 do { \
519 rc = (S); \
520 if (nxt_slow_path(rc != NXT_UNIT_OK)) { \
521 goto fail; \
522 } \
523 } while(0)
524
554
555#define RC(S) \
556 do { \
557 rc = (S); \
558 if (nxt_slow_path(rc != NXT_UNIT_OK)) { \
559 goto fail; \
560 } \
561 } while(0)
562
525 RC(nxt_python_add_sptr(ctx, nxt_py_request_method_str, &r->method,
563 RC(nxt_python_add_sptr(pctx, nxt_py_request_method_str, &r->method,
526 r->method_length));
564 r->method_length));
527 RC(nxt_python_add_sptr(ctx, nxt_py_request_uri_str, &r->target,
565 RC(nxt_python_add_sptr(pctx, nxt_py_request_uri_str, &r->target,
528 r->target_length));
566 r->target_length));
529 RC(nxt_python_add_sptr(ctx, nxt_py_query_string_str, &r->query,
567 RC(nxt_python_add_sptr(pctx, nxt_py_query_string_str, &r->query,
530 r->query_length));
568 r->query_length));
531 RC(nxt_python_add_sptr(ctx, nxt_py_path_info_str, &r->path,
569 RC(nxt_python_add_sptr(pctx, nxt_py_path_info_str, &r->path,
532 r->path_length));
533
570 r->path_length));
571
534 RC(nxt_python_add_sptr(ctx, nxt_py_remote_addr_str, &r->remote,
572 RC(nxt_python_add_sptr(pctx, nxt_py_remote_addr_str, &r->remote,
535 r->remote_length));
573 r->remote_length));
536 RC(nxt_python_add_sptr(ctx, nxt_py_server_addr_str, &r->local,
574 RC(nxt_python_add_sptr(pctx, nxt_py_server_addr_str, &r->local,
537 r->local_length));
538
539 if (r->tls) {
575 r->local_length));
576
577 if (r->tls) {
540 RC(nxt_python_add_obj(ctx, nxt_py_wsgi_uri_scheme_str,
578 RC(nxt_python_add_obj(pctx, nxt_py_wsgi_uri_scheme_str,
541 nxt_py_https_str));
542 } else {
579 nxt_py_https_str));
580 } else {
543 RC(nxt_python_add_obj(ctx, nxt_py_wsgi_uri_scheme_str,
581 RC(nxt_python_add_obj(pctx, nxt_py_wsgi_uri_scheme_str,
544 nxt_py_http_str));
545 }
546
582 nxt_py_http_str));
583 }
584
547 RC(nxt_python_add_sptr(ctx, nxt_py_server_protocol_str, &r->version,
585 RC(nxt_python_add_sptr(pctx, nxt_py_server_protocol_str, &r->version,
548 r->version_length));
549
586 r->version_length));
587
550 RC(nxt_python_add_sptr(ctx, nxt_py_server_name_str, &r->server_name,
588 RC(nxt_python_add_sptr(pctx, nxt_py_server_name_str, &r->server_name,
551 r->server_name_length));
589 r->server_name_length));
552 RC(nxt_python_add_obj(ctx, nxt_py_server_port_str, nxt_py_80_str));
590 RC(nxt_python_add_obj(pctx, nxt_py_server_port_str, nxt_py_80_str));
553
591
554 nxt_unit_request_group_dup_fields(ctx->req);
592 nxt_unit_request_group_dup_fields(pctx->req);
555
556 for (i = 0; i < r->fields_count;) {
557 f = r->fields + i;
558 vl = f->value_length;
559
560 for (j = i + 1; j < r->fields_count; j++) {
561 f2 = r->fields + j;
562
563 if (f2->hash != f->hash
564 || nxt_unit_sptr_get(&f2->name) != nxt_unit_sptr_get(&f->name))
565 {
566 break;
567 }
568
569 vl += 2 + f2->value_length;
570 }
571
593
594 for (i = 0; i < r->fields_count;) {
595 f = r->fields + i;
596 vl = f->value_length;
597
598 for (j = i + 1; j < r->fields_count; j++) {
599 f2 = r->fields + j;
600
601 if (f2->hash != f->hash
602 || nxt_unit_sptr_get(&f2->name) != nxt_unit_sptr_get(&f->name))
603 {
604 break;
605 }
606
607 vl += 2 + f2->value_length;
608 }
609
572 RC(nxt_python_add_field(ctx, f, j - i, vl));
610 RC(nxt_python_add_field(pctx, f, j - i, vl));
573
574 i = j;
575 }
576
577 if (r->content_length_field != NXT_UNIT_NONE_FIELD) {
578 f = r->fields + r->content_length_field;
579
611
612 i = j;
613 }
614
615 if (r->content_length_field != NXT_UNIT_NONE_FIELD) {
616 f = r->fields + r->content_length_field;
617
580 RC(nxt_python_add_sptr(ctx, nxt_py_content_length_str, &f->value,
618 RC(nxt_python_add_sptr(pctx, nxt_py_content_length_str, &f->value,
581 f->value_length));
582 }
583
584 if (r->content_type_field != NXT_UNIT_NONE_FIELD) {
585 f = r->fields + r->content_type_field;
586
619 f->value_length));
620 }
621
622 if (r->content_type_field != NXT_UNIT_NONE_FIELD) {
623 f = r->fields + r->content_type_field;
624
587 RC(nxt_python_add_sptr(ctx, nxt_py_content_type_str, &f->value,
625 RC(nxt_python_add_sptr(pctx, nxt_py_content_type_str, &f->value,
588 f->value_length));
589 }
590
591#undef RC
592
626 f->value_length));
627 }
628
629#undef RC
630
631 if (nxt_slow_path(PyDict_SetItem(environ, nxt_py_wsgi_input_str,
632 (PyObject *) pctx) != 0))
633 {
634 nxt_unit_req_error(pctx->req,
635 "Python failed to set the \"wsgi.input\" environ value");
636 goto fail;
637 }
638
593 return environ;
594
595fail:
596
597 Py_DECREF(environ);
598
599 return NULL;
600}
601
602
603static int
639 return environ;
640
641fail:
642
643 Py_DECREF(environ);
644
645 return NULL;
646}
647
648
649static int
604nxt_python_add_sptr(nxt_python_run_ctx_t *ctx, PyObject *name,
650nxt_python_add_sptr(nxt_python_ctx_t *pctx, PyObject *name,
605 nxt_unit_sptr_t *sptr, uint32_t size)
606{
607 char *src;
608 PyObject *value;
609
610 src = nxt_unit_sptr_get(sptr);
611
612 value = PyString_FromStringAndSize(src, size);
613 if (nxt_slow_path(value == NULL)) {
651 nxt_unit_sptr_t *sptr, uint32_t size)
652{
653 char *src;
654 PyObject *value;
655
656 src = nxt_unit_sptr_get(sptr);
657
658 value = PyString_FromStringAndSize(src, size);
659 if (nxt_slow_path(value == NULL)) {
614 nxt_unit_req_error(ctx->req,
660 nxt_unit_req_error(pctx->req,
615 "Python failed to create value string \"%.*s\"",
616 (int) size, src);
617 nxt_python_print_exception();
618
619 return NXT_UNIT_ERROR;
620 }
621
661 "Python failed to create value string \"%.*s\"",
662 (int) size, src);
663 nxt_python_print_exception();
664
665 return NXT_UNIT_ERROR;
666 }
667
622 if (nxt_slow_path(PyDict_SetItem(ctx->environ, name, value) != 0)) {
623 nxt_unit_req_error(ctx->req,
668 if (nxt_slow_path(PyDict_SetItem(pctx->environ, name, value) != 0)) {
669 nxt_unit_req_error(pctx->req,
624 "Python failed to set the \"%s\" environ value",
625 PyUnicode_AsUTF8(name));
626 Py_DECREF(value);
627
628 return NXT_UNIT_ERROR;
629 }
630
631 Py_DECREF(value);
632
633 return NXT_UNIT_OK;
634}
635
636
637static int
670 "Python failed to set the \"%s\" environ value",
671 PyUnicode_AsUTF8(name));
672 Py_DECREF(value);
673
674 return NXT_UNIT_ERROR;
675 }
676
677 Py_DECREF(value);
678
679 return NXT_UNIT_OK;
680}
681
682
683static int
638nxt_python_add_field(nxt_python_run_ctx_t *ctx, nxt_unit_field_t *field, int n,
684nxt_python_add_field(nxt_python_ctx_t *pctx, nxt_unit_field_t *field, int n,
639 uint32_t vl)
640{
641 char *src;
642 PyObject *name, *value;
643
644 src = nxt_unit_sptr_get(&field->name);
645
646 name = nxt_python_field_name(src, field->name_length);
647 if (nxt_slow_path(name == NULL)) {
685 uint32_t vl)
686{
687 char *src;
688 PyObject *name, *value;
689
690 src = nxt_unit_sptr_get(&field->name);
691
692 name = nxt_python_field_name(src, field->name_length);
693 if (nxt_slow_path(name == NULL)) {
648 nxt_unit_req_error(ctx->req,
694 nxt_unit_req_error(pctx->req,
649 "Python failed to create name string \"%.*s\"",
650 (int) field->name_length, src);
651 nxt_python_print_exception();
652
653 return NXT_UNIT_ERROR;
654 }
655
656 value = nxt_python_field_value(field, n, vl);
657
658 if (nxt_slow_path(value == NULL)) {
695 "Python failed to create name string \"%.*s\"",
696 (int) field->name_length, src);
697 nxt_python_print_exception();
698
699 return NXT_UNIT_ERROR;
700 }
701
702 value = nxt_python_field_value(field, n, vl);
703
704 if (nxt_slow_path(value == NULL)) {
659 nxt_unit_req_error(ctx->req,
705 nxt_unit_req_error(pctx->req,
660 "Python failed to create value string \"%.*s\"",
661 (int) field->value_length,
662 (char *) nxt_unit_sptr_get(&field->value));
663 nxt_python_print_exception();
664
665 goto fail;
666 }
667
706 "Python failed to create value string \"%.*s\"",
707 (int) field->value_length,
708 (char *) nxt_unit_sptr_get(&field->value));
709 nxt_python_print_exception();
710
711 goto fail;
712 }
713
668 if (nxt_slow_path(PyDict_SetItem(ctx->environ, name, value) != 0)) {
669 nxt_unit_req_error(ctx->req,
714 if (nxt_slow_path(PyDict_SetItem(pctx->environ, name, value) != 0)) {
715 nxt_unit_req_error(pctx->req,
670 "Python failed to set the \"%s\" environ value",
671 PyUnicode_AsUTF8(name));
672 goto fail;
673 }
674
675 Py_DECREF(name);
676 Py_DECREF(value);
677

--- 78 unchanged lines hidden (view full) ---

756 p = nxt_cpymem(p, src, f[i].value_length);
757 }
758
759 return res;
760}
761
762
763static int
716 "Python failed to set the \"%s\" environ value",
717 PyUnicode_AsUTF8(name));
718 goto fail;
719 }
720
721 Py_DECREF(name);
722 Py_DECREF(value);
723

--- 78 unchanged lines hidden (view full) ---

802 p = nxt_cpymem(p, src, f[i].value_length);
803 }
804
805 return res;
806}
807
808
809static int
764nxt_python_add_obj(nxt_python_run_ctx_t *ctx, PyObject *name, PyObject *value)
810nxt_python_add_obj(nxt_python_ctx_t *pctx, PyObject *name, PyObject *value)
765{
811{
766 if (nxt_slow_path(PyDict_SetItem(ctx->environ, name, value) != 0)) {
767 nxt_unit_req_error(ctx->req,
812 if (nxt_slow_path(PyDict_SetItem(pctx->environ, name, value) != 0)) {
813 nxt_unit_req_error(pctx->req,
768 "Python failed to set the \"%s\" environ value",
769 PyUnicode_AsUTF8(name));
770
771 return NXT_UNIT_ERROR;
772 }
773
774 return NXT_UNIT_OK;
775}
776
777
778static PyObject *
779nxt_py_start_resp(PyObject *self, PyObject *args)
780{
814 "Python failed to set the \"%s\" environ value",
815 PyUnicode_AsUTF8(name));
816
817 return NXT_UNIT_ERROR;
818 }
819
820 return NXT_UNIT_OK;
821}
822
823
824static PyObject *
825nxt_py_start_resp(PyObject *self, PyObject *args)
826{
781 int rc, status;
782 char *status_str, *space_ptr;
783 uint32_t status_len;
784 PyObject *headers, *tuple, *string, *status_bytes;
785 Py_ssize_t i, n, fields_size, fields_count;
786 nxt_python_run_ctx_t *ctx;
827 int rc, status;
828 char *status_str, *space_ptr;
829 uint32_t status_len;
830 PyObject *headers, *tuple, *string, *status_bytes;
831 Py_ssize_t i, n, fields_size, fields_count;
832 nxt_python_ctx_t *pctx;
787
833
788 ctx = nxt_python_run_ctx;
789 if (nxt_slow_path(ctx == NULL)) {
834 pctx = (nxt_python_ctx_t *) self;
835 if (nxt_slow_path(pctx->req == NULL)) {
790 return PyErr_Format(PyExc_RuntimeError,
791 "start_response() is called "
792 "outside of WSGI request processing");
793 }
794
795 n = PyTuple_GET_SIZE(args);
796
797 if (n < 2 || n > 3) {

--- 48 unchanged lines hidden (view full) ---

846 fields_size += PyUnicode_GET_LENGTH(string);
847
848 } else {
849 return PyErr_Format(PyExc_TypeError,
850 "header #%d value is not a string", (int) i);
851 }
852 }
853
836 return PyErr_Format(PyExc_RuntimeError,
837 "start_response() is called "
838 "outside of WSGI request processing");
839 }
840
841 n = PyTuple_GET_SIZE(args);
842
843 if (n < 2 || n > 3) {

--- 48 unchanged lines hidden (view full) ---

892 fields_size += PyUnicode_GET_LENGTH(string);
893
894 } else {
895 return PyErr_Format(PyExc_TypeError,
896 "header #%d value is not a string", (int) i);
897 }
898 }
899
854 ctx->content_length = -1;
900 pctx->content_length = -1;
855
856 string = PyTuple_GET_ITEM(args, 0);
857 rc = nxt_python_str_buf(string, &status_str, &status_len, &status_bytes);
858 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
859 return PyErr_Format(PyExc_TypeError, "status is not a string");
860 }
861
862 space_ptr = memchr(status_str, ' ', status_len);

--- 9 unchanged lines hidden (view full) ---

872 Py_XDECREF(status_bytes);
873
874 /*
875 * PEP 3333:
876 *
877 * ... applications can replace their originally intended output with error
878 * output, up until the last possible moment.
879 */
901
902 string = PyTuple_GET_ITEM(args, 0);
903 rc = nxt_python_str_buf(string, &status_str, &status_len, &status_bytes);
904 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
905 return PyErr_Format(PyExc_TypeError, "status is not a string");
906 }
907
908 space_ptr = memchr(status_str, ' ', status_len);

--- 9 unchanged lines hidden (view full) ---

918 Py_XDECREF(status_bytes);
919
920 /*
921 * PEP 3333:
922 *
923 * ... applications can replace their originally intended output with error
924 * output, up until the last possible moment.
925 */
880 rc = nxt_unit_response_init(ctx->req, status, fields_count, fields_size);
926 rc = nxt_unit_response_init(pctx->req, status, fields_count, fields_size);
881 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
882 return PyErr_Format(PyExc_RuntimeError,
883 "failed to allocate response object");
884 }
885
886 for (i = 0; i < fields_count; i++) {
887 tuple = PyList_GET_ITEM(headers, i);
888
927 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
928 return PyErr_Format(PyExc_RuntimeError,
929 "failed to allocate response object");
930 }
931
932 for (i = 0; i < fields_count; i++) {
933 tuple = PyList_GET_ITEM(headers, i);
934
889 rc = nxt_python_response_add_field(ctx, PyTuple_GET_ITEM(tuple, 0),
935 rc = nxt_python_response_add_field(pctx, PyTuple_GET_ITEM(tuple, 0),
890 PyTuple_GET_ITEM(tuple, 1), i);
891 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
892 return PyErr_Format(PyExc_RuntimeError,
893 "failed to add header #%d", (int) i);
894 }
895 }
896
897 /*

--- 4 unchanged lines hidden (view full) ---

902 * to transmit only after the first iteration of the application return
903 * value that yields a non-empty bytestring, or upon the application's
904 * first invocation of the write() callable. In other words, response
905 * headers must not be sent until there is actual body data available, or
906 * until the application's returned iterable is exhausted. (The only
907 * possible exception to this rule is if the response headers explicitly
908 * include a Content-Length of zero.)
909 */
936 PyTuple_GET_ITEM(tuple, 1), i);
937 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
938 return PyErr_Format(PyExc_RuntimeError,
939 "failed to add header #%d", (int) i);
940 }
941 }
942
943 /*

--- 4 unchanged lines hidden (view full) ---

948 * to transmit only after the first iteration of the application return
949 * value that yields a non-empty bytestring, or upon the application's
950 * first invocation of the write() callable. In other words, response
951 * headers must not be sent until there is actual body data available, or
952 * until the application's returned iterable is exhausted. (The only
953 * possible exception to this rule is if the response headers explicitly
954 * include a Content-Length of zero.)
955 */
910 if (ctx->content_length == 0) {
911 rc = nxt_unit_response_send(ctx->req);
956 if (pctx->content_length == 0) {
957 rc = nxt_unit_response_send(pctx->req);
912 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
913 return PyErr_Format(PyExc_RuntimeError,
914 "failed to send response headers");
915 }
916 }
917
958 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
959 return PyErr_Format(PyExc_RuntimeError,
960 "failed to send response headers");
961 }
962 }
963
918 Py_INCREF(nxt_py_write_obj);
919 return nxt_py_write_obj;
964 Py_INCREF(pctx->write);
965 return pctx->write;
920}
921
922
923static int
966}
967
968
969static int
924nxt_python_response_add_field(nxt_python_run_ctx_t *ctx, PyObject *name,
970nxt_python_response_add_field(nxt_python_ctx_t *pctx, PyObject *name,
925 PyObject *value, int i)
926{
927 int rc;
928 char *name_str, *value_str;
929 uint32_t name_length, value_length;
930 PyObject *name_bytes, *value_bytes;
931 nxt_off_t content_length;
932

--- 5 unchanged lines hidden (view full) ---

938 goto fail;
939 }
940
941 rc = nxt_python_str_buf(value, &value_str, &value_length, &value_bytes);
942 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
943 goto fail;
944 }
945
971 PyObject *value, int i)
972{
973 int rc;
974 char *name_str, *value_str;
975 uint32_t name_length, value_length;
976 PyObject *name_bytes, *value_bytes;
977 nxt_off_t content_length;
978

--- 5 unchanged lines hidden (view full) ---

984 goto fail;
985 }
986
987 rc = nxt_python_str_buf(value, &value_str, &value_length, &value_bytes);
988 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
989 goto fail;
990 }
991
946 rc = nxt_unit_response_add_field(ctx->req, name_str, name_length,
992 rc = nxt_unit_response_add_field(pctx->req, name_str, name_length,
947 value_str, value_length);
948 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
949 goto fail;
950 }
951
993 value_str, value_length);
994 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
995 goto fail;
996 }
997
952 if (ctx->req->response->fields[i].hash == NXT_UNIT_HASH_CONTENT_LENGTH) {
998 if (pctx->req->response->fields[i].hash == NXT_UNIT_HASH_CONTENT_LENGTH) {
953 content_length = nxt_off_t_parse((u_char *) value_str, value_length);
954 if (nxt_slow_path(content_length < 0)) {
999 content_length = nxt_off_t_parse((u_char *) value_str, value_length);
1000 if (nxt_slow_path(content_length < 0)) {
955 nxt_unit_req_error(ctx->req, "failed to parse Content-Length "
1001 nxt_unit_req_error(pctx->req, "failed to parse Content-Length "
956 "value %.*s", (int) value_length, value_str);
957
958 } else {
1002 "value %.*s", (int) value_length, value_str);
1003
1004 } else {
959 ctx->content_length = content_length;
1005 pctx->content_length = content_length;
960 }
961 }
962
963fail:
964
965 Py_XDECREF(name_bytes);
966 Py_XDECREF(value_bytes);
967

--- 28 unchanged lines hidden (view full) ---

996{
997 int rc;
998
999 if (nxt_fast_path(!PyBytes_Check(str))) {
1000 return PyErr_Format(PyExc_TypeError, "the argument is not a %s",
1001 NXT_PYTHON_BYTES_TYPE);
1002 }
1003
1006 }
1007 }
1008
1009fail:
1010
1011 Py_XDECREF(name_bytes);
1012 Py_XDECREF(value_bytes);
1013

--- 28 unchanged lines hidden (view full) ---

1042{
1043 int rc;
1044
1045 if (nxt_fast_path(!PyBytes_Check(str))) {
1046 return PyErr_Format(PyExc_TypeError, "the argument is not a %s",
1047 NXT_PYTHON_BYTES_TYPE);
1048 }
1049
1004 rc = nxt_python_write(nxt_python_run_ctx, str);
1050 rc = nxt_python_write((nxt_python_ctx_t *) self, str);
1005 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
1006 return PyErr_Format(PyExc_RuntimeError,
1007 "failed to write response value");
1008 }
1009
1010 Py_RETURN_NONE;
1011}
1012
1013
1014static void
1051 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
1052 return PyErr_Format(PyExc_RuntimeError,
1053 "failed to write response value");
1054 }
1055
1056 Py_RETURN_NONE;
1057}
1058
1059
1060static void
1015nxt_py_input_dealloc(nxt_py_input_t *self)
1061nxt_py_input_dealloc(nxt_python_ctx_t *self)
1016{
1017 PyObject_Del(self);
1018}
1019
1020
1021static PyObject *
1062{
1063 PyObject_Del(self);
1064}
1065
1066
1067static PyObject *
1022nxt_py_input_read(nxt_py_input_t *self, PyObject *args)
1068nxt_py_input_read(nxt_python_ctx_t *pctx, PyObject *args)
1023{
1069{
1024 char *buf;
1025 PyObject *content, *obj;
1026 Py_ssize_t size, n;
1027 nxt_python_run_ctx_t *ctx;
1070 char *buf;
1071 PyObject *content, *obj;
1072 Py_ssize_t size, n;
1028
1073
1029 ctx = nxt_python_run_ctx;
1030 if (nxt_slow_path(ctx == NULL)) {
1074 if (nxt_slow_path(pctx->req == NULL)) {
1031 return PyErr_Format(PyExc_RuntimeError,
1032 "wsgi.input.read() is called "
1033 "outside of WSGI request processing");
1034 }
1035
1075 return PyErr_Format(PyExc_RuntimeError,
1076 "wsgi.input.read() is called "
1077 "outside of WSGI request processing");
1078 }
1079
1036 size = ctx->req->content_length;
1080 size = pctx->req->content_length;
1037
1038 n = PyTuple_GET_SIZE(args);
1039
1040 if (n > 0) {
1041 if (n != 1) {
1042 return PyErr_Format(PyExc_TypeError, "invalid number of arguments");
1043 }
1044

--- 7 unchanged lines hidden (view full) ---

1052 }
1053
1054 if (size != -1) {
1055 return PyErr_Format(PyExc_ValueError,
1056 "the read body size cannot be zero or less");
1057 }
1058 }
1059
1081
1082 n = PyTuple_GET_SIZE(args);
1083
1084 if (n > 0) {
1085 if (n != 1) {
1086 return PyErr_Format(PyExc_TypeError, "invalid number of arguments");
1087 }
1088

--- 7 unchanged lines hidden (view full) ---

1096 }
1097
1098 if (size != -1) {
1099 return PyErr_Format(PyExc_ValueError,
1100 "the read body size cannot be zero or less");
1101 }
1102 }
1103
1060 if (size == -1 || size > (Py_ssize_t) ctx->req->content_length) {
1061 size = ctx->req->content_length;
1104 if (size == -1 || size > (Py_ssize_t) pctx->req->content_length) {
1105 size = pctx->req->content_length;
1062 }
1063 }
1064
1065 content = PyBytes_FromStringAndSize(NULL, size);
1066 if (nxt_slow_path(content == NULL)) {
1067 return NULL;
1068 }
1069
1070 buf = PyBytes_AS_STRING(content);
1071
1106 }
1107 }
1108
1109 content = PyBytes_FromStringAndSize(NULL, size);
1110 if (nxt_slow_path(content == NULL)) {
1111 return NULL;
1112 }
1113
1114 buf = PyBytes_AS_STRING(content);
1115
1072 size = nxt_unit_request_read(ctx->req, buf, size);
1116 size = nxt_unit_request_read(pctx->req, buf, size);
1073
1074 return content;
1075}
1076
1077
1078static PyObject *
1117
1118 return content;
1119}
1120
1121
1122static PyObject *
1079nxt_py_input_readline(nxt_py_input_t *self, PyObject *args)
1123nxt_py_input_readline(nxt_python_ctx_t *pctx, PyObject *args)
1080{
1124{
1081 ssize_t ssize;
1082 PyObject *obj;
1083 Py_ssize_t n;
1084 nxt_python_run_ctx_t *ctx;
1125 ssize_t ssize;
1126 PyObject *obj;
1127 Py_ssize_t n;
1085
1128
1086 ctx = nxt_python_run_ctx;
1087 if (nxt_slow_path(ctx == NULL)) {
1129 if (nxt_slow_path(pctx->req == NULL)) {
1088 return PyErr_Format(PyExc_RuntimeError,
1089 "wsgi.input.readline() is called "
1090 "outside of WSGI request processing");
1091 }
1092
1093 n = PyTuple_GET_SIZE(args);
1094
1095 if (n > 0) {
1096 if (n != 1) {
1097 return PyErr_Format(PyExc_TypeError, "invalid number of arguments");
1098 }
1099
1100 obj = PyTuple_GET_ITEM(args, 0);
1101
1102 ssize = PyNumber_AsSsize_t(obj, PyExc_OverflowError);
1103
1104 if (nxt_fast_path(ssize > 0)) {
1130 return PyErr_Format(PyExc_RuntimeError,
1131 "wsgi.input.readline() is called "
1132 "outside of WSGI request processing");
1133 }
1134
1135 n = PyTuple_GET_SIZE(args);
1136
1137 if (n > 0) {
1138 if (n != 1) {
1139 return PyErr_Format(PyExc_TypeError, "invalid number of arguments");
1140 }
1141
1142 obj = PyTuple_GET_ITEM(args, 0);
1143
1144 ssize = PyNumber_AsSsize_t(obj, PyExc_OverflowError);
1145
1146 if (nxt_fast_path(ssize > 0)) {
1105 return nxt_py_input_getline(ctx, ssize);
1147 return nxt_py_input_getline(pctx, ssize);
1106 }
1107
1108 if (ssize == 0) {
1109 return PyBytes_FromStringAndSize("", 0);
1110 }
1111
1112 if (ssize != -1) {
1113 return PyErr_Format(PyExc_ValueError,
1114 "the read line size cannot be zero or less");
1115 }
1116
1117 if (PyErr_Occurred()) {
1118 return NULL;
1119 }
1120 }
1121
1148 }
1149
1150 if (ssize == 0) {
1151 return PyBytes_FromStringAndSize("", 0);
1152 }
1153
1154 if (ssize != -1) {
1155 return PyErr_Format(PyExc_ValueError,
1156 "the read line size cannot be zero or less");
1157 }
1158
1159 if (PyErr_Occurred()) {
1160 return NULL;
1161 }
1162 }
1163
1122 return nxt_py_input_getline(ctx, SSIZE_MAX);
1164 return nxt_py_input_getline(pctx, SSIZE_MAX);
1123}
1124
1125
1126static PyObject *
1165}
1166
1167
1168static PyObject *
1127nxt_py_input_getline(nxt_python_run_ctx_t *ctx, size_t size)
1169nxt_py_input_getline(nxt_python_ctx_t *pctx, size_t size)
1128{
1129 void *buf;
1130 ssize_t res;
1131 PyObject *content;
1132
1170{
1171 void *buf;
1172 ssize_t res;
1173 PyObject *content;
1174
1133 res = nxt_unit_request_readline_size(ctx->req, size);
1175 res = nxt_unit_request_readline_size(pctx->req, size);
1134 if (nxt_slow_path(res < 0)) {
1135 return NULL;
1136 }
1137
1138 if (res == 0) {
1139 return PyBytes_FromStringAndSize("", 0);
1140 }
1141
1142 content = PyBytes_FromStringAndSize(NULL, res);
1143 if (nxt_slow_path(content == NULL)) {
1144 return NULL;
1145 }
1146
1147 buf = PyBytes_AS_STRING(content);
1148
1176 if (nxt_slow_path(res < 0)) {
1177 return NULL;
1178 }
1179
1180 if (res == 0) {
1181 return PyBytes_FromStringAndSize("", 0);
1182 }
1183
1184 content = PyBytes_FromStringAndSize(NULL, res);
1185 if (nxt_slow_path(content == NULL)) {
1186 return NULL;
1187 }
1188
1189 buf = PyBytes_AS_STRING(content);
1190
1149 res = nxt_unit_request_read(ctx->req, buf, res);
1191 res = nxt_unit_request_read(pctx->req, buf, res);
1150
1151 return content;
1152}
1153
1154
1155static PyObject *
1192
1193 return content;
1194}
1195
1196
1197static PyObject *
1156nxt_py_input_readlines(nxt_py_input_t *self, PyObject *args)
1198nxt_py_input_readlines(nxt_python_ctx_t *pctx, PyObject *args)
1157{
1199{
1158 PyObject *res;
1159 nxt_python_run_ctx_t *ctx;
1200 PyObject *res;
1160
1201
1161 ctx = nxt_python_run_ctx;
1162 if (nxt_slow_path(ctx == NULL)) {
1202 if (nxt_slow_path(pctx->req == NULL)) {
1163 return PyErr_Format(PyExc_RuntimeError,
1164 "wsgi.input.readlines() is called "
1165 "outside of WSGI request processing");
1166 }
1167
1168 res = PyList_New(0);
1169 if (nxt_slow_path(res == NULL)) {
1170 return NULL;
1171 }
1172
1173 for ( ;; ) {
1203 return PyErr_Format(PyExc_RuntimeError,
1204 "wsgi.input.readlines() is called "
1205 "outside of WSGI request processing");
1206 }
1207
1208 res = PyList_New(0);
1209 if (nxt_slow_path(res == NULL)) {
1210 return NULL;
1211 }
1212
1213 for ( ;; ) {
1174 PyObject *line = nxt_py_input_getline(ctx, SSIZE_MAX);
1214 PyObject *line = nxt_py_input_getline(pctx, SSIZE_MAX);
1175 if (nxt_slow_path(line == NULL)) {
1176 Py_DECREF(res);
1177 return NULL;
1178 }
1179
1180 if (PyBytes_GET_SIZE(line) == 0) {
1181 Py_DECREF(line);
1182 return res;

--- 13 unchanged lines hidden (view full) ---

1196 Py_INCREF(self);
1197 return self;
1198}
1199
1200
1201static PyObject *
1202nxt_py_input_next(PyObject *self)
1203{
1215 if (nxt_slow_path(line == NULL)) {
1216 Py_DECREF(res);
1217 return NULL;
1218 }
1219
1220 if (PyBytes_GET_SIZE(line) == 0) {
1221 Py_DECREF(line);
1222 return res;

--- 13 unchanged lines hidden (view full) ---

1236 Py_INCREF(self);
1237 return self;
1238}
1239
1240
1241static PyObject *
1242nxt_py_input_next(PyObject *self)
1243{
1204 PyObject *line;
1205 nxt_python_run_ctx_t *ctx;
1244 PyObject *line;
1245 nxt_python_ctx_t *pctx;
1206
1246
1207 ctx = nxt_python_run_ctx;
1208 if (nxt_slow_path(ctx == NULL)) {
1247 pctx = (nxt_python_ctx_t *) self;
1248 if (nxt_slow_path(pctx->req == NULL)) {
1209 return PyErr_Format(PyExc_RuntimeError,
1210 "wsgi.input.next() is called "
1211 "outside of WSGI request processing");
1212 }
1213
1249 return PyErr_Format(PyExc_RuntimeError,
1250 "wsgi.input.next() is called "
1251 "outside of WSGI request processing");
1252 }
1253
1214 line = nxt_py_input_getline(ctx, SSIZE_MAX);
1254 line = nxt_py_input_getline(pctx, SSIZE_MAX);
1215 if (nxt_slow_path(line == NULL)) {
1216 return NULL;
1217 }
1218
1219 if (PyBytes_GET_SIZE(line) == 0) {
1220 Py_DECREF(line);
1221 PyErr_SetNone(PyExc_StopIteration);
1222 return NULL;
1223 }
1224
1225 return line;
1226}
1227
1228
1229static int
1255 if (nxt_slow_path(line == NULL)) {
1256 return NULL;
1257 }
1258
1259 if (PyBytes_GET_SIZE(line) == 0) {
1260 Py_DECREF(line);
1261 PyErr_SetNone(PyExc_StopIteration);
1262 return NULL;
1263 }
1264
1265 return line;
1266}
1267
1268
1269static int
1230nxt_python_write(nxt_python_run_ctx_t *ctx, PyObject *bytes)
1270nxt_python_write(nxt_python_ctx_t *pctx, PyObject *bytes)
1231{
1232 int rc;
1233 char *str_buf;
1234 uint32_t str_length;
1235
1236 str_buf = PyBytes_AS_STRING(bytes);
1237 str_length = PyBytes_GET_SIZE(bytes);
1238

--- 4 unchanged lines hidden (view full) ---

1243 /*
1244 * PEP 3333:
1245 *
1246 * If the application supplies a Content-Length header, the server should
1247 * not transmit more bytes to the client than the header allows, and should
1248 * stop iterating over the response when enough data has been sent, or raise
1249 * an error if the application tries to write() past that point.
1250 */
1271{
1272 int rc;
1273 char *str_buf;
1274 uint32_t str_length;
1275
1276 str_buf = PyBytes_AS_STRING(bytes);
1277 str_length = PyBytes_GET_SIZE(bytes);
1278

--- 4 unchanged lines hidden (view full) ---

1283 /*
1284 * PEP 3333:
1285 *
1286 * If the application supplies a Content-Length header, the server should
1287 * not transmit more bytes to the client than the header allows, and should
1288 * stop iterating over the response when enough data has been sent, or raise
1289 * an error if the application tries to write() past that point.
1290 */
1251 if (nxt_slow_path(str_length > ctx->content_length - ctx->bytes_sent)) {
1252 nxt_unit_req_error(ctx->req, "content length %"PRIu64" exceeded",
1253 ctx->content_length);
1291 if (nxt_slow_path(str_length > pctx->content_length - pctx->bytes_sent)) {
1292 nxt_unit_req_error(pctx->req, "content length %"PRIu64" exceeded",
1293 pctx->content_length);
1254
1255 return NXT_UNIT_ERROR;
1256 }
1257
1294
1295 return NXT_UNIT_ERROR;
1296 }
1297
1258 rc = nxt_unit_response_write(ctx->req, str_buf, str_length);
1298 rc = nxt_unit_response_write(pctx->req, str_buf, str_length);
1259 if (nxt_fast_path(rc == NXT_UNIT_OK)) {
1299 if (nxt_fast_path(rc == NXT_UNIT_OK)) {
1260 ctx->bytes_sent += str_length;
1300 pctx->bytes_sent += str_length;
1261 }
1262
1263 return rc;
1264}
1301 }
1302
1303 return rc;
1304}