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