Line data Source code
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 : #include "ngx_http_lua_common.h"
13 :
14 :
15 : #ifndef NGX_UNESCAPE_URI_COMPONENT
16 : #define NGX_UNESCAPE_URI_COMPONENT 0
17 : #endif
18 :
19 :
20 : #ifndef NGX_LUA_NO_FFI_API
21 : typedef struct {
22 : int len;
23 : /* this padding hole on 64-bit systems is expected */
24 : u_char *data;
25 : } ngx_http_lua_ffi_str_t;
26 :
27 :
28 : typedef struct {
29 : ngx_http_lua_ffi_str_t key;
30 : ngx_http_lua_ffi_str_t value;
31 : } ngx_http_lua_ffi_table_elt_t;
32 : #endif /* NGX_LUA_NO_FFI_API */
33 :
34 :
35 : /* char whose address we use as the key in Lua vm registry for
36 : * user code cache table */
37 : extern char ngx_http_lua_code_cache_key;
38 :
39 :
40 : /* key in Lua vm registry for all the "ngx.ctx" tables */
41 : #define ngx_http_lua_ctx_tables_key "ngx_lua_ctx_tables"
42 :
43 :
44 : /* char whose address we use as the key in Lua vm registry for
45 : * regex cache table */
46 : extern char ngx_http_lua_regex_cache_key;
47 :
48 : /* char whose address we use as the key in Lua vm registry for
49 : * socket connection pool table */
50 : extern char ngx_http_lua_socket_pool_key;
51 :
52 : /* char whose address we use as the key for the coroutine parent relationship */
53 : extern char ngx_http_lua_coroutine_parents_key;
54 :
55 : /* coroutine anchoring table key in Lua VM registry */
56 : extern char ngx_http_lua_coroutines_key;
57 :
58 : /* key to the metatable for ngx.req.get_headers() and ngx.resp.get_headers() */
59 : extern char ngx_http_lua_headers_metatable_key;
60 :
61 :
62 : #ifndef ngx_str_set
63 : #define ngx_str_set(str, text) \
64 : (str)->len = sizeof(text) - 1; (str)->data = (u_char *) text
65 : #endif
66 :
67 :
68 : #ifndef NGX_HTTP_SWITCHING_PROTOCOLS
69 : #define NGX_HTTP_SWITCHING_PROTOCOLS 101
70 : #endif
71 :
72 :
73 : #if defined(nginx_version) && nginx_version < 1000000
74 : #define ngx_memmove(dst, src, n) (void) memmove(dst, src, n)
75 : #endif
76 :
77 :
78 : #define ngx_http_lua_context_name(c) \
79 : ((c) == NGX_HTTP_LUA_CONTEXT_SET ? "set_by_lua*" \
80 : : (c) == NGX_HTTP_LUA_CONTEXT_REWRITE ? "rewrite_by_lua*" \
81 : : (c) == NGX_HTTP_LUA_CONTEXT_ACCESS ? "access_by_lua*" \
82 : : (c) == NGX_HTTP_LUA_CONTEXT_CONTENT ? "content_by_lua*" \
83 : : (c) == NGX_HTTP_LUA_CONTEXT_LOG ? "log_by_lua*" \
84 : : (c) == NGX_HTTP_LUA_CONTEXT_HEADER_FILTER ? "header_filter_by_lua*" \
85 : : (c) == NGX_HTTP_LUA_CONTEXT_BODY_FILTER ? "body_filter_by_lua*" \
86 : : (c) == NGX_HTTP_LUA_CONTEXT_TIMER ? "ngx.timer" \
87 : : (c) == NGX_HTTP_LUA_CONTEXT_INIT_WORKER ? "init_worker_by_lua*" \
88 : : (c) == NGX_HTTP_LUA_CONTEXT_BALANCER ? "balancer_by_lua*" \
89 : : (c) == NGX_HTTP_LUA_CONTEXT_SSL_CERT ? "ssl_certificate_by_lua*" \
90 : : (c) == NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE ? \
91 : "ssl_session_store_by_lua*" \
92 : : (c) == NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH ? \
93 : "ssl_session_fetch_by_lua*" \
94 : : "(unknown)")
95 :
96 :
97 : #define ngx_http_lua_check_context(L, ctx, flags) \
98 : if (!((ctx)->context & (flags))) { \
99 : return luaL_error(L, "API disabled in the context of %s", \
100 : ngx_http_lua_context_name((ctx)->context)); \
101 : }
102 :
103 :
104 : #ifndef NGX_LUA_NO_FFI_API
105 : static ngx_inline ngx_int_t
106 0 : ngx_http_lua_ffi_check_context(ngx_http_lua_ctx_t *ctx, unsigned flags,
107 : u_char *err, size_t *errlen)
108 : {
109 0 : if (!(ctx->context & flags)) {
110 0 : *errlen = ngx_snprintf(err, *errlen,
111 : "API disabled in the context of %s",
112 0 : ngx_http_lua_context_name((ctx)->context))
113 0 : - err;
114 :
115 0 : return NGX_DECLINED;
116 : }
117 :
118 0 : return NGX_OK;
119 : }
120 : #endif
121 :
122 :
123 : #define ngx_http_lua_check_fake_request(L, r) \
124 : if ((r)->connection->fd == (ngx_socket_t) -1) { \
125 : return luaL_error(L, "API disabled in the current context"); \
126 : }
127 :
128 :
129 : #define ngx_http_lua_check_fake_request2(L, r, ctx) \
130 : if ((r)->connection->fd == (ngx_socket_t) -1) { \
131 : return luaL_error(L, "API disabled in the context of %s", \
132 : ngx_http_lua_context_name((ctx)->context)); \
133 : }
134 :
135 :
136 : #define ngx_http_lua_ssl_get_ctx(ssl_conn) \
137 : SSL_get_ex_data(ssl_conn, ngx_http_lua_ssl_ctx_index)
138 :
139 :
140 : lua_State *ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle,
141 : ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log,
142 : ngx_pool_cleanup_t **pcln);
143 :
144 : lua_State *ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *l,
145 : int *ref);
146 :
147 : u_char *ngx_http_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len);
148 :
149 : ngx_int_t ngx_http_lua_send_header_if_needed(ngx_http_request_t *r,
150 : ngx_http_lua_ctx_t *ctx);
151 :
152 : ngx_int_t ngx_http_lua_send_chain_link(ngx_http_request_t *r,
153 : ngx_http_lua_ctx_t *ctx, ngx_chain_t *cl);
154 :
155 : void ngx_http_lua_discard_bufs(ngx_pool_t *pool, ngx_chain_t *in);
156 :
157 : ngx_int_t ngx_http_lua_add_copy_chain(ngx_http_request_t *r,
158 : ngx_http_lua_ctx_t *ctx, ngx_chain_t ***plast, ngx_chain_t *in,
159 : ngx_int_t *eof);
160 :
161 : void ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L,
162 : ngx_http_lua_ctx_t *ctx);
163 :
164 : void ngx_http_lua_generic_phase_post_read(ngx_http_request_t *r);
165 :
166 : void ngx_http_lua_request_cleanup(ngx_http_lua_ctx_t *ctx, int foricible);
167 :
168 : void ngx_http_lua_request_cleanup_handler(void *data);
169 :
170 : ngx_int_t ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r,
171 : ngx_http_lua_ctx_t *ctx, volatile int nret);
172 :
173 : ngx_int_t ngx_http_lua_wev_handler(ngx_http_request_t *r);
174 :
175 : u_char *ngx_http_lua_digest_hex(u_char *dest, const u_char *buf,
176 : int buf_len);
177 :
178 : void ngx_http_lua_set_multi_value_table(lua_State *L, int index);
179 :
180 : void ngx_http_lua_unescape_uri(u_char **dst, u_char **src, size_t size,
181 : ngx_uint_t type);
182 :
183 : uintptr_t ngx_http_lua_escape_uri(u_char *dst, u_char *src,
184 : size_t size, ngx_uint_t type);
185 :
186 : void ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L);
187 :
188 : void ngx_http_lua_process_args_option(ngx_http_request_t *r,
189 : lua_State *L, int table, ngx_str_t *args);
190 :
191 : ngx_int_t ngx_http_lua_open_and_stat_file(u_char *name,
192 : ngx_open_file_info_t *of, ngx_log_t *log);
193 :
194 : ngx_chain_t *ngx_http_lua_chain_get_free_buf(ngx_log_t *log, ngx_pool_t *p,
195 : ngx_chain_t **free, size_t len);
196 :
197 : void ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec);
198 :
199 : int ngx_http_lua_traceback(lua_State *L);
200 :
201 : ngx_http_lua_co_ctx_t *ngx_http_lua_get_co_ctx(lua_State *L,
202 : ngx_http_lua_ctx_t *ctx);
203 :
204 : ngx_http_lua_co_ctx_t *ngx_http_lua_create_co_ctx(ngx_http_request_t *r,
205 : ngx_http_lua_ctx_t *ctx);
206 :
207 : ngx_int_t ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L,
208 : ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_uint_t nreqs);
209 :
210 : ngx_int_t ngx_http_lua_post_thread(ngx_http_request_t *r,
211 : ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx);
212 :
213 : void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L,
214 : ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx);
215 :
216 : void ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r);
217 :
218 : ngx_int_t ngx_http_lua_test_expect(ngx_http_request_t *r);
219 :
220 : ngx_int_t ngx_http_lua_check_broken_connection(ngx_http_request_t *r,
221 : ngx_event_t *ev);
222 :
223 : void ngx_http_lua_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
224 :
225 : void ngx_http_lua_finalize_fake_request(ngx_http_request_t *r,
226 : ngx_int_t rc);
227 :
228 : void ngx_http_lua_close_fake_connection(ngx_connection_t *c);
229 :
230 : void ngx_http_lua_free_fake_request(ngx_http_request_t *r);
231 :
232 : void ngx_http_lua_release_ngx_ctx_table(ngx_log_t *log, lua_State *L,
233 : ngx_http_lua_ctx_t *ctx);
234 :
235 : void ngx_http_lua_cleanup_vm(void *data);
236 :
237 : ngx_connection_t *ngx_http_lua_create_fake_connection(ngx_pool_t *pool);
238 :
239 : ngx_http_request_t *ngx_http_lua_create_fake_request(ngx_connection_t *c);
240 :
241 : ngx_int_t ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status,
242 : const char *prefix);
243 :
244 : int ngx_http_lua_do_call(ngx_log_t *log, lua_State *L);
245 :
246 : ngx_http_cleanup_t *ngx_http_lua_cleanup_add(ngx_http_request_t *r,
247 : size_t size);
248 :
249 : void ngx_http_lua_cleanup_free(ngx_http_request_t *r,
250 : ngx_http_cleanup_pt *cleanup);
251 :
252 :
253 : #define ngx_http_lua_check_if_abortable(L, ctx) \
254 : if ((ctx)->no_abort) { \
255 : return luaL_error(L, "attempt to abort with pending subrequests"); \
256 : }
257 :
258 :
259 : static ngx_inline void
260 1 : ngx_http_lua_init_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx)
261 : {
262 1 : ngx_memzero(ctx, sizeof(ngx_http_lua_ctx_t));
263 1 : ctx->ctx_ref = LUA_NOREF;
264 1 : ctx->entry_co_ctx.co_ref = LUA_NOREF;
265 1 : ctx->resume_handler = ngx_http_lua_wev_handler;
266 1 : ctx->request = r;
267 1 : }
268 :
269 :
270 : static ngx_inline ngx_http_lua_ctx_t *
271 1 : ngx_http_lua_create_ctx(ngx_http_request_t *r)
272 : {
273 : lua_State *L;
274 : ngx_http_lua_ctx_t *ctx;
275 : ngx_pool_cleanup_t *cln;
276 : ngx_http_lua_loc_conf_t *llcf;
277 : ngx_http_lua_main_conf_t *lmcf;
278 :
279 1 : ctx = ngx_palloc(r->pool, sizeof(ngx_http_lua_ctx_t));
280 1 : if (ctx == NULL) {
281 0 : return NULL;
282 : }
283 :
284 1 : ngx_http_lua_init_ctx(r, ctx);
285 1 : ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
286 :
287 1 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
288 1 : if (!llcf->enable_code_cache && r->connection->fd != (ngx_socket_t) -1) {
289 0 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
290 :
291 : dd("lmcf: %p", lmcf);
292 :
293 0 : L = ngx_http_lua_init_vm(lmcf->lua, lmcf->cycle, r->pool, lmcf,
294 0 : r->connection->log, &cln);
295 0 : if (L == NULL) {
296 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
297 : "failed to initialize Lua VM");
298 0 : return NULL;
299 : }
300 :
301 0 : if (lmcf->init_handler) {
302 0 : if (lmcf->init_handler(r->connection->log, lmcf, L) != NGX_OK) {
303 : /* an error happened */
304 0 : return NULL;
305 : }
306 : }
307 :
308 0 : ctx->vm_state = cln->data;
309 :
310 : } else {
311 1 : ctx->vm_state = NULL;
312 : }
313 :
314 1 : return ctx;
315 : }
316 :
317 :
318 : static ngx_inline lua_State *
319 3 : ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx)
320 : {
321 : ngx_http_lua_main_conf_t *lmcf;
322 :
323 3 : if (ctx == NULL) {
324 1 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
325 : }
326 :
327 3 : if (ctx && ctx->vm_state) {
328 0 : return ctx->vm_state->vm;
329 : }
330 :
331 3 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
332 : dd("lmcf->lua: %p", lmcf->lua);
333 3 : return lmcf->lua;
334 : }
335 :
336 :
337 : #define ngx_http_lua_req_key "__ngx_req"
338 :
339 :
340 : static ngx_inline ngx_http_request_t *
341 5 : ngx_http_lua_get_req(lua_State *L)
342 : {
343 : ngx_http_request_t *r;
344 :
345 5 : lua_getglobal(L, ngx_http_lua_req_key);
346 5 : r = lua_touserdata(L, -1);
347 5 : lua_pop(L, 1);
348 :
349 5 : return r;
350 : }
351 :
352 :
353 : static ngx_inline void
354 1 : ngx_http_lua_set_req(lua_State *L, ngx_http_request_t *r)
355 : {
356 1 : lua_pushlightuserdata(L, r);
357 1 : lua_setglobal(L, ngx_http_lua_req_key);
358 1 : }
359 :
360 :
361 : static ngx_inline void
362 2 : ngx_http_lua_get_globals_table(lua_State *L)
363 : {
364 2 : lua_pushvalue(L, LUA_GLOBALSINDEX);
365 2 : }
366 :
367 :
368 : static ngx_inline void
369 1 : ngx_http_lua_set_globals_table(lua_State *L)
370 : {
371 1 : lua_replace(L, LUA_GLOBALSINDEX);
372 1 : }
373 :
374 :
375 : #define ngx_http_lua_hash_literal(s) \
376 : ngx_http_lua_hash_str((u_char *) s, sizeof(s) - 1)
377 :
378 :
379 : static ngx_inline ngx_uint_t
380 36 : ngx_http_lua_hash_str(u_char *src, size_t n)
381 : {
382 : ngx_uint_t key;
383 :
384 36 : key = 0;
385 :
386 468 : while (n--) {
387 396 : key = ngx_hash(key, *src);
388 396 : src++;
389 : }
390 :
391 36 : return key;
392 : }
393 :
394 :
395 : static ngx_inline ngx_int_t
396 1 : ngx_http_lua_set_content_type(ngx_http_request_t *r)
397 : {
398 : ngx_http_lua_loc_conf_t *llcf;
399 :
400 1 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
401 1 : if (llcf->use_default_type
402 1 : && r->headers_out.status != NGX_HTTP_NOT_MODIFIED)
403 : {
404 1 : return ngx_http_set_content_type(r);
405 : }
406 :
407 0 : return NGX_OK;
408 : }
409 :
410 :
411 : static ngx_inline void
412 3 : ngx_http_lua_cleanup_pending_operation(ngx_http_lua_co_ctx_t *coctx)
413 : {
414 3 : if (coctx->cleanup) {
415 0 : coctx->cleanup(coctx);
416 0 : coctx->cleanup = NULL;
417 : }
418 3 : }
419 :
420 :
421 : static ngx_inline ngx_chain_t *
422 0 : ngx_http_lua_get_flush_chain(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx)
423 : {
424 : ngx_chain_t *cl;
425 :
426 0 : cl = ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool,
427 : &ctx->free_bufs, 0);
428 0 : if (cl == NULL) {
429 0 : return NULL;
430 : }
431 :
432 0 : cl->buf->flush = 1;
433 :
434 0 : return cl;
435 : }
436 :
437 :
438 : extern ngx_uint_t ngx_http_lua_location_hash;
439 : extern ngx_uint_t ngx_http_lua_content_length_hash;
440 :
441 :
442 : #endif /* _NGX_HTTP_LUA_UTIL_H_INCLUDED_ */
443 :
444 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|