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