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 "ngx_http_lua_subrequest.h"
15 #include "ngx_http_lua_util.h"
16 #include "ngx_http_lua_ctx.h"
17 #include "ngx_http_lua_contentby.h"
18 #include "ngx_http_lua_headers_in.h"
19 #if defined(NGX_DTRACE) && NGX_DTRACE
20 #include "ngx_http_probe.h"
21 #endif
22 
23 
24 #define NGX_HTTP_LUA_SHARE_ALL_VARS     0x01
25 #define NGX_HTTP_LUA_COPY_ALL_VARS      0x02
26 
27 
28 #define ngx_http_lua_method_name(m) { sizeof(m) - 1, (u_char *) m " " }
29 
30 
31 ngx_str_t  ngx_http_lua_get_method = ngx_http_lua_method_name("GET");
32 ngx_str_t  ngx_http_lua_put_method = ngx_http_lua_method_name("PUT");
33 ngx_str_t  ngx_http_lua_post_method = ngx_http_lua_method_name("POST");
34 ngx_str_t  ngx_http_lua_head_method = ngx_http_lua_method_name("HEAD");
35 ngx_str_t  ngx_http_lua_delete_method =
36         ngx_http_lua_method_name("DELETE");
37 ngx_str_t  ngx_http_lua_options_method =
38         ngx_http_lua_method_name("OPTIONS");
39 ngx_str_t  ngx_http_lua_copy_method = ngx_http_lua_method_name("COPY");
40 ngx_str_t  ngx_http_lua_move_method = ngx_http_lua_method_name("MOVE");
41 ngx_str_t  ngx_http_lua_lock_method = ngx_http_lua_method_name("LOCK");
42 ngx_str_t  ngx_http_lua_mkcol_method =
43         ngx_http_lua_method_name("MKCOL");
44 ngx_str_t  ngx_http_lua_propfind_method =
45         ngx_http_lua_method_name("PROPFIND");
46 ngx_str_t  ngx_http_lua_proppatch_method =
47         ngx_http_lua_method_name("PROPPATCH");
48 ngx_str_t  ngx_http_lua_unlock_method =
49         ngx_http_lua_method_name("UNLOCK");
50 ngx_str_t  ngx_http_lua_patch_method =
51         ngx_http_lua_method_name("PATCH");
52 ngx_str_t  ngx_http_lua_trace_method =
53         ngx_http_lua_method_name("TRACE");
54 
55 
56 static ngx_str_t  ngx_http_lua_content_length_header_key =
57     ngx_string("Content-Length");
58 
59 
60 static ngx_int_t ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr,
61     ngx_uint_t method, int forward_body,
62     ngx_http_request_body_t *body, unsigned vars_action,
63     ngx_array_t *extra_vars);
64 static int ngx_http_lua_ngx_location_capture(lua_State *L);
65 static int ngx_http_lua_ngx_location_capture_multi(lua_State *L);
66 static void ngx_http_lua_process_vars_option(ngx_http_request_t *r,
67     lua_State *L, int table, ngx_array_t **varsp);
68 static ngx_int_t ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *r,
69     ngx_array_t *extra_vars);
70 static ngx_int_t ngx_http_lua_subrequest(ngx_http_request_t *r,
71     ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,
72     ngx_http_post_subrequest_t *ps, ngx_uint_t flags);
73 static ngx_int_t ngx_http_lua_subrequest_resume(ngx_http_request_t *r);
74 static void ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r,
75     ngx_http_lua_ctx_t *ctx);
76 static void ngx_http_lua_cancel_subreq(ngx_http_request_t *r);
77 static ngx_int_t ngx_http_post_request_to_head(ngx_http_request_t *r);
78 static ngx_int_t ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r);
79 static ngx_int_t ngx_http_lua_copy_request_headers(ngx_http_request_t *sr,
80     ngx_http_request_t *pr, int pr_not_chunked);
81 
82 
83 enum {
84     NGX_HTTP_LUA_SUBREQ_TRUNCATED = 1,
85 };
86 
87 
88 /* ngx.location.capture is just a thin wrapper around
89  * ngx.location.capture_multi */
90 static int
ngx_http_lua_ngx_location_capture(lua_State * L)91 ngx_http_lua_ngx_location_capture(lua_State *L)
92 {
93     int                 n;
94 
95     n = lua_gettop(L);
96 
97     if (n != 1 && n != 2) {
98         return luaL_error(L, "expecting one or two arguments");
99     }
100 
101     lua_createtable(L, n, 0); /* uri opts? table  */
102     lua_insert(L, 1); /* table uri opts? */
103     if (n == 1) { /* table uri */
104         lua_rawseti(L, 1, 1); /* table */
105 
106     } else { /* table uri opts */
107         lua_rawseti(L, 1, 2); /* table uri */
108         lua_rawseti(L, 1, 1); /* table */
109     }
110 
111     lua_createtable(L, 1, 0); /* table table' */
112     lua_insert(L, 1);   /* table' table */
113     lua_rawseti(L, 1, 1); /* table' */
114 
115     return ngx_http_lua_ngx_location_capture_multi(L);
116 }
117 
118 
119 static int
ngx_http_lua_ngx_location_capture_multi(lua_State * L)120 ngx_http_lua_ngx_location_capture_multi(lua_State *L)
121 {
122     ngx_http_request_t              *r;
123     ngx_http_request_t              *sr = NULL; /* subrequest object */
124     ngx_http_post_subrequest_t      *psr;
125     ngx_http_lua_ctx_t              *sr_ctx;
126     ngx_http_lua_ctx_t              *ctx;
127     ngx_array_t                     *extra_vars;
128     ngx_str_t                        uri;
129     ngx_str_t                        args;
130     ngx_str_t                        extra_args;
131     ngx_uint_t                       flags;
132     u_char                          *p;
133     u_char                          *q;
134     size_t                           len;
135     size_t                           nargs;
136     int                              rc;
137     int                              n;
138     int                              always_forward_body = 0;
139     ngx_uint_t                       method;
140     ngx_http_request_body_t         *body;
141     int                              type;
142     ngx_buf_t                       *b;
143     unsigned                         vars_action;
144     ngx_uint_t                       nsubreqs;
145     ngx_uint_t                       index;
146     size_t                           sr_statuses_len;
147     size_t                           sr_headers_len;
148     size_t                           sr_bodies_len;
149     size_t                           sr_flags_len;
150     size_t                           ofs1, ofs2;
151     unsigned                         custom_ctx;
152     ngx_http_lua_co_ctx_t           *coctx;
153 
154     ngx_http_lua_post_subrequest_data_t      *psr_data;
155 
156     n = lua_gettop(L);
157     if (n != 1) {
158         return luaL_error(L, "only one argument is expected, but got %d", n);
159     }
160 
161     luaL_checktype(L, 1, LUA_TTABLE);
162 
163     nsubreqs = lua_objlen(L, 1);
164     if (nsubreqs == 0) {
165         return luaL_error(L, "at least one subrequest should be specified");
166     }
167 
168     r = ngx_http_lua_get_req(L);
169     if (r == NULL) {
170         return luaL_error(L, "no request object found");
171     }
172 
173 #if (NGX_HTTP_V2)
174     if (r->main->stream) {
175         return luaL_error(L, "http2 requests not supported yet");
176     }
177 #endif
178 
179     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
180     if (ctx == NULL) {
181         return luaL_error(L, "no ctx found");
182     }
183 
184     ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
185                                | NGX_HTTP_LUA_CONTEXT_ACCESS
186                                | NGX_HTTP_LUA_CONTEXT_CONTENT);
187 
188     coctx = ctx->cur_co_ctx;
189     if (coctx == NULL) {
190         return luaL_error(L, "no co ctx found");
191     }
192 
193     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
194                    "lua location capture, uri:\"%V\" c:%ud", &r->uri,
195                    r->main->count);
196 
197     sr_statuses_len = nsubreqs * sizeof(ngx_int_t);
198     sr_headers_len  = nsubreqs * sizeof(ngx_http_headers_out_t *);
199     sr_bodies_len   = nsubreqs * sizeof(ngx_str_t);
200     sr_flags_len    = nsubreqs * sizeof(uint8_t);
201 
202     p = ngx_pcalloc(r->pool, sr_statuses_len + sr_headers_len +
203                     sr_bodies_len + sr_flags_len);
204 
205     if (p == NULL) {
206         return luaL_error(L, "no memory");
207     }
208 
209     coctx->sr_statuses = (void *) p;
210     p += sr_statuses_len;
211 
212     coctx->sr_headers = (void *) p;
213     p += sr_headers_len;
214 
215     coctx->sr_bodies = (void *) p;
216     p += sr_bodies_len;
217 
218     coctx->sr_flags = (void *) p;
219 
220     coctx->nsubreqs = nsubreqs;
221 
222     coctx->pending_subreqs = 0;
223 
224     extra_vars = NULL;
225 
226     for (index = 0; index < nsubreqs; index++) {
227         coctx->pending_subreqs++;
228 
229         lua_rawgeti(L, 1, index + 1);
230         if (lua_isnil(L, -1)) {
231             return luaL_error(L, "only array-like tables are allowed");
232         }
233 
234         dd("queries query: top %d", lua_gettop(L));
235 
236         if (lua_type(L, -1) != LUA_TTABLE) {
237             return luaL_error(L, "the query argument %d is not a table, "
238                               "but a %s",
239                               index, lua_typename(L, lua_type(L, -1)));
240         }
241 
242         nargs = lua_objlen(L, -1);
243 
244         if (nargs != 1 && nargs != 2) {
245             return luaL_error(L, "query argument %d expecting one or "
246                               "two arguments", index);
247         }
248 
249         lua_rawgeti(L, 2, 1); /* queries query uri */
250 
251         dd("queries query uri: %d", lua_gettop(L));
252 
253         dd("first arg in first query: %s", lua_typename(L, lua_type(L, -1)));
254 
255         body = NULL;
256 
257         ngx_str_null(&extra_args);
258 
259         if (extra_vars != NULL) {
260             /* flush out existing elements in the array */
261             extra_vars->nelts = 0;
262         }
263 
264         vars_action = 0;
265 
266         custom_ctx = 0;
267 
268         if (nargs == 2) {
269             /* check out the options table */
270 
271             lua_rawgeti(L, 2, 2); /* queries query uri opts */
272 
273             dd("queries query uri opts: %d", lua_gettop(L));
274 
275             if (lua_type(L, 4) != LUA_TTABLE) {
276                 return luaL_error(L, "expecting table as the 2nd argument for "
277                                   "subrequest %d, but got %s", index,
278                                   luaL_typename(L, 4));
279             }
280 
281             dd("queries query uri opts: %d", lua_gettop(L));
282 
283             /* check the args option */
284 
285             lua_getfield(L, 4, "args");
286 
287             type = lua_type(L, -1);
288 
289             switch (type) {
290             case LUA_TTABLE:
291                 ngx_http_lua_process_args_option(r, L, -1, &extra_args);
292                 break;
293 
294             case LUA_TNIL:
295                 /* do nothing */
296                 break;
297 
298             case LUA_TNUMBER:
299             case LUA_TSTRING:
300                 extra_args.data = (u_char *) lua_tolstring(L, -1, &len);
301                 extra_args.len = len;
302 
303                 break;
304 
305             default:
306                 return luaL_error(L, "Bad args option value");
307             }
308 
309             lua_pop(L, 1);
310 
311             dd("queries query uri opts: %d", lua_gettop(L));
312 
313             /* check the vars option */
314 
315             lua_getfield(L, 4, "vars");
316 
317             switch (lua_type(L, -1)) {
318             case LUA_TTABLE:
319                 ngx_http_lua_process_vars_option(r, L, -1, &extra_vars);
320 
321                 dd("post process vars top: %d", lua_gettop(L));
322                 break;
323 
324             case LUA_TNIL:
325                 /* do nothing */
326                 break;
327 
328             default:
329                 return luaL_error(L, "Bad vars option value");
330             }
331 
332             lua_pop(L, 1);
333 
334             dd("queries query uri opts: %d", lua_gettop(L));
335 
336             /* check the share_all_vars option */
337 
338             lua_getfield(L, 4, "share_all_vars");
339 
340             switch (lua_type(L, -1)) {
341             case LUA_TNIL:
342                 /* do nothing */
343                 break;
344 
345             case LUA_TBOOLEAN:
346                 if (lua_toboolean(L, -1)) {
347                     vars_action |= NGX_HTTP_LUA_SHARE_ALL_VARS;
348                 }
349                 break;
350 
351             default:
352                 return luaL_error(L, "Bad share_all_vars option value");
353             }
354 
355             lua_pop(L, 1);
356 
357             dd("queries query uri opts: %d", lua_gettop(L));
358 
359             /* check the copy_all_vars option */
360 
361             lua_getfield(L, 4, "copy_all_vars");
362 
363             switch (lua_type(L, -1)) {
364             case LUA_TNIL:
365                 /* do nothing */
366                 break;
367 
368             case LUA_TBOOLEAN:
369                 if (lua_toboolean(L, -1)) {
370                     vars_action |= NGX_HTTP_LUA_COPY_ALL_VARS;
371                 }
372                 break;
373 
374             default:
375                 return luaL_error(L, "Bad copy_all_vars option value");
376             }
377 
378             lua_pop(L, 1);
379 
380             dd("queries query uri opts: %d", lua_gettop(L));
381 
382             /* check the "forward_body" option */
383 
384             lua_getfield(L, 4, "always_forward_body");
385             always_forward_body = lua_toboolean(L, -1);
386             lua_pop(L, 1);
387 
388             dd("always forward body: %d", always_forward_body);
389 
390             /* check the "method" option */
391 
392             lua_getfield(L, 4, "method");
393 
394             type = lua_type(L, -1);
395 
396             if (type == LUA_TNIL) {
397                 method = NGX_HTTP_GET;
398 
399             } else {
400                 if (type != LUA_TNUMBER) {
401                     return luaL_error(L, "Bad http request method");
402                 }
403 
404                 method = (ngx_uint_t) lua_tonumber(L, -1);
405             }
406 
407             lua_pop(L, 1);
408 
409             dd("queries query uri opts: %d", lua_gettop(L));
410 
411             /* check the "ctx" option */
412 
413             lua_getfield(L, 4, "ctx");
414 
415             type = lua_type(L, -1);
416 
417             if (type != LUA_TNIL) {
418                 if (type != LUA_TTABLE) {
419                     return luaL_error(L, "Bad ctx option value type %s, "
420                                       "expected a Lua table",
421                                       lua_typename(L, type));
422                 }
423 
424                 custom_ctx = 1;
425 
426             } else {
427                 lua_pop(L, 1);
428             }
429 
430             dd("queries query uri opts ctx?: %d", lua_gettop(L));
431 
432             /* check the "body" option */
433 
434             lua_getfield(L, 4, "body");
435 
436             type = lua_type(L, -1);
437 
438             if (type != LUA_TNIL) {
439                 if (type != LUA_TSTRING && type != LUA_TNUMBER) {
440                     return luaL_error(L, "Bad http request body");
441                 }
442 
443                 body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
444 
445                 if (body == NULL) {
446                     return luaL_error(L, "no memory");
447                 }
448 
449                 q = (u_char *) lua_tolstring(L, -1, &len);
450 
451                 dd("request body: [%.*s]", (int) len, q);
452 
453                 if (len) {
454                     b = ngx_create_temp_buf(r->pool, len);
455                     if (b == NULL) {
456                         return luaL_error(L, "no memory");
457                     }
458 
459                     b->last = ngx_copy(b->last, q, len);
460 
461                     body->bufs = ngx_alloc_chain_link(r->pool);
462                     if (body->bufs == NULL) {
463                         return luaL_error(L, "no memory");
464                     }
465 
466                     body->bufs->buf = b;
467                     body->bufs->next = NULL;
468 
469                     body->buf = b;
470                 }
471             }
472 
473             lua_pop(L, 1); /* pop the body */
474 
475             /* stack: queries query uri opts ctx? */
476 
477             lua_remove(L, 4);
478 
479             /* stack: queries query uri ctx? */
480 
481             dd("queries query uri ctx?: %d", lua_gettop(L));
482 
483         } else {
484             method = NGX_HTTP_GET;
485         }
486 
487         /* stack: queries query uri ctx? */
488 
489         p = (u_char *) luaL_checklstring(L, 3, &len);
490 
491         uri.data = ngx_palloc(r->pool, len);
492         if (uri.data == NULL) {
493             return luaL_error(L, "memory allocation error");
494         }
495 
496         ngx_memcpy(uri.data, p, len);
497 
498         uri.len = len;
499 
500         ngx_str_null(&args);
501 
502         flags = 0;
503 
504         rc = ngx_http_parse_unsafe_uri(r, &uri, &args, &flags);
505         if (rc != NGX_OK) {
506             dd("rc = %d", (int) rc);
507 
508             return luaL_error(L, "unsafe uri in argument #1: %s", p);
509         }
510 
511         if (args.len == 0) {
512             if (extra_args.len) {
513                 p = ngx_palloc(r->pool, extra_args.len);
514                 if (p == NULL) {
515                     return luaL_error(L, "no memory");
516                 }
517 
518                 ngx_memcpy(p, extra_args.data, extra_args.len);
519 
520                 args.data = p;
521                 args.len = extra_args.len;
522             }
523 
524         } else if (extra_args.len) {
525             /* concatenate the two parts of args together */
526             len = args.len + (sizeof("&") - 1) + extra_args.len;
527 
528             p = ngx_palloc(r->pool, len);
529             if (p == NULL) {
530                 return luaL_error(L, "no memory");
531             }
532 
533             q = ngx_copy(p, args.data, args.len);
534             *q++ = '&';
535             ngx_memcpy(q, extra_args.data, extra_args.len);
536 
537             args.data = p;
538             args.len = len;
539         }
540 
541         ofs1 = ngx_align(sizeof(ngx_http_post_subrequest_t), sizeof(void *));
542         ofs2 = ngx_align(sizeof(ngx_http_lua_ctx_t), sizeof(void *));
543 
544         p = ngx_palloc(r->pool, ofs1 + ofs2
545                        + sizeof(ngx_http_lua_post_subrequest_data_t));
546         if (p == NULL) {
547             return luaL_error(L, "no memory");
548         }
549 
550         psr = (ngx_http_post_subrequest_t *) p;
551 
552         p += ofs1;
553 
554         sr_ctx = (ngx_http_lua_ctx_t *) p;
555 
556         ngx_http_lua_assert((void *) sr_ctx == ngx_align_ptr(sr_ctx,
557                                                              sizeof(void *)));
558 
559         p += ofs2;
560 
561         psr_data = (ngx_http_lua_post_subrequest_data_t *) p;
562 
563         ngx_http_lua_assert((void *) psr_data == ngx_align_ptr(psr_data,
564                                                                sizeof(void *)));
565 
566         ngx_memzero(sr_ctx, sizeof(ngx_http_lua_ctx_t));
567 
568         /* set by ngx_memzero:
569          *      sr_ctx->run_post_subrequest = 0
570          *      sr_ctx->free = NULL
571          *      sr_ctx->body = NULL
572          */
573 
574         psr_data->ctx = sr_ctx;
575         psr_data->pr_co_ctx = coctx;
576 
577         psr->handler = ngx_http_lua_post_subrequest;
578         psr->data = psr_data;
579 
580         rc = ngx_http_lua_subrequest(r, &uri, &args, &sr, psr, 0);
581 
582         if (rc != NGX_OK) {
583             return luaL_error(L, "failed to issue subrequest: %d", (int) rc);
584         }
585 
586         ngx_http_lua_init_ctx(sr, sr_ctx);
587 
588         sr_ctx->capture = 1;
589         sr_ctx->index = index;
590         sr_ctx->last_body = &sr_ctx->body;
591         sr_ctx->vm_state = ctx->vm_state;
592 
593         ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module);
594 
595         rc = ngx_http_lua_adjust_subrequest(sr, method, always_forward_body,
596                                             body, vars_action, extra_vars);
597 
598         if (rc != NGX_OK) {
599             ngx_http_lua_cancel_subreq(sr);
600             return luaL_error(L, "failed to adjust the subrequest: %d",
601                               (int) rc);
602         }
603 
604         dd("queries query uri opts ctx? %d", lua_gettop(L));
605 
606         /* stack: queries query uri ctx? */
607 
608         if (custom_ctx) {
609             ngx_http_lua_ngx_set_ctx_helper(L, sr, sr_ctx, -1);
610             lua_pop(L, 3);
611 
612         } else {
613             lua_pop(L, 2);
614         }
615 
616         /* stack: queries */
617     }
618 
619     if (extra_vars) {
620         ngx_array_destroy(extra_vars);
621     }
622 
623     ctx->no_abort = 1;
624 
625     return lua_yield(L, 0);
626 }
627 
628 
629 static ngx_int_t
ngx_http_lua_adjust_subrequest(ngx_http_request_t * sr,ngx_uint_t method,int always_forward_body,ngx_http_request_body_t * body,unsigned vars_action,ngx_array_t * extra_vars)630 ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method,
631     int always_forward_body, ngx_http_request_body_t *body,
632     unsigned vars_action, ngx_array_t *extra_vars)
633 {
634     ngx_http_request_t          *r;
635     ngx_http_core_main_conf_t   *cmcf;
636     int                          pr_not_chunked = 0;
637     size_t                       size;
638 
639     r = sr->parent;
640 
641     sr->header_in = r->header_in;
642 
643     if (body) {
644         sr->request_body = body;
645 
646     } else if (!always_forward_body
647                && method != NGX_HTTP_PUT
648                && method != NGX_HTTP_POST
649                && r->headers_in.content_length_n > 0)
650     {
651         sr->request_body = NULL;
652 
653     } else {
654         if (!r->headers_in.chunked) {
655             pr_not_chunked = 1;
656         }
657 
658         if (sr->request_body && sr->request_body->temp_file) {
659 
660             /* deep-copy the request body */
661 
662             if (ngx_http_lua_copy_in_file_request_body(sr) != NGX_OK) {
663                 return NGX_ERROR;
664             }
665         }
666     }
667 
668     if (ngx_http_lua_copy_request_headers(sr, r, pr_not_chunked) != NGX_OK) {
669         return NGX_ERROR;
670     }
671 
672     sr->method = method;
673 
674     switch (method) {
675         case NGX_HTTP_GET:
676             sr->method_name = ngx_http_lua_get_method;
677             break;
678 
679         case NGX_HTTP_POST:
680             sr->method_name = ngx_http_lua_post_method;
681             break;
682 
683         case NGX_HTTP_PUT:
684             sr->method_name = ngx_http_lua_put_method;
685             break;
686 
687         case NGX_HTTP_HEAD:
688             sr->method_name = ngx_http_lua_head_method;
689             break;
690 
691         case NGX_HTTP_DELETE:
692             sr->method_name = ngx_http_lua_delete_method;
693             break;
694 
695         case NGX_HTTP_OPTIONS:
696             sr->method_name = ngx_http_lua_options_method;
697             break;
698 
699         case NGX_HTTP_MKCOL:
700             sr->method_name = ngx_http_lua_mkcol_method;
701             break;
702 
703         case NGX_HTTP_COPY:
704             sr->method_name = ngx_http_lua_copy_method;
705             break;
706 
707         case NGX_HTTP_MOVE:
708             sr->method_name = ngx_http_lua_move_method;
709             break;
710 
711         case NGX_HTTP_PROPFIND:
712             sr->method_name = ngx_http_lua_propfind_method;
713             break;
714 
715         case NGX_HTTP_PROPPATCH:
716             sr->method_name = ngx_http_lua_proppatch_method;
717             break;
718 
719         case NGX_HTTP_LOCK:
720             sr->method_name = ngx_http_lua_lock_method;
721             break;
722 
723         case NGX_HTTP_UNLOCK:
724             sr->method_name = ngx_http_lua_unlock_method;
725             break;
726 
727         case NGX_HTTP_PATCH:
728             sr->method_name = ngx_http_lua_patch_method;
729             break;
730 
731         case NGX_HTTP_TRACE:
732             sr->method_name = ngx_http_lua_trace_method;
733             break;
734 
735         default:
736             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
737                           "unsupported HTTP method: %u", (unsigned) method);
738 
739             return NGX_ERROR;
740     }
741 
742     if (!(vars_action & NGX_HTTP_LUA_SHARE_ALL_VARS)) {
743         /* we do not inherit the parent request's variables */
744         cmcf = ngx_http_get_module_main_conf(sr, ngx_http_core_module);
745 
746         size = cmcf->variables.nelts * sizeof(ngx_http_variable_value_t);
747 
748         if (vars_action & NGX_HTTP_LUA_COPY_ALL_VARS) {
749 
750             sr->variables = ngx_palloc(sr->pool, size);
751             if (sr->variables == NULL) {
752                 return NGX_ERROR;
753             }
754 
755             ngx_memcpy(sr->variables, r->variables, size);
756 
757         } else {
758 
759             /* we do not inherit the parent request's variables */
760 
761             sr->variables = ngx_pcalloc(sr->pool, size);
762             if (sr->variables == NULL) {
763                 return NGX_ERROR;
764             }
765         }
766     }
767 
768     return ngx_http_lua_subrequest_add_extra_vars(sr, extra_vars);
769 }
770 
771 
772 static ngx_int_t
ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t * sr,ngx_array_t * extra_vars)773 ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *sr,
774     ngx_array_t *extra_vars)
775 {
776     ngx_http_core_main_conf_t   *cmcf;
777     ngx_http_variable_t         *v;
778     ngx_http_variable_value_t   *vv;
779     u_char                      *val;
780     u_char                      *p;
781     ngx_uint_t                   i, hash;
782     ngx_str_t                    name;
783     size_t                       len;
784     ngx_hash_t                  *variables_hash;
785     ngx_keyval_t                *var;
786 
787     /* set any extra variables that were passed to the subrequest */
788 
789     if (extra_vars == NULL || extra_vars->nelts == 0) {
790         return NGX_OK;
791     }
792 
793     cmcf = ngx_http_get_module_main_conf(sr, ngx_http_core_module);
794 
795     variables_hash = &cmcf->variables_hash;
796 
797     var = extra_vars->elts;
798 
799     for (i = 0; i < extra_vars->nelts; i++, var++) {
800         /* copy the variable's name and value because they are allocated
801          * by the lua VM */
802 
803         len = var->key.len + var->value.len;
804 
805         p = ngx_pnalloc(sr->pool, len);
806         if (p == NULL) {
807             return NGX_ERROR;
808         }
809 
810         name.data = p;
811         name.len = var->key.len;
812 
813         p = ngx_copy(p, var->key.data, var->key.len);
814 
815         hash = ngx_hash_strlow(name.data, name.data, name.len);
816 
817         val = p;
818         len = var->value.len;
819 
820         ngx_memcpy(p, var->value.data, len);
821 
822         v = ngx_hash_find(variables_hash, hash, name.data, name.len);
823 
824         if (v) {
825             if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) {
826                 ngx_log_error(NGX_LOG_ERR, sr->connection->log, 0,
827                               "variable \"%V\" not changeable", &name);
828                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
829             }
830 
831             if (v->set_handler) {
832                 vv = ngx_palloc(sr->pool, sizeof(ngx_http_variable_value_t));
833                 if (vv == NULL) {
834                     return NGX_ERROR;
835                 }
836 
837                 vv->valid = 1;
838                 vv->not_found = 0;
839                 vv->no_cacheable = 0;
840 
841                 vv->data = val;
842                 vv->len = len;
843 
844                 v->set_handler(sr, vv, v->data);
845 
846                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sr->connection->log, 0,
847                                "variable \"%V\" set to value \"%v\"", &name,
848                                vv);
849 
850                 continue;
851             }
852 
853             if (v->flags & NGX_HTTP_VAR_INDEXED) {
854                 vv = &sr->variables[v->index];
855 
856                 vv->valid = 1;
857                 vv->not_found = 0;
858                 vv->no_cacheable = 0;
859 
860                 vv->data = val;
861                 vv->len = len;
862 
863                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sr->connection->log, 0,
864                                "variable \"%V\" set to value \"%v\"",
865                                &name, vv);
866 
867                 continue;
868             }
869         }
870 
871         ngx_log_error(NGX_LOG_ERR, sr->connection->log, 0,
872                       "variable \"%V\" cannot be assigned a value (maybe you "
873                       "forgot to define it first?) ", &name);
874 
875         return NGX_ERROR;
876     }
877 
878     return NGX_OK;
879 }
880 
881 
882 static void
ngx_http_lua_process_vars_option(ngx_http_request_t * r,lua_State * L,int table,ngx_array_t ** varsp)883 ngx_http_lua_process_vars_option(ngx_http_request_t *r, lua_State *L,
884     int table, ngx_array_t **varsp)
885 {
886     ngx_array_t         *vars;
887     ngx_keyval_t        *var;
888 
889     if (table < 0) {
890         table = lua_gettop(L) + table + 1;
891     }
892 
893     vars = *varsp;
894 
895     if (vars == NULL) {
896 
897         vars = ngx_array_create(r->pool, 4, sizeof(ngx_keyval_t));
898         if (vars == NULL) {
899             dd("here");
900             luaL_error(L, "no memory");
901             return;
902         }
903 
904         *varsp = vars;
905     }
906 
907     lua_pushnil(L);
908     while (lua_next(L, table) != 0) {
909 
910         if (lua_type(L, -2) != LUA_TSTRING) {
911             luaL_error(L, "attempt to use a non-string key in the "
912                        "\"vars\" option table");
913             return;
914         }
915 
916         if (!lua_isstring(L, -1)) {
917             luaL_error(L, "attempt to use bad variable value type %s",
918                        luaL_typename(L, -1));
919             return;
920         }
921 
922         var = ngx_array_push(vars);
923         if (var == NULL) {
924             dd("here");
925             luaL_error(L, "no memory");
926             return;
927         }
928 
929         var->key.data = (u_char *) lua_tolstring(L, -2, &var->key.len);
930         var->value.data = (u_char *) lua_tolstring(L, -1, &var->value.len);
931 
932         lua_pop(L, 1);
933     }
934 }
935 
936 
937 ngx_int_t
ngx_http_lua_post_subrequest(ngx_http_request_t * r,void * data,ngx_int_t rc)938 ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc)
939 {
940     ngx_http_request_t            *pr;
941     ngx_http_lua_ctx_t            *pr_ctx;
942     ngx_http_lua_ctx_t            *ctx; /* subrequest ctx */
943     ngx_http_lua_co_ctx_t         *pr_coctx;
944     size_t                         len;
945     ngx_str_t                     *body_str;
946     u_char                        *p;
947     ngx_chain_t                   *cl;
948 
949     ngx_http_lua_post_subrequest_data_t    *psr_data = data;
950 
951     ctx = psr_data->ctx;
952 
953     if (ctx->run_post_subrequest) {
954         if (r != r->connection->data) {
955             r->connection->data = r;
956         }
957 
958         return NGX_OK;
959     }
960 
961     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
962                    "lua run post subrequest handler, rc:%i c:%ud", rc,
963                    r->main->count);
964 
965     ctx->run_post_subrequest = 1;
966 
967     pr = r->parent;
968 
969     pr_ctx = ngx_http_get_module_ctx(pr, ngx_http_lua_module);
970     if (pr_ctx == NULL) {
971         return NGX_ERROR;
972     }
973 
974     pr_coctx = psr_data->pr_co_ctx;
975     pr_coctx->pending_subreqs--;
976 
977     if (pr_coctx->pending_subreqs == 0) {
978         dd("all subrequests are done");
979 
980         pr_ctx->no_abort = 0;
981         pr_ctx->resume_handler = ngx_http_lua_subrequest_resume;
982         pr_ctx->cur_co_ctx = pr_coctx;
983     }
984 
985     if (pr_ctx->entered_content_phase) {
986         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
987                        "lua restoring write event handler");
988 
989         pr->write_event_handler = ngx_http_lua_content_wev_handler;
990 
991     } else {
992         pr->write_event_handler = ngx_http_core_run_phases;
993     }
994 
995     dd("status rc = %d", (int) rc);
996     dd("status headers_out.status = %d", (int) r->headers_out.status);
997     dd("uri: %.*s", (int) r->uri.len, r->uri.data);
998 
999     /*  capture subrequest response status */
1000 
1001     pr_coctx->sr_statuses[ctx->index] = r->headers_out.status;
1002 
1003     if (pr_coctx->sr_statuses[ctx->index] == 0) {
1004         if (rc == NGX_OK) {
1005             rc = NGX_HTTP_OK;
1006         }
1007 
1008         if (rc == NGX_ERROR) {
1009             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
1010         }
1011 
1012         if (rc >= 100) {
1013             pr_coctx->sr_statuses[ctx->index] = rc;
1014         }
1015     }
1016 
1017     if (!ctx->seen_last_for_subreq) {
1018         pr_coctx->sr_flags[ctx->index] |= NGX_HTTP_LUA_SUBREQ_TRUNCATED;
1019     }
1020 
1021     dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]);
1022 
1023     /* copy subrequest response headers */
1024     if (ctx->headers_set) {
1025         rc = ngx_http_lua_set_content_type(r, ctx);
1026         if (rc != NGX_OK) {
1027             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1028                           "failed to set default content type: %i", rc);
1029             return NGX_ERROR;
1030         }
1031     }
1032 
1033     pr_coctx->sr_headers[ctx->index] = &r->headers_out;
1034 
1035     /* copy subrequest response body */
1036 
1037     body_str = &pr_coctx->sr_bodies[ctx->index];
1038 
1039     len = 0;
1040     for (cl = ctx->body; cl; cl = cl->next) {
1041         /*  ignore all non-memory buffers */
1042         len += cl->buf->last - cl->buf->pos;
1043     }
1044 
1045     body_str->len = len;
1046 
1047     if (len == 0) {
1048         body_str->data = NULL;
1049 
1050     } else {
1051         p = ngx_palloc(r->pool, len);
1052         if (p == NULL) {
1053             return NGX_ERROR;
1054         }
1055 
1056         body_str->data = p;
1057 
1058         /* copy from and then free the data buffers */
1059 
1060         for (cl = ctx->body; cl; cl = cl->next) {
1061             p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos);
1062 
1063             cl->buf->last = cl->buf->pos;
1064 
1065 #if 0
1066             dd("free body chain link buf ASAP");
1067             ngx_pfree(r->pool, cl->buf->start);
1068 #endif
1069         }
1070     }
1071 
1072     if (ctx->body) {
1073 
1074         ngx_chain_update_chains(r->pool,
1075                                 &pr_ctx->free_bufs, &pr_ctx->busy_bufs,
1076                                 &ctx->body,
1077                                 (ngx_buf_tag_t) &ngx_http_lua_module);
1078 
1079         dd("free bufs: %p", pr_ctx->free_bufs);
1080     }
1081 
1082     ngx_http_post_request_to_head(pr);
1083 
1084     if (r != r->connection->data) {
1085         r->connection->data = r;
1086     }
1087 
1088     if (rc == NGX_ERROR
1089         || rc == NGX_HTTP_CREATED
1090         || rc == NGX_HTTP_NO_CONTENT
1091         || (rc >= NGX_HTTP_SPECIAL_RESPONSE
1092             && rc != NGX_HTTP_CLOSE
1093             && rc != NGX_HTTP_REQUEST_TIME_OUT
1094             && rc != NGX_HTTP_CLIENT_CLOSED_REQUEST))
1095     {
1096         /* emulate ngx_http_special_response_handler */
1097 
1098         if (rc > NGX_OK) {
1099             r->err_status = rc;
1100 
1101             r->expect_tested = 1;
1102             r->headers_out.content_type.len = 0;
1103             r->headers_out.content_length_n = 0;
1104 
1105             ngx_http_clear_accept_ranges(r);
1106             ngx_http_clear_last_modified(r);
1107 
1108             rc = ngx_http_lua_send_header_if_needed(r, ctx);
1109             if (rc == NGX_ERROR) {
1110                 return NGX_ERROR;
1111             }
1112         }
1113 
1114         return NGX_OK;
1115     }
1116 
1117     return rc;
1118 }
1119 
1120 
1121 static void
ngx_http_lua_handle_subreq_responses(ngx_http_request_t * r,ngx_http_lua_ctx_t * ctx)1122 ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r,
1123     ngx_http_lua_ctx_t *ctx)
1124 {
1125     ngx_uint_t                   i, count;
1126     ngx_uint_t                   index;
1127     lua_State                   *co;
1128     ngx_str_t                   *body_str;
1129     ngx_table_elt_t             *header;
1130     ngx_list_part_t             *part;
1131     ngx_http_headers_out_t      *sr_headers;
1132     ngx_http_lua_co_ctx_t       *coctx;
1133 
1134     u_char                  buf[sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1];
1135 
1136     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1137                    "lua handle subrequest responses");
1138 
1139     coctx = ctx->cur_co_ctx;
1140     co = coctx->co;
1141 
1142     for (index = 0; index < coctx->nsubreqs; index++) {
1143         dd("summary: reqs %d, subquery %d, pending %d, req %.*s",
1144            (int) coctx->nsubreqs,
1145            (int) index,
1146            (int) coctx->pending_subreqs,
1147            (int) r->uri.len, r->uri.data);
1148 
1149         /*  {{{ construct ret value */
1150         lua_createtable(co, 0 /* narr */, 4 /* nrec */);
1151 
1152         /*  copy captured status */
1153         lua_pushinteger(co, coctx->sr_statuses[index]);
1154         lua_setfield(co, -2, "status");
1155 
1156         dd("captured subrequest flags: %d", (int) coctx->sr_flags[index]);
1157 
1158         /* set truncated flag if truncation happens */
1159         if (coctx->sr_flags[index] & NGX_HTTP_LUA_SUBREQ_TRUNCATED) {
1160             lua_pushboolean(co, 1);
1161             lua_setfield(co, -2, "truncated");
1162 
1163         } else {
1164             lua_pushboolean(co, 0);
1165             lua_setfield(co, -2, "truncated");
1166         }
1167 
1168         /*  copy captured body */
1169 
1170         body_str = &coctx->sr_bodies[index];
1171 
1172         lua_pushlstring(co, (char *) body_str->data, body_str->len);
1173         lua_setfield(co, -2, "body");
1174 
1175         if (body_str->data) {
1176             dd("free body buffer ASAP");
1177             ngx_pfree(r->pool, body_str->data);
1178         }
1179 
1180         /* copy captured headers */
1181 
1182         sr_headers = coctx->sr_headers[index];
1183 
1184         part = &sr_headers->headers.part;
1185         count = part->nelts;
1186         while (part->next) {
1187             part = part->next;
1188             count += part->nelts;
1189         }
1190 
1191         lua_createtable(co, 0, count + 5); /* res.header */
1192 
1193         dd("saving subrequest response headers");
1194 
1195         part = &sr_headers->headers.part;
1196         header = part->elts;
1197 
1198         for (i = 0; /* void */; i++) {
1199 
1200             if (i >= part->nelts) {
1201                 if (part->next == NULL) {
1202                     break;
1203                 }
1204 
1205                 part = part->next;
1206                 header = part->elts;
1207                 i = 0;
1208             }
1209 
1210             dd("checking sr header %.*s", (int) header[i].key.len,
1211                header[i].key.data);
1212 
1213 #if 1
1214             if (header[i].hash == 0) {
1215                 continue;
1216             }
1217 #endif
1218 
1219             header[i].hash = 0;
1220 
1221             dd("pushing sr header %.*s", (int) header[i].key.len,
1222                header[i].key.data);
1223 
1224             lua_pushlstring(co, (char *) header[i].key.data,
1225                             header[i].key.len); /* header key */
1226             lua_pushvalue(co, -1); /* stack: table key key */
1227 
1228             /* check if header already exists */
1229             lua_rawget(co, -3); /* stack: table key value */
1230 
1231             if (lua_isnil(co, -1)) {
1232                 lua_pop(co, 1); /* stack: table key */
1233 
1234                 lua_pushlstring(co, (char *) header[i].value.data,
1235                                 header[i].value.len);
1236                     /* stack: table key value */
1237 
1238                 lua_rawset(co, -3); /* stack: table */
1239 
1240             } else {
1241 
1242                 if (!lua_istable(co, -1)) { /* already inserted one value */
1243                     lua_createtable(co, 4, 0);
1244                         /* stack: table key value table */
1245 
1246                     lua_insert(co, -2); /* stack: table key table value */
1247                     lua_rawseti(co, -2, 1); /* stack: table key table */
1248 
1249                     lua_pushlstring(co, (char *) header[i].value.data,
1250                                     header[i].value.len);
1251                         /* stack: table key table value */
1252 
1253                     lua_rawseti(co, -2, lua_objlen(co, -2) + 1);
1254                         /* stack: table key table */
1255 
1256                     lua_rawset(co, -3); /* stack: table */
1257 
1258                 } else {
1259                     lua_pushlstring(co, (char *) header[i].value.data,
1260                                     header[i].value.len);
1261                         /* stack: table key table value */
1262 
1263                     lua_rawseti(co, -2, lua_objlen(co, -2) + 1);
1264                         /* stack: table key table */
1265 
1266                     lua_pop(co, 2); /* stack: table */
1267                 }
1268             }
1269         }
1270 
1271         if (sr_headers->content_type.len) {
1272             lua_pushliteral(co, "Content-Type"); /* header key */
1273             lua_pushlstring(co, (char *) sr_headers->content_type.data,
1274                             sr_headers->content_type.len); /* head key value */
1275             lua_rawset(co, -3); /* head */
1276         }
1277 
1278         if (sr_headers->content_length == NULL
1279             && sr_headers->content_length_n >= 0)
1280         {
1281             lua_pushliteral(co, "Content-Length"); /* header key */
1282 
1283             lua_pushnumber(co, (lua_Number) sr_headers->content_length_n);
1284                 /* head key value */
1285 
1286             lua_rawset(co, -3); /* head */
1287         }
1288 
1289         /* to work-around an issue in ngx_http_static_module
1290          * (github issue #41) */
1291         if (sr_headers->location && sr_headers->location->value.len) {
1292             lua_pushliteral(co, "Location"); /* header key */
1293             lua_pushlstring(co, (char *) sr_headers->location->value.data,
1294                             sr_headers->location->value.len);
1295             /* head key value */
1296             lua_rawset(co, -3); /* head */
1297         }
1298 
1299         if (sr_headers->last_modified_time != -1) {
1300             if (sr_headers->status != NGX_HTTP_OK
1301                 && sr_headers->status != NGX_HTTP_PARTIAL_CONTENT
1302                 && sr_headers->status != NGX_HTTP_NOT_MODIFIED
1303                 && sr_headers->status != NGX_HTTP_NO_CONTENT)
1304             {
1305                 sr_headers->last_modified_time = -1;
1306                 sr_headers->last_modified = NULL;
1307             }
1308         }
1309 
1310         if (sr_headers->last_modified == NULL
1311             && sr_headers->last_modified_time != -1)
1312         {
1313             (void) ngx_http_time(buf, sr_headers->last_modified_time);
1314 
1315             lua_pushliteral(co, "Last-Modified"); /* header key */
1316             lua_pushlstring(co, (char *) buf, sizeof(buf)); /* head key value */
1317             lua_rawset(co, -3); /* head */
1318         }
1319 
1320         lua_setfield(co, -2, "header");
1321 
1322         /*  }}} */
1323     }
1324 }
1325 
1326 
1327 void
ngx_http_lua_inject_subrequest_api(lua_State * L)1328 ngx_http_lua_inject_subrequest_api(lua_State *L)
1329 {
1330     lua_createtable(L, 0 /* narr */, 2 /* nrec */); /* .location */
1331 
1332     lua_pushcfunction(L, ngx_http_lua_ngx_location_capture);
1333     lua_setfield(L, -2, "capture");
1334 
1335     lua_pushcfunction(L, ngx_http_lua_ngx_location_capture_multi);
1336     lua_setfield(L, -2, "capture_multi");
1337 
1338     lua_setfield(L, -2, "location");
1339 }
1340 
1341 
1342 static ngx_int_t
ngx_http_lua_subrequest(ngx_http_request_t * r,ngx_str_t * uri,ngx_str_t * args,ngx_http_request_t ** psr,ngx_http_post_subrequest_t * ps,ngx_uint_t flags)1343 ngx_http_lua_subrequest(ngx_http_request_t *r,
1344     ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,
1345     ngx_http_post_subrequest_t *ps, ngx_uint_t flags)
1346 {
1347     ngx_time_t                    *tp;
1348     ngx_connection_t              *c;
1349     ngx_http_request_t            *sr;
1350     ngx_http_core_srv_conf_t      *cscf;
1351 
1352 #if (nginx_version >= 1009005)
1353 
1354     if (r->subrequests == 0) {
1355 #if defined(NGX_DTRACE) && NGX_DTRACE
1356         ngx_http_probe_subrequest_cycle(r, uri, args);
1357 #endif
1358 
1359         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1360                       "lua subrequests cycle while processing \"%V\"", uri);
1361         return NGX_ERROR;
1362     }
1363 
1364 #else  /* nginx_version <= 1009004 */
1365 
1366     r->main->subrequests--;
1367 
1368     if (r->main->subrequests == 0) {
1369 #if defined(NGX_DTRACE) && NGX_DTRACE
1370         ngx_http_probe_subrequest_cycle(r, uri, args);
1371 #endif
1372 
1373         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1374                       "lua subrequests cycle while processing \"%V\"", uri);
1375         r->main->subrequests = 1;
1376         return NGX_ERROR;
1377     }
1378 
1379 #endif
1380 
1381     sr = ngx_pcalloc(r->pool, sizeof(ngx_http_request_t));
1382     if (sr == NULL) {
1383         return NGX_ERROR;
1384     }
1385 
1386     sr->signature = NGX_HTTP_MODULE;
1387 
1388     c = r->connection;
1389     sr->connection = c;
1390 
1391     sr->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
1392     if (sr->ctx == NULL) {
1393         return NGX_ERROR;
1394     }
1395 
1396     if (ngx_list_init(&sr->headers_out.headers, r->pool, 20,
1397                       sizeof(ngx_table_elt_t))
1398         != NGX_OK)
1399     {
1400         return NGX_ERROR;
1401     }
1402 
1403     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1404     sr->main_conf = cscf->ctx->main_conf;
1405     sr->srv_conf = cscf->ctx->srv_conf;
1406     sr->loc_conf = cscf->ctx->loc_conf;
1407 
1408     sr->pool = r->pool;
1409 
1410     sr->headers_in.content_length_n = -1;
1411     sr->headers_in.keep_alive_n = -1;
1412 
1413     ngx_http_clear_content_length(sr);
1414     ngx_http_clear_accept_ranges(sr);
1415     ngx_http_clear_last_modified(sr);
1416 
1417     sr->request_body = r->request_body;
1418 
1419 #if (NGX_HTTP_SPDY)
1420     sr->spdy_stream = r->spdy_stream;
1421 #endif
1422 
1423 #if (NGX_HTTP_V2)
1424     sr->stream = r->stream;
1425 #endif
1426 
1427 #ifdef HAVE_ALLOW_REQUEST_BODY_UPDATING_PATCH
1428     sr->content_length_n = -1;
1429 #endif
1430 
1431     sr->method = NGX_HTTP_GET;
1432     sr->http_version = r->http_version;
1433 
1434     sr->request_line = r->request_line;
1435     sr->uri = *uri;
1436 
1437     if (args) {
1438         sr->args = *args;
1439     }
1440 
1441     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
1442                    "lua http subrequest \"%V?%V\"", uri, &sr->args);
1443 
1444     sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0;
1445     sr->waited = (flags & NGX_HTTP_SUBREQUEST_WAITED) != 0;
1446 
1447     sr->unparsed_uri = r->unparsed_uri;
1448     sr->method_name = ngx_http_core_get_method;
1449     sr->http_protocol = r->http_protocol;
1450 
1451     ngx_http_set_exten(sr);
1452 
1453     sr->main = r->main;
1454     sr->parent = r;
1455     sr->post_subrequest = ps;
1456     sr->read_event_handler = ngx_http_request_empty_handler;
1457     sr->write_event_handler = ngx_http_handler;
1458 
1459     sr->variables = r->variables;
1460 
1461     sr->log_handler = r->log_handler;
1462 
1463     sr->internal = 1;
1464 
1465     sr->discard_body = r->discard_body;
1466     sr->expect_tested = 1;
1467     sr->main_filter_need_in_memory = r->main_filter_need_in_memory;
1468 
1469     sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;
1470 
1471 #if (nginx_version >= 1009005)
1472     sr->subrequests = r->subrequests - 1;
1473 #endif
1474 
1475     tp = ngx_timeofday();
1476     sr->start_sec = tp->sec;
1477     sr->start_msec = tp->msec;
1478 
1479     r->main->count++;
1480 
1481     *psr = sr;
1482 
1483 #if defined(NGX_DTRACE) && NGX_DTRACE
1484     ngx_http_probe_subrequest_start(sr);
1485 #endif
1486 
1487     return ngx_http_post_request(sr, NULL);
1488 }
1489 
1490 
1491 static ngx_int_t
ngx_http_lua_subrequest_resume(ngx_http_request_t * r)1492 ngx_http_lua_subrequest_resume(ngx_http_request_t *r)
1493 {
1494     lua_State                   *vm;
1495     ngx_int_t                    rc;
1496     ngx_uint_t                   nreqs;
1497     ngx_connection_t            *c;
1498     ngx_http_lua_ctx_t          *ctx;
1499     ngx_http_lua_co_ctx_t       *coctx;
1500 
1501     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
1502     if (ctx == NULL) {
1503         return NGX_ERROR;
1504     }
1505 
1506     ctx->resume_handler = ngx_http_lua_wev_handler;
1507 
1508     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1509                    "lua run subrequests done, resuming lua thread");
1510 
1511     coctx = ctx->cur_co_ctx;
1512 
1513     dd("nsubreqs: %d", (int) coctx->nsubreqs);
1514 
1515     ngx_http_lua_handle_subreq_responses(r, ctx);
1516 
1517     dd("free sr_statues/headers/bodies memory ASAP");
1518 
1519 #if 1
1520     ngx_pfree(r->pool, coctx->sr_statuses);
1521 
1522     coctx->sr_statuses = NULL;
1523     coctx->sr_headers = NULL;
1524     coctx->sr_bodies = NULL;
1525     coctx->sr_flags = NULL;
1526 #endif
1527 
1528     c = r->connection;
1529     vm = ngx_http_lua_get_lua_vm(r, ctx);
1530     nreqs = c->requests;
1531 
1532     rc = ngx_http_lua_run_thread(vm, r, ctx, coctx->nsubreqs);
1533 
1534     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1535                    "lua run thread returned %d", rc);
1536 
1537     if (rc == NGX_AGAIN) {
1538         return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
1539     }
1540 
1541     if (rc == NGX_DONE) {
1542         ngx_http_lua_finalize_request(r, NGX_DONE);
1543         return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
1544     }
1545 
1546     /* rc == NGX_ERROR || rc >= NGX_OK */
1547 
1548     if (ctx->entered_content_phase) {
1549         ngx_http_lua_finalize_request(r, rc);
1550         return NGX_DONE;
1551     }
1552 
1553     return rc;
1554 }
1555 
1556 
1557 static void
ngx_http_lua_cancel_subreq(ngx_http_request_t * r)1558 ngx_http_lua_cancel_subreq(ngx_http_request_t *r)
1559 {
1560     ngx_http_posted_request_t   *pr;
1561     ngx_http_posted_request_t  **p;
1562 
1563 #if 1
1564     r->main->count--;
1565     r->main->subrequests++;
1566 #endif
1567 
1568     p = &r->main->posted_requests;
1569     for (pr = r->main->posted_requests; pr->next; pr = pr->next) {
1570         p = &pr->next;
1571     }
1572 
1573     *p = NULL;
1574 
1575     r->connection->data = r->parent;
1576 }
1577 
1578 
1579 static ngx_int_t
ngx_http_post_request_to_head(ngx_http_request_t * r)1580 ngx_http_post_request_to_head(ngx_http_request_t *r)
1581 {
1582     ngx_http_posted_request_t  *pr;
1583 
1584     pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t));
1585     if (pr == NULL) {
1586         return NGX_ERROR;
1587     }
1588 
1589     pr->request = r;
1590     pr->next = r->main->posted_requests;
1591     r->main->posted_requests = pr;
1592 
1593     return NGX_OK;
1594 }
1595 
1596 
1597 static ngx_int_t
ngx_http_lua_copy_in_file_request_body(ngx_http_request_t * r)1598 ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r)
1599 {
1600     ngx_temp_file_t     *tf;
1601 
1602     ngx_http_request_body_t   *body;
1603 
1604     tf = r->request_body->temp_file;
1605 
1606     if (!tf->persistent || !tf->clean) {
1607         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1608                       "the request body was not read by ngx_lua");
1609 
1610         return NGX_ERROR;
1611     }
1612 
1613     body = ngx_palloc(r->pool, sizeof(ngx_http_request_body_t));
1614     if (body == NULL) {
1615         return NGX_ERROR;
1616     }
1617 
1618     ngx_memcpy(body, r->request_body, sizeof(ngx_http_request_body_t));
1619 
1620     body->temp_file = ngx_palloc(r->pool, sizeof(ngx_temp_file_t));
1621     if (body->temp_file == NULL) {
1622         return NGX_ERROR;
1623     }
1624 
1625     ngx_memcpy(body->temp_file, tf, sizeof(ngx_temp_file_t));
1626     dd("file fd: %d", body->temp_file->file.fd);
1627 
1628     r->request_body = body;
1629 
1630     return NGX_OK;
1631 }
1632 
1633 
1634 static ngx_int_t
ngx_http_lua_copy_request_headers(ngx_http_request_t * sr,ngx_http_request_t * pr,int pr_not_chunked)1635 ngx_http_lua_copy_request_headers(ngx_http_request_t *sr,
1636     ngx_http_request_t *pr, int pr_not_chunked)
1637 {
1638     ngx_table_elt_t                 *clh, *header;
1639     ngx_list_part_t                 *part;
1640     ngx_chain_t                     *in;
1641     ngx_uint_t                       i;
1642     u_char                          *p;
1643     off_t                            len;
1644 
1645     dd("before: parent req headers count: %d",
1646        (int) pr->headers_in.headers.part.nelts);
1647 
1648     if (ngx_list_init(&sr->headers_in.headers, sr->pool, 20,
1649                       sizeof(ngx_table_elt_t)) != NGX_OK)
1650     {
1651         return NGX_ERROR;
1652     }
1653 
1654     if (sr->request_body && !pr_not_chunked) {
1655 
1656         /* craft our own Content-Length */
1657         len = 0;
1658 
1659         for (in = sr->request_body->bufs; in; in = in->next) {
1660             len += ngx_buf_size(in->buf);
1661         }
1662 
1663         clh = ngx_list_push(&sr->headers_in.headers);
1664         if (clh == NULL) {
1665             return NGX_ERROR;
1666         }
1667 
1668         clh->hash = ngx_http_lua_content_length_hash;
1669         clh->key = ngx_http_lua_content_length_header_key;
1670         clh->lowcase_key = ngx_pnalloc(sr->pool, clh->key.len);
1671         if (clh->lowcase_key == NULL) {
1672             return NGX_ERROR;
1673         }
1674 
1675         ngx_strlow(clh->lowcase_key, clh->key.data, clh->key.len);
1676 
1677         p = ngx_palloc(sr->pool, NGX_OFF_T_LEN);
1678         if (p == NULL) {
1679             return NGX_ERROR;
1680         }
1681 
1682         clh->value.data = p;
1683         clh->value.len = ngx_sprintf(clh->value.data, "%O", len)
1684                          - clh->value.data;
1685 
1686         sr->headers_in.content_length = clh;
1687         sr->headers_in.content_length_n = len;
1688 
1689         dd("sr crafted content-length: %.*s",
1690            (int) sr->headers_in.content_length->value.len,
1691            sr->headers_in.content_length->value.data);
1692     }
1693 
1694     /* copy the parent request's headers */
1695 
1696     part = &pr->headers_in.headers.part;
1697     header = part->elts;
1698 
1699     for (i = 0; /* void */; i++) {
1700 
1701         if (i >= part->nelts) {
1702             if (part->next == NULL) {
1703                 break;
1704             }
1705 
1706             part = part->next;
1707             header = part->elts;
1708             i = 0;
1709         }
1710 
1711         if (!pr_not_chunked && header[i].key.len == sizeof("Content-Length") - 1
1712             && ngx_strncasecmp(header[i].key.data, (u_char *) "Content-Length",
1713                                sizeof("Content-Length") - 1) == 0)
1714         {
1715             continue;
1716         }
1717 
1718         dd("sr copied req header %.*s: %.*s", (int) header[i].key.len,
1719            header[i].key.data, (int) header[i].value.len,
1720            header[i].value.data);
1721 
1722         if (ngx_http_lua_set_input_header(sr, header[i].key,
1723                                           header[i].value, 0) == NGX_ERROR)
1724         {
1725             return NGX_ERROR;
1726         }
1727     }
1728 
1729     dd("after: parent req headers count: %d",
1730        (int) pr->headers_in.headers.part.nelts);
1731 
1732     return NGX_OK;
1733 }
1734 
1735 
1736 /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
1737