1
2 /*
3 * Copyright (C) Xiaozhe Wang (chaoslawful)
4 * Copyright (C) Yichun Zhang (agentzh)
5 */
6
7
8 #ifndef _NGX_HTTP_LUA_UTIL_H_INCLUDED_
9 #define _NGX_HTTP_LUA_UTIL_H_INCLUDED_
10
11
12 #ifdef DDEBUG
13 #include "ddebug.h"
14 #endif
15
16
17 #include "ngx_http_lua_common.h"
18 #include "ngx_http_lua_ssl.h"
19 #include "ngx_http_lua_api.h"
20
21
22 #ifndef NGX_UNESCAPE_URI_COMPONENT
23 # define NGX_UNESCAPE_URI_COMPONENT 0
24 #endif
25
26
27 #ifndef NGX_HTTP_SWITCHING_PROTOCOLS
28 # define NGX_HTTP_SWITCHING_PROTOCOLS 101
29 #endif
30
31 #define NGX_HTTP_LUA_ESCAPE_HEADER_NAME 7
32
33 #define NGX_HTTP_LUA_ESCAPE_HEADER_VALUE 8
34
35 #define NGX_HTTP_LUA_CONTEXT_YIELDABLE (NGX_HTTP_LUA_CONTEXT_REWRITE \
36 | NGX_HTTP_LUA_CONTEXT_ACCESS \
37 | NGX_HTTP_LUA_CONTEXT_CONTENT \
38 | NGX_HTTP_LUA_CONTEXT_TIMER \
39 | NGX_HTTP_LUA_CONTEXT_SSL_CERT \
40 | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH)
41
42
43 /* key in Lua vm registry for all the "ngx.ctx" tables */
44 #define ngx_http_lua_ctx_tables_key "ngx_lua_ctx_tables"
45
46
47 #define ngx_http_lua_context_name(c) \
48 ((c) == NGX_HTTP_LUA_CONTEXT_SET ? "set_by_lua*" \
49 : (c) == NGX_HTTP_LUA_CONTEXT_REWRITE ? "rewrite_by_lua*" \
50 : (c) == NGX_HTTP_LUA_CONTEXT_ACCESS ? "access_by_lua*" \
51 : (c) == NGX_HTTP_LUA_CONTEXT_CONTENT ? "content_by_lua*" \
52 : (c) == NGX_HTTP_LUA_CONTEXT_LOG ? "log_by_lua*" \
53 : (c) == NGX_HTTP_LUA_CONTEXT_HEADER_FILTER ? "header_filter_by_lua*" \
54 : (c) == NGX_HTTP_LUA_CONTEXT_BODY_FILTER ? "body_filter_by_lua*" \
55 : (c) == NGX_HTTP_LUA_CONTEXT_TIMER ? "ngx.timer" \
56 : (c) == NGX_HTTP_LUA_CONTEXT_INIT_WORKER ? "init_worker_by_lua*" \
57 : (c) == NGX_HTTP_LUA_CONTEXT_EXIT_WORKER ? "exit_worker_by_lua*" \
58 : (c) == NGX_HTTP_LUA_CONTEXT_BALANCER ? "balancer_by_lua*" \
59 : (c) == NGX_HTTP_LUA_CONTEXT_SSL_CERT ? "ssl_certificate_by_lua*" \
60 : (c) == NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE ? \
61 "ssl_session_store_by_lua*" \
62 : (c) == NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH ? \
63 "ssl_session_fetch_by_lua*" \
64 : "(unknown)")
65
66
67 #define ngx_http_lua_check_context(L, ctx, flags) \
68 if (!((ctx)->context & (flags))) { \
69 return luaL_error(L, "API disabled in the context of %s", \
70 ngx_http_lua_context_name((ctx)->context)); \
71 }
72
73
74 #define ngx_http_lua_check_fake_request(L, r) \
75 if ((r)->connection->fd == (ngx_socket_t) -1) { \
76 return luaL_error(L, "API disabled in the current context"); \
77 }
78
79
80 #define ngx_http_lua_check_fake_request2(L, r, ctx) \
81 if ((r)->connection->fd == (ngx_socket_t) -1) { \
82 return luaL_error(L, "API disabled in the context of %s", \
83 ngx_http_lua_context_name((ctx)->context)); \
84 }
85
86
87 #define ngx_http_lua_check_if_abortable(L, ctx) \
88 if ((ctx)->no_abort) { \
89 return luaL_error(L, "attempt to abort with pending subrequests"); \
90 }
91
92
93 #define ngx_http_lua_ssl_get_ctx(ssl_conn) \
94 SSL_get_ex_data(ssl_conn, ngx_http_lua_ssl_ctx_index)
95
96
97 #define ngx_http_lua_hash_literal(s) \
98 ngx_http_lua_hash_str((u_char *) s, sizeof(s) - 1)
99
100
101 typedef struct {
102 ngx_http_lua_ffi_str_t key;
103 ngx_http_lua_ffi_str_t value;
104 } ngx_http_lua_ffi_table_elt_t;
105
106
107 /* char whose address we use as the key in Lua vm registry for
108 * user code cache table */
109 extern char ngx_http_lua_code_cache_key;
110
111 /* char whose address we use as the key in Lua vm registry for
112 * socket connection pool table */
113 extern char ngx_http_lua_socket_pool_key;
114
115 /* coroutine anchoring table key in Lua VM registry */
116 extern char ngx_http_lua_coroutines_key;
117
118 /* key to the metatable for ngx.req.get_headers() and ngx.resp.get_headers() */
119 extern char ngx_http_lua_headers_metatable_key;
120
121
122 static ngx_inline ngx_int_t
ngx_http_lua_ffi_check_context(ngx_http_lua_ctx_t * ctx,unsigned flags,u_char * err,size_t * errlen)123 ngx_http_lua_ffi_check_context(ngx_http_lua_ctx_t *ctx, unsigned flags,
124 u_char *err, size_t *errlen)
125 {
126 if (!(ctx->context & flags)) {
127 *errlen = ngx_snprintf(err, *errlen,
128 "API disabled in the context of %s",
129 ngx_http_lua_context_name((ctx)->context))
130 - err;
131
132 return NGX_DECLINED;
133 }
134
135 return NGX_OK;
136 }
137
138
139 ngx_int_t ngx_http_lua_init_vm(lua_State **new_vm, lua_State *parent_vm,
140 ngx_cycle_t *cycle, ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf,
141 ngx_log_t *log, ngx_pool_cleanup_t **pcln);
142
143 lua_State *ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *l,
144 int *ref);
145
146 u_char *ngx_http_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len);
147
148 ngx_int_t ngx_http_lua_send_header_if_needed(ngx_http_request_t *r,
149 ngx_http_lua_ctx_t *ctx);
150
151 ngx_int_t ngx_http_lua_send_chain_link(ngx_http_request_t *r,
152 ngx_http_lua_ctx_t *ctx, ngx_chain_t *cl);
153
154 void ngx_http_lua_discard_bufs(ngx_pool_t *pool, ngx_chain_t *in);
155
156 ngx_int_t ngx_http_lua_add_copy_chain(ngx_http_request_t *r,
157 ngx_http_lua_ctx_t *ctx, ngx_chain_t ***plast, ngx_chain_t *in,
158 ngx_int_t *eof);
159
160 void ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L,
161 ngx_http_lua_ctx_t *ctx);
162
163 void ngx_http_lua_generic_phase_post_read(ngx_http_request_t *r);
164
165 void ngx_http_lua_request_cleanup(ngx_http_lua_ctx_t *ctx, int foricible);
166
167 void ngx_http_lua_request_cleanup_handler(void *data);
168
169 ngx_int_t ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r,
170 ngx_http_lua_ctx_t *ctx, volatile int nret);
171
172 ngx_int_t ngx_http_lua_wev_handler(ngx_http_request_t *r);
173
174 u_char *ngx_http_lua_digest_hex(u_char *dest, const u_char *buf,
175 int buf_len);
176
177 void ngx_http_lua_set_multi_value_table(lua_State *L, int index);
178
179 void ngx_http_lua_unescape_uri(u_char **dst, u_char **src, size_t size,
180 ngx_uint_t type);
181
182 uintptr_t ngx_http_lua_escape_uri(u_char *dst, u_char *src,
183 size_t size, ngx_uint_t type);
184
185 ngx_int_t ngx_http_lua_copy_escaped_header(ngx_http_request_t *r,
186 ngx_str_t *dst, int is_name);
187
188 void ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L);
189
190 void ngx_http_lua_process_args_option(ngx_http_request_t *r,
191 lua_State *L, int table, ngx_str_t *args);
192
193 ngx_int_t ngx_http_lua_open_and_stat_file(u_char *name,
194 ngx_open_file_info_t *of, ngx_log_t *log);
195
196 ngx_chain_t *ngx_http_lua_chain_get_free_buf(ngx_log_t *log, ngx_pool_t *p,
197 ngx_chain_t **free, size_t len);
198
199 #ifndef OPENRESTY_LUAJIT
200 void ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec);
201 #endif
202
203 int ngx_http_lua_traceback(lua_State *L);
204
205 ngx_http_lua_co_ctx_t *ngx_http_lua_get_co_ctx(lua_State *L,
206 ngx_http_lua_ctx_t *ctx);
207
208 ngx_http_lua_co_ctx_t *ngx_http_lua_create_co_ctx(ngx_http_request_t *r,
209 ngx_http_lua_ctx_t *ctx);
210
211 ngx_int_t ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L,
212 ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_uint_t nreqs);
213
214 ngx_int_t ngx_http_lua_post_thread(ngx_http_request_t *r,
215 ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx);
216
217 void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L,
218 ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx);
219
220 void ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r);
221
222 ngx_int_t ngx_http_lua_test_expect(ngx_http_request_t *r);
223
224 ngx_int_t ngx_http_lua_check_broken_connection(ngx_http_request_t *r,
225 ngx_event_t *ev);
226
227 void ngx_http_lua_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
228
229 void ngx_http_lua_finalize_fake_request(ngx_http_request_t *r,
230 ngx_int_t rc);
231
232 void ngx_http_lua_close_fake_connection(ngx_connection_t *c);
233
234 void ngx_http_lua_free_fake_request(ngx_http_request_t *r);
235
236 void ngx_http_lua_release_ngx_ctx_table(ngx_log_t *log, lua_State *L,
237 ngx_http_lua_ctx_t *ctx);
238
239 void ngx_http_lua_cleanup_vm(void *data);
240
241 ngx_connection_t *ngx_http_lua_create_fake_connection(ngx_pool_t *pool);
242
243 ngx_http_request_t *ngx_http_lua_create_fake_request(ngx_connection_t *c);
244
245 ngx_int_t ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status,
246 const char *prefix);
247
248 int ngx_http_lua_do_call(ngx_log_t *log, lua_State *L);
249
250 ngx_http_cleanup_t *ngx_http_lua_cleanup_add(ngx_http_request_t *r,
251 size_t size);
252
253 void ngx_http_lua_cleanup_free(ngx_http_request_t *r,
254 ngx_http_cleanup_pt *cleanup);
255
256 #if (NGX_HTTP_LUA_HAVE_SA_RESTART)
257 void ngx_http_lua_set_sa_restart(ngx_log_t *log);
258 #endif
259
260 size_t ngx_http_lua_escape_log(u_char *dst, u_char *src, size_t size);
261
262
263 static ngx_inline void
ngx_http_lua_init_ctx(ngx_http_request_t * r,ngx_http_lua_ctx_t * ctx)264 ngx_http_lua_init_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx)
265 {
266 ngx_memzero(ctx, sizeof(ngx_http_lua_ctx_t));
267 ctx->ctx_ref = LUA_NOREF;
268 ctx->entry_co_ctx.co_ref = LUA_NOREF;
269 ctx->entry_co_ctx.next_zombie_child_thread =
270 &ctx->entry_co_ctx.zombie_child_threads;
271 ctx->resume_handler = ngx_http_lua_wev_handler;
272 ctx->request = r;
273 }
274
275
276 static ngx_inline ngx_http_lua_ctx_t *
ngx_http_lua_create_ctx(ngx_http_request_t * r)277 ngx_http_lua_create_ctx(ngx_http_request_t *r)
278 {
279 ngx_int_t rc;
280 lua_State *L = NULL;
281 ngx_http_lua_ctx_t *ctx;
282 ngx_pool_cleanup_t *cln;
283 ngx_http_lua_loc_conf_t *llcf;
284 ngx_http_lua_main_conf_t *lmcf;
285
286 ctx = ngx_palloc(r->pool, sizeof(ngx_http_lua_ctx_t));
287 if (ctx == NULL) {
288 return NULL;
289 }
290
291 ngx_http_lua_init_ctx(r, ctx);
292 ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
293
294 llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
295 if (!llcf->enable_code_cache && r->connection->fd != (ngx_socket_t) -1) {
296 lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
297
298 #ifdef DDEBUG
299 dd("lmcf: %p", lmcf);
300 #endif
301
302 rc = ngx_http_lua_init_vm(&L, lmcf->lua, lmcf->cycle, r->pool, lmcf,
303 r->connection->log, &cln);
304 if (rc != NGX_OK) {
305 if (rc == NGX_DECLINED) {
306 ngx_http_lua_assert(L != NULL);
307
308 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
309 "failed to load the 'resty.core' module "
310 "(https://github.com/openresty/lua-resty"
311 "-core); ensure you are using an OpenResty "
312 "release from https://openresty.org/en/"
313 "download.html (reason: %s)",
314 lua_tostring(L, -1));
315
316 } else {
317 /* rc == NGX_ERROR */
318 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
319 "failed to initialize Lua VM");
320 }
321
322 return NULL;
323 }
324
325 /* rc == NGX_OK */
326
327 ngx_http_lua_assert(L != NULL);
328
329 if (lmcf->init_handler) {
330 if (lmcf->init_handler(r->connection->log, lmcf, L) != NGX_OK) {
331 /* an error happened */
332 return NULL;
333 }
334 }
335
336 ctx->vm_state = cln->data;
337
338 } else {
339 ctx->vm_state = NULL;
340 }
341
342 return ctx;
343 }
344
345
346 static ngx_inline lua_State *
ngx_http_lua_get_lua_vm(ngx_http_request_t * r,ngx_http_lua_ctx_t * ctx)347 ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx)
348 {
349 ngx_http_lua_main_conf_t *lmcf;
350
351 if (ctx == NULL) {
352 ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
353 }
354
355 if (ctx && ctx->vm_state) {
356 return ctx->vm_state->vm;
357 }
358
359 lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
360
361 #ifdef DDEBUG
362 dd("lmcf->lua: %p", lmcf->lua);
363 #endif
364
365 return lmcf->lua;
366 }
367
368
369 #ifndef OPENRESTY_LUAJIT
370 #define ngx_http_lua_req_key "__ngx_req"
371 #endif
372
373
374 static ngx_inline ngx_http_request_t *
ngx_http_lua_get_req(lua_State * L)375 ngx_http_lua_get_req(lua_State *L)
376 {
377 #ifdef OPENRESTY_LUAJIT
378 return lua_getexdata(L);
379 #else
380 ngx_http_request_t *r;
381
382 lua_getglobal(L, ngx_http_lua_req_key);
383 r = lua_touserdata(L, -1);
384 lua_pop(L, 1);
385
386 return r;
387 #endif
388 }
389
390
391 static ngx_inline void
ngx_http_lua_set_req(lua_State * L,ngx_http_request_t * r)392 ngx_http_lua_set_req(lua_State *L, ngx_http_request_t *r)
393 {
394 #ifdef OPENRESTY_LUAJIT
395 lua_setexdata(L, (void *) r);
396 #else
397 lua_pushlightuserdata(L, r);
398 lua_setglobal(L, ngx_http_lua_req_key);
399 #endif
400 }
401
402
403 static ngx_inline void
ngx_http_lua_attach_co_ctx_to_L(lua_State * L,ngx_http_lua_co_ctx_t * coctx)404 ngx_http_lua_attach_co_ctx_to_L(lua_State *L, ngx_http_lua_co_ctx_t *coctx)
405 {
406 #ifdef HAVE_LUA_EXDATA2
407 lua_setexdata2(L, (void *) coctx);
408 #endif
409 }
410
411
412 #ifndef OPENRESTY_LUAJIT
413 static ngx_inline void
ngx_http_lua_get_globals_table(lua_State * L)414 ngx_http_lua_get_globals_table(lua_State *L)
415 {
416 lua_pushvalue(L, LUA_GLOBALSINDEX);
417 }
418
419
420 static ngx_inline void
ngx_http_lua_set_globals_table(lua_State * L)421 ngx_http_lua_set_globals_table(lua_State *L)
422 {
423 lua_replace(L, LUA_GLOBALSINDEX);
424 }
425 #endif /* OPENRESTY_LUAJIT */
426
427
428 static ngx_inline ngx_uint_t
ngx_http_lua_hash_str(u_char * src,size_t n)429 ngx_http_lua_hash_str(u_char *src, size_t n)
430 {
431 ngx_uint_t key;
432
433 key = 0;
434
435 while (n--) {
436 key = ngx_hash(key, *src);
437 src++;
438 }
439
440 return key;
441 }
442
443
444 static ngx_inline ngx_int_t
ngx_http_lua_set_content_type(ngx_http_request_t * r,ngx_http_lua_ctx_t * ctx)445 ngx_http_lua_set_content_type(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx)
446 {
447 ngx_http_lua_loc_conf_t *llcf;
448
449 ctx->mime_set = 1;
450
451 llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
452 if (llcf->use_default_type
453 && r->headers_out.status != NGX_HTTP_NOT_MODIFIED)
454 {
455 return ngx_http_set_content_type(r);
456 }
457
458 return NGX_OK;
459 }
460
461
462 static ngx_inline void
ngx_http_lua_cleanup_pending_operation(ngx_http_lua_co_ctx_t * coctx)463 ngx_http_lua_cleanup_pending_operation(ngx_http_lua_co_ctx_t *coctx)
464 {
465 if (coctx->cleanup) {
466 coctx->cleanup(coctx);
467 coctx->cleanup = NULL;
468 }
469 }
470
471
472 static ngx_inline ngx_chain_t *
ngx_http_lua_get_flush_chain(ngx_http_request_t * r,ngx_http_lua_ctx_t * ctx)473 ngx_http_lua_get_flush_chain(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx)
474 {
475 ngx_chain_t *cl;
476
477 cl = ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool,
478 &ctx->free_bufs, 0);
479 if (cl == NULL) {
480 return NULL;
481 }
482
483 cl->buf->flush = 1;
484
485 return cl;
486 }
487
488
489 #if (nginx_version < 1011002)
490 static ngx_inline in_port_t
ngx_inet_get_port(struct sockaddr * sa)491 ngx_inet_get_port(struct sockaddr *sa)
492 {
493 struct sockaddr_in *sin;
494 #if (NGX_HAVE_INET6)
495 struct sockaddr_in6 *sin6;
496 #endif
497
498 switch (sa->sa_family) {
499
500 #if (NGX_HAVE_INET6)
501 case AF_INET6:
502 sin6 = (struct sockaddr_in6 *) sa;
503 return ntohs(sin6->sin6_port);
504 #endif
505
506 #if (NGX_HAVE_UNIX_DOMAIN)
507 case AF_UNIX:
508 return 0;
509 #endif
510
511 default: /* AF_INET */
512 sin = (struct sockaddr_in *) sa;
513 return ntohs(sin->sin_port);
514 }
515 }
516 #endif
517
518
519 static ngx_inline ngx_int_t
ngx_http_lua_check_unsafe_uri_bytes(ngx_http_request_t * r,u_char * str,size_t len,u_char * byte)520 ngx_http_lua_check_unsafe_uri_bytes(ngx_http_request_t *r, u_char *str,
521 size_t len, u_char *byte)
522 {
523 size_t i;
524 u_char c;
525
526 /* %00-%08, %0A-%1F, %7F */
527
528 static uint32_t unsafe[] = {
529 0xfffffdff, /* 1111 1111 1111 1111 1111 1101 1111 1111 */
530
531 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
532 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
533
534 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
535 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
536
537 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
538 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
539
540 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
541 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
542 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
543 0x00000000 /* 0000 0000 0000 0000 0000 0000 0000 0000 */
544 };
545
546 for (i = 0; i < len; i++, str++) {
547 c = *str;
548 if (unsafe[c >> 5] & (1 << (c & 0x1f))) {
549 *byte = c;
550 return NGX_ERROR;
551 }
552 }
553
554 return NGX_OK;
555 }
556
557
558 static ngx_inline void
ngx_http_lua_free_thread(ngx_http_request_t * r,lua_State * L,int co_ref,lua_State * co,ngx_http_lua_main_conf_t * lmcf)559 ngx_http_lua_free_thread(ngx_http_request_t *r, lua_State *L, int co_ref,
560 lua_State *co, ngx_http_lua_main_conf_t *lmcf)
561 {
562 #ifdef HAVE_LUA_RESETTHREAD
563 ngx_queue_t *q;
564 ngx_http_lua_thread_ref_t *tref ;
565 ngx_http_lua_ctx_t *ctx;
566
567 ngx_log_debug2(NGX_LOG_DEBUG_HTTP,
568 r == NULL ? ngx_cycle->log : r->connection->log, 0,
569 "lua freeing light thread %p (ref %d)", co, co_ref);
570
571 ctx = r != NULL ? ngx_http_get_module_ctx(r, ngx_http_lua_module) : NULL;
572 if (ctx != NULL
573 && L == ctx->entry_co_ctx.co
574 && L == lmcf->lua
575 && !ngx_queue_empty(&lmcf->free_lua_threads))
576 {
577 lua_resetthread(L, co);
578
579 q = ngx_queue_head(&lmcf->free_lua_threads);
580 tref = ngx_queue_data(q, ngx_http_lua_thread_ref_t, queue);
581
582 ngx_http_lua_assert(tref->ref == LUA_NOREF);
583 ngx_http_lua_assert(tref->co == NULL);
584
585 tref->ref = co_ref;
586 tref->co = co;
587
588 ngx_queue_remove(q);
589 ngx_queue_insert_head(&lmcf->cached_lua_threads, q);
590
591 ngx_log_debug2(NGX_LOG_DEBUG_HTTP,
592 r != NULL ? r->connection->log : ngx_cycle->log, 0,
593 "lua caching unused lua thread %p (ref %d)", co,
594 co_ref);
595
596 return;
597 }
598 #endif
599
600 ngx_log_debug2(NGX_LOG_DEBUG_HTTP,
601 r != NULL ? r->connection->log : ngx_cycle->log, 0,
602 "lua unref lua thread %p (ref %d)", co, co_ref);
603
604 lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(
605 coroutines_key));
606 lua_rawget(L, LUA_REGISTRYINDEX);
607
608 luaL_unref(L, -1, co_ref);
609 lua_pop(L, 1);
610 }
611
612
613 static ngx_inline int
ngx_http_lua_new_cached_thread(lua_State * L,lua_State ** out_co,ngx_http_lua_main_conf_t * lmcf,int set_globals)614 ngx_http_lua_new_cached_thread(lua_State *L, lua_State **out_co,
615 ngx_http_lua_main_conf_t *lmcf, int set_globals)
616 {
617 int co_ref;
618 lua_State *co;
619
620 #ifdef HAVE_LUA_RESETTHREAD
621 ngx_queue_t *q;
622 ngx_http_lua_thread_ref_t *tref;
623
624 if (L == lmcf->lua && !ngx_queue_empty(&lmcf->cached_lua_threads)) {
625 q = ngx_queue_head(&lmcf->cached_lua_threads);
626 tref = ngx_queue_data(q, ngx_http_lua_thread_ref_t, queue);
627
628 ngx_http_lua_assert(tref->ref != LUA_NOREF);
629 ngx_http_lua_assert(tref->co != NULL);
630
631 co = tref->co;
632 co_ref = tref->ref;
633
634 tref->co = NULL;
635 tref->ref = LUA_NOREF;
636
637 ngx_queue_remove(q);
638 ngx_queue_insert_head(&lmcf->free_lua_threads, q);
639
640 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
641 "lua reusing cached lua thread %p (ref %d)", co, co_ref);
642
643 lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(
644 coroutines_key));
645 lua_rawget(L, LUA_REGISTRYINDEX);
646 lua_rawgeti(L, -1, co_ref);
647
648 } else {
649 #else
650 {
651 #endif
652 lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(
653 coroutines_key));
654 lua_rawget(L, LUA_REGISTRYINDEX);
655 co = lua_newthread(L);
656 lua_pushvalue(L, -1);
657 co_ref = luaL_ref(L, -3);
658
659 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
660 "lua ref lua thread %p (ref %d)", co, co_ref);
661
662 #ifndef OPENRESTY_LUAJIT
663 if (set_globals) {
664 lua_createtable(co, 0, 0); /* the new globals table */
665
666 /* co stack: global_tb */
667
668 lua_createtable(co, 0, 1); /* the metatable */
669 ngx_http_lua_get_globals_table(co);
670 lua_setfield(co, -2, "__index");
671 lua_setmetatable(co, -2);
672
673 /* co stack: global_tb */
674
675 ngx_http_lua_set_globals_table(co);
676 }
677 #endif
678 }
679
680 *out_co = co;
681
682 return co_ref;
683 }
684
685
686 extern ngx_uint_t ngx_http_lua_location_hash;
687 extern ngx_uint_t ngx_http_lua_content_length_hash;
688
689
690 #endif /* _NGX_HTTP_LUA_UTIL_H_INCLUDED_ */
691
692 /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
693