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