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