Line data Source code
1 :
2 : /*
3 : * Copyright (C) Xiaozhe Wang (chaoslawful)
4 : * Copyright (C) Yichun Zhang (agentzh)
5 : */
6 :
7 :
8 : #ifndef DDEBUG
9 : #define DDEBUG 0
10 : #endif
11 : #include "ddebug.h"
12 :
13 :
14 : #include "nginx.h"
15 : #include "ngx_http_lua_directive.h"
16 : #include "ngx_http_lua_util.h"
17 : #include "ngx_http_lua_exception.h"
18 : #include "ngx_http_lua_pcrefix.h"
19 : #include "ngx_http_lua_regex.h"
20 : #include "ngx_http_lua_args.h"
21 : #include "ngx_http_lua_uri.h"
22 : #include "ngx_http_lua_req_body.h"
23 : #include "ngx_http_lua_headers.h"
24 : #include "ngx_http_lua_output.h"
25 : #include "ngx_http_lua_time.h"
26 : #include "ngx_http_lua_control.h"
27 : #include "ngx_http_lua_ndk.h"
28 : #include "ngx_http_lua_subrequest.h"
29 : #include "ngx_http_lua_log.h"
30 : #include "ngx_http_lua_variable.h"
31 : #include "ngx_http_lua_string.h"
32 : #include "ngx_http_lua_misc.h"
33 : #include "ngx_http_lua_consts.h"
34 : #include "ngx_http_lua_req_method.h"
35 : #include "ngx_http_lua_shdict.h"
36 : #include "ngx_http_lua_coroutine.h"
37 : #include "ngx_http_lua_socket_tcp.h"
38 : #include "ngx_http_lua_socket_udp.h"
39 : #include "ngx_http_lua_sleep.h"
40 : #include "ngx_http_lua_setby.h"
41 : #include "ngx_http_lua_headerfilterby.h"
42 : #include "ngx_http_lua_bodyfilterby.h"
43 : #include "ngx_http_lua_logby.h"
44 : #include "ngx_http_lua_phase.h"
45 : #include "ngx_http_lua_probe.h"
46 : #include "ngx_http_lua_uthread.h"
47 : #include "ngx_http_lua_contentby.h"
48 : #include "ngx_http_lua_timer.h"
49 : #include "ngx_http_lua_config.h"
50 : #include "ngx_http_lua_worker.h"
51 : #include "ngx_http_lua_socket_tcp.h"
52 : #include "ngx_http_lua_ssl_certby.h"
53 : #include "ngx_http_lua_ssl.h"
54 : #include "ngx_http_lua_log_ringbuf.h"
55 :
56 :
57 : #if 1
58 : #undef ngx_http_lua_probe_info
59 : #define ngx_http_lua_probe_info(msg)
60 : #endif
61 :
62 :
63 : #ifndef NGX_HTTP_LUA_BT_DEPTH
64 : #define NGX_HTTP_LUA_BT_DEPTH 22
65 : #endif
66 :
67 :
68 : #ifndef NGX_HTTP_LUA_BT_MAX_COROS
69 : #define NGX_HTTP_LUA_BT_MAX_COROS 5
70 : #endif
71 :
72 :
73 : char ngx_http_lua_code_cache_key;
74 : char ngx_http_lua_regex_cache_key;
75 : char ngx_http_lua_socket_pool_key;
76 : char ngx_http_lua_coroutines_key;
77 : char ngx_http_lua_headers_metatable_key;
78 :
79 :
80 : ngx_uint_t ngx_http_lua_location_hash = 0;
81 : ngx_uint_t ngx_http_lua_content_length_hash = 0;
82 :
83 :
84 : static ngx_int_t ngx_http_lua_send_http10_headers(ngx_http_request_t *r,
85 : ngx_http_lua_ctx_t *ctx);
86 : static void ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log);
87 : static void ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle,
88 : ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log);
89 : static void ngx_http_lua_set_path(ngx_cycle_t *cycle, lua_State *L, int tab_idx,
90 : const char *fieldname, const char *path, const char *default_path,
91 : ngx_log_t *log);
92 : static ngx_int_t ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r,
93 : ngx_http_lua_ctx_t *ctx);
94 : static ngx_int_t ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r,
95 : ngx_http_lua_ctx_t *ctx);
96 : static ngx_int_t ngx_http_lua_handle_rewrite_jump(lua_State *L,
97 : ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx);
98 : static int ngx_http_lua_thread_traceback(lua_State *L, lua_State *co,
99 : ngx_http_lua_co_ctx_t *coctx);
100 : static void ngx_http_lua_inject_ngx_api(lua_State *L,
101 : ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log);
102 : static void ngx_http_lua_inject_arg_api(lua_State *L);
103 : static int ngx_http_lua_param_get(lua_State *L);
104 : static int ngx_http_lua_param_set(lua_State *L);
105 : static ngx_int_t ngx_http_lua_output_filter(ngx_http_request_t *r,
106 : ngx_chain_t *in);
107 : static ngx_int_t ngx_http_lua_send_special(ngx_http_request_t *r,
108 : ngx_uint_t flags);
109 : static void ngx_http_lua_finalize_threads(ngx_http_request_t *r,
110 : ngx_http_lua_ctx_t *ctx, lua_State *L);
111 : static ngx_int_t ngx_http_lua_post_zombie_thread(ngx_http_request_t *r,
112 : ngx_http_lua_co_ctx_t *parent, ngx_http_lua_co_ctx_t *thread);
113 : static void ngx_http_lua_cleanup_zombie_child_uthreads(ngx_http_request_t *r,
114 : lua_State *L, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx);
115 : static ngx_int_t ngx_http_lua_on_abort_resume(ngx_http_request_t *r);
116 : static void ngx_http_lua_close_fake_request(ngx_http_request_t *r);
117 : static ngx_int_t ngx_http_lua_flush_pending_output(ngx_http_request_t *r,
118 : ngx_http_lua_ctx_t *ctx);
119 : static ngx_int_t
120 : ngx_http_lua_process_flushing_coroutines(ngx_http_request_t *r,
121 : ngx_http_lua_ctx_t *ctx);
122 : static lua_State *ngx_http_lua_new_state(lua_State *parent_vm,
123 : ngx_cycle_t *cycle, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log);
124 : static int ngx_http_lua_get_raw_phase_context(lua_State *L);
125 :
126 :
127 : #ifndef LUA_PATH_SEP
128 : #define LUA_PATH_SEP ";"
129 : #endif
130 :
131 : #define AUX_MARK "\1"
132 :
133 :
134 : static void
135 0 : ngx_http_lua_set_path(ngx_cycle_t *cycle, lua_State *L, int tab_idx,
136 : const char *fieldname, const char *path, const char *default_path,
137 : ngx_log_t *log)
138 : {
139 : const char *tmp_path;
140 : const char *prefix;
141 :
142 : /* XXX here we use some hack to simplify string manipulation */
143 0 : tmp_path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,
144 : LUA_PATH_SEP AUX_MARK LUA_PATH_SEP);
145 :
146 0 : lua_pushlstring(L, (char *) cycle->prefix.data, cycle->prefix.len);
147 0 : prefix = lua_tostring(L, -1);
148 0 : tmp_path = luaL_gsub(L, tmp_path, "$prefix", prefix);
149 0 : tmp_path = luaL_gsub(L, tmp_path, "${prefix}", prefix);
150 0 : lua_pop(L, 3);
151 :
152 : dd("tmp_path path: %s", tmp_path);
153 :
154 : #if (NGX_DEBUG)
155 0 : tmp_path =
156 : #else
157 : (void)
158 : #endif
159 : luaL_gsub(L, tmp_path, AUX_MARK, default_path);
160 :
161 : #if (NGX_DEBUG)
162 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
163 : "lua setting lua package.%s to \"%s\"", fieldname, tmp_path);
164 : #endif
165 :
166 0 : lua_remove(L, -2);
167 :
168 : /* fix negative index as there's new data on stack */
169 0 : tab_idx = (tab_idx < 0) ? (tab_idx - 1) : tab_idx;
170 0 : lua_setfield(L, tab_idx, fieldname);
171 0 : }
172 :
173 :
174 : /**
175 : * Create new table and set _G field to itself.
176 : *
177 : * After:
178 : * | new table | <- top
179 : * | ... |
180 : * */
181 : void
182 1 : ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec)
183 : {
184 1 : lua_createtable(L, narr, nrec + 1);
185 1 : lua_pushvalue(L, -1);
186 1 : lua_setfield(L, -2, "_G");
187 1 : }
188 :
189 :
190 : static lua_State *
191 18 : ngx_http_lua_new_state(lua_State *parent_vm, ngx_cycle_t *cycle,
192 : ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log)
193 : {
194 : lua_State *L;
195 : const char *old_path;
196 : const char *new_path;
197 : size_t old_path_len;
198 : const char *old_cpath;
199 : const char *new_cpath;
200 : size_t old_cpath_len;
201 :
202 18 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "lua creating new vm state");
203 :
204 18 : L = luaL_newstate();
205 18 : if (L == NULL) {
206 0 : return NULL;
207 : }
208 :
209 18 : luaL_openlibs(L);
210 :
211 18 : lua_getglobal(L, "package");
212 :
213 18 : if (!lua_istable(L, -1)) {
214 0 : ngx_log_error(NGX_LOG_EMERG, log, 0,
215 : "the \"package\" table does not exist");
216 0 : return NULL;
217 : }
218 :
219 18 : if (parent_vm) {
220 0 : lua_getglobal(parent_vm, "package");
221 0 : lua_getfield(parent_vm, -1, "path");
222 0 : old_path = lua_tolstring(parent_vm, -1, &old_path_len);
223 0 : lua_pop(parent_vm, 1);
224 :
225 0 : lua_pushlstring(L, old_path, old_path_len);
226 0 : lua_setfield(L, -2, "path");
227 :
228 0 : lua_getfield(parent_vm, -1, "cpath");
229 0 : old_path = lua_tolstring(parent_vm, -1, &old_path_len);
230 0 : lua_pop(parent_vm, 2);
231 :
232 0 : lua_pushlstring(L, old_path, old_path_len);
233 0 : lua_setfield(L, -2, "cpath");
234 :
235 : } else {
236 : #ifdef LUA_DEFAULT_PATH
237 : # define LUA_DEFAULT_PATH_LEN (sizeof(LUA_DEFAULT_PATH) - 1)
238 18 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
239 : "lua prepending default package.path with %s",
240 : LUA_DEFAULT_PATH);
241 :
242 18 : lua_pushliteral(L, LUA_DEFAULT_PATH ";"); /* package default */
243 18 : lua_getfield(L, -2, "path"); /* package default old */
244 18 : old_path = lua_tolstring(L, -1, &old_path_len);
245 18 : lua_concat(L, 2); /* package new */
246 18 : lua_setfield(L, -2, "path"); /* package */
247 : #endif
248 :
249 : #ifdef LUA_DEFAULT_CPATH
250 : # define LUA_DEFAULT_CPATH_LEN (sizeof(LUA_DEFAULT_CPATH) - 1)
251 18 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
252 : "lua prepending default package.cpath with %s",
253 : LUA_DEFAULT_CPATH);
254 :
255 18 : lua_pushliteral(L, LUA_DEFAULT_CPATH ";"); /* package default */
256 18 : lua_getfield(L, -2, "cpath"); /* package default old */
257 18 : old_cpath = lua_tolstring(L, -1, &old_cpath_len);
258 18 : lua_concat(L, 2); /* package new */
259 18 : lua_setfield(L, -2, "cpath"); /* package */
260 : #endif
261 :
262 18 : if (lmcf->lua_path.len != 0) {
263 0 : lua_getfield(L, -1, "path"); /* get original package.path */
264 0 : old_path = lua_tolstring(L, -1, &old_path_len);
265 :
266 : dd("old path: %s", old_path);
267 :
268 0 : lua_pushlstring(L, (char *) lmcf->lua_path.data,
269 : lmcf->lua_path.len);
270 0 : new_path = lua_tostring(L, -1);
271 :
272 0 : ngx_http_lua_set_path(cycle, L, -3, "path", new_path, old_path,
273 : log);
274 :
275 0 : lua_pop(L, 2);
276 : }
277 :
278 18 : if (lmcf->lua_cpath.len != 0) {
279 0 : lua_getfield(L, -1, "cpath"); /* get original package.cpath */
280 0 : old_cpath = lua_tolstring(L, -1, &old_cpath_len);
281 :
282 : dd("old cpath: %s", old_cpath);
283 :
284 0 : lua_pushlstring(L, (char *) lmcf->lua_cpath.data,
285 : lmcf->lua_cpath.len);
286 0 : new_cpath = lua_tostring(L, -1);
287 :
288 0 : ngx_http_lua_set_path(cycle, L, -3, "cpath", new_cpath, old_cpath,
289 : log);
290 :
291 :
292 0 : lua_pop(L, 2);
293 : }
294 : }
295 :
296 18 : lua_pop(L, 1); /* remove the "package" table */
297 :
298 18 : ngx_http_lua_init_registry(L, log);
299 18 : ngx_http_lua_init_globals(L, cycle, lmcf, log);
300 :
301 18 : return L;
302 : }
303 :
304 :
305 : lua_State *
306 1 : ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref)
307 : {
308 : int base;
309 : lua_State *co;
310 :
311 1 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
312 : "lua creating new thread");
313 :
314 1 : base = lua_gettop(L);
315 :
316 1 : lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
317 1 : lua_rawget(L, LUA_REGISTRYINDEX);
318 :
319 1 : co = lua_newthread(L);
320 :
321 : /* {{{ inherit coroutine's globals to main thread's globals table
322 : * for print() function will try to find tostring() in current
323 : * globals table.
324 : */
325 : /* new globals table for coroutine */
326 1 : ngx_http_lua_create_new_globals_table(co, 0, 0);
327 :
328 1 : lua_createtable(co, 0, 1);
329 1 : ngx_http_lua_get_globals_table(co);
330 1 : lua_setfield(co, -2, "__index");
331 1 : lua_setmetatable(co, -2);
332 :
333 1 : ngx_http_lua_set_globals_table(co);
334 : /* }}} */
335 :
336 1 : *ref = luaL_ref(L, -2);
337 :
338 1 : if (*ref == LUA_NOREF) {
339 0 : lua_settop(L, base); /* restore main thread stack */
340 0 : return NULL;
341 : }
342 :
343 1 : lua_settop(L, base);
344 1 : return co;
345 : }
346 :
347 :
348 : void
349 1 : ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L,
350 : ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx)
351 : {
352 1 : if (coctx->co_ref == LUA_NOREF) {
353 0 : return;
354 : }
355 :
356 1 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
357 : "lua deleting light thread");
358 :
359 1 : lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
360 1 : lua_rawget(L, LUA_REGISTRYINDEX);
361 :
362 : ngx_http_lua_probe_thread_delete(r, coctx->co, ctx);
363 :
364 1 : luaL_unref(L, -1, coctx->co_ref);
365 1 : coctx->co_ref = LUA_NOREF;
366 1 : coctx->co_status = NGX_HTTP_LUA_CO_DEAD;
367 :
368 1 : lua_pop(L, 1);
369 : }
370 :
371 :
372 : u_char *
373 0 : ngx_http_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len)
374 : {
375 : u_char *p;
376 : ngx_str_t dst;
377 :
378 0 : dst.data = ngx_palloc(pool, len + 1);
379 0 : if (dst.data == NULL) {
380 0 : return NULL;
381 : }
382 :
383 0 : dst.len = len;
384 :
385 0 : p = ngx_copy(dst.data, src, len);
386 0 : *p = '\0';
387 :
388 0 : if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->prefix, &dst)
389 : != NGX_OK)
390 : {
391 0 : return NULL;
392 : }
393 :
394 0 : return dst.data;
395 : }
396 :
397 :
398 : ngx_int_t
399 2 : ngx_http_lua_send_header_if_needed(ngx_http_request_t *r,
400 : ngx_http_lua_ctx_t *ctx)
401 : {
402 : ngx_int_t rc;
403 :
404 : dd("send header if needed: %d", r->header_sent || ctx->header_sent);
405 :
406 2 : if (!r->header_sent && !ctx->header_sent) {
407 1 : if (r->headers_out.status == 0) {
408 1 : r->headers_out.status = NGX_HTTP_OK;
409 : }
410 :
411 1 : if (!ctx->headers_set && ngx_http_lua_set_content_type(r) != NGX_OK) {
412 0 : return NGX_ERROR;
413 : }
414 :
415 1 : if (!ctx->headers_set) {
416 1 : ngx_http_clear_content_length(r);
417 1 : ngx_http_clear_accept_ranges(r);
418 : }
419 :
420 1 : if (!ctx->buffering) {
421 : dd("sending headers");
422 1 : rc = ngx_http_send_header(r);
423 1 : ctx->header_sent = 1;
424 1 : return rc;
425 : }
426 : }
427 :
428 1 : return NGX_OK;
429 : }
430 :
431 :
432 : ngx_int_t
433 2 : ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx,
434 : ngx_chain_t *in)
435 : {
436 : ngx_int_t rc;
437 : ngx_chain_t *cl;
438 : ngx_chain_t **ll;
439 : ngx_http_lua_loc_conf_t *llcf;
440 :
441 : #if 1
442 2 : if (ctx->acquired_raw_req_socket || ctx->eof) {
443 : dd("ctx->eof already set or raw req socket already acquired");
444 0 : return NGX_OK;
445 : }
446 : #endif
447 :
448 2 : if ((r->method & NGX_HTTP_HEAD) && !r->header_only) {
449 0 : r->header_only = 1;
450 : }
451 :
452 2 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
453 :
454 2 : if (llcf->http10_buffering
455 2 : && !ctx->buffering
456 2 : && !r->header_sent
457 1 : && !ctx->header_sent
458 1 : && r->http_version < NGX_HTTP_VERSION_11
459 0 : && r->headers_out.content_length_n < 0)
460 : {
461 0 : ctx->buffering = 1;
462 : }
463 :
464 2 : rc = ngx_http_lua_send_header_if_needed(r, ctx);
465 :
466 2 : if (rc == NGX_ERROR || rc > NGX_OK) {
467 0 : return rc;
468 : }
469 :
470 2 : if (r->header_only) {
471 0 : ctx->eof = 1;
472 :
473 0 : if (ctx->buffering) {
474 0 : return ngx_http_lua_send_http10_headers(r, ctx);
475 : }
476 :
477 0 : return rc;
478 : }
479 :
480 2 : if (in == NULL) {
481 : dd("last buf to be sent");
482 :
483 : #if 1
484 1 : if (!r->request_body && r == r->main) {
485 1 : if (ngx_http_discard_request_body(r) != NGX_OK) {
486 0 : return NGX_ERROR;
487 : }
488 : }
489 : #endif
490 :
491 1 : if (ctx->buffering) {
492 0 : rc = ngx_http_lua_send_http10_headers(r, ctx);
493 0 : if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
494 0 : return rc;
495 : }
496 :
497 0 : if (ctx->out) {
498 :
499 0 : rc = ngx_http_lua_output_filter(r, ctx->out);
500 :
501 0 : if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
502 0 : return rc;
503 : }
504 :
505 0 : ctx->out = NULL;
506 : }
507 : }
508 :
509 : #if defined(nginx_version) && nginx_version <= 8004
510 :
511 : /* earlier versions of nginx does not allow subrequests
512 : to send last_buf themselves */
513 : if (r != r->main) {
514 : return NGX_OK;
515 : }
516 :
517 : #endif
518 :
519 1 : ctx->eof = 1;
520 :
521 1 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
522 : "lua sending last buf of the response body");
523 :
524 1 : rc = ngx_http_lua_send_special(r, NGX_HTTP_LAST);
525 :
526 1 : if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
527 0 : return rc;
528 : }
529 :
530 1 : return NGX_OK;
531 : }
532 :
533 : /* in != NULL */
534 :
535 1 : if (ctx->buffering) {
536 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
537 : "lua buffering output bufs for the HTTP 1.0 request");
538 :
539 0 : for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
540 0 : ll = &cl->next;
541 : }
542 :
543 0 : *ll = in;
544 :
545 0 : return NGX_OK;
546 : }
547 :
548 1 : return ngx_http_lua_output_filter(r, in);
549 : }
550 :
551 :
552 : static ngx_int_t
553 1 : ngx_http_lua_send_special(ngx_http_request_t *r, ngx_uint_t flags)
554 : {
555 : ngx_int_t rc;
556 : ngx_http_request_t *ar; /* active request */
557 :
558 1 : ar = r->connection->data;
559 :
560 1 : if (ar != r) {
561 :
562 : /* bypass ngx_http_postpone_filter_module */
563 :
564 0 : r->connection->data = r;
565 0 : rc = ngx_http_send_special(r, flags);
566 0 : r->connection->data = ar;
567 0 : return rc;
568 : }
569 :
570 1 : return ngx_http_send_special(r, flags);
571 : }
572 :
573 :
574 : static ngx_int_t
575 1 : ngx_http_lua_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
576 : {
577 : ngx_int_t rc;
578 : ngx_http_lua_ctx_t *ctx;
579 : ngx_http_request_t *ar; /* active request */
580 :
581 1 : ar = r->connection->data;
582 :
583 1 : if (ar != r) {
584 :
585 : /* bypass ngx_http_postpone_filter_module */
586 :
587 0 : r->connection->data = r;
588 0 : rc = ngx_http_output_filter(r, in);
589 0 : r->connection->data = ar;
590 0 : return rc;
591 : }
592 :
593 1 : rc = ngx_http_output_filter(r, in);
594 :
595 1 : if (rc == NGX_ERROR) {
596 0 : return NGX_ERROR;
597 : }
598 :
599 1 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
600 :
601 : #if nginx_version >= 1001004
602 1 : ngx_chain_update_chains(r->pool,
603 : #else
604 : ngx_chain_update_chains(
605 : #endif
606 : &ctx->free_bufs, &ctx->busy_bufs, &in,
607 : (ngx_buf_tag_t) &ngx_http_lua_module);
608 :
609 1 : return rc;
610 : }
611 :
612 :
613 : static ngx_int_t
614 0 : ngx_http_lua_send_http10_headers(ngx_http_request_t *r,
615 : ngx_http_lua_ctx_t *ctx)
616 : {
617 : off_t size;
618 : ngx_chain_t *cl;
619 : ngx_int_t rc;
620 :
621 0 : if (r->header_sent || ctx->header_sent) {
622 0 : return NGX_OK;
623 : }
624 :
625 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
626 : "lua sending HTTP 1.0 response headers");
627 :
628 0 : if (r->header_only) {
629 0 : goto send;
630 : }
631 :
632 0 : if (r->headers_out.content_length == NULL) {
633 0 : for (size = 0, cl = ctx->out; cl; cl = cl->next) {
634 0 : size += ngx_buf_size(cl->buf);
635 : }
636 :
637 0 : r->headers_out.content_length_n = size;
638 :
639 0 : if (r->headers_out.content_length) {
640 0 : r->headers_out.content_length->hash = 0;
641 : }
642 : }
643 :
644 0 : send:
645 :
646 0 : rc = ngx_http_send_header(r);
647 0 : ctx->header_sent = 1;
648 0 : return rc;
649 : }
650 :
651 :
652 : static void
653 18 : ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log)
654 : {
655 18 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0,
656 : "lua initializing lua registry");
657 :
658 : /* {{{ register a table to anchor lua coroutines reliably:
659 : * {([int]ref) = [cort]} */
660 18 : lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
661 18 : lua_createtable(L, 0, 32 /* nrec */);
662 18 : lua_rawset(L, LUA_REGISTRYINDEX);
663 : /* }}} */
664 :
665 : /* create the registry entry for the Lua request ctx data table */
666 18 : lua_pushliteral(L, ngx_http_lua_ctx_tables_key);
667 18 : lua_createtable(L, 0, 32 /* nrec */);
668 18 : lua_rawset(L, LUA_REGISTRYINDEX);
669 :
670 : /* create the registry entry for the Lua socket connection pool table */
671 18 : lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key);
672 18 : lua_createtable(L, 0, 8 /* nrec */);
673 18 : lua_rawset(L, LUA_REGISTRYINDEX);
674 :
675 : #if (NGX_PCRE)
676 : /* create the registry entry for the Lua precompiled regex object cache */
677 18 : lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key);
678 18 : lua_createtable(L, 0, 16 /* nrec */);
679 18 : lua_rawset(L, LUA_REGISTRYINDEX);
680 : #endif
681 :
682 : /* {{{ register table to cache user code:
683 : * { [(string)cache_key] = <code closure> } */
684 18 : lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key);
685 18 : lua_createtable(L, 0, 8 /* nrec */);
686 18 : lua_rawset(L, LUA_REGISTRYINDEX);
687 : /* }}} */
688 18 : }
689 :
690 :
691 : static void
692 18 : ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle,
693 : ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log)
694 : {
695 18 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0,
696 : "lua initializing lua globals");
697 :
698 18 : lua_pushlightuserdata(L, cycle);
699 18 : lua_setglobal(L, "__ngx_cycle");
700 :
701 : #if defined(NDK) && NDK
702 18 : ngx_http_lua_inject_ndk_api(L);
703 : #endif /* defined(NDK) && NDK */
704 :
705 18 : ngx_http_lua_inject_ngx_api(L, lmcf, log);
706 18 : }
707 :
708 :
709 : static void
710 18 : ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf,
711 : ngx_log_t *log)
712 : {
713 18 : lua_createtable(L, 0 /* narr */, 116 /* nrec */); /* ngx.* */
714 :
715 18 : lua_pushcfunction(L, ngx_http_lua_get_raw_phase_context);
716 18 : lua_setfield(L, -2, "_phase_ctx");
717 :
718 18 : ngx_http_lua_inject_arg_api(L);
719 :
720 18 : ngx_http_lua_inject_http_consts(L);
721 18 : ngx_http_lua_inject_core_consts(L);
722 :
723 18 : ngx_http_lua_inject_log_api(L);
724 18 : ngx_http_lua_inject_output_api(L);
725 18 : ngx_http_lua_inject_time_api(L);
726 18 : ngx_http_lua_inject_string_api(L);
727 18 : ngx_http_lua_inject_control_api(log, L);
728 18 : ngx_http_lua_inject_subrequest_api(L);
729 18 : ngx_http_lua_inject_sleep_api(L);
730 18 : ngx_http_lua_inject_phase_api(L);
731 :
732 : #if (NGX_PCRE)
733 18 : ngx_http_lua_inject_regex_api(L);
734 : #endif
735 :
736 18 : ngx_http_lua_inject_req_api(log, L);
737 18 : ngx_http_lua_inject_resp_header_api(L);
738 18 : ngx_http_lua_create_headers_metatable(log, L);
739 18 : ngx_http_lua_inject_variable_api(L);
740 18 : ngx_http_lua_inject_shdict_api(lmcf, L);
741 18 : ngx_http_lua_inject_socket_tcp_api(log, L);
742 18 : ngx_http_lua_inject_socket_udp_api(log, L);
743 18 : ngx_http_lua_inject_uthread_api(log, L);
744 18 : ngx_http_lua_inject_timer_api(L);
745 18 : ngx_http_lua_inject_config_api(L);
746 18 : ngx_http_lua_inject_worker_api(L);
747 :
748 18 : ngx_http_lua_inject_misc_api(L);
749 :
750 18 : lua_getglobal(L, "package"); /* ngx package */
751 18 : lua_getfield(L, -1, "loaded"); /* ngx package loaded */
752 18 : lua_pushvalue(L, -3); /* ngx package loaded ngx */
753 18 : lua_setfield(L, -2, "ngx"); /* ngx package loaded */
754 18 : lua_pop(L, 2);
755 :
756 18 : lua_setglobal(L, "ngx");
757 :
758 18 : ngx_http_lua_inject_coroutine_api(log, L);
759 18 : }
760 :
761 :
762 : void
763 0 : ngx_http_lua_discard_bufs(ngx_pool_t *pool, ngx_chain_t *in)
764 : {
765 : ngx_chain_t *cl;
766 :
767 0 : for (cl = in; cl; cl = cl->next) {
768 0 : cl->buf->pos = cl->buf->last;
769 0 : cl->buf->file_pos = cl->buf->file_last;
770 : }
771 0 : }
772 :
773 :
774 : ngx_int_t
775 0 : ngx_http_lua_add_copy_chain(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx,
776 : ngx_chain_t ***plast, ngx_chain_t *in, ngx_int_t *eof)
777 : {
778 : ngx_chain_t *cl;
779 : size_t len;
780 : ngx_buf_t *b;
781 :
782 0 : len = 0;
783 0 : *eof = 0;
784 :
785 0 : for (cl = in; cl; cl = cl->next) {
786 0 : if (ngx_buf_in_memory(cl->buf)) {
787 0 : len += cl->buf->last - cl->buf->pos;
788 : }
789 :
790 0 : if (cl->buf->last_in_chain || cl->buf->last_buf) {
791 0 : *eof = 1;
792 : }
793 : }
794 :
795 0 : if (len == 0) {
796 0 : return NGX_OK;
797 : }
798 :
799 0 : cl = ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool,
800 : &ctx->free_bufs, len);
801 0 : if (cl == NULL) {
802 0 : return NGX_ERROR;
803 : }
804 :
805 : dd("chains get free buf: %d == %d", (int) (cl->buf->end - cl->buf->start),
806 : (int) len);
807 :
808 0 : b = cl->buf;
809 :
810 0 : while (in) {
811 0 : if (ngx_buf_in_memory(in->buf)) {
812 0 : b->last = ngx_copy(b->last, in->buf->pos,
813 : in->buf->last - in->buf->pos);
814 : }
815 :
816 0 : in = in->next;
817 : }
818 :
819 0 : **plast = cl;
820 0 : *plast = &cl->next;
821 :
822 0 : return NGX_OK;
823 : }
824 :
825 :
826 : void
827 1 : ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L,
828 : ngx_http_lua_ctx_t *ctx)
829 : {
830 1 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
831 : "lua reset ctx");
832 :
833 1 : ngx_http_lua_finalize_threads(r, ctx, L);
834 :
835 : #if 0
836 : if (ctx->user_co_ctx) {
837 : /* no way to destroy a list but clean up the whole pool */
838 : ctx->user_co_ctx = NULL;
839 : }
840 : #endif
841 :
842 1 : ngx_memzero(&ctx->entry_co_ctx, sizeof(ngx_http_lua_co_ctx_t));
843 :
844 1 : ctx->entry_co_ctx.co_ref = LUA_NOREF;
845 :
846 1 : ctx->entered_rewrite_phase = 0;
847 1 : ctx->entered_access_phase = 0;
848 1 : ctx->entered_content_phase = 0;
849 :
850 1 : ctx->exit_code = 0;
851 1 : ctx->exited = 0;
852 1 : ctx->resume_handler = ngx_http_lua_wev_handler;
853 :
854 1 : ngx_str_null(&ctx->exec_uri);
855 1 : ngx_str_null(&ctx->exec_args);
856 :
857 1 : ctx->co_op = 0;
858 1 : }
859 :
860 :
861 : /* post read callback for rewrite and access phases */
862 : void
863 0 : ngx_http_lua_generic_phase_post_read(ngx_http_request_t *r)
864 : {
865 : ngx_http_lua_ctx_t *ctx;
866 :
867 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
868 : "lua post read for rewrite/access phases");
869 :
870 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
871 :
872 0 : ctx->read_body_done = 1;
873 :
874 : #if defined(nginx_version) && nginx_version >= 8011
875 0 : r->main->count--;
876 : #endif
877 :
878 0 : if (ctx->waiting_more_body) {
879 0 : ctx->waiting_more_body = 0;
880 0 : ngx_http_core_run_phases(r);
881 : }
882 0 : }
883 :
884 :
885 : void
886 1 : ngx_http_lua_request_cleanup_handler(void *data)
887 : {
888 1 : ngx_http_lua_ctx_t *ctx = data;
889 :
890 1 : ngx_http_lua_request_cleanup(ctx, 0 /* forcible */);
891 1 : }
892 :
893 :
894 : void
895 1 : ngx_http_lua_request_cleanup(ngx_http_lua_ctx_t *ctx, int forcible)
896 : {
897 : lua_State *L;
898 : ngx_http_request_t *r;
899 : ngx_http_lua_main_conf_t *lmcf;
900 :
901 : /* force coroutine handling the request quit */
902 1 : if (ctx == NULL) {
903 : dd("ctx is NULL");
904 0 : return;
905 : }
906 :
907 1 : r = ctx->request;
908 :
909 1 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
910 : "lua request cleanup: forcible=%d", forcible);
911 :
912 1 : if (ctx->cleanup) {
913 1 : *ctx->cleanup = NULL;
914 1 : ctx->cleanup = NULL;
915 : }
916 :
917 1 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
918 :
919 : #if 1
920 1 : if (r->connection->fd == (ngx_socket_t) -1) {
921 : /* being a fake request */
922 :
923 0 : if (ctx->context == NGX_HTTP_LUA_CONTEXT_TIMER) {
924 : /* being a timer handler */
925 0 : lmcf->running_timers--;
926 : }
927 : }
928 : #endif
929 :
930 1 : L = ngx_http_lua_get_lua_vm(r, ctx);
931 :
932 1 : ngx_http_lua_finalize_threads(r, ctx, L);
933 : }
934 :
935 :
936 : /*
937 : * description:
938 : * run a Lua coroutine specified by ctx->cur_co_ctx->co
939 : * return value:
940 : * NGX_AGAIN: I/O interruption: r->main->count intact
941 : * NGX_DONE: I/O interruption: r->main->count already incremented by 1
942 : * NGX_ERROR: error
943 : * >= 200 HTTP status code
944 : */
945 : ngx_int_t
946 2 : ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r,
947 : ngx_http_lua_ctx_t *ctx, volatile int nrets)
948 : {
949 : ngx_http_lua_co_ctx_t *next_coctx, *parent_coctx, *orig_coctx;
950 2 : int rv, success = 1;
951 : lua_State *next_co;
952 : lua_State *old_co;
953 : const char *err, *msg, *trace;
954 : ngx_int_t rc;
955 : #if (NGX_PCRE)
956 2 : ngx_pool_t *old_pool = NULL;
957 : #endif
958 :
959 2 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
960 : "lua run thread, top:%d c:%ud", lua_gettop(L),
961 : r->main->count);
962 :
963 : /* set Lua VM panic handler */
964 2 : lua_atpanic(L, ngx_http_lua_atpanic);
965 :
966 : dd("ctx = %p", ctx);
967 :
968 2 : NGX_LUA_EXCEPTION_TRY {
969 :
970 2 : if (ctx->cur_co_ctx->thread_spawn_yielded) {
971 : ngx_http_lua_probe_info("thread spawn yielded");
972 :
973 0 : ctx->cur_co_ctx->thread_spawn_yielded = 0;
974 0 : nrets = 1;
975 : }
976 :
977 : for ( ;; ) {
978 :
979 : dd("calling lua_resume: vm %p, nret %d", ctx->cur_co_ctx->co,
980 : (int) nrets);
981 :
982 : #if (NGX_PCRE)
983 : /* XXX: work-around to nginx regex subsystem */
984 2 : old_pool = ngx_http_lua_pcre_malloc_init(r->pool);
985 : #endif
986 :
987 : /* run code */
988 : dd("ctx: %p", ctx);
989 : dd("cur co: %p", ctx->cur_co_ctx->co);
990 : dd("cur co status: %d", ctx->cur_co_ctx->co_status);
991 :
992 2 : orig_coctx = ctx->cur_co_ctx;
993 :
994 : #ifdef NGX_LUA_USE_ASSERT
995 : dd("%p: saved co top: %d, nrets: %d, true top: %d",
996 : orig_coctx->co,
997 : (int) orig_coctx->co_top, (int) nrets,
998 : (int) lua_gettop(orig_coctx->co));
999 : #endif
1000 :
1001 : #if DDEBUG
1002 : if (lua_gettop(orig_coctx->co) > 0) {
1003 : dd("top elem: %s", luaL_typename(orig_coctx->co, -1));
1004 : }
1005 : #endif
1006 :
1007 2 : ngx_http_lua_assert(orig_coctx->co_top + nrets
1008 : == lua_gettop(orig_coctx->co));
1009 :
1010 2 : rv = lua_resume(orig_coctx->co, nrets);
1011 :
1012 : #if (NGX_PCRE)
1013 : /* XXX: work-around to nginx regex subsystem */
1014 2 : ngx_http_lua_pcre_malloc_done(old_pool);
1015 : #endif
1016 :
1017 : #if 0
1018 : /* test the longjmp thing */
1019 : if (rand() % 2 == 0) {
1020 : NGX_LUA_EXCEPTION_THROW(1);
1021 : }
1022 : #endif
1023 :
1024 2 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1025 : "lua resume returned %d", rv);
1026 :
1027 2 : switch (rv) {
1028 1 : case LUA_YIELD:
1029 : /* yielded, let event handler do the rest job */
1030 : /* FIXME: add io cmd dispatcher here */
1031 :
1032 1 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1033 : "lua thread yielded");
1034 :
1035 : #ifdef NGX_LUA_USE_ASSERT
1036 : dd("%p: saving curr top after yield: %d (co-op: %d)",
1037 : orig_coctx->co,
1038 : (int) lua_gettop(orig_coctx->co), (int) ctx->co_op);
1039 1 : orig_coctx->co_top = lua_gettop(orig_coctx->co);
1040 : #endif
1041 :
1042 1 : if (r->uri_changed) {
1043 0 : return ngx_http_lua_handle_rewrite_jump(L, r, ctx);
1044 : }
1045 :
1046 1 : if (ctx->exited) {
1047 0 : return ngx_http_lua_handle_exit(L, r, ctx);
1048 : }
1049 :
1050 1 : if (ctx->exec_uri.len) {
1051 0 : return ngx_http_lua_handle_exec(L, r, ctx);
1052 : }
1053 :
1054 : /*
1055 : * check if coroutine.resume or coroutine.yield called
1056 : * lua_yield()
1057 : */
1058 1 : switch(ctx->co_op) {
1059 1 : case NGX_HTTP_LUA_USER_CORO_NOP:
1060 : dd("hit! it is the API yield");
1061 :
1062 1 : ngx_http_lua_assert(lua_gettop(ctx->cur_co_ctx->co) == 0);
1063 :
1064 1 : ctx->cur_co_ctx = NULL;
1065 :
1066 1 : return NGX_AGAIN;
1067 :
1068 0 : case NGX_HTTP_LUA_USER_THREAD_RESUME:
1069 :
1070 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1071 : "lua user thread resume");
1072 :
1073 0 : ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP;
1074 0 : nrets = lua_gettop(ctx->cur_co_ctx->co) - 1;
1075 : dd("nrets = %d", nrets);
1076 :
1077 : #ifdef NGX_LUA_USE_ASSERT
1078 : /* ignore the return value (the thread) already pushed */
1079 0 : orig_coctx->co_top--;
1080 : #endif
1081 :
1082 0 : break;
1083 :
1084 0 : case NGX_HTTP_LUA_USER_CORO_RESUME:
1085 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1086 : "lua coroutine: resume");
1087 :
1088 : /*
1089 : * the target coroutine lies at the base of the
1090 : * parent's stack
1091 : */
1092 0 : ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP;
1093 :
1094 0 : old_co = ctx->cur_co_ctx->parent_co_ctx->co;
1095 :
1096 0 : nrets = lua_gettop(old_co);
1097 0 : if (nrets) {
1098 : dd("moving %d return values to parent", nrets);
1099 0 : lua_xmove(old_co, ctx->cur_co_ctx->co, nrets);
1100 :
1101 : #ifdef NGX_LUA_USE_ASSERT
1102 0 : ctx->cur_co_ctx->parent_co_ctx->co_top -= nrets;
1103 : #endif
1104 : }
1105 :
1106 0 : break;
1107 :
1108 0 : default:
1109 : /* ctx->co_op == NGX_HTTP_LUA_USER_CORO_YIELD */
1110 :
1111 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1112 : "lua coroutine: yield");
1113 :
1114 0 : ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP;
1115 :
1116 0 : if (ngx_http_lua_is_thread(ctx)) {
1117 : ngx_http_lua_probe_thread_yield(r, ctx->cur_co_ctx->co);
1118 :
1119 : /* discard any return values from user
1120 : * coroutine.yield()'s arguments */
1121 0 : lua_settop(ctx->cur_co_ctx->co, 0);
1122 :
1123 : #ifdef NGX_LUA_USE_ASSERT
1124 0 : ctx->cur_co_ctx->co_top = 0;
1125 : #endif
1126 :
1127 : ngx_http_lua_probe_info("set co running");
1128 0 : ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING;
1129 :
1130 0 : if (ctx->posted_threads) {
1131 0 : ngx_http_lua_post_thread(r, ctx, ctx->cur_co_ctx);
1132 0 : ctx->cur_co_ctx = NULL;
1133 0 : return NGX_AGAIN;
1134 : }
1135 :
1136 : /* no pending threads, so resume the thread
1137 : * immediately */
1138 :
1139 0 : nrets = 0;
1140 0 : continue;
1141 : }
1142 :
1143 : /* being a user coroutine that has a parent */
1144 :
1145 0 : nrets = lua_gettop(ctx->cur_co_ctx->co);
1146 :
1147 0 : next_coctx = ctx->cur_co_ctx->parent_co_ctx;
1148 0 : next_co = next_coctx->co;
1149 :
1150 : /*
1151 : * prepare return values for coroutine.resume
1152 : * (true plus any retvals)
1153 : */
1154 0 : lua_pushboolean(next_co, 1);
1155 :
1156 0 : if (nrets) {
1157 : dd("moving %d return values to next co", nrets);
1158 0 : lua_xmove(ctx->cur_co_ctx->co, next_co, nrets);
1159 : #ifdef NGX_LUA_USE_ASSERT
1160 0 : ctx->cur_co_ctx->co_top -= nrets;
1161 : #endif
1162 : }
1163 :
1164 0 : nrets++; /* add the true boolean value */
1165 :
1166 0 : ctx->cur_co_ctx = next_coctx;
1167 :
1168 0 : break;
1169 : }
1170 :
1171 : /* try resuming on the new coroutine again */
1172 0 : continue;
1173 :
1174 1 : case 0:
1175 :
1176 1 : ngx_http_lua_cleanup_pending_operation(ctx->cur_co_ctx);
1177 :
1178 : ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1);
1179 :
1180 1 : ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD;
1181 :
1182 1 : if (ctx->cur_co_ctx->zombie_child_threads) {
1183 0 : ngx_http_lua_cleanup_zombie_child_uthreads(r, L, ctx,
1184 : ctx->cur_co_ctx);
1185 : }
1186 :
1187 1 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1188 : "lua light thread ended normally");
1189 :
1190 1 : if (ngx_http_lua_is_entry_thread(ctx)) {
1191 :
1192 1 : lua_settop(L, 0);
1193 :
1194 1 : ngx_http_lua_del_thread(r, L, ctx, ctx->cur_co_ctx);
1195 :
1196 : dd("uthreads: %d", (int) ctx->uthreads);
1197 :
1198 1 : if (ctx->uthreads) {
1199 :
1200 0 : ctx->cur_co_ctx = NULL;
1201 0 : return NGX_AGAIN;
1202 : }
1203 :
1204 : /* all user threads terminated already */
1205 1 : goto done;
1206 : }
1207 :
1208 0 : if (ctx->cur_co_ctx->is_uthread) {
1209 : /* being a user thread */
1210 :
1211 0 : lua_settop(L, 0);
1212 :
1213 0 : parent_coctx = ctx->cur_co_ctx->parent_co_ctx;
1214 :
1215 0 : if (ngx_http_lua_coroutine_alive(parent_coctx)) {
1216 0 : if (ctx->cur_co_ctx->waited_by_parent) {
1217 : ngx_http_lua_probe_info("parent already waiting");
1218 0 : ctx->cur_co_ctx->waited_by_parent = 0;
1219 0 : success = 1;
1220 0 : goto user_co_done;
1221 : }
1222 :
1223 : ngx_http_lua_probe_info("parent still alive");
1224 :
1225 0 : if (ngx_http_lua_post_zombie_thread(r, parent_coctx,
1226 : ctx->cur_co_ctx)
1227 : != NGX_OK)
1228 : {
1229 0 : return NGX_ERROR;
1230 : }
1231 :
1232 0 : lua_pushboolean(ctx->cur_co_ctx->co, 1);
1233 0 : lua_insert(ctx->cur_co_ctx->co, 1);
1234 :
1235 0 : ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_ZOMBIE;
1236 0 : ctx->cur_co_ctx = NULL;
1237 0 : return NGX_AGAIN;
1238 : }
1239 :
1240 0 : ngx_http_lua_del_thread(r, L, ctx, ctx->cur_co_ctx);
1241 0 : ctx->uthreads--;
1242 :
1243 0 : if (ctx->uthreads == 0) {
1244 0 : if (ngx_http_lua_entry_thread_alive(ctx)) {
1245 0 : ctx->cur_co_ctx = NULL;
1246 0 : return NGX_AGAIN;
1247 : }
1248 :
1249 : /* all threads terminated already */
1250 0 : goto done;
1251 : }
1252 :
1253 : /* some other user threads still running */
1254 0 : ctx->cur_co_ctx = NULL;
1255 0 : return NGX_AGAIN;
1256 : }
1257 :
1258 : /* being a user coroutine that has a parent */
1259 :
1260 0 : success = 1;
1261 :
1262 0 : user_co_done:
1263 :
1264 0 : nrets = lua_gettop(ctx->cur_co_ctx->co);
1265 :
1266 0 : next_coctx = ctx->cur_co_ctx->parent_co_ctx;
1267 :
1268 0 : if (next_coctx == NULL) {
1269 : /* being a light thread */
1270 0 : goto no_parent;
1271 : }
1272 :
1273 0 : next_co = next_coctx->co;
1274 :
1275 : /*
1276 : * ended successful, coroutine.resume returns true plus
1277 : * any return values
1278 : */
1279 0 : lua_pushboolean(next_co, success);
1280 :
1281 0 : if (nrets) {
1282 0 : lua_xmove(ctx->cur_co_ctx->co, next_co, nrets);
1283 : }
1284 :
1285 0 : if (ctx->cur_co_ctx->is_uthread) {
1286 0 : ngx_http_lua_del_thread(r, L, ctx, ctx->cur_co_ctx);
1287 0 : ctx->uthreads--;
1288 : }
1289 :
1290 0 : nrets++;
1291 0 : ctx->cur_co_ctx = next_coctx;
1292 :
1293 : ngx_http_lua_probe_info("set parent running");
1294 :
1295 0 : next_coctx->co_status = NGX_HTTP_LUA_CO_RUNNING;
1296 :
1297 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1298 : "lua coroutine: lua user thread ended normally");
1299 :
1300 0 : continue;
1301 :
1302 0 : case LUA_ERRRUN:
1303 0 : err = "runtime error";
1304 0 : break;
1305 :
1306 0 : case LUA_ERRSYNTAX:
1307 0 : err = "syntax error";
1308 0 : break;
1309 :
1310 0 : case LUA_ERRMEM:
1311 0 : err = "memory allocation error";
1312 0 : ngx_quit = 1;
1313 0 : break;
1314 :
1315 0 : case LUA_ERRERR:
1316 0 : err = "error handler error";
1317 0 : break;
1318 :
1319 0 : default:
1320 0 : err = "unknown error";
1321 0 : break;
1322 : }
1323 :
1324 0 : if (ctx->cur_co_ctx != orig_coctx) {
1325 0 : ctx->cur_co_ctx = orig_coctx;
1326 : }
1327 :
1328 0 : if (lua_isstring(ctx->cur_co_ctx->co, -1)) {
1329 : dd("user custom error msg");
1330 0 : msg = lua_tostring(ctx->cur_co_ctx->co, -1);
1331 :
1332 : } else {
1333 0 : msg = "unknown reason";
1334 : }
1335 :
1336 0 : ngx_http_lua_cleanup_pending_operation(ctx->cur_co_ctx);
1337 :
1338 : ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 0);
1339 :
1340 0 : ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD;
1341 :
1342 0 : ngx_http_lua_thread_traceback(L, ctx->cur_co_ctx->co,
1343 : ctx->cur_co_ctx);
1344 0 : trace = lua_tostring(L, -1);
1345 :
1346 0 : if (ctx->cur_co_ctx->is_uthread) {
1347 :
1348 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1349 : "lua user thread aborted: %s: %s\n%s",
1350 : err, msg, trace);
1351 :
1352 0 : lua_settop(L, 0);
1353 :
1354 0 : parent_coctx = ctx->cur_co_ctx->parent_co_ctx;
1355 :
1356 0 : if (ngx_http_lua_coroutine_alive(parent_coctx)) {
1357 0 : if (ctx->cur_co_ctx->waited_by_parent) {
1358 0 : ctx->cur_co_ctx->waited_by_parent = 0;
1359 0 : success = 0;
1360 0 : goto user_co_done;
1361 : }
1362 :
1363 0 : if (ngx_http_lua_post_zombie_thread(r, parent_coctx,
1364 : ctx->cur_co_ctx)
1365 : != NGX_OK)
1366 : {
1367 0 : return NGX_ERROR;
1368 : }
1369 :
1370 0 : lua_pushboolean(ctx->cur_co_ctx->co, 0);
1371 0 : lua_insert(ctx->cur_co_ctx->co, 1);
1372 :
1373 0 : ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_ZOMBIE;
1374 0 : ctx->cur_co_ctx = NULL;
1375 0 : return NGX_AGAIN;
1376 : }
1377 :
1378 0 : ngx_http_lua_del_thread(r, L, ctx, ctx->cur_co_ctx);
1379 0 : ctx->uthreads--;
1380 :
1381 0 : if (ctx->uthreads == 0) {
1382 0 : if (ngx_http_lua_entry_thread_alive(ctx)) {
1383 0 : ctx->cur_co_ctx = NULL;
1384 0 : return NGX_AGAIN;
1385 : }
1386 :
1387 : /* all threads terminated already */
1388 0 : goto done;
1389 : }
1390 :
1391 : /* some other user threads still running */
1392 0 : ctx->cur_co_ctx = NULL;
1393 0 : return NGX_AGAIN;
1394 : }
1395 :
1396 0 : if (ngx_http_lua_is_entry_thread(ctx)) {
1397 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1398 : "lua entry thread aborted: %s: %s\n%s",
1399 : err, msg, trace);
1400 :
1401 0 : lua_settop(L, 0);
1402 :
1403 : /* being the entry thread aborted */
1404 :
1405 0 : if (r->filter_finalize) {
1406 0 : ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
1407 : }
1408 :
1409 0 : ngx_http_lua_request_cleanup(ctx, 0);
1410 :
1411 : dd("headers sent? %d", r->header_sent || ctx->header_sent);
1412 :
1413 0 : if (ctx->no_abort) {
1414 0 : ctx->no_abort = 0;
1415 0 : return NGX_ERROR;
1416 : }
1417 :
1418 0 : return (r->header_sent || ctx->header_sent) ? NGX_ERROR :
1419 : NGX_HTTP_INTERNAL_SERVER_ERROR;
1420 : }
1421 :
1422 : /* being a user coroutine that has a parent */
1423 :
1424 0 : next_coctx = ctx->cur_co_ctx->parent_co_ctx;
1425 0 : if (next_coctx == NULL) {
1426 0 : goto no_parent;
1427 : }
1428 :
1429 0 : next_co = next_coctx->co;
1430 :
1431 : ngx_http_lua_probe_info("set parent running");
1432 :
1433 0 : next_coctx->co_status = NGX_HTTP_LUA_CO_RUNNING;
1434 :
1435 : /*
1436 : * ended with error, coroutine.resume returns false plus
1437 : * err msg
1438 : */
1439 0 : lua_pushboolean(next_co, 0);
1440 0 : lua_xmove(ctx->cur_co_ctx->co, next_co, 1);
1441 0 : nrets = 2;
1442 :
1443 0 : ctx->cur_co_ctx = next_coctx;
1444 :
1445 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1446 : "lua coroutine: %s: %s\n%s", err, msg, trace);
1447 :
1448 : /* try resuming on the new coroutine again */
1449 0 : continue;
1450 : }
1451 :
1452 : } NGX_LUA_EXCEPTION_CATCH {
1453 : dd("nginx execution restored");
1454 : }
1455 :
1456 0 : return NGX_ERROR;
1457 :
1458 0 : no_parent:
1459 :
1460 0 : lua_settop(L, 0);
1461 :
1462 0 : ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD;
1463 :
1464 0 : if (r->filter_finalize) {
1465 0 : ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
1466 : }
1467 :
1468 0 : ngx_http_lua_request_cleanup(ctx, 0);
1469 :
1470 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua handler aborted: "
1471 : "user coroutine has no parent");
1472 :
1473 0 : return (r->header_sent || ctx->header_sent) ?
1474 0 : NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR;
1475 :
1476 1 : done:
1477 :
1478 1 : if (ctx->entered_content_phase
1479 1 : && r->connection->fd != (ngx_socket_t) -1)
1480 : {
1481 1 : rc = ngx_http_lua_send_chain_link(r, ctx,
1482 : NULL /* last_buf */);
1483 :
1484 1 : if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
1485 0 : return rc;
1486 : }
1487 : }
1488 :
1489 1 : return NGX_OK;
1490 : }
1491 :
1492 :
1493 : ngx_int_t
1494 0 : ngx_http_lua_wev_handler(ngx_http_request_t *r)
1495 : {
1496 : ngx_int_t rc;
1497 : ngx_event_t *wev;
1498 : ngx_connection_t *c;
1499 : ngx_http_lua_ctx_t *ctx;
1500 : ngx_http_core_loc_conf_t *clcf;
1501 :
1502 : ngx_http_lua_socket_tcp_upstream_t *u;
1503 :
1504 0 : c = r->connection;
1505 0 : wev = c->write;
1506 :
1507 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
1508 0 : if (ctx == NULL) {
1509 0 : return NGX_ERROR;
1510 : }
1511 :
1512 0 : ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
1513 : "lua run write event handler: timedout:%ud, ready:%ud, "
1514 : "writing_raw_req_socket:%ud",
1515 : wev->timedout, wev->ready, ctx->writing_raw_req_socket);
1516 :
1517 0 : clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module);
1518 :
1519 0 : if (wev->timedout && !ctx->writing_raw_req_socket) {
1520 0 : if (!wev->delayed) {
1521 0 : ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
1522 : "client timed out");
1523 0 : c->timedout = 1;
1524 :
1525 0 : goto flush_coros;
1526 : }
1527 :
1528 0 : wev->timedout = 0;
1529 0 : wev->delayed = 0;
1530 :
1531 0 : if (!wev->ready) {
1532 0 : ngx_add_timer(wev, clcf->send_timeout);
1533 :
1534 0 : if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
1535 0 : if (ctx->entered_content_phase) {
1536 0 : ngx_http_lua_finalize_request(r, NGX_ERROR);
1537 : }
1538 0 : return NGX_ERROR;
1539 : }
1540 : }
1541 : }
1542 :
1543 0 : if (!wev->ready && !wev->timedout) {
1544 0 : goto useless;
1545 : }
1546 :
1547 0 : if (ctx->writing_raw_req_socket) {
1548 0 : ctx->writing_raw_req_socket = 0;
1549 :
1550 0 : u = ctx->downstream;
1551 0 : if (u == NULL) {
1552 0 : return NGX_ERROR;
1553 : }
1554 :
1555 0 : u->write_event_handler(r, u);
1556 0 : return NGX_DONE;
1557 : }
1558 :
1559 0 : if (c->buffered & NGX_HTTP_LOWLEVEL_BUFFERED) {
1560 0 : rc = ngx_http_lua_flush_pending_output(r, ctx);
1561 :
1562 : dd("flush pending output returned %d, c->error: %d", (int) rc,
1563 : c->error);
1564 :
1565 0 : if (rc != NGX_ERROR && rc != NGX_OK) {
1566 0 : goto useless;
1567 : }
1568 :
1569 : /* when rc == NGX_ERROR, c->error must be set */
1570 : }
1571 :
1572 0 : flush_coros:
1573 :
1574 : dd("ctx->flushing_coros: %d", (int) ctx->flushing_coros);
1575 :
1576 0 : if (ctx->flushing_coros) {
1577 0 : return ngx_http_lua_process_flushing_coroutines(r, ctx);
1578 : }
1579 :
1580 : /* ctx->flushing_coros == 0 */
1581 :
1582 0 : useless:
1583 :
1584 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1585 : "useless lua write event handler");
1586 :
1587 0 : if (ctx->entered_content_phase) {
1588 0 : return NGX_OK;
1589 : }
1590 :
1591 0 : return NGX_DONE;
1592 : }
1593 :
1594 :
1595 : static ngx_int_t
1596 0 : ngx_http_lua_process_flushing_coroutines(ngx_http_request_t *r,
1597 : ngx_http_lua_ctx_t *ctx)
1598 : {
1599 : ngx_int_t rc, n;
1600 : ngx_uint_t i;
1601 : ngx_list_part_t *part;
1602 : ngx_http_lua_co_ctx_t *coctx;
1603 :
1604 : dd("processing flushing coroutines");
1605 :
1606 0 : coctx = &ctx->entry_co_ctx;
1607 0 : n = ctx->flushing_coros;
1608 :
1609 0 : if (coctx->flushing) {
1610 0 : coctx->flushing = 0;
1611 :
1612 0 : ctx->flushing_coros--;
1613 0 : n--;
1614 0 : ctx->cur_co_ctx = coctx;
1615 :
1616 0 : rc = ngx_http_lua_flush_resume_helper(r, ctx);
1617 0 : if (rc == NGX_ERROR || rc >= NGX_OK) {
1618 0 : return rc;
1619 : }
1620 :
1621 : /* rc == NGX_DONE */
1622 : }
1623 :
1624 0 : if (n) {
1625 :
1626 0 : if (ctx->user_co_ctx == NULL) {
1627 0 : return NGX_ERROR;
1628 : }
1629 :
1630 0 : part = &ctx->user_co_ctx->part;
1631 0 : coctx = part->elts;
1632 :
1633 0 : for (i = 0; /* void */; i++) {
1634 :
1635 0 : if (i >= part->nelts) {
1636 0 : if (part->next == NULL) {
1637 0 : break;
1638 : }
1639 :
1640 0 : part = part->next;
1641 0 : coctx = part->elts;
1642 0 : i = 0;
1643 : }
1644 :
1645 0 : if (coctx[i].flushing) {
1646 0 : coctx[i].flushing = 0;
1647 0 : ctx->flushing_coros--;
1648 0 : n--;
1649 0 : ctx->cur_co_ctx = &coctx[i];
1650 :
1651 0 : rc = ngx_http_lua_flush_resume_helper(r, ctx);
1652 0 : if (rc == NGX_ERROR || rc >= NGX_OK) {
1653 0 : return rc;
1654 : }
1655 :
1656 : /* rc == NGX_DONE */
1657 :
1658 0 : if (n == 0) {
1659 0 : return NGX_DONE;
1660 : }
1661 : }
1662 : }
1663 : }
1664 :
1665 0 : if (n) {
1666 0 : return NGX_ERROR;
1667 : }
1668 :
1669 0 : return NGX_DONE;
1670 : }
1671 :
1672 :
1673 : static ngx_int_t
1674 0 : ngx_http_lua_flush_pending_output(ngx_http_request_t *r,
1675 : ngx_http_lua_ctx_t *ctx)
1676 : {
1677 : ngx_int_t rc;
1678 : ngx_chain_t *cl;
1679 : ngx_event_t *wev;
1680 : ngx_connection_t *c;
1681 :
1682 : ngx_http_core_loc_conf_t *clcf;
1683 :
1684 0 : c = r->connection;
1685 0 : wev = c->write;
1686 :
1687 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
1688 : "lua flushing output: buffered 0x%uxd",
1689 : c->buffered);
1690 :
1691 0 : if (ctx->busy_bufs) {
1692 : /* FIXME since cosockets also share this busy_bufs chain, this condition
1693 : * might not be strong enough. better use separate busy_bufs chains. */
1694 0 : rc = ngx_http_lua_output_filter(r, NULL);
1695 :
1696 : } else {
1697 0 : cl = ngx_http_lua_get_flush_chain(r, ctx);
1698 0 : if (cl == NULL) {
1699 0 : return NGX_ERROR;
1700 : }
1701 :
1702 0 : rc = ngx_http_lua_output_filter(r, cl);
1703 : }
1704 :
1705 : dd("output filter returned %d", (int) rc);
1706 :
1707 0 : if (rc == NGX_ERROR || rc > NGX_OK) {
1708 0 : return rc;
1709 : }
1710 :
1711 0 : if (c->buffered & NGX_HTTP_LOWLEVEL_BUFFERED) {
1712 :
1713 0 : clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module);
1714 :
1715 0 : if (!wev->delayed) {
1716 0 : ngx_add_timer(wev, clcf->send_timeout);
1717 : }
1718 :
1719 0 : if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
1720 0 : if (ctx->entered_content_phase) {
1721 0 : ngx_http_lua_finalize_request(r, NGX_ERROR);
1722 : }
1723 :
1724 0 : return NGX_ERROR;
1725 : }
1726 :
1727 0 : if (ctx->flushing_coros) {
1728 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
1729 : "lua flush still waiting: buffered 0x%uxd",
1730 : c->buffered);
1731 :
1732 0 : return NGX_DONE;
1733 : }
1734 :
1735 : } else {
1736 : #if 1
1737 0 : if (wev->timer_set && !wev->delayed) {
1738 0 : ngx_del_timer(wev);
1739 : }
1740 : #endif
1741 : }
1742 :
1743 0 : return NGX_OK;
1744 : }
1745 :
1746 :
1747 : u_char *
1748 1 : ngx_http_lua_digest_hex(u_char *dest, const u_char *buf, int buf_len)
1749 : {
1750 : ngx_md5_t md5;
1751 : u_char md5_buf[MD5_DIGEST_LENGTH];
1752 :
1753 1 : ngx_md5_init(&md5);
1754 1 : ngx_md5_update(&md5, buf, buf_len);
1755 1 : ngx_md5_final(md5_buf, &md5);
1756 :
1757 1 : return ngx_hex_dump(dest, md5_buf, sizeof(md5_buf));
1758 : }
1759 :
1760 :
1761 : void
1762 0 : ngx_http_lua_set_multi_value_table(lua_State *L, int index)
1763 : {
1764 0 : if (index < 0) {
1765 0 : index = lua_gettop(L) + index + 1;
1766 : }
1767 :
1768 0 : lua_pushvalue(L, -2); /* stack: table key value key */
1769 0 : lua_rawget(L, index);
1770 0 : if (lua_isnil(L, -1)) {
1771 0 : lua_pop(L, 1); /* stack: table key value */
1772 0 : lua_rawset(L, index); /* stack: table */
1773 :
1774 : } else {
1775 0 : if (!lua_istable(L, -1)) {
1776 : /* just inserted one value */
1777 0 : lua_createtable(L, 4, 0);
1778 : /* stack: table key value value table */
1779 0 : lua_insert(L, -2);
1780 : /* stack: table key value table value */
1781 0 : lua_rawseti(L, -2, 1);
1782 : /* stack: table key value table */
1783 0 : lua_insert(L, -2);
1784 : /* stack: table key table value */
1785 :
1786 0 : lua_rawseti(L, -2, 2); /* stack: table key table */
1787 :
1788 0 : lua_rawset(L, index); /* stack: table */
1789 :
1790 : } else {
1791 : /* stack: table key value table */
1792 0 : lua_insert(L, -2); /* stack: table key table value */
1793 :
1794 0 : lua_rawseti(L, -2, lua_objlen(L, -2) + 1);
1795 : /* stack: table key table */
1796 0 : lua_pop(L, 2); /* stack: table */
1797 : }
1798 : }
1799 0 : }
1800 :
1801 :
1802 : uintptr_t
1803 0 : ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
1804 : {
1805 : ngx_uint_t n;
1806 : uint32_t *escape;
1807 : static u_char hex[] = "0123456789ABCDEF";
1808 :
1809 : /* " ", "#", "%", "?", %00-%1F, %7F-%FF */
1810 :
1811 : static uint32_t uri[] = {
1812 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1813 :
1814 : /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1815 : 0xfc00886d, /* 1111 1100 0000 0000 1000 1000 0110 1101 */
1816 :
1817 : /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1818 : 0x78000000, /* 0111 1000 0000 0000 0000 0000 0000 0000 */
1819 :
1820 : /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1821 : 0xa8000000, /* 1010 1000 0000 0000 0000 0000 0000 0000 */
1822 :
1823 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1824 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1825 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1826 : 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1827 : };
1828 :
1829 : /* " ", "#", "%", "+", "?", %00-%1F, %7F-%FF */
1830 :
1831 : static uint32_t args[] = {
1832 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1833 :
1834 : /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1835 : 0x80000829, /* 1000 0000 0000 0000 0000 1000 0010 1001 */
1836 :
1837 : /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1838 : 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1839 :
1840 : /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1841 : 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1842 :
1843 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1844 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1845 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1846 : 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1847 : };
1848 :
1849 : /* not ALPHA, DIGIT, "-", ".", "_", "~" */
1850 :
1851 : static uint32_t uri_component[] = {
1852 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1853 :
1854 : /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1855 : 0xfc00987d, /* 1111 1100 0000 0000 1001 1000 0111 1101 */
1856 :
1857 : /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1858 : 0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */
1859 :
1860 : /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1861 : 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
1862 :
1863 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1864 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1865 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1866 : 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1867 : };
1868 :
1869 : /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */
1870 :
1871 : static uint32_t html[] = {
1872 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1873 :
1874 : /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1875 : 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */
1876 :
1877 : /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1878 : 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1879 :
1880 : /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1881 : 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1882 :
1883 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1884 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1885 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1886 : 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1887 : };
1888 :
1889 : /* " ", """, "%", "'", %00-%1F, %7F-%FF */
1890 :
1891 : static uint32_t refresh[] = {
1892 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1893 :
1894 : /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1895 : 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */
1896 :
1897 : /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1898 : 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1899 :
1900 : /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1901 : 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1902 :
1903 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1904 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1905 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1906 : 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1907 : };
1908 :
1909 : /* " ", "%", %00-%1F */
1910 :
1911 : static uint32_t memcached[] = {
1912 : 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1913 :
1914 : /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1915 : 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */
1916 :
1917 : /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1918 : 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1919 :
1920 : /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1921 : 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1922 :
1923 : 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1924 : 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1925 : 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1926 : 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1927 : };
1928 :
1929 : /* mail_auth is the same as memcached */
1930 :
1931 : static uint32_t *map[] =
1932 : { uri, args, uri_component, html, refresh, memcached, memcached };
1933 :
1934 0 : escape = map[type];
1935 :
1936 0 : if (dst == NULL) {
1937 :
1938 : /* find the number of the characters to be escaped */
1939 :
1940 0 : n = 0;
1941 :
1942 0 : while (size) {
1943 0 : if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1944 0 : n++;
1945 : }
1946 0 : src++;
1947 0 : size--;
1948 : }
1949 :
1950 0 : return (uintptr_t) n;
1951 : }
1952 :
1953 0 : while (size) {
1954 0 : if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1955 0 : *dst++ = '%';
1956 0 : *dst++ = hex[*src >> 4];
1957 0 : *dst++ = hex[*src & 0xf];
1958 0 : src++;
1959 :
1960 : } else {
1961 0 : *dst++ = *src++;
1962 : }
1963 0 : size--;
1964 : }
1965 :
1966 0 : return (uintptr_t) dst;
1967 : }
1968 :
1969 :
1970 : /* XXX we also decode '+' to ' ' */
1971 : void
1972 0 : ngx_http_lua_unescape_uri(u_char **dst, u_char **src, size_t size,
1973 : ngx_uint_t type)
1974 : {
1975 : u_char *d, *s, ch, c, decoded;
1976 : enum {
1977 : sw_usual = 0,
1978 : sw_quoted,
1979 : sw_quoted_second
1980 : } state;
1981 :
1982 0 : d = *dst;
1983 0 : s = *src;
1984 :
1985 0 : state = 0;
1986 0 : decoded = 0;
1987 :
1988 0 : while (size--) {
1989 :
1990 0 : ch = *s++;
1991 :
1992 0 : switch (state) {
1993 0 : case sw_usual:
1994 0 : if (ch == '?'
1995 0 : && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
1996 : {
1997 0 : *d++ = ch;
1998 0 : goto done;
1999 : }
2000 :
2001 0 : if (ch == '%') {
2002 0 : state = sw_quoted;
2003 0 : break;
2004 : }
2005 :
2006 0 : if (ch == '+') {
2007 0 : *d++ = ' ';
2008 0 : break;
2009 : }
2010 :
2011 0 : *d++ = ch;
2012 0 : break;
2013 :
2014 0 : case sw_quoted:
2015 :
2016 0 : if (ch >= '0' && ch <= '9') {
2017 0 : decoded = (u_char) (ch - '0');
2018 0 : state = sw_quoted_second;
2019 0 : break;
2020 : }
2021 :
2022 0 : c = (u_char) (ch | 0x20);
2023 0 : if (c >= 'a' && c <= 'f') {
2024 0 : decoded = (u_char) (c - 'a' + 10);
2025 0 : state = sw_quoted_second;
2026 0 : break;
2027 : }
2028 :
2029 : /* the invalid quoted character */
2030 :
2031 0 : state = sw_usual;
2032 :
2033 0 : *d++ = ch;
2034 :
2035 0 : break;
2036 :
2037 0 : case sw_quoted_second:
2038 :
2039 0 : state = sw_usual;
2040 :
2041 0 : if (ch >= '0' && ch <= '9') {
2042 0 : ch = (u_char) ((decoded << 4) + ch - '0');
2043 :
2044 0 : if (type & NGX_UNESCAPE_REDIRECT) {
2045 0 : if (ch > '%' && ch < 0x7f) {
2046 0 : *d++ = ch;
2047 0 : break;
2048 : }
2049 :
2050 0 : *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
2051 0 : break;
2052 : }
2053 :
2054 0 : *d++ = ch;
2055 :
2056 0 : break;
2057 : }
2058 :
2059 0 : c = (u_char) (ch | 0x20);
2060 0 : if (c >= 'a' && c <= 'f') {
2061 0 : ch = (u_char) ((decoded << 4) + c - 'a' + 10);
2062 :
2063 0 : if (type & NGX_UNESCAPE_URI) {
2064 0 : if (ch == '?') {
2065 0 : *d++ = ch;
2066 0 : goto done;
2067 : }
2068 :
2069 0 : *d++ = ch;
2070 0 : break;
2071 : }
2072 :
2073 0 : if (type & NGX_UNESCAPE_REDIRECT) {
2074 0 : if (ch == '?') {
2075 0 : *d++ = ch;
2076 0 : goto done;
2077 : }
2078 :
2079 0 : if (ch > '%' && ch < 0x7f) {
2080 0 : *d++ = ch;
2081 0 : break;
2082 : }
2083 :
2084 0 : *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
2085 0 : break;
2086 : }
2087 :
2088 0 : *d++ = ch;
2089 :
2090 0 : break;
2091 : }
2092 :
2093 : /* the invalid quoted character */
2094 :
2095 0 : break;
2096 : }
2097 : }
2098 :
2099 0 : done:
2100 :
2101 0 : *dst = d;
2102 0 : *src = s;
2103 0 : }
2104 :
2105 :
2106 : void
2107 18 : ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L)
2108 : {
2109 : /* ngx.req table */
2110 :
2111 18 : lua_createtable(L, 0 /* narr */, 24 /* nrec */); /* .req */
2112 :
2113 18 : ngx_http_lua_inject_req_header_api(L);
2114 18 : ngx_http_lua_inject_req_uri_api(log, L);
2115 18 : ngx_http_lua_inject_req_args_api(L);
2116 18 : ngx_http_lua_inject_req_body_api(L);
2117 18 : ngx_http_lua_inject_req_socket_api(L);
2118 18 : ngx_http_lua_inject_req_method_api(L);
2119 18 : ngx_http_lua_inject_req_time_api(L);
2120 18 : ngx_http_lua_inject_req_misc_api(L);
2121 :
2122 18 : lua_setfield(L, -2, "req");
2123 18 : }
2124 :
2125 :
2126 : static ngx_int_t
2127 0 : ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r,
2128 : ngx_http_lua_ctx_t *ctx)
2129 : {
2130 : ngx_int_t rc;
2131 :
2132 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2133 : "lua thread initiated internal redirect to %V",
2134 : &ctx->exec_uri);
2135 :
2136 0 : ngx_http_lua_cleanup_pending_operation(ctx->cur_co_ctx);
2137 :
2138 : ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1);
2139 :
2140 0 : ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD;
2141 :
2142 0 : if (r->filter_finalize) {
2143 0 : ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
2144 : }
2145 :
2146 0 : ngx_http_lua_request_cleanup(ctx, 1 /* forcible */);
2147 :
2148 0 : if (ctx->exec_uri.data[0] == '@') {
2149 0 : if (ctx->exec_args.len > 0) {
2150 0 : ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
2151 : "query strings %V ignored when exec'ing "
2152 : "named location %V",
2153 : &ctx->exec_args, &ctx->exec_uri);
2154 : }
2155 :
2156 0 : r->write_event_handler = ngx_http_request_empty_handler;
2157 :
2158 : #if 1
2159 0 : if (r->read_event_handler == ngx_http_lua_rd_check_broken_connection) {
2160 : /* resume the read event handler */
2161 :
2162 0 : r->read_event_handler = ngx_http_block_reading;
2163 : }
2164 : #endif
2165 :
2166 : #if 1
2167 : /* clear the modules contexts */
2168 0 : ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);
2169 : #endif
2170 :
2171 0 : rc = ngx_http_named_location(r, &ctx->exec_uri);
2172 0 : if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)
2173 : {
2174 0 : return rc;
2175 : }
2176 :
2177 : #if 0
2178 : if (!ctx->entered_content_phase) {
2179 : /* XXX ensure the main request ref count
2180 : * is decreased because the current
2181 : * request will be quit */
2182 : r->main->count--;
2183 : dd("XXX decrement main count: c:%d", (int) r->main->count);
2184 : }
2185 : #endif
2186 :
2187 0 : return NGX_DONE;
2188 : }
2189 :
2190 : dd("internal redirect to %.*s", (int) ctx->exec_uri.len,
2191 : ctx->exec_uri.data);
2192 :
2193 0 : r->write_event_handler = ngx_http_request_empty_handler;
2194 :
2195 0 : if (r->read_event_handler == ngx_http_lua_rd_check_broken_connection) {
2196 : /* resume the read event handler */
2197 :
2198 0 : r->read_event_handler = ngx_http_block_reading;
2199 : }
2200 :
2201 0 : rc = ngx_http_internal_redirect(r, &ctx->exec_uri, &ctx->exec_args);
2202 :
2203 : dd("internal redirect returned %d when in content phase? "
2204 : "%d", (int) rc, ctx->entered_content_phase);
2205 :
2206 0 : if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
2207 0 : return rc;
2208 : }
2209 :
2210 : #if 0
2211 : if (!ctx->entered_content_phase) {
2212 : /* XXX ensure the main request ref count
2213 : * is decreased because the current
2214 : * request will be quit */
2215 : dd("XXX decrement main count");
2216 : r->main->count--;
2217 : }
2218 : #endif
2219 :
2220 0 : return NGX_DONE;
2221 : }
2222 :
2223 :
2224 : static ngx_int_t
2225 0 : ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r,
2226 : ngx_http_lua_ctx_t *ctx)
2227 : {
2228 : ngx_int_t rc;
2229 :
2230 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2231 : "lua thread aborting request with status %d",
2232 : ctx->exit_code);
2233 :
2234 0 : ngx_http_lua_cleanup_pending_operation(ctx->cur_co_ctx);
2235 :
2236 : ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1);
2237 :
2238 0 : ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD;
2239 :
2240 0 : if (r->filter_finalize) {
2241 0 : ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
2242 : }
2243 :
2244 0 : ngx_http_lua_request_cleanup(ctx, 0);
2245 :
2246 0 : if (r->connection->fd == (ngx_socket_t) -1) { /* fake request */
2247 0 : return ctx->exit_code;
2248 : }
2249 :
2250 : #if 1
2251 0 : if (!r->header_sent
2252 0 : && !ctx->header_sent
2253 0 : && r->headers_out.status == 0
2254 0 : && ctx->exit_code >= NGX_HTTP_OK)
2255 : {
2256 0 : r->headers_out.status = ctx->exit_code;
2257 : }
2258 : #endif
2259 :
2260 0 : if (ctx->buffering
2261 0 : && r->headers_out.status
2262 0 : && ctx->exit_code != NGX_ERROR
2263 0 : && ctx->exit_code != NGX_HTTP_REQUEST_TIME_OUT
2264 0 : && ctx->exit_code != NGX_HTTP_CLIENT_CLOSED_REQUEST
2265 0 : && ctx->exit_code != NGX_HTTP_CLOSE)
2266 : {
2267 0 : rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */);
2268 :
2269 0 : if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
2270 0 : return rc;
2271 : }
2272 :
2273 0 : if (ctx->exit_code >= NGX_HTTP_OK) {
2274 0 : return NGX_HTTP_OK;
2275 : }
2276 :
2277 0 : return ctx->exit_code;
2278 : }
2279 :
2280 0 : if ((ctx->exit_code == NGX_OK
2281 0 : && ctx->entered_content_phase)
2282 0 : || (ctx->exit_code >= NGX_HTTP_OK
2283 0 : && ctx->exit_code < NGX_HTTP_SPECIAL_RESPONSE
2284 0 : && ctx->exit_code != NGX_HTTP_NO_CONTENT))
2285 : {
2286 0 : rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */);
2287 :
2288 0 : if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
2289 0 : return rc;
2290 : }
2291 : }
2292 :
2293 : #if 1
2294 0 : if ((r->header_sent || ctx->header_sent)
2295 0 : && ctx->exit_code > NGX_OK
2296 0 : && ctx->exit_code != NGX_HTTP_REQUEST_TIME_OUT
2297 0 : && ctx->exit_code != NGX_HTTP_CLIENT_CLOSED_REQUEST
2298 0 : && ctx->exit_code != NGX_HTTP_CLOSE)
2299 : {
2300 0 : if (ctx->entered_content_phase) {
2301 0 : return NGX_OK;
2302 : }
2303 :
2304 0 : return NGX_HTTP_OK;
2305 : }
2306 : #endif
2307 :
2308 0 : return ctx->exit_code;
2309 : }
2310 :
2311 :
2312 : void
2313 0 : ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L,
2314 : int table, ngx_str_t *args)
2315 : {
2316 : u_char *key;
2317 : size_t key_len;
2318 : u_char *value;
2319 : size_t value_len;
2320 0 : size_t len = 0;
2321 0 : size_t key_escape = 0;
2322 0 : uintptr_t total_escape = 0;
2323 : int n;
2324 : int i;
2325 : u_char *p;
2326 :
2327 0 : if (table < 0) {
2328 0 : table = lua_gettop(L) + table + 1;
2329 : }
2330 :
2331 0 : n = 0;
2332 0 : lua_pushnil(L);
2333 0 : while (lua_next(L, table) != 0) {
2334 0 : if (lua_type(L, -2) != LUA_TSTRING) {
2335 0 : luaL_error(L, "attempt to use a non-string key in the "
2336 : "\"args\" option table");
2337 0 : return;
2338 : }
2339 :
2340 0 : key = (u_char *) lua_tolstring(L, -2, &key_len);
2341 :
2342 0 : key_escape = 2 * ngx_http_lua_escape_uri(NULL, key, key_len,
2343 : NGX_ESCAPE_URI_COMPONENT);
2344 0 : total_escape += key_escape;
2345 :
2346 0 : switch (lua_type(L, -1)) {
2347 0 : case LUA_TNUMBER:
2348 : case LUA_TSTRING:
2349 0 : value = (u_char *) lua_tolstring(L, -1, &value_len);
2350 :
2351 0 : total_escape += 2 * ngx_http_lua_escape_uri(NULL, value, value_len,
2352 : NGX_ESCAPE_URI_COMPONENT);
2353 :
2354 0 : len += key_len + value_len + (sizeof("=") - 1);
2355 0 : n++;
2356 :
2357 0 : break;
2358 :
2359 0 : case LUA_TBOOLEAN:
2360 0 : if (lua_toboolean(L, -1)) {
2361 0 : len += key_len;
2362 0 : n++;
2363 : }
2364 :
2365 0 : break;
2366 :
2367 0 : case LUA_TTABLE:
2368 :
2369 0 : i = 0;
2370 0 : lua_pushnil(L);
2371 0 : while (lua_next(L, -2) != 0) {
2372 0 : if (lua_isboolean(L, -1)) {
2373 0 : if (lua_toboolean(L, -1)) {
2374 0 : len += key_len;
2375 :
2376 : } else {
2377 0 : lua_pop(L, 1);
2378 0 : continue;
2379 : }
2380 :
2381 : } else {
2382 0 : value = (u_char *) lua_tolstring(L, -1, &value_len);
2383 :
2384 0 : if (value == NULL) {
2385 0 : luaL_error(L, "attempt to use %s as query arg value",
2386 : luaL_typename(L, -1));
2387 0 : return;
2388 : }
2389 :
2390 0 : total_escape +=
2391 0 : 2 * ngx_http_lua_escape_uri(NULL, value,
2392 : value_len,
2393 : NGX_ESCAPE_URI_COMPONENT);
2394 :
2395 0 : len += key_len + value_len + (sizeof("=") - 1);
2396 : }
2397 :
2398 0 : if (i++ > 0) {
2399 0 : total_escape += key_escape;
2400 : }
2401 :
2402 0 : n++;
2403 0 : lua_pop(L, 1);
2404 : }
2405 :
2406 0 : break;
2407 :
2408 0 : default:
2409 0 : luaL_error(L, "attempt to use %s as query arg value",
2410 : luaL_typename(L, -1));
2411 0 : return;
2412 : }
2413 :
2414 0 : lua_pop(L, 1);
2415 : }
2416 :
2417 0 : len += (size_t) total_escape;
2418 :
2419 0 : if (n > 1) {
2420 0 : len += (n - 1) * (sizeof("&") - 1);
2421 : }
2422 :
2423 : dd("len 1: %d", (int) len);
2424 :
2425 0 : if (r) {
2426 0 : p = ngx_palloc(r->pool, len);
2427 0 : if (p == NULL) {
2428 0 : luaL_error(L, "no memory");
2429 0 : return;
2430 : }
2431 :
2432 : } else {
2433 0 : p = lua_newuserdata(L, len);
2434 : }
2435 :
2436 0 : args->data = p;
2437 0 : args->len = len;
2438 :
2439 0 : i = 0;
2440 0 : lua_pushnil(L);
2441 0 : while (lua_next(L, table) != 0) {
2442 0 : key = (u_char *) lua_tolstring(L, -2, &key_len);
2443 :
2444 0 : switch (lua_type(L, -1)) {
2445 0 : case LUA_TNUMBER:
2446 : case LUA_TSTRING:
2447 :
2448 0 : if (total_escape) {
2449 0 : p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len,
2450 : NGX_ESCAPE_URI_COMPONENT
2451 : );
2452 :
2453 : } else {
2454 : dd("shortcut: no escape required");
2455 :
2456 0 : p = ngx_copy(p, key, key_len);
2457 : }
2458 :
2459 0 : *p++ = '=';
2460 :
2461 0 : value = (u_char *) lua_tolstring(L, -1, &value_len);
2462 :
2463 0 : if (total_escape) {
2464 0 : p = (u_char *) ngx_http_lua_escape_uri(p, value, value_len,
2465 : NGX_ESCAPE_URI_COMPONENT
2466 : );
2467 :
2468 : } else {
2469 0 : p = ngx_copy(p, value, value_len);
2470 : }
2471 :
2472 0 : if (i != n - 1) {
2473 : /* not the last pair */
2474 0 : *p++ = '&';
2475 : }
2476 :
2477 0 : i++;
2478 :
2479 0 : break;
2480 :
2481 0 : case LUA_TBOOLEAN:
2482 0 : if (lua_toboolean(L, -1)) {
2483 0 : if (total_escape) {
2484 0 : p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len,
2485 : NGX_ESCAPE_URI_COMPONENT);
2486 :
2487 : } else {
2488 : dd("shortcut: no escape required");
2489 :
2490 0 : p = ngx_copy(p, key, key_len);
2491 : }
2492 :
2493 0 : if (i != n - 1) {
2494 : /* not the last pair */
2495 0 : *p++ = '&';
2496 : }
2497 :
2498 0 : i++;
2499 : }
2500 :
2501 0 : break;
2502 :
2503 0 : case LUA_TTABLE:
2504 :
2505 0 : lua_pushnil(L);
2506 0 : while (lua_next(L, -2) != 0) {
2507 :
2508 0 : if (lua_isboolean(L, -1)) {
2509 0 : if (lua_toboolean(L, -1)) {
2510 0 : if (total_escape) {
2511 0 : p = (u_char *) ngx_http_lua_escape_uri(p, key,
2512 : key_len,
2513 : NGX_ESCAPE_URI_COMPONENT);
2514 :
2515 : } else {
2516 : dd("shortcut: no escape required");
2517 :
2518 0 : p = ngx_copy(p, key, key_len);
2519 : }
2520 :
2521 : } else {
2522 0 : lua_pop(L, 1);
2523 0 : continue;
2524 : }
2525 :
2526 : } else {
2527 :
2528 0 : if (total_escape) {
2529 0 : p = (u_char *)
2530 0 : ngx_http_lua_escape_uri(p, key,
2531 : key_len,
2532 : NGX_ESCAPE_URI_COMPONENT
2533 : );
2534 :
2535 : } else {
2536 : dd("shortcut: no escape required");
2537 :
2538 0 : p = ngx_copy(p, key, key_len);
2539 : }
2540 :
2541 0 : *p++ = '=';
2542 :
2543 0 : value = (u_char *) lua_tolstring(L, -1, &value_len);
2544 :
2545 0 : if (total_escape) {
2546 0 : p = (u_char *)
2547 0 : ngx_http_lua_escape_uri(p, value,
2548 : value_len,
2549 : NGX_ESCAPE_URI_COMPONENT
2550 : );
2551 :
2552 : } else {
2553 0 : p = ngx_copy(p, value, value_len);
2554 : }
2555 : }
2556 :
2557 0 : if (i != n - 1) {
2558 : /* not the last pair */
2559 0 : *p++ = '&';
2560 : }
2561 :
2562 0 : i++;
2563 0 : lua_pop(L, 1);
2564 : }
2565 :
2566 0 : break;
2567 :
2568 0 : default:
2569 0 : luaL_error(L, "should not reach here");
2570 0 : return;
2571 : }
2572 :
2573 0 : lua_pop(L, 1);
2574 : }
2575 :
2576 0 : if (p - args->data != (ssize_t) len) {
2577 0 : luaL_error(L, "buffer error: %d != %d",
2578 0 : (int) (p - args->data), (int) len);
2579 0 : return;
2580 : }
2581 : }
2582 :
2583 :
2584 : static ngx_int_t
2585 0 : ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r,
2586 : ngx_http_lua_ctx_t *ctx)
2587 : {
2588 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2589 : "lua thread aborting request with URI rewrite jump: "
2590 : "\"%V?%V\"", &r->uri, &r->args);
2591 :
2592 0 : ngx_http_lua_cleanup_pending_operation(ctx->cur_co_ctx);
2593 :
2594 : ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1);
2595 :
2596 0 : ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD;
2597 :
2598 0 : if (r->filter_finalize) {
2599 0 : ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
2600 : }
2601 :
2602 0 : ngx_http_lua_request_cleanup(ctx, 1 /* forcible */);
2603 0 : ngx_http_lua_init_ctx(r, ctx);
2604 :
2605 0 : return NGX_OK;
2606 : }
2607 :
2608 :
2609 : /* XXX ngx_open_and_stat_file is static in the core. sigh. */
2610 : ngx_int_t
2611 0 : ngx_http_lua_open_and_stat_file(u_char *name, ngx_open_file_info_t *of,
2612 : ngx_log_t *log)
2613 : {
2614 : ngx_fd_t fd;
2615 : ngx_file_info_t fi;
2616 :
2617 0 : if (of->fd != NGX_INVALID_FILE) {
2618 :
2619 0 : if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) {
2620 0 : of->failed = ngx_file_info_n;
2621 0 : goto failed;
2622 : }
2623 :
2624 0 : if (of->uniq == ngx_file_uniq(&fi)) {
2625 0 : goto done;
2626 : }
2627 :
2628 0 : } else if (of->test_dir) {
2629 :
2630 0 : if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) {
2631 0 : of->failed = ngx_file_info_n;
2632 0 : goto failed;
2633 : }
2634 :
2635 0 : if (ngx_is_dir(&fi)) {
2636 0 : goto done;
2637 : }
2638 : }
2639 :
2640 0 : if (!of->log) {
2641 :
2642 : /*
2643 : * Use non-blocking open() not to hang on FIFO files, etc.
2644 : * This flag has no effect on a regular files.
2645 : */
2646 :
2647 0 : fd = ngx_open_file(name, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
2648 : NGX_FILE_OPEN, 0);
2649 :
2650 : } else {
2651 0 : fd = ngx_open_file(name, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN,
2652 : NGX_FILE_DEFAULT_ACCESS);
2653 : }
2654 :
2655 0 : if (fd == NGX_INVALID_FILE) {
2656 0 : of->failed = ngx_open_file_n;
2657 0 : goto failed;
2658 : }
2659 :
2660 0 : if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
2661 0 : ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
2662 : ngx_fd_info_n " \"%s\" failed", name);
2663 :
2664 0 : if (ngx_close_file(fd) == NGX_FILE_ERROR) {
2665 0 : ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
2666 : ngx_close_file_n " \"%s\" failed", name);
2667 : }
2668 :
2669 0 : of->fd = NGX_INVALID_FILE;
2670 :
2671 0 : return NGX_ERROR;
2672 : }
2673 :
2674 0 : if (ngx_is_dir(&fi)) {
2675 0 : if (ngx_close_file(fd) == NGX_FILE_ERROR) {
2676 0 : ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
2677 : ngx_close_file_n " \"%s\" failed", name);
2678 : }
2679 :
2680 0 : of->fd = NGX_INVALID_FILE;
2681 :
2682 : } else {
2683 0 : of->fd = fd;
2684 :
2685 0 : if (of->directio <= ngx_file_size(&fi)) {
2686 0 : if (ngx_directio_on(fd) == NGX_FILE_ERROR) {
2687 0 : ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
2688 : ngx_directio_on_n " \"%s\" failed", name);
2689 :
2690 : } else {
2691 0 : of->is_directio = 1;
2692 : }
2693 : }
2694 : }
2695 :
2696 0 : done:
2697 :
2698 0 : of->uniq = ngx_file_uniq(&fi);
2699 0 : of->mtime = ngx_file_mtime(&fi);
2700 0 : of->size = ngx_file_size(&fi);
2701 : #if defined(nginx_version) && nginx_version >= 1000001
2702 0 : of->fs_size = ngx_file_fs_size(&fi);
2703 : #endif
2704 0 : of->is_dir = ngx_is_dir(&fi);
2705 0 : of->is_file = ngx_is_file(&fi);
2706 0 : of->is_link = ngx_is_link(&fi);
2707 0 : of->is_exec = ngx_is_exec(&fi);
2708 :
2709 0 : return NGX_OK;
2710 :
2711 0 : failed:
2712 :
2713 0 : of->fd = NGX_INVALID_FILE;
2714 0 : of->err = ngx_errno;
2715 :
2716 0 : return NGX_ERROR;
2717 : }
2718 :
2719 :
2720 : ngx_chain_t *
2721 2 : ngx_http_lua_chain_get_free_buf(ngx_log_t *log, ngx_pool_t *p,
2722 : ngx_chain_t **free, size_t len)
2723 : {
2724 : ngx_buf_t *b;
2725 : ngx_chain_t *cl;
2726 : u_char *start, *end;
2727 :
2728 2 : const ngx_buf_tag_t tag = (ngx_buf_tag_t) &ngx_http_lua_module;
2729 :
2730 2 : if (*free) {
2731 0 : cl = *free;
2732 0 : *free = cl->next;
2733 0 : cl->next = NULL;
2734 :
2735 0 : b = cl->buf;
2736 0 : start = b->start;
2737 0 : end = b->end;
2738 0 : if (start && (size_t) (end - start) >= len) {
2739 0 : ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0,
2740 : "lua reuse free buf memory %O >= %uz, cl:%p, p:%p",
2741 : (off_t) (end - start), len, cl, start);
2742 :
2743 0 : ngx_memzero(b, sizeof(ngx_buf_t));
2744 :
2745 0 : b->start = start;
2746 0 : b->pos = start;
2747 0 : b->last = start;
2748 0 : b->end = end;
2749 0 : b->tag = tag;
2750 :
2751 0 : if (len) {
2752 0 : b->temporary = 1;
2753 : }
2754 :
2755 0 : return cl;
2756 : }
2757 :
2758 0 : ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0,
2759 : "lua reuse free buf chain, but reallocate memory "
2760 : "because %uz >= %O, cl:%p, p:%p", len,
2761 : (off_t) (b->end - b->start), cl, b->start);
2762 :
2763 0 : if (ngx_buf_in_memory(b) && b->start) {
2764 0 : ngx_pfree(p, b->start);
2765 : }
2766 :
2767 0 : ngx_memzero(b, sizeof(ngx_buf_t));
2768 :
2769 0 : if (len == 0) {
2770 0 : return cl;
2771 : }
2772 :
2773 0 : b->start = ngx_palloc(p, len);
2774 0 : if (b->start == NULL) {
2775 0 : return NULL;
2776 : }
2777 :
2778 0 : b->end = b->start + len;
2779 :
2780 : dd("buf start: %p", cl->buf->start);
2781 :
2782 0 : b->pos = b->start;
2783 0 : b->last = b->start;
2784 0 : b->tag = tag;
2785 0 : b->temporary = 1;
2786 :
2787 0 : return cl;
2788 : }
2789 :
2790 2 : cl = ngx_alloc_chain_link(p);
2791 2 : if (cl == NULL) {
2792 0 : return NULL;
2793 : }
2794 :
2795 2 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
2796 : "lua allocate new chainlink and new buf of size %uz, cl:%p",
2797 : len, cl);
2798 :
2799 2 : cl->buf = len ? ngx_create_temp_buf(p, len) : ngx_calloc_buf(p);
2800 2 : if (cl->buf == NULL) {
2801 0 : return NULL;
2802 : }
2803 :
2804 : dd("buf start: %p", cl->buf->start);
2805 :
2806 2 : cl->buf->tag = tag;
2807 2 : cl->next = NULL;
2808 :
2809 2 : return cl;
2810 : }
2811 :
2812 :
2813 : static int
2814 0 : ngx_http_lua_thread_traceback(lua_State *L, lua_State *co,
2815 : ngx_http_lua_co_ctx_t *coctx)
2816 : {
2817 : int base;
2818 : int level, coid;
2819 : lua_Debug ar;
2820 :
2821 0 : base = lua_gettop(L);
2822 0 : lua_checkstack(L, 3);
2823 0 : lua_pushliteral(L, "stack traceback:");
2824 0 : coid = 0;
2825 :
2826 0 : while (co) {
2827 :
2828 0 : if (coid >= NGX_HTTP_LUA_BT_MAX_COROS) {
2829 0 : break;
2830 : }
2831 :
2832 0 : lua_checkstack(L, 2);
2833 0 : lua_pushfstring(L, "\ncoroutine %d:", coid++);
2834 :
2835 0 : level = 0;
2836 :
2837 0 : while (lua_getstack(co, level++, &ar)) {
2838 :
2839 0 : lua_checkstack(L, 5);
2840 :
2841 0 : if (level > NGX_HTTP_LUA_BT_DEPTH) {
2842 0 : lua_pushliteral(L, "\n\t...");
2843 0 : break;
2844 : }
2845 :
2846 0 : lua_pushliteral(L, "\n\t");
2847 0 : lua_getinfo(co, "Snl", &ar);
2848 0 : lua_pushfstring(L, "%s:", ar.short_src);
2849 :
2850 0 : if (ar.currentline > 0) {
2851 0 : lua_pushfstring(L, "%d:", ar.currentline);
2852 : }
2853 :
2854 0 : if (*ar.namewhat != '\0') { /* is there a name? */
2855 0 : lua_pushfstring(L, " in function " LUA_QS, ar.name);
2856 :
2857 : } else {
2858 0 : if (*ar.what == 'm') { /* main? */
2859 0 : lua_pushliteral(L, " in main chunk");
2860 :
2861 0 : } else if (*ar.what == 'C' || *ar.what == 't') {
2862 0 : lua_pushliteral(L, " ?"); /* C function or tail call */
2863 :
2864 : } else {
2865 0 : lua_pushfstring(L, " in function <%s:%d>",
2866 : ar.short_src, ar.linedefined);
2867 : }
2868 : }
2869 : }
2870 :
2871 0 : if (lua_gettop(L) - base >= 15) {
2872 0 : lua_concat(L, lua_gettop(L) - base);
2873 : }
2874 :
2875 : /* check if the coroutine has a parent coroutine*/
2876 0 : coctx = coctx->parent_co_ctx;
2877 0 : if (!coctx || coctx->co_status == NGX_HTTP_LUA_CO_DEAD) {
2878 : break;
2879 : }
2880 :
2881 0 : co = coctx->co;
2882 : }
2883 :
2884 0 : lua_concat(L, lua_gettop(L) - base);
2885 0 : return 1;
2886 : }
2887 :
2888 :
2889 : int
2890 0 : ngx_http_lua_traceback(lua_State *L)
2891 : {
2892 0 : if (!lua_isstring(L, 1)) { /* 'message' not a string? */
2893 0 : return 1; /* keep it intact */
2894 : }
2895 :
2896 0 : lua_getglobal(L, "debug");
2897 0 : if (!lua_istable(L, -1)) {
2898 0 : lua_pop(L, 1);
2899 0 : return 1;
2900 : }
2901 :
2902 0 : lua_getfield(L, -1, "traceback");
2903 0 : if (!lua_isfunction(L, -1)) {
2904 0 : lua_pop(L, 2);
2905 0 : return 1;
2906 : }
2907 :
2908 0 : lua_pushvalue(L, 1); /* pass error message */
2909 0 : lua_pushinteger(L, 2); /* skip this function and traceback */
2910 0 : lua_call(L, 2, 1); /* call debug.traceback */
2911 0 : return 1;
2912 : }
2913 :
2914 :
2915 : static void
2916 18 : ngx_http_lua_inject_arg_api(lua_State *L)
2917 : {
2918 18 : lua_pushliteral(L, "arg");
2919 18 : lua_newtable(L); /* .arg table aka {} */
2920 :
2921 18 : lua_createtable(L, 0 /* narr */, 2 /* nrec */); /* the metatable */
2922 :
2923 18 : lua_pushcfunction(L, ngx_http_lua_param_get);
2924 18 : lua_setfield(L, -2, "__index");
2925 :
2926 18 : lua_pushcfunction(L, ngx_http_lua_param_set);
2927 18 : lua_setfield(L, -2, "__newindex");
2928 :
2929 18 : lua_setmetatable(L, -2); /* tie the metatable to param table */
2930 :
2931 : dd("top: %d, type -1: %s", lua_gettop(L), luaL_typename(L, -1));
2932 :
2933 18 : lua_rawset(L, -3); /* set ngx.arg table */
2934 18 : }
2935 :
2936 :
2937 : static int
2938 0 : ngx_http_lua_param_get(lua_State *L)
2939 : {
2940 : ngx_http_lua_ctx_t *ctx;
2941 : ngx_http_request_t *r;
2942 :
2943 0 : r = ngx_http_lua_get_req(L);
2944 0 : if (r == NULL) {
2945 0 : return 0;
2946 : }
2947 :
2948 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
2949 0 : if (ctx == NULL) {
2950 0 : return luaL_error(L, "ctx not found");
2951 : }
2952 :
2953 0 : ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_SET
2954 : | NGX_HTTP_LUA_CONTEXT_BODY_FILTER);
2955 :
2956 0 : if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SET)) {
2957 0 : return ngx_http_lua_setby_param_get(L);
2958 : }
2959 :
2960 : /* ctx->context & (NGX_HTTP_LUA_CONTEXT_BODY_FILTER) */
2961 :
2962 0 : return ngx_http_lua_body_filter_param_get(L);
2963 : }
2964 :
2965 :
2966 : static int
2967 0 : ngx_http_lua_param_set(lua_State *L)
2968 : {
2969 : ngx_http_lua_ctx_t *ctx;
2970 : ngx_http_request_t *r;
2971 :
2972 0 : r = ngx_http_lua_get_req(L);
2973 0 : if (r == NULL) {
2974 0 : return 0;
2975 : }
2976 :
2977 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
2978 0 : if (ctx == NULL) {
2979 0 : return luaL_error(L, "ctx not found");
2980 : }
2981 :
2982 0 : ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_BODY_FILTER);
2983 :
2984 0 : return ngx_http_lua_body_filter_param_set(L, r, ctx);
2985 : }
2986 :
2987 :
2988 : ngx_http_lua_co_ctx_t *
2989 0 : ngx_http_lua_get_co_ctx(lua_State *L, ngx_http_lua_ctx_t *ctx)
2990 : {
2991 : ngx_uint_t i;
2992 : ngx_list_part_t *part;
2993 : ngx_http_lua_co_ctx_t *coctx;
2994 :
2995 0 : if (L == ctx->entry_co_ctx.co) {
2996 0 : return &ctx->entry_co_ctx;
2997 : }
2998 :
2999 0 : if (ctx->user_co_ctx == NULL) {
3000 0 : return NULL;
3001 : }
3002 :
3003 0 : part = &ctx->user_co_ctx->part;
3004 0 : coctx = part->elts;
3005 :
3006 : /* FIXME: we should use rbtree here to prevent O(n) lookup overhead */
3007 :
3008 0 : for (i = 0; /* void */; i++) {
3009 :
3010 0 : if (i >= part->nelts) {
3011 0 : if (part->next == NULL) {
3012 0 : break;
3013 : }
3014 :
3015 0 : part = part->next;
3016 0 : coctx = part->elts;
3017 0 : i = 0;
3018 : }
3019 :
3020 0 : if (coctx[i].co == L) {
3021 0 : return &coctx[i];
3022 : }
3023 : }
3024 :
3025 0 : return NULL;
3026 : }
3027 :
3028 :
3029 : ngx_http_lua_co_ctx_t *
3030 0 : ngx_http_lua_create_co_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx)
3031 : {
3032 : ngx_http_lua_co_ctx_t *coctx;
3033 :
3034 0 : if (ctx->user_co_ctx == NULL) {
3035 0 : ctx->user_co_ctx = ngx_list_create(r->pool, 4,
3036 : sizeof(ngx_http_lua_co_ctx_t));
3037 0 : if (ctx->user_co_ctx == NULL) {
3038 0 : return NULL;
3039 : }
3040 : }
3041 :
3042 0 : coctx = ngx_list_push(ctx->user_co_ctx);
3043 0 : if (coctx == NULL) {
3044 0 : return NULL;
3045 : }
3046 :
3047 0 : ngx_memzero(coctx, sizeof(ngx_http_lua_co_ctx_t));
3048 :
3049 0 : coctx->co_ref = LUA_NOREF;
3050 :
3051 0 : return coctx;
3052 : }
3053 :
3054 :
3055 : /* this is for callers other than the content handler */
3056 : ngx_int_t
3057 0 : ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L,
3058 : ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_uint_t nreqs)
3059 : {
3060 : ngx_int_t rc;
3061 : ngx_http_lua_posted_thread_t *pt;
3062 :
3063 : for ( ;; ) {
3064 0 : if (c->destroyed || c->requests != nreqs) {
3065 0 : return NGX_DONE;
3066 : }
3067 :
3068 0 : pt = ctx->posted_threads;
3069 0 : if (pt == NULL) {
3070 0 : return NGX_DONE;
3071 : }
3072 :
3073 0 : ctx->posted_threads = pt->next;
3074 :
3075 : ngx_http_lua_probe_run_posted_thread(r, pt->co_ctx->co,
3076 : (int) pt->co_ctx->co_status);
3077 :
3078 0 : if (pt->co_ctx->co_status != NGX_HTTP_LUA_CO_RUNNING) {
3079 0 : continue;
3080 : }
3081 :
3082 0 : ctx->cur_co_ctx = pt->co_ctx;
3083 :
3084 0 : rc = ngx_http_lua_run_thread(L, r, ctx, 0);
3085 :
3086 0 : if (rc == NGX_AGAIN) {
3087 0 : continue;
3088 : }
3089 :
3090 0 : if (rc == NGX_DONE) {
3091 0 : ngx_http_lua_finalize_request(r, NGX_DONE);
3092 0 : continue;
3093 : }
3094 :
3095 : /* rc == NGX_ERROR || rc >= NGX_OK */
3096 :
3097 0 : if (ctx->entered_content_phase) {
3098 0 : ngx_http_lua_finalize_request(r, rc);
3099 : }
3100 :
3101 0 : return rc;
3102 : }
3103 :
3104 : /* impossible to reach here */
3105 : }
3106 :
3107 :
3108 : ngx_int_t
3109 0 : ngx_http_lua_post_thread(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx,
3110 : ngx_http_lua_co_ctx_t *coctx)
3111 : {
3112 : ngx_http_lua_posted_thread_t **p;
3113 : ngx_http_lua_posted_thread_t *pt;
3114 :
3115 0 : pt = ngx_palloc(r->pool, sizeof(ngx_http_lua_posted_thread_t));
3116 0 : if (pt == NULL) {
3117 0 : return NGX_ERROR;
3118 : }
3119 :
3120 0 : pt->co_ctx = coctx;
3121 0 : pt->next = NULL;
3122 :
3123 0 : for (p = &ctx->posted_threads; *p; p = &(*p)->next) { /* void */ }
3124 :
3125 0 : *p = pt;
3126 :
3127 0 : return NGX_OK;
3128 : }
3129 :
3130 :
3131 : static void
3132 2 : ngx_http_lua_finalize_threads(ngx_http_request_t *r,
3133 : ngx_http_lua_ctx_t *ctx, lua_State *L)
3134 : {
3135 : #ifdef NGX_LUA_USE_ASSERT
3136 : int top;
3137 : #endif
3138 2 : int inited = 0, ref;
3139 : ngx_uint_t i;
3140 : ngx_list_part_t *part;
3141 : ngx_http_lua_co_ctx_t *cc, *coctx;
3142 :
3143 : #ifdef NGX_LUA_USE_ASSERT
3144 2 : top = lua_gettop(L);
3145 : #endif
3146 :
3147 : #if 1
3148 2 : coctx = ctx->on_abort_co_ctx;
3149 2 : if (coctx && coctx->co_ref != LUA_NOREF) {
3150 0 : if (coctx->co_status != NGX_HTTP_LUA_CO_SUSPENDED) {
3151 : /* the on_abort thread contributes to the coctx->uthreads
3152 : * counter only when it actually starts running */
3153 0 : ngx_http_lua_cleanup_pending_operation(coctx);
3154 0 : ctx->uthreads--;
3155 : }
3156 :
3157 : ngx_http_lua_probe_thread_delete(r, coctx->co, ctx);
3158 :
3159 0 : lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
3160 0 : lua_rawget(L, LUA_REGISTRYINDEX);
3161 0 : inited = 1;
3162 :
3163 0 : luaL_unref(L, -1, coctx->co_ref);
3164 0 : coctx->co_ref = LUA_NOREF;
3165 :
3166 0 : coctx->co_status = NGX_HTTP_LUA_CO_DEAD;
3167 0 : ctx->on_abort_co_ctx = NULL;
3168 : }
3169 : #endif
3170 :
3171 2 : if (ctx->user_co_ctx) {
3172 0 : part = &ctx->user_co_ctx->part;
3173 0 : cc = part->elts;
3174 :
3175 0 : for (i = 0; /* void */; i++) {
3176 :
3177 0 : if (i >= part->nelts) {
3178 0 : if (part->next == NULL) {
3179 0 : break;
3180 : }
3181 :
3182 0 : part = part->next;
3183 0 : cc = part->elts;
3184 0 : i = 0;
3185 : }
3186 :
3187 0 : coctx = &cc[i];
3188 :
3189 0 : ref = coctx->co_ref;
3190 :
3191 0 : if (ref != LUA_NOREF) {
3192 0 : ngx_http_lua_cleanup_pending_operation(coctx);
3193 :
3194 : ngx_http_lua_probe_thread_delete(r, coctx->co, ctx);
3195 :
3196 0 : if (!inited) {
3197 0 : lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
3198 0 : lua_rawget(L, LUA_REGISTRYINDEX);
3199 0 : inited = 1;
3200 : }
3201 :
3202 0 : ngx_http_lua_assert(lua_gettop(L) - top == 1);
3203 :
3204 0 : luaL_unref(L, -1, ref);
3205 0 : coctx->co_ref = LUA_NOREF;
3206 :
3207 0 : coctx->co_status = NGX_HTTP_LUA_CO_DEAD;
3208 0 : ctx->uthreads--;
3209 : }
3210 : }
3211 :
3212 0 : ctx->user_co_ctx = NULL;
3213 : }
3214 :
3215 2 : ngx_http_lua_assert(ctx->uthreads == 0);
3216 :
3217 2 : coctx = &ctx->entry_co_ctx;
3218 :
3219 2 : ref = coctx->co_ref;
3220 2 : if (ref != LUA_NOREF) {
3221 0 : ngx_http_lua_cleanup_pending_operation(coctx);
3222 :
3223 : ngx_http_lua_probe_thread_delete(r, coctx->co, ctx);
3224 :
3225 0 : if (!inited) {
3226 0 : lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key);
3227 0 : lua_rawget(L, LUA_REGISTRYINDEX);
3228 0 : inited = 1;
3229 : }
3230 :
3231 0 : ngx_http_lua_assert(lua_gettop(L) - top == 1);
3232 :
3233 0 : luaL_unref(L, -1, coctx->co_ref);
3234 0 : coctx->co_ref = LUA_NOREF;
3235 0 : coctx->co_status = NGX_HTTP_LUA_CO_DEAD;
3236 : }
3237 :
3238 2 : if (inited) {
3239 0 : lua_pop(L, 1);
3240 : }
3241 2 : }
3242 :
3243 :
3244 : static ngx_int_t
3245 0 : ngx_http_lua_post_zombie_thread(ngx_http_request_t *r,
3246 : ngx_http_lua_co_ctx_t *parent, ngx_http_lua_co_ctx_t *thread)
3247 : {
3248 : ngx_http_lua_posted_thread_t **p;
3249 : ngx_http_lua_posted_thread_t *pt;
3250 :
3251 0 : pt = ngx_palloc(r->pool, sizeof(ngx_http_lua_posted_thread_t));
3252 0 : if (pt == NULL) {
3253 0 : return NGX_ERROR;
3254 : }
3255 :
3256 0 : pt->co_ctx = thread;
3257 0 : pt->next = NULL;
3258 :
3259 0 : for (p = &parent->zombie_child_threads; *p; p = &(*p)->next) { /* void */ }
3260 :
3261 0 : *p = pt;
3262 :
3263 0 : return NGX_OK;
3264 : }
3265 :
3266 :
3267 : static void
3268 0 : ngx_http_lua_cleanup_zombie_child_uthreads(ngx_http_request_t *r,
3269 : lua_State *L, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx)
3270 : {
3271 : ngx_http_lua_posted_thread_t *pt;
3272 :
3273 0 : for (pt = coctx->zombie_child_threads; pt; pt = pt->next) {
3274 0 : if (pt->co_ctx->co_ref != LUA_NOREF) {
3275 0 : ngx_http_lua_del_thread(r, L, ctx, pt->co_ctx);
3276 0 : ctx->uthreads--;
3277 : }
3278 : }
3279 :
3280 0 : coctx->zombie_child_threads = NULL;
3281 0 : }
3282 :
3283 :
3284 : ngx_int_t
3285 0 : ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev)
3286 : {
3287 : int n;
3288 : char buf[1];
3289 : ngx_err_t err;
3290 : ngx_int_t event;
3291 : ngx_connection_t *c;
3292 :
3293 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
3294 : "http lua check client, write event:%d, \"%V\"",
3295 : ev->write, &r->uri);
3296 :
3297 0 : c = r->connection;
3298 :
3299 0 : if (c->error) {
3300 0 : if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
3301 :
3302 0 : event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
3303 :
3304 0 : if (ngx_del_event(ev, event, 0) != NGX_OK) {
3305 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
3306 : }
3307 : }
3308 :
3309 0 : return NGX_HTTP_CLIENT_CLOSED_REQUEST;
3310 : }
3311 :
3312 : #if (NGX_HTTP_V2)
3313 0 : if (r->stream) {
3314 0 : return NGX_OK;
3315 : }
3316 : #endif
3317 :
3318 : #if (NGX_HAVE_KQUEUE)
3319 :
3320 : if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
3321 :
3322 : if (!ev->pending_eof) {
3323 : return NGX_OK;
3324 : }
3325 :
3326 : ev->eof = 1;
3327 :
3328 : if (ev->kq_errno) {
3329 : ev->error = 1;
3330 : }
3331 :
3332 : ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
3333 : "kevent() reported that client prematurely closed "
3334 : "connection");
3335 :
3336 : return NGX_HTTP_CLIENT_CLOSED_REQUEST;
3337 : }
3338 :
3339 : #endif
3340 :
3341 0 : n = recv(c->fd, buf, 1, MSG_PEEK);
3342 :
3343 0 : err = ngx_socket_errno;
3344 :
3345 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err,
3346 : "http lua recv(): %d", n);
3347 :
3348 0 : if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
3349 0 : return NGX_OK;
3350 : }
3351 :
3352 0 : if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
3353 : dd("event is active");
3354 :
3355 0 : event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
3356 :
3357 : #if 1
3358 0 : if (ngx_del_event(ev, event, 0) != NGX_OK) {
3359 0 : return NGX_HTTP_INTERNAL_SERVER_ERROR;
3360 : }
3361 : #endif
3362 : }
3363 :
3364 : dd("HERE %d", (int) n);
3365 :
3366 0 : if (n > 0) {
3367 0 : return NGX_OK;
3368 : }
3369 :
3370 0 : if (n == -1) {
3371 0 : if (err == NGX_EAGAIN) {
3372 : dd("HERE");
3373 0 : return NGX_OK;
3374 : }
3375 :
3376 0 : ev->error = 1;
3377 :
3378 : } else { /* n == 0 */
3379 0 : err = 0;
3380 : }
3381 :
3382 0 : ev->eof = 1;
3383 :
3384 0 : ngx_log_error(NGX_LOG_INFO, ev->log, err,
3385 : "client prematurely closed connection");
3386 :
3387 0 : return NGX_HTTP_CLIENT_CLOSED_REQUEST;
3388 : }
3389 :
3390 :
3391 : void
3392 0 : ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r)
3393 : {
3394 : ngx_int_t rc;
3395 : ngx_event_t *rev;
3396 : ngx_http_lua_ctx_t *ctx;
3397 :
3398 0 : if (r->done) {
3399 0 : return;
3400 : }
3401 :
3402 0 : rc = ngx_http_lua_check_broken_connection(r, r->connection->read);
3403 :
3404 0 : if (rc == NGX_OK) {
3405 0 : return;
3406 : }
3407 :
3408 : /* rc == NGX_ERROR || rc > NGX_OK */
3409 :
3410 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
3411 0 : if (ctx == NULL) {
3412 0 : return;
3413 : }
3414 :
3415 0 : if (ctx->on_abort_co_ctx == NULL) {
3416 0 : r->connection->error = 1;
3417 0 : ngx_http_lua_request_cleanup(ctx, 0);
3418 0 : ngx_http_lua_finalize_request(r, rc);
3419 0 : return;
3420 : }
3421 :
3422 0 : if (ctx->on_abort_co_ctx->co_status != NGX_HTTP_LUA_CO_SUSPENDED) {
3423 :
3424 : /* on_abort already run for the current request handler */
3425 :
3426 0 : rev = r->connection->read;
3427 :
3428 0 : if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && rev->active) {
3429 0 : if (ngx_del_event(rev, NGX_READ_EVENT, 0) != NGX_OK) {
3430 0 : ngx_http_lua_request_cleanup(ctx, 0);
3431 0 : ngx_http_lua_finalize_request(r,
3432 : NGX_HTTP_INTERNAL_SERVER_ERROR);
3433 0 : return;
3434 : }
3435 : }
3436 :
3437 0 : return;
3438 : }
3439 :
3440 0 : ctx->uthreads++;
3441 0 : ctx->resume_handler = ngx_http_lua_on_abort_resume;
3442 0 : ctx->on_abort_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING;
3443 0 : ctx->cur_co_ctx = ctx->on_abort_co_ctx;
3444 :
3445 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3446 : "lua waking up the on_abort callback thread");
3447 :
3448 0 : if (ctx->entered_content_phase) {
3449 0 : r->write_event_handler = ngx_http_lua_content_wev_handler;
3450 :
3451 : } else {
3452 0 : r->write_event_handler = ngx_http_core_run_phases;
3453 : }
3454 :
3455 0 : r->write_event_handler(r);
3456 : }
3457 :
3458 :
3459 : static ngx_int_t
3460 0 : ngx_http_lua_on_abort_resume(ngx_http_request_t *r)
3461 : {
3462 : lua_State *vm;
3463 : ngx_int_t rc;
3464 : ngx_uint_t nreqs;
3465 : ngx_connection_t *c;
3466 : ngx_http_lua_ctx_t *ctx;
3467 :
3468 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
3469 0 : if (ctx == NULL) {
3470 0 : return NGX_ERROR;
3471 : }
3472 :
3473 0 : ctx->resume_handler = ngx_http_lua_wev_handler;
3474 :
3475 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3476 : "lua resuming the on_abort callback thread");
3477 :
3478 : #if 0
3479 : ngx_http_lua_probe_info("tcp resume");
3480 : #endif
3481 :
3482 0 : c = r->connection;
3483 0 : vm = ngx_http_lua_get_lua_vm(r, ctx);
3484 0 : nreqs = c->requests;
3485 :
3486 0 : rc = ngx_http_lua_run_thread(vm, r, ctx, 0);
3487 :
3488 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3489 : "lua run thread returned %d", rc);
3490 :
3491 0 : if (rc == NGX_AGAIN) {
3492 0 : return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
3493 : }
3494 :
3495 0 : if (rc == NGX_DONE) {
3496 0 : ngx_http_lua_finalize_request(r, NGX_DONE);
3497 0 : return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
3498 : }
3499 :
3500 0 : if (ctx->entered_content_phase) {
3501 0 : ngx_http_lua_finalize_request(r, rc);
3502 0 : return NGX_DONE;
3503 : }
3504 :
3505 0 : return rc;
3506 : }
3507 :
3508 :
3509 : ngx_int_t
3510 0 : ngx_http_lua_test_expect(ngx_http_request_t *r)
3511 : {
3512 : ngx_int_t n;
3513 : ngx_str_t *expect;
3514 :
3515 0 : if (r->expect_tested
3516 0 : || r->headers_in.expect == NULL
3517 0 : || r->http_version < NGX_HTTP_VERSION_11)
3518 : {
3519 0 : return NGX_OK;
3520 : }
3521 :
3522 0 : r->expect_tested = 1;
3523 :
3524 0 : expect = &r->headers_in.expect->value;
3525 :
3526 0 : if (expect->len != sizeof("100-continue") - 1
3527 0 : || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
3528 : sizeof("100-continue") - 1)
3529 : != 0)
3530 : {
3531 0 : return NGX_OK;
3532 : }
3533 :
3534 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3535 : "send 100 Continue");
3536 :
3537 0 : n = r->connection->send(r->connection,
3538 : (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
3539 : sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);
3540 :
3541 0 : if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
3542 0 : return NGX_OK;
3543 : }
3544 :
3545 : /* we assume that such small packet should be send successfully */
3546 :
3547 0 : return NGX_ERROR;
3548 : }
3549 :
3550 :
3551 : void
3552 1 : ngx_http_lua_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
3553 : {
3554 : ngx_http_lua_ctx_t *ctx;
3555 :
3556 1 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
3557 1 : if (ctx && ctx->cur_co_ctx) {
3558 1 : ngx_http_lua_cleanup_pending_operation(ctx->cur_co_ctx);
3559 : }
3560 :
3561 1 : if (r->connection->fd != (ngx_socket_t) -1) {
3562 1 : ngx_http_finalize_request(r, rc);
3563 1 : return;
3564 : }
3565 :
3566 0 : ngx_http_lua_finalize_fake_request(r, rc);
3567 : }
3568 :
3569 :
3570 : void
3571 0 : ngx_http_lua_finalize_fake_request(ngx_http_request_t *r, ngx_int_t rc)
3572 : {
3573 : ngx_connection_t *c;
3574 : #if (NGX_HTTP_SSL)
3575 : ngx_ssl_conn_t *ssl_conn;
3576 : ngx_http_lua_ssl_ctx_t *cctx;
3577 : #endif
3578 :
3579 0 : c = r->connection;
3580 :
3581 0 : ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
3582 : "http lua finalize fake request: %d, a:%d, c:%d",
3583 : rc, r == c->data, r->main->count);
3584 :
3585 0 : if (rc == NGX_DONE) {
3586 0 : ngx_http_lua_close_fake_request(r);
3587 0 : return;
3588 : }
3589 :
3590 0 : if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
3591 :
3592 : #if (NGX_HTTP_SSL)
3593 :
3594 0 : if (r->connection->ssl) {
3595 0 : ssl_conn = r->connection->ssl->connection;
3596 0 : if (ssl_conn) {
3597 0 : c = ngx_ssl_get_connection(ssl_conn);
3598 :
3599 0 : if (c && c->ssl) {
3600 0 : cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection);
3601 0 : if (cctx != NULL) {
3602 0 : cctx->exit_code = 0;
3603 : }
3604 : }
3605 : }
3606 : }
3607 :
3608 : #endif
3609 :
3610 0 : ngx_http_lua_close_fake_request(r);
3611 0 : return;
3612 : }
3613 :
3614 0 : if (c->read->timer_set) {
3615 0 : ngx_del_timer(c->read);
3616 : }
3617 :
3618 0 : if (c->write->timer_set) {
3619 0 : c->write->delayed = 0;
3620 0 : ngx_del_timer(c->write);
3621 : }
3622 :
3623 0 : ngx_http_lua_close_fake_request(r);
3624 : }
3625 :
3626 :
3627 : static void
3628 0 : ngx_http_lua_close_fake_request(ngx_http_request_t *r)
3629 : {
3630 : ngx_connection_t *c;
3631 :
3632 0 : r = r->main;
3633 0 : c = r->connection;
3634 :
3635 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
3636 : "http lua fake request count:%d", r->count);
3637 :
3638 0 : if (r->count == 0) {
3639 0 : ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http lua fake request "
3640 : "count is zero");
3641 : }
3642 :
3643 0 : r->count--;
3644 :
3645 0 : if (r->count) {
3646 0 : return;
3647 : }
3648 :
3649 0 : ngx_http_lua_free_fake_request(r);
3650 0 : ngx_http_lua_close_fake_connection(c);
3651 : }
3652 :
3653 :
3654 : void
3655 0 : ngx_http_lua_free_fake_request(ngx_http_request_t *r)
3656 : {
3657 : ngx_log_t *log;
3658 : ngx_http_cleanup_t *cln;
3659 :
3660 0 : log = r->connection->log;
3661 :
3662 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http lua close fake "
3663 : "request");
3664 :
3665 0 : if (r->pool == NULL) {
3666 0 : ngx_log_error(NGX_LOG_ALERT, log, 0, "http lua fake request "
3667 : "already closed");
3668 0 : return;
3669 : }
3670 :
3671 0 : cln = r->cleanup;
3672 0 : r->cleanup = NULL;
3673 :
3674 0 : while (cln) {
3675 0 : if (cln->handler) {
3676 0 : cln->handler(cln->data);
3677 : }
3678 :
3679 0 : cln = cln->next;
3680 : }
3681 :
3682 0 : r->request_line.len = 0;
3683 :
3684 0 : r->connection->destroyed = 1;
3685 : }
3686 :
3687 :
3688 : void
3689 0 : ngx_http_lua_close_fake_connection(ngx_connection_t *c)
3690 : {
3691 : ngx_pool_t *pool;
3692 0 : ngx_connection_t *saved_c = NULL;
3693 :
3694 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
3695 : "http lua close fake http connection %p", c);
3696 :
3697 0 : c->destroyed = 1;
3698 :
3699 0 : pool = c->pool;
3700 :
3701 0 : if (c->read->timer_set) {
3702 0 : ngx_del_timer(c->read);
3703 : }
3704 :
3705 0 : if (c->write->timer_set) {
3706 0 : ngx_del_timer(c->write);
3707 : }
3708 :
3709 0 : c->read->closed = 1;
3710 0 : c->write->closed = 1;
3711 :
3712 : /* we temporarily use a valid fd (0) to make ngx_free_connection happy */
3713 :
3714 0 : c->fd = 0;
3715 :
3716 0 : if (ngx_cycle->files) {
3717 0 : saved_c = ngx_cycle->files[0];
3718 : }
3719 :
3720 0 : ngx_free_connection(c);
3721 :
3722 0 : c->fd = (ngx_socket_t) -1;
3723 :
3724 0 : if (ngx_cycle->files) {
3725 0 : ngx_cycle->files[0] = saved_c;
3726 : }
3727 :
3728 0 : if (pool) {
3729 0 : ngx_destroy_pool(pool);
3730 : }
3731 0 : }
3732 :
3733 :
3734 : lua_State *
3735 18 : ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle,
3736 : ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log,
3737 : ngx_pool_cleanup_t **pcln)
3738 : {
3739 : lua_State *L;
3740 : ngx_uint_t i;
3741 : ngx_pool_cleanup_t *cln;
3742 : ngx_http_lua_preload_hook_t *hook;
3743 : ngx_http_lua_vm_state_t *state;
3744 :
3745 18 : cln = ngx_pool_cleanup_add(pool, 0);
3746 18 : if (cln == NULL) {
3747 0 : return NULL;
3748 : }
3749 :
3750 : /* create new Lua VM instance */
3751 18 : L = ngx_http_lua_new_state(parent_vm, cycle, lmcf, log);
3752 18 : if (L == NULL) {
3753 0 : return NULL;
3754 : }
3755 :
3756 18 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "lua initialize the "
3757 : "global Lua VM %p", L);
3758 :
3759 : /* register cleanup handler for Lua VM */
3760 18 : cln->handler = ngx_http_lua_cleanup_vm;
3761 :
3762 18 : state = ngx_alloc(sizeof(ngx_http_lua_vm_state_t), log);
3763 18 : if (state == NULL) {
3764 0 : return NULL;
3765 : }
3766 18 : state->vm = L;
3767 18 : state->count = 1;
3768 :
3769 18 : cln->data = state;
3770 :
3771 18 : if (pcln) {
3772 0 : *pcln = cln;
3773 : }
3774 :
3775 18 : if (lmcf->preload_hooks) {
3776 :
3777 : /* register the 3rd-party module's preload hooks */
3778 :
3779 18 : lua_getglobal(L, "package");
3780 18 : lua_getfield(L, -1, "preload");
3781 :
3782 18 : hook = lmcf->preload_hooks->elts;
3783 :
3784 36 : for (i = 0; i < lmcf->preload_hooks->nelts; i++) {
3785 :
3786 : ngx_http_lua_probe_register_preload_package(L, hook[i].package);
3787 :
3788 18 : lua_pushcfunction(L, hook[i].loader);
3789 18 : lua_setfield(L, -2, (char *) hook[i].package);
3790 : }
3791 :
3792 18 : lua_pop(L, 2);
3793 : }
3794 :
3795 18 : return L;
3796 : }
3797 :
3798 :
3799 : void
3800 19 : ngx_http_lua_cleanup_vm(void *data)
3801 : {
3802 : lua_State *L;
3803 19 : ngx_http_lua_vm_state_t *state = data;
3804 :
3805 : #if (DDEBUG)
3806 : if (state) {
3807 : dd("cleanup VM: c:%d, s:%p", (int) state->count, state->vm);
3808 : }
3809 : #endif
3810 :
3811 19 : if (state) {
3812 19 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
3813 : "lua decrementing the reference count for Lua VM: %i",
3814 : state->count);
3815 :
3816 19 : if (--state->count == 0) {
3817 19 : L = state->vm;
3818 19 : ngx_http_lua_cleanup_conn_pools(L);
3819 19 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
3820 : "lua close the global Lua VM %p", L);
3821 19 : lua_close(L);
3822 19 : ngx_free(state);
3823 : }
3824 : }
3825 19 : }
3826 :
3827 :
3828 : ngx_connection_t *
3829 0 : ngx_http_lua_create_fake_connection(ngx_pool_t *pool)
3830 : {
3831 : ngx_log_t *log;
3832 : ngx_connection_t *c;
3833 0 : ngx_connection_t *saved_c = NULL;
3834 :
3835 : /* (we temporarily use a valid fd (0) to make ngx_get_connection happy) */
3836 0 : if (ngx_cycle->files) {
3837 0 : saved_c = ngx_cycle->files[0];
3838 : }
3839 :
3840 0 : c = ngx_get_connection(0, ngx_cycle->log);
3841 :
3842 0 : if (ngx_cycle->files) {
3843 0 : ngx_cycle->files[0] = saved_c;
3844 : }
3845 :
3846 0 : if (c == NULL) {
3847 0 : return NULL;
3848 : }
3849 :
3850 0 : c->fd = (ngx_socket_t) -1;
3851 0 : c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
3852 :
3853 0 : if (pool) {
3854 0 : c->pool = pool;
3855 :
3856 : } else {
3857 0 : c->pool = ngx_create_pool(128, c->log);
3858 0 : if (c->pool == NULL) {
3859 0 : goto failed;
3860 : }
3861 : }
3862 :
3863 0 : log = ngx_pcalloc(c->pool, sizeof(ngx_log_t));
3864 0 : if (log == NULL) {
3865 0 : goto failed;
3866 : }
3867 :
3868 0 : c->log = log;
3869 0 : c->log->connection = c->number;
3870 0 : c->log->action = NULL;
3871 0 : c->log->data = NULL;
3872 :
3873 0 : c->log_error = NGX_ERROR_INFO;
3874 :
3875 : #if 0
3876 : c->buffer = ngx_create_temp_buf(c->pool, 2);
3877 : if (c->buffer == NULL) {
3878 : goto failed;
3879 : }
3880 :
3881 : c->buffer->start[0] = CR;
3882 : c->buffer->start[1] = LF;
3883 : #endif
3884 :
3885 0 : c->error = 1;
3886 :
3887 : dd("created fake connection: %p", c);
3888 :
3889 0 : return c;
3890 :
3891 0 : failed:
3892 :
3893 0 : ngx_http_lua_close_fake_connection(c);
3894 0 : return NULL;
3895 : }
3896 :
3897 :
3898 : ngx_http_request_t *
3899 0 : ngx_http_lua_create_fake_request(ngx_connection_t *c)
3900 : {
3901 : ngx_http_request_t *r;
3902 :
3903 0 : r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t));
3904 0 : if (r == NULL) {
3905 0 : return NULL;
3906 : }
3907 :
3908 0 : c->requests++;
3909 :
3910 0 : r->pool = c->pool;
3911 :
3912 : dd("r pool allocated: %d", (int) (sizeof(ngx_http_lua_ctx_t)
3913 : + sizeof(void *) * ngx_http_max_module + sizeof(ngx_http_cleanup_t)));
3914 :
3915 : #if 0
3916 : hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t));
3917 : if (hc == NULL) {
3918 : goto failed;
3919 : }
3920 :
3921 : r->header_in = c->buffer;
3922 : r->header_end = c->buffer->start;
3923 :
3924 : if (ngx_list_init(&r->headers_out.headers, r->pool, 0,
3925 : sizeof(ngx_table_elt_t))
3926 : != NGX_OK)
3927 : {
3928 : goto failed;
3929 : }
3930 :
3931 : if (ngx_list_init(&r->headers_in.headers, r->pool, 0,
3932 : sizeof(ngx_table_elt_t))
3933 : != NGX_OK)
3934 : {
3935 : goto failed;
3936 : }
3937 : #endif
3938 :
3939 0 : r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
3940 0 : if (r->ctx == NULL) {
3941 0 : return NULL;
3942 : }
3943 :
3944 : #if 0
3945 : cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
3946 :
3947 : r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts
3948 : * sizeof(ngx_http_variable_value_t));
3949 : if (r->variables == NULL) {
3950 : goto failed;
3951 : }
3952 : #endif
3953 :
3954 0 : r->connection = c;
3955 :
3956 0 : r->headers_in.content_length_n = 0;
3957 0 : c->data = r;
3958 : #if 0
3959 : hc->request = r;
3960 : r->http_connection = hc;
3961 : #endif
3962 0 : r->signature = NGX_HTTP_MODULE;
3963 0 : r->main = r;
3964 0 : r->count = 1;
3965 :
3966 0 : r->method = NGX_HTTP_UNKNOWN;
3967 :
3968 0 : r->headers_in.keep_alive_n = -1;
3969 0 : r->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;
3970 0 : r->subrequests = NGX_HTTP_MAX_SUBREQUESTS + 1;
3971 :
3972 0 : r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
3973 0 : r->discard_body = 1;
3974 :
3975 : dd("created fake request %p", r);
3976 :
3977 0 : return r;
3978 : }
3979 :
3980 :
3981 : ngx_int_t
3982 0 : ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status,
3983 : const char *prefix)
3984 : {
3985 : const char *msg;
3986 :
3987 0 : if (status && !lua_isnil(L, -1)) {
3988 0 : msg = lua_tostring(L, -1);
3989 0 : if (msg == NULL) {
3990 0 : msg = "unknown error";
3991 : }
3992 :
3993 0 : ngx_log_error(NGX_LOG_ERR, log, 0, "%s error: %s", prefix, msg);
3994 0 : lua_pop(L, 1);
3995 : }
3996 :
3997 : /* force a full garbage-collection cycle */
3998 0 : lua_gc(L, LUA_GCCOLLECT, 0);
3999 :
4000 0 : return status == 0 ? NGX_OK : NGX_ERROR;
4001 : }
4002 :
4003 :
4004 : int
4005 0 : ngx_http_lua_do_call(ngx_log_t *log, lua_State *L)
4006 : {
4007 : int status, base;
4008 : #if (NGX_PCRE)
4009 : ngx_pool_t *old_pool;
4010 : #endif
4011 :
4012 0 : base = lua_gettop(L); /* function index */
4013 0 : lua_pushcfunction(L, ngx_http_lua_traceback); /* push traceback function */
4014 0 : lua_insert(L, base); /* put it under chunk and args */
4015 :
4016 : #if (NGX_PCRE)
4017 0 : old_pool = ngx_http_lua_pcre_malloc_init(ngx_cycle->pool);
4018 : #endif
4019 :
4020 0 : status = lua_pcall(L, 0, 0, base);
4021 :
4022 : #if (NGX_PCRE)
4023 0 : ngx_http_lua_pcre_malloc_done(old_pool);
4024 : #endif
4025 :
4026 0 : lua_remove(L, base);
4027 :
4028 0 : return status;
4029 : }
4030 :
4031 :
4032 : static int
4033 0 : ngx_http_lua_get_raw_phase_context(lua_State *L)
4034 : {
4035 : ngx_http_request_t *r;
4036 : ngx_http_lua_ctx_t *ctx;
4037 :
4038 0 : r = lua_touserdata(L, 1);
4039 0 : if (r == NULL) {
4040 0 : return 0;
4041 : }
4042 :
4043 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
4044 0 : if (ctx == NULL) {
4045 0 : return 0;
4046 : }
4047 :
4048 0 : lua_pushinteger(L, (int) ctx->context);
4049 0 : return 1;
4050 : }
4051 :
4052 :
4053 : ngx_http_cleanup_t *
4054 1 : ngx_http_lua_cleanup_add(ngx_http_request_t *r, size_t size)
4055 : {
4056 : ngx_http_cleanup_t *cln;
4057 : ngx_http_lua_ctx_t *ctx;
4058 :
4059 1 : if (size == 0) {
4060 1 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
4061 :
4062 1 : r = r->main;
4063 :
4064 1 : if (ctx != NULL && ctx->free_cleanup) {
4065 0 : cln = ctx->free_cleanup;
4066 0 : ctx->free_cleanup = cln->next;
4067 :
4068 : dd("reuse cleanup: %p", cln);
4069 :
4070 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4071 : "lua http cleanup reuse: %p", cln);
4072 :
4073 0 : cln->handler = NULL;
4074 0 : cln->next = r->cleanup;
4075 :
4076 0 : r->cleanup = cln;
4077 :
4078 0 : return cln;
4079 : }
4080 : }
4081 :
4082 1 : return ngx_http_cleanup_add(r, size);
4083 : }
4084 :
4085 :
4086 : void
4087 1 : ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup)
4088 : {
4089 : ngx_http_cleanup_t **last;
4090 : ngx_http_cleanup_t *cln;
4091 : ngx_http_lua_ctx_t *ctx;
4092 :
4093 1 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
4094 1 : if (ctx == NULL) {
4095 0 : return;
4096 : }
4097 :
4098 1 : r = r->main;
4099 :
4100 1 : cln = (ngx_http_cleanup_t *)
4101 : ((u_char *) cleanup - offsetof(ngx_http_cleanup_t, handler));
4102 :
4103 : dd("cln: %p, cln->handler: %p, &cln->handler: %p",
4104 : cln, cln->handler, &cln->handler);
4105 :
4106 1 : last = &r->cleanup;
4107 :
4108 2 : while (*last) {
4109 1 : if (*last == cln) {
4110 1 : *last = cln->next;
4111 :
4112 1 : cln->next = ctx->free_cleanup;
4113 1 : ctx->free_cleanup = cln;
4114 :
4115 1 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4116 : "lua http cleanup free: %p", cln);
4117 :
4118 1 : return;
4119 : }
4120 :
4121 0 : last = &(*last)->next;
4122 : }
4123 : }
4124 :
4125 :
4126 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|