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_headers.h"
15 : #include "ngx_http_lua_headers_out.h"
16 : #include "ngx_http_lua_headers_in.h"
17 : #include "ngx_http_lua_util.h"
18 :
19 :
20 : static int ngx_http_lua_ngx_req_http_version(lua_State *L);
21 : static int ngx_http_lua_ngx_req_raw_header(lua_State *L);
22 : static int ngx_http_lua_ngx_req_header_set_helper(lua_State *L);
23 : static int ngx_http_lua_ngx_header_get(lua_State *L);
24 : static int ngx_http_lua_ngx_header_set(lua_State *L);
25 : static int ngx_http_lua_ngx_req_get_headers(lua_State *L);
26 : static int ngx_http_lua_ngx_req_header_clear(lua_State *L);
27 : static int ngx_http_lua_ngx_req_header_set(lua_State *L);
28 : static int ngx_http_lua_ngx_resp_get_headers(lua_State *L);
29 : #if nginx_version >= 1011011
30 : void ngx_http_lua_ngx_raw_header_cleanup(void *data);
31 : #endif
32 :
33 :
34 : static int
35 0 : ngx_http_lua_ngx_req_http_version(lua_State *L)
36 : {
37 : ngx_http_request_t *r;
38 :
39 0 : r = ngx_http_lua_get_req(L);
40 0 : if (r == NULL) {
41 0 : return luaL_error(L, "no request object found");
42 : }
43 :
44 0 : ngx_http_lua_check_fake_request(L, r);
45 :
46 0 : switch (r->http_version) {
47 0 : case NGX_HTTP_VERSION_9:
48 0 : lua_pushnumber(L, 0.9);
49 0 : break;
50 :
51 0 : case NGX_HTTP_VERSION_10:
52 0 : lua_pushnumber(L, 1.0);
53 0 : break;
54 :
55 0 : case NGX_HTTP_VERSION_11:
56 0 : lua_pushnumber(L, 1.1);
57 0 : break;
58 :
59 : #ifdef NGX_HTTP_VERSION_20
60 0 : case NGX_HTTP_VERSION_20:
61 0 : lua_pushnumber(L, 2.0);
62 0 : break;
63 : #endif
64 :
65 0 : default:
66 0 : lua_pushnil(L);
67 0 : break;
68 : }
69 :
70 0 : return 1;
71 : }
72 :
73 :
74 : static int
75 0 : ngx_http_lua_ngx_req_raw_header(lua_State *L)
76 : {
77 : int n, line_break_len;
78 : u_char *data, *p, *last, *pos;
79 0 : unsigned no_req_line = 0, found;
80 : size_t size;
81 0 : ngx_buf_t *b, *first = NULL;
82 : ngx_int_t i, j;
83 : #if nginx_version >= 1011011
84 : ngx_buf_t **bb;
85 : ngx_chain_t *cl;
86 : ngx_http_lua_main_conf_t *lmcf;
87 : #endif
88 : ngx_connection_t *c;
89 : ngx_http_request_t *r, *mr;
90 : ngx_http_connection_t *hc;
91 :
92 0 : n = lua_gettop(L);
93 0 : if (n > 0) {
94 0 : no_req_line = lua_toboolean(L, 1);
95 : }
96 :
97 : dd("no req line: %d", (int) no_req_line);
98 :
99 0 : r = ngx_http_lua_get_req(L);
100 0 : if (r == NULL) {
101 0 : return luaL_error(L, "no request object found");
102 : }
103 :
104 : #if nginx_version >= 1011011
105 0 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
106 : #endif
107 :
108 0 : ngx_http_lua_check_fake_request(L, r);
109 :
110 0 : mr = r->main;
111 0 : hc = mr->http_connection;
112 0 : c = mr->connection;
113 :
114 : #if (NGX_HTTP_V2)
115 0 : if (mr->stream) {
116 0 : return luaL_error(L, "http v2 not supported yet");
117 : }
118 : #endif
119 :
120 : #if 1
121 : dd("hc->nbusy: %d", (int) hc->nbusy);
122 :
123 0 : if (hc->nbusy) {
124 : #if nginx_version >= 1011011
125 : dd("hc->busy: %p %p %p %p", hc->busy->buf->start, hc->busy->buf->pos,
126 : hc->busy->buf->last, hc->busy->buf->end);
127 : #else
128 : dd("hc->busy: %p %p %p %p", hc->busy[0]->start, hc->busy[0]->pos,
129 : hc->busy[0]->last, hc->busy[0]->end);
130 : #endif
131 : }
132 :
133 : dd("request line: %p %p", mr->request_line.data,
134 : mr->request_line.data + mr->request_line.len);
135 :
136 : dd("header in: %p %p %p %p", mr->header_in->start,
137 : mr->header_in->pos, mr->header_in->last,
138 : mr->header_in->end);
139 :
140 : dd("c->buffer: %p %p %p %p", c->buffer->start,
141 : c->buffer->pos, c->buffer->last,
142 : c->buffer->end);
143 : #endif
144 :
145 0 : size = 0;
146 0 : b = c->buffer;
147 :
148 0 : if (mr->request_line.data[mr->request_line.len] == CR) {
149 0 : line_break_len = 2;
150 :
151 : } else {
152 0 : line_break_len = 1;
153 : }
154 :
155 0 : if (mr->request_line.data >= b->start
156 0 : && mr->request_line.data + mr->request_line.len
157 0 : + line_break_len <= b->pos)
158 : {
159 0 : first = b;
160 0 : size += b->pos - mr->request_line.data;
161 : }
162 :
163 : dd("size: %d", (int) size);
164 :
165 0 : if (hc->nbusy) {
166 : #if nginx_version >= 1011011
167 0 : if (hc->nbusy > lmcf->busy_buf_ptr_count) {
168 0 : if (lmcf->busy_buf_ptrs) {
169 0 : ngx_free(lmcf->busy_buf_ptrs);
170 : }
171 :
172 0 : lmcf->busy_buf_ptrs = ngx_alloc(hc->nbusy * sizeof(ngx_buf_t *),
173 0 : r->connection->log);
174 :
175 0 : if (lmcf->busy_buf_ptrs == NULL) {
176 0 : return luaL_error(L, "no memory");
177 : }
178 :
179 0 : lmcf->busy_buf_ptr_count = hc->nbusy;
180 : }
181 :
182 0 : bb = lmcf->busy_buf_ptrs;
183 0 : for (cl = hc->busy; cl; cl = cl->next) {
184 0 : *bb++ = cl->buf;
185 : }
186 : #endif
187 0 : b = NULL;
188 :
189 : #if nginx_version >= 1011011
190 0 : bb = lmcf->busy_buf_ptrs;
191 0 : for (i = hc->nbusy; i > 0; i--) {
192 0 : b = bb[i - 1];
193 : #else
194 : for (i = 0; i < hc->nbusy; i++) {
195 : b = hc->busy[i];
196 : #endif
197 :
198 : dd("busy buf: %d: [%.*s]", (int) i, (int) (b->pos - b->start),
199 : b->start);
200 :
201 0 : if (first == NULL) {
202 0 : if (mr->request_line.data >= b->pos
203 0 : || mr->request_line.data
204 0 : + mr->request_line.len + line_break_len
205 0 : <= b->start)
206 : {
207 0 : continue;
208 : }
209 :
210 : dd("found first at %d", (int) i);
211 0 : first = b;
212 : }
213 :
214 : dd("adding size %d", (int) (b->pos - b->start));
215 0 : size += b->pos - b->start;
216 : }
217 : }
218 :
219 0 : size++; /* plus the null terminator, as required by the later
220 : ngx_strstr() call */
221 :
222 : dd("header size: %d", (int) size);
223 :
224 0 : data = lua_newuserdata(L, size);
225 0 : last = data;
226 :
227 0 : b = c->buffer;
228 0 : found = 0;
229 :
230 0 : if (first == b) {
231 0 : found = 1;
232 0 : pos = b->pos;
233 :
234 0 : if (no_req_line) {
235 0 : last = ngx_copy(data,
236 : mr->request_line.data
237 : + mr->request_line.len + line_break_len,
238 : pos - mr->request_line.data
239 : - mr->request_line.len - line_break_len);
240 :
241 : } else {
242 0 : last = ngx_copy(data, mr->request_line.data,
243 : pos - mr->request_line.data);
244 : }
245 :
246 0 : if (b != mr->header_in) {
247 : /* skip truncated header entries (if any) */
248 0 : while (last > data && last[-1] != LF) {
249 0 : last--;
250 : }
251 : }
252 :
253 0 : i = 0;
254 0 : for (p = data; p != last; p++) {
255 0 : if (*p == '\0') {
256 0 : i++;
257 0 : if (p + 1 != last && *(p + 1) == LF) {
258 0 : *p = CR;
259 :
260 0 : } else if (i % 2 == 1) {
261 0 : *p = ':';
262 :
263 : } else {
264 0 : *p = LF;
265 : }
266 : }
267 : }
268 : }
269 :
270 0 : if (hc->nbusy) {
271 :
272 : #if nginx_version >= 1011011
273 0 : bb = lmcf->busy_buf_ptrs;
274 0 : for (i = hc->nbusy - 1; i >= 0; i--) {
275 0 : b = bb[i];
276 : #else
277 : for (i = 0; i < hc->nbusy; i++) {
278 : b = hc->busy[i];
279 : #endif
280 :
281 0 : if (!found) {
282 0 : if (b != first) {
283 0 : continue;
284 : }
285 :
286 : dd("found first");
287 0 : found = 1;
288 : }
289 :
290 0 : p = last;
291 :
292 0 : pos = b->pos;
293 :
294 0 : if (b == first) {
295 : dd("request line: %.*s", (int) mr->request_line.len,
296 : mr->request_line.data);
297 :
298 0 : if (no_req_line) {
299 0 : last = ngx_copy(last,
300 : mr->request_line.data
301 : + mr->request_line.len + line_break_len,
302 : pos - mr->request_line.data
303 : - mr->request_line.len - line_break_len);
304 :
305 : } else {
306 0 : last = ngx_copy(last,
307 : mr->request_line.data,
308 : pos - mr->request_line.data);
309 :
310 : }
311 :
312 : } else {
313 0 : last = ngx_copy(last, b->start, pos - b->start);
314 : }
315 :
316 : #if 1
317 : /* skip truncated header entries (if any) */
318 0 : while (last > p && last[-1] != LF) {
319 0 : last--;
320 : }
321 : #endif
322 :
323 0 : j = 0;
324 0 : for (; p != last; p++) {
325 0 : if (*p == '\0') {
326 0 : j++;
327 0 : if (p + 1 == last) {
328 : /* XXX this should not happen */
329 : dd("found string end!!");
330 :
331 0 : } else if (*(p + 1) == LF) {
332 0 : *p = CR;
333 :
334 0 : } else if (j % 2 == 1) {
335 0 : *p = ':';
336 :
337 : } else {
338 0 : *p = LF;
339 : }
340 : }
341 : }
342 :
343 0 : if (b == mr->header_in) {
344 0 : break;
345 : }
346 : }
347 : }
348 :
349 0 : *last++ = '\0';
350 :
351 0 : if (last - data > (ssize_t) size) {
352 0 : return luaL_error(L, "buffer error: %d", (int) (last - data - size));
353 : }
354 :
355 : /* strip the leading part (if any) of the request body in our header.
356 : * the first part of the request body could slip in because nginx core's
357 : * ngx_http_request_body_length_filter and etc can move r->header_in->pos
358 : * in case that some of the body data has been preread into r->header_in.
359 : */
360 :
361 0 : if ((p = (u_char *) ngx_strstr(data, CRLF CRLF)) != NULL) {
362 0 : last = p + sizeof(CRLF CRLF) - 1;
363 :
364 0 : } else if ((p = (u_char *) ngx_strstr(data, CRLF "\n")) != NULL) {
365 0 : last = p + sizeof(CRLF "\n") - 1;
366 :
367 0 : } else if ((p = (u_char *) ngx_strstr(data, "\n" CRLF)) != NULL) {
368 0 : last = p + sizeof("\n" CRLF) - 1;
369 :
370 : } else {
371 0 : for (p = last - 1; p - data >= 2; p--) {
372 0 : if (p[0] == LF && p[-1] == CR) {
373 0 : p[-1] = LF;
374 0 : last = p + 1;
375 0 : break;
376 : }
377 :
378 0 : if (p[0] == LF && p[-1] == LF) {
379 0 : last = p + 1;
380 0 : break;
381 : }
382 : }
383 : }
384 :
385 0 : lua_pushlstring(L, (char *) data, last - data);
386 0 : return 1;
387 : }
388 :
389 :
390 : static int
391 0 : ngx_http_lua_ngx_req_get_headers(lua_State *L)
392 : {
393 : ngx_list_part_t *part;
394 : ngx_table_elt_t *header;
395 : ngx_http_request_t *r;
396 : ngx_uint_t i;
397 : int n;
398 : int max;
399 0 : int raw = 0;
400 0 : int count = 0;
401 :
402 0 : n = lua_gettop(L);
403 :
404 0 : if (n >= 1) {
405 0 : if (lua_isnil(L, 1)) {
406 0 : max = NGX_HTTP_LUA_MAX_HEADERS;
407 :
408 : } else {
409 0 : max = luaL_checkinteger(L, 1);
410 : }
411 :
412 0 : if (n >= 2) {
413 0 : raw = lua_toboolean(L, 2);
414 : }
415 :
416 : } else {
417 0 : max = NGX_HTTP_LUA_MAX_HEADERS;
418 : }
419 :
420 0 : r = ngx_http_lua_get_req(L);
421 0 : if (r == NULL) {
422 0 : return luaL_error(L, "no request object found");
423 : }
424 :
425 0 : ngx_http_lua_check_fake_request(L, r);
426 :
427 0 : part = &r->headers_in.headers.part;
428 0 : count = part->nelts;
429 0 : while (part->next) {
430 0 : part = part->next;
431 0 : count += part->nelts;
432 : }
433 :
434 0 : if (max > 0 && count > max) {
435 0 : count = max;
436 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
437 : "lua exceeding request header limit %d", max);
438 : }
439 :
440 0 : lua_createtable(L, 0, count);
441 :
442 0 : if (!raw) {
443 0 : lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key);
444 0 : lua_rawget(L, LUA_REGISTRYINDEX);
445 0 : lua_setmetatable(L, -2);
446 : }
447 :
448 0 : part = &r->headers_in.headers.part;
449 0 : header = part->elts;
450 :
451 0 : for (i = 0; /* void */; i++) {
452 :
453 : dd("stack top: %d", lua_gettop(L));
454 :
455 0 : if (i >= part->nelts) {
456 0 : if (part->next == NULL) {
457 0 : break;
458 : }
459 :
460 0 : part = part->next;
461 0 : header = part->elts;
462 0 : i = 0;
463 : }
464 :
465 0 : if (raw) {
466 0 : lua_pushlstring(L, (char *) header[i].key.data, header[i].key.len);
467 :
468 : } else {
469 0 : lua_pushlstring(L, (char *) header[i].lowcase_key,
470 0 : header[i].key.len);
471 : }
472 :
473 : /* stack: table key */
474 :
475 0 : lua_pushlstring(L, (char *) header[i].value.data,
476 0 : header[i].value.len); /* stack: table key value */
477 :
478 0 : ngx_http_lua_set_multi_value_table(L, -3);
479 :
480 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
481 : "lua request header: \"%V: %V\"",
482 : &header[i].key, &header[i].value);
483 :
484 0 : if (--count == 0) {
485 0 : return 1;
486 : }
487 : }
488 :
489 0 : return 1;
490 : }
491 :
492 :
493 : static int
494 0 : ngx_http_lua_ngx_resp_get_headers(lua_State *L)
495 : {
496 : ngx_list_part_t *part;
497 : ngx_table_elt_t *header;
498 : ngx_http_request_t *r;
499 : ngx_http_lua_ctx_t *ctx;
500 : ngx_int_t rc;
501 0 : u_char *lowcase_key = NULL;
502 0 : size_t lowcase_key_sz = 0;
503 : ngx_uint_t i;
504 : int n;
505 : int max;
506 0 : int raw = 0;
507 0 : int count = 0;
508 :
509 0 : n = lua_gettop(L);
510 :
511 0 : if (n >= 1) {
512 0 : if (lua_isnil(L, 1)) {
513 0 : max = NGX_HTTP_LUA_MAX_HEADERS;
514 :
515 : } else {
516 0 : max = luaL_checkinteger(L, 1);
517 : }
518 :
519 0 : if (n >= 2) {
520 0 : raw = lua_toboolean(L, 2);
521 : }
522 :
523 : } else {
524 0 : max = NGX_HTTP_LUA_MAX_HEADERS;
525 : }
526 :
527 0 : r = ngx_http_lua_get_req(L);
528 0 : if (r == NULL) {
529 0 : return luaL_error(L, "no request object found");
530 : }
531 :
532 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
533 0 : if (ctx == NULL) {
534 0 : return luaL_error(L, "no ctx found");
535 : }
536 :
537 0 : if (!ctx->headers_set) {
538 0 : rc = ngx_http_lua_set_content_type(r);
539 0 : if (rc != NGX_OK) {
540 0 : return luaL_error(L,
541 : "failed to set default content type: %d",
542 : (int) rc);
543 : }
544 :
545 0 : ctx->headers_set = 1;
546 : }
547 :
548 0 : ngx_http_lua_check_fake_request(L, r);
549 :
550 0 : part = &r->headers_out.headers.part;
551 0 : count = part->nelts;
552 0 : while (part->next) {
553 0 : part = part->next;
554 0 : count += part->nelts;
555 : }
556 :
557 0 : if (max > 0 && count > max) {
558 0 : count = max;
559 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
560 : "lua exceeding request header limit %d", max);
561 : }
562 :
563 0 : lua_createtable(L, 0, count);
564 :
565 0 : if (!raw) {
566 0 : lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key);
567 0 : lua_rawget(L, LUA_REGISTRYINDEX);
568 0 : lua_setmetatable(L, -2);
569 : }
570 :
571 : #if 1
572 0 : if (r->headers_out.content_type.len) {
573 0 : lua_pushliteral(L, "content-type");
574 0 : lua_pushlstring(L, (char *) r->headers_out.content_type.data,
575 : r->headers_out.content_type.len);
576 0 : lua_rawset(L, -3);
577 : }
578 :
579 0 : if (r->headers_out.content_length == NULL
580 0 : && r->headers_out.content_length_n >= 0)
581 : {
582 0 : lua_pushliteral(L, "content-length");
583 0 : lua_pushfstring(L, "%d", (int) r->headers_out.content_length_n);
584 0 : lua_rawset(L, -3);
585 : }
586 :
587 0 : lua_pushliteral(L, "connection");
588 0 : if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
589 0 : lua_pushliteral(L, "upgrade");
590 :
591 0 : } else if (r->keepalive) {
592 0 : lua_pushliteral(L, "keep-alive");
593 :
594 : } else {
595 0 : lua_pushliteral(L, "close");
596 : }
597 0 : lua_rawset(L, -3);
598 :
599 0 : if (r->chunked) {
600 0 : lua_pushliteral(L, "transfer-encoding");
601 0 : lua_pushliteral(L, "chunked");
602 0 : lua_rawset(L, -3);
603 : }
604 : #endif
605 :
606 0 : part = &r->headers_out.headers.part;
607 0 : header = part->elts;
608 :
609 0 : for (i = 0; /* void */; i++) {
610 :
611 : dd("stack top: %d", lua_gettop(L));
612 :
613 0 : if (i >= part->nelts) {
614 0 : if (part->next == NULL) {
615 0 : break;
616 : }
617 :
618 0 : part = part->next;
619 0 : header = part->elts;
620 0 : i = 0;
621 : }
622 :
623 0 : if (header[i].hash == 0) {
624 0 : continue;
625 : }
626 :
627 0 : if (raw) {
628 0 : lua_pushlstring(L, (char *) header[i].key.data, header[i].key.len);
629 :
630 : } else {
631 : /* nginx does not even bother initializing output header entry's
632 : * "lowcase_key" field. so we cannot count on that at all. */
633 0 : if (header[i].key.len > lowcase_key_sz) {
634 0 : lowcase_key_sz = header[i].key.len * 2;
635 :
636 : /* we allocate via Lua's GC to prevent in-request
637 : * leaks in the nginx request memory pools */
638 0 : lowcase_key = lua_newuserdata(L, lowcase_key_sz);
639 0 : lua_insert(L, 1);
640 : }
641 :
642 0 : ngx_strlow(lowcase_key, header[i].key.data, header[i].key.len);
643 0 : lua_pushlstring(L, (char *) lowcase_key, header[i].key.len);
644 : }
645 :
646 : /* stack: [udata] table key */
647 :
648 0 : lua_pushlstring(L, (char *) header[i].value.data,
649 0 : header[i].value.len); /* stack: [udata] table key
650 : value */
651 :
652 0 : ngx_http_lua_set_multi_value_table(L, -3);
653 :
654 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
655 : "lua response header: \"%V: %V\"",
656 : &header[i].key, &header[i].value);
657 :
658 0 : if (--count == 0) {
659 0 : return 1;
660 : }
661 : }
662 :
663 0 : return 1;
664 : }
665 :
666 :
667 : static int
668 0 : ngx_http_lua_ngx_header_get(lua_State *L)
669 : {
670 : ngx_http_request_t *r;
671 : u_char *p, c;
672 : ngx_str_t key;
673 : ngx_uint_t i;
674 : size_t len;
675 : ngx_http_lua_loc_conf_t *llcf;
676 : ngx_http_lua_ctx_t *ctx;
677 : ngx_int_t rc;
678 :
679 0 : r = ngx_http_lua_get_req(L);
680 0 : if (r == NULL) {
681 0 : return luaL_error(L, "no request object found");
682 : }
683 :
684 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
685 0 : if (ctx == NULL) {
686 0 : return luaL_error(L, "no ctx found");
687 : }
688 :
689 0 : ngx_http_lua_check_fake_request(L, r);
690 :
691 : /* we skip the first argument that is the table */
692 0 : p = (u_char *) luaL_checklstring(L, 2, &len);
693 :
694 : dd("key: %.*s, len %d", (int) len, p, (int) len);
695 :
696 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
697 0 : if (llcf->transform_underscores_in_resp_headers
698 0 : && memchr(p, '_', len) != NULL)
699 : {
700 0 : key.data = (u_char *) lua_newuserdata(L, len);
701 0 : if (key.data == NULL) {
702 0 : return luaL_error(L, "no memory");
703 : }
704 :
705 : /* replace "_" with "-" */
706 0 : for (i = 0; i < len; i++) {
707 0 : c = p[i];
708 0 : if (c == '_') {
709 0 : c = '-';
710 : }
711 0 : key.data[i] = c;
712 : }
713 :
714 : } else {
715 0 : key.data = p;
716 : }
717 :
718 0 : key.len = len;
719 :
720 0 : if (!ctx->headers_set) {
721 0 : rc = ngx_http_lua_set_content_type(r);
722 0 : if (rc != NGX_OK) {
723 0 : return luaL_error(L,
724 : "failed to set default content type: %d",
725 : (int) rc);
726 : }
727 :
728 0 : ctx->headers_set = 1;
729 : }
730 :
731 0 : return ngx_http_lua_get_output_header(L, r, &key);
732 : }
733 :
734 :
735 : static int
736 0 : ngx_http_lua_ngx_header_set(lua_State *L)
737 : {
738 : ngx_http_request_t *r;
739 : u_char *p;
740 : ngx_str_t key;
741 : ngx_str_t value;
742 : ngx_uint_t i;
743 : size_t len;
744 : ngx_http_lua_ctx_t *ctx;
745 : ngx_int_t rc;
746 : ngx_uint_t n;
747 : ngx_http_lua_loc_conf_t *llcf;
748 :
749 0 : r = ngx_http_lua_get_req(L);
750 0 : if (r == NULL) {
751 0 : return luaL_error(L, "no request object found");
752 : }
753 :
754 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
755 0 : if (ctx == NULL) {
756 0 : return luaL_error(L, "no ctx");
757 : }
758 :
759 0 : ngx_http_lua_check_fake_request(L, r);
760 :
761 0 : if (r->header_sent || ctx->header_sent) {
762 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to "
763 : "set ngx.header.HEADER after sending out "
764 : "response headers");
765 0 : return 0;
766 : }
767 :
768 : /* we skip the first argument that is the table */
769 0 : p = (u_char *) luaL_checklstring(L, 2, &len);
770 :
771 : dd("key: %.*s, len %d", (int) len, p, (int) len);
772 :
773 0 : key.data = ngx_palloc(r->pool, len + 1);
774 0 : if (key.data == NULL) {
775 0 : return luaL_error(L, "no memory");
776 : }
777 :
778 0 : ngx_memcpy(key.data, p, len);
779 0 : key.data[len] = '\0';
780 0 : key.len = len;
781 :
782 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
783 :
784 0 : if (llcf->transform_underscores_in_resp_headers) {
785 : /* replace "_" with "-" */
786 0 : p = key.data;
787 0 : for (i = 0; i < len; i++) {
788 0 : if (p[i] == '_') {
789 0 : p[i] = '-';
790 : }
791 : }
792 : }
793 :
794 0 : if (!ctx->headers_set) {
795 0 : rc = ngx_http_lua_set_content_type(r);
796 0 : if (rc != NGX_OK) {
797 0 : return luaL_error(L,
798 : "failed to set default content type: %d",
799 : (int) rc);
800 : }
801 :
802 0 : ctx->headers_set = 1;
803 : }
804 :
805 0 : if (lua_type(L, 3) == LUA_TNIL) {
806 0 : ngx_str_null(&value);
807 :
808 0 : } else if (lua_type(L, 3) == LUA_TTABLE) {
809 0 : n = lua_objlen(L, 3);
810 0 : if (n == 0) {
811 0 : ngx_str_null(&value);
812 :
813 : } else {
814 0 : for (i = 1; i <= n; i++) {
815 : dd("header value table index %d", (int) i);
816 :
817 0 : lua_rawgeti(L, 3, i);
818 0 : p = (u_char *) luaL_checklstring(L, -1, &len);
819 :
820 0 : value.data = ngx_palloc(r->pool, len);
821 0 : if (value.data == NULL) {
822 0 : return luaL_error(L, "no memory");
823 : }
824 :
825 0 : ngx_memcpy(value.data, p, len);
826 0 : value.len = len;
827 :
828 0 : rc = ngx_http_lua_set_output_header(r, key, value,
829 : i == 1 /* override */);
830 :
831 0 : if (rc == NGX_ERROR) {
832 0 : return luaL_error(L,
833 : "failed to set header %s (error: %d)",
834 : key.data, (int) rc);
835 : }
836 : }
837 :
838 0 : return 0;
839 : }
840 :
841 : } else {
842 0 : p = (u_char *) luaL_checklstring(L, 3, &len);
843 0 : value.data = ngx_palloc(r->pool, len);
844 0 : if (value.data == NULL) {
845 0 : return luaL_error(L, "no memory");
846 : }
847 :
848 0 : ngx_memcpy(value.data, p, len);
849 0 : value.len = len;
850 : }
851 :
852 : dd("key: %.*s, value: %.*s",
853 : (int) key.len, key.data, (int) value.len, value.data);
854 :
855 0 : rc = ngx_http_lua_set_output_header(r, key, value, 1 /* override */);
856 :
857 0 : if (rc == NGX_ERROR) {
858 0 : return luaL_error(L, "failed to set header %s (error: %d)",
859 : key.data, (int) rc);
860 : }
861 :
862 0 : return 0;
863 : }
864 :
865 :
866 : static int
867 0 : ngx_http_lua_ngx_req_header_clear(lua_State *L)
868 : {
869 0 : if (lua_gettop(L) != 1) {
870 0 : return luaL_error(L, "expecting one arguments, but seen %d",
871 : lua_gettop(L));
872 : }
873 :
874 0 : lua_pushnil(L);
875 :
876 0 : return ngx_http_lua_ngx_req_header_set_helper(L);
877 : }
878 :
879 :
880 : static int
881 0 : ngx_http_lua_ngx_req_header_set(lua_State *L)
882 : {
883 0 : if (lua_gettop(L) != 2) {
884 0 : return luaL_error(L, "expecting two arguments, but seen %d",
885 : lua_gettop(L));
886 : }
887 :
888 0 : return ngx_http_lua_ngx_req_header_set_helper(L);
889 : }
890 :
891 :
892 : static int
893 0 : ngx_http_lua_ngx_req_header_set_helper(lua_State *L)
894 : {
895 : ngx_http_request_t *r;
896 : u_char *p;
897 : ngx_str_t key;
898 : ngx_str_t value;
899 : ngx_uint_t i;
900 : size_t len;
901 : ngx_int_t rc;
902 : ngx_uint_t n;
903 :
904 0 : r = ngx_http_lua_get_req(L);
905 0 : if (r == NULL) {
906 0 : return luaL_error(L, "no request object found");
907 : }
908 :
909 0 : ngx_http_lua_check_fake_request(L, r);
910 :
911 0 : if (r->http_version < NGX_HTTP_VERSION_10) {
912 0 : return 0;
913 : }
914 :
915 0 : p = (u_char *) luaL_checklstring(L, 1, &len);
916 :
917 : dd("key: %.*s, len %d", (int) len, p, (int) len);
918 :
919 : #if 0
920 : /* replace "_" with "-" */
921 : for (i = 0; i < len; i++) {
922 : if (p[i] == '_') {
923 : p[i] = '-';
924 : }
925 : }
926 : #endif
927 :
928 0 : key.data = ngx_palloc(r->pool, len + 1);
929 0 : if (key.data == NULL) {
930 0 : return luaL_error(L, "no memory");
931 : }
932 :
933 0 : ngx_memcpy(key.data, p, len);
934 :
935 0 : key.data[len] = '\0';
936 :
937 0 : key.len = len;
938 :
939 0 : if (lua_type(L, 2) == LUA_TNIL) {
940 0 : ngx_str_null(&value);
941 :
942 0 : } else if (lua_type(L, 2) == LUA_TTABLE) {
943 0 : n = lua_objlen(L, 2);
944 0 : if (n == 0) {
945 0 : ngx_str_null(&value);
946 :
947 : } else {
948 0 : for (i = 1; i <= n; i++) {
949 : dd("header value table index %d, top: %d", (int) i,
950 : lua_gettop(L));
951 :
952 0 : lua_rawgeti(L, 2, i);
953 0 : p = (u_char *) luaL_checklstring(L, -1, &len);
954 :
955 : /*
956 : * we also copy the trailling '\0' char here because nginx
957 : * header values must be null-terminated
958 : * */
959 :
960 0 : value.data = ngx_palloc(r->pool, len + 1);
961 0 : if (value.data == NULL) {
962 0 : return luaL_error(L, "no memory");
963 : }
964 :
965 0 : ngx_memcpy(value.data, p, len + 1);
966 0 : value.len = len;
967 :
968 0 : rc = ngx_http_lua_set_input_header(r, key, value,
969 : i == 1 /* override */);
970 :
971 0 : if (rc == NGX_ERROR) {
972 0 : return luaL_error(L,
973 : "failed to set header %s (error: %d)",
974 : key.data, (int) rc);
975 : }
976 : }
977 :
978 0 : return 0;
979 : }
980 :
981 : } else {
982 :
983 : /*
984 : * we also copy the trailling '\0' char here because nginx
985 : * header values must be null-terminated
986 : * */
987 :
988 0 : p = (u_char *) luaL_checklstring(L, 2, &len);
989 0 : value.data = ngx_palloc(r->pool, len + 1);
990 0 : if (value.data == NULL) {
991 0 : return luaL_error(L, "no memory");
992 : }
993 :
994 0 : ngx_memcpy(value.data, p, len + 1);
995 0 : value.len = len;
996 : }
997 :
998 : dd("key: %.*s, value: %.*s",
999 : (int) key.len, key.data, (int) value.len, value.data);
1000 :
1001 0 : rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */);
1002 :
1003 0 : if (rc == NGX_ERROR) {
1004 0 : return luaL_error(L, "failed to set header %s (error: %d)",
1005 : key.data, (int) rc);
1006 : }
1007 :
1008 0 : return 0;
1009 : }
1010 :
1011 :
1012 : void
1013 18 : ngx_http_lua_inject_resp_header_api(lua_State *L)
1014 : {
1015 18 : lua_newtable(L); /* .header */
1016 :
1017 18 : lua_createtable(L, 0, 2); /* metatable for .header */
1018 18 : lua_pushcfunction(L, ngx_http_lua_ngx_header_get);
1019 18 : lua_setfield(L, -2, "__index");
1020 18 : lua_pushcfunction(L, ngx_http_lua_ngx_header_set);
1021 18 : lua_setfield(L, -2, "__newindex");
1022 18 : lua_setmetatable(L, -2);
1023 :
1024 18 : lua_setfield(L, -2, "header");
1025 :
1026 18 : lua_createtable(L, 0, 1); /* .resp */
1027 :
1028 18 : lua_pushcfunction(L, ngx_http_lua_ngx_resp_get_headers);
1029 18 : lua_setfield(L, -2, "get_headers");
1030 :
1031 18 : lua_setfield(L, -2, "resp");
1032 18 : }
1033 :
1034 :
1035 : void
1036 18 : ngx_http_lua_inject_req_header_api(lua_State *L)
1037 : {
1038 18 : lua_pushcfunction(L, ngx_http_lua_ngx_req_http_version);
1039 18 : lua_setfield(L, -2, "http_version");
1040 :
1041 18 : lua_pushcfunction(L, ngx_http_lua_ngx_req_raw_header);
1042 18 : lua_setfield(L, -2, "raw_header");
1043 :
1044 18 : lua_pushcfunction(L, ngx_http_lua_ngx_req_header_clear);
1045 18 : lua_setfield(L, -2, "clear_header");
1046 :
1047 18 : lua_pushcfunction(L, ngx_http_lua_ngx_req_header_set);
1048 18 : lua_setfield(L, -2, "set_header");
1049 :
1050 18 : lua_pushcfunction(L, ngx_http_lua_ngx_req_get_headers);
1051 18 : lua_setfield(L, -2, "get_headers");
1052 18 : }
1053 :
1054 :
1055 : void
1056 18 : ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L)
1057 : {
1058 : int rc;
1059 18 : const char buf[] =
1060 : "local tb, key = ...\n"
1061 : "local new_key = string.gsub(string.lower(key), '_', '-')\n"
1062 : "if new_key ~= key then return tb[new_key] else return nil end";
1063 :
1064 18 : lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key);
1065 :
1066 : /* metatable for ngx.req.get_headers(_, true) and
1067 : * ngx.resp.get_headers(_, true) */
1068 18 : lua_createtable(L, 0, 1);
1069 :
1070 18 : rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=headers metatable");
1071 18 : if (rc != 0) {
1072 0 : ngx_log_error(NGX_LOG_ERR, log, 0,
1073 : "failed to load Lua code for the metamethod for "
1074 : "headers: %i: %s", rc, lua_tostring(L, -1));
1075 :
1076 0 : lua_pop(L, 3);
1077 0 : return;
1078 : }
1079 :
1080 18 : lua_setfield(L, -2, "__index");
1081 18 : lua_rawset(L, LUA_REGISTRYINDEX);
1082 : }
1083 :
1084 :
1085 : #ifndef NGX_LUA_NO_FFI_API
1086 : int
1087 0 : ngx_http_lua_ffi_req_get_headers_count(ngx_http_request_t *r, int max)
1088 : {
1089 : int count;
1090 : ngx_list_part_t *part;
1091 :
1092 0 : if (r->connection->fd == (ngx_socket_t) -1) {
1093 0 : return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
1094 : }
1095 :
1096 0 : if (max < 0) {
1097 0 : max = NGX_HTTP_LUA_MAX_HEADERS;
1098 : }
1099 :
1100 0 : part = &r->headers_in.headers.part;
1101 0 : count = part->nelts;
1102 0 : while (part->next) {
1103 0 : part = part->next;
1104 0 : count += part->nelts;
1105 : }
1106 :
1107 0 : if (max > 0 && count > max) {
1108 0 : count = max;
1109 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1110 : "lua exceeding request header limit %d", max);
1111 : }
1112 :
1113 0 : return count;
1114 : }
1115 :
1116 :
1117 : int
1118 0 : ngx_http_lua_ffi_req_get_headers(ngx_http_request_t *r,
1119 : ngx_http_lua_ffi_table_elt_t *out, int count, int raw)
1120 : {
1121 : int n;
1122 : ngx_uint_t i;
1123 : ngx_list_part_t *part;
1124 : ngx_table_elt_t *header;
1125 :
1126 0 : if (count <= 0) {
1127 0 : return NGX_OK;
1128 : }
1129 :
1130 0 : n = 0;
1131 0 : part = &r->headers_in.headers.part;
1132 0 : header = part->elts;
1133 :
1134 0 : for (i = 0; /* void */; i++) {
1135 :
1136 0 : if (i >= part->nelts) {
1137 0 : if (part->next == NULL) {
1138 0 : break;
1139 : }
1140 :
1141 0 : part = part->next;
1142 0 : header = part->elts;
1143 0 : i = 0;
1144 : }
1145 :
1146 0 : if (raw) {
1147 0 : out[n].key.data = header[i].key.data;
1148 0 : out[n].key.len = (int) header[i].key.len;
1149 :
1150 : } else {
1151 0 : out[n].key.data = header[i].lowcase_key;
1152 0 : out[n].key.len = (int) header[i].key.len;
1153 : }
1154 :
1155 0 : out[n].value.data = header[i].value.data;
1156 0 : out[n].value.len = (int) header[i].value.len;
1157 :
1158 0 : if (++n == count) {
1159 0 : return NGX_OK;
1160 : }
1161 : }
1162 :
1163 0 : return NGX_OK;
1164 : }
1165 :
1166 :
1167 : int
1168 0 : ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data,
1169 : size_t key_len, int is_nil, const u_char *sval, size_t sval_len,
1170 : ngx_http_lua_ffi_str_t *mvals, size_t mvals_len, char **errmsg)
1171 : {
1172 : u_char *p;
1173 : ngx_str_t value, key;
1174 : ngx_uint_t i;
1175 : size_t len;
1176 : ngx_http_lua_ctx_t *ctx;
1177 : ngx_int_t rc;
1178 : ngx_http_lua_loc_conf_t *llcf;
1179 :
1180 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
1181 0 : if (ctx == NULL) {
1182 0 : return NGX_HTTP_LUA_FFI_NO_REQ_CTX;
1183 : }
1184 :
1185 0 : if (r->connection->fd == (ngx_socket_t) -1) {
1186 0 : return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
1187 : }
1188 :
1189 0 : if (r->header_sent || ctx->header_sent) {
1190 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to "
1191 : "set ngx.header.HEADER after sending out "
1192 : "response headers");
1193 0 : return NGX_DECLINED;
1194 : }
1195 :
1196 0 : key.data = ngx_palloc(r->pool, key_len + 1);
1197 0 : if (key.data == NULL) {
1198 0 : goto nomem;
1199 : }
1200 :
1201 0 : ngx_memcpy(key.data, key_data, key_len);
1202 0 : key.data[key_len] = '\0';
1203 0 : key.len = key_len;
1204 :
1205 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
1206 :
1207 0 : if (llcf->transform_underscores_in_resp_headers) {
1208 : /* replace "_" with "-" */
1209 0 : p = key.data;
1210 0 : for (i = 0; i < key_len; i++) {
1211 0 : if (p[i] == '_') {
1212 0 : p[i] = '-';
1213 : }
1214 : }
1215 : }
1216 :
1217 0 : if (!ctx->headers_set) {
1218 0 : rc = ngx_http_lua_set_content_type(r);
1219 0 : if (rc != NGX_OK) {
1220 0 : *errmsg = "failed to set default content type";
1221 0 : return NGX_ERROR;
1222 : }
1223 :
1224 0 : ctx->headers_set = 1;
1225 : }
1226 :
1227 0 : if (is_nil) {
1228 0 : value.data = NULL;
1229 0 : value.len = 0;
1230 :
1231 0 : } else if (mvals) {
1232 :
1233 0 : if (mvals_len == 0) {
1234 0 : value.data = NULL;
1235 0 : value.len = 0;
1236 :
1237 : } else {
1238 0 : for (i = 0; i < mvals_len; i++) {
1239 : dd("header value table index %d", (int) i);
1240 :
1241 0 : p = mvals[i].data;
1242 0 : len = mvals[i].len;
1243 :
1244 0 : value.data = ngx_palloc(r->pool, len);
1245 0 : if (value.data == NULL) {
1246 0 : goto nomem;
1247 : }
1248 :
1249 0 : ngx_memcpy(value.data, p, len);
1250 0 : value.len = len;
1251 :
1252 0 : rc = ngx_http_lua_set_output_header(r, key, value,
1253 : i == 0 /* override */);
1254 :
1255 0 : if (rc == NGX_ERROR) {
1256 0 : *errmsg = "failed to set header";
1257 0 : return NGX_ERROR;
1258 : }
1259 : }
1260 :
1261 0 : return NGX_OK;
1262 : }
1263 :
1264 : } else {
1265 0 : p = (u_char *) sval;
1266 0 : value.data = ngx_palloc(r->pool, sval_len);
1267 0 : if (value.data == NULL) {
1268 0 : goto nomem;
1269 : }
1270 :
1271 0 : ngx_memcpy(value.data, p, sval_len);
1272 0 : value.len = sval_len;
1273 : }
1274 :
1275 : dd("key: %.*s, value: %.*s",
1276 : (int) key.len, key.data, (int) value.len, value.data);
1277 :
1278 0 : rc = ngx_http_lua_set_output_header(r, key, value, 1 /* override */);
1279 :
1280 0 : if (rc == NGX_ERROR) {
1281 0 : *errmsg = "failed to set header";
1282 0 : return NGX_ERROR;
1283 : }
1284 :
1285 0 : return 0;
1286 :
1287 0 : nomem:
1288 :
1289 0 : *errmsg = "no memory";
1290 0 : return NGX_ERROR;
1291 : }
1292 :
1293 :
1294 : int
1295 0 : ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r,
1296 : const u_char *key, size_t key_len, const u_char *value, size_t value_len)
1297 : {
1298 : ngx_str_t k;
1299 : ngx_str_t v;
1300 :
1301 0 : if (r->connection->fd == (ngx_socket_t) -1) { /* fake request */
1302 0 : return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
1303 : }
1304 :
1305 0 : if (r->http_version < NGX_HTTP_VERSION_10) {
1306 0 : return NGX_DECLINED;
1307 : }
1308 :
1309 0 : k.data = ngx_palloc(r->pool, key_len + 1);
1310 0 : if (k.data == NULL) {
1311 0 : return NGX_ERROR;
1312 : }
1313 0 : ngx_memcpy(k.data, key, key_len);
1314 0 : k.data[key_len] = '\0';
1315 :
1316 0 : k.len = key_len;
1317 :
1318 0 : if (value_len == 0) {
1319 0 : v.data = NULL;
1320 0 : v.len = 0;
1321 :
1322 : } else {
1323 0 : v.data = ngx_palloc(r->pool, value_len + 1);
1324 0 : if (v.data == NULL) {
1325 0 : return NGX_ERROR;
1326 : }
1327 0 : ngx_memcpy(v.data, value, value_len);
1328 0 : v.data[value_len] = '\0';
1329 : }
1330 :
1331 0 : v.len = value_len;
1332 :
1333 0 : if (ngx_http_lua_set_input_header(r, k, v, 1 /* override */)
1334 : != NGX_OK)
1335 : {
1336 0 : return NGX_ERROR;
1337 : }
1338 :
1339 0 : return NGX_OK;
1340 : }
1341 :
1342 :
1343 : int
1344 0 : ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r,
1345 : const u_char *key, size_t key_len,
1346 : u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues)
1347 : {
1348 : int found;
1349 : u_char c, *p;
1350 : ngx_uint_t i;
1351 : ngx_table_elt_t *h;
1352 : ngx_list_part_t *part;
1353 : ngx_http_lua_ctx_t *ctx;
1354 :
1355 : ngx_http_lua_loc_conf_t *llcf;
1356 :
1357 0 : if (r->connection->fd == (ngx_socket_t) -1) {
1358 0 : return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
1359 : }
1360 :
1361 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
1362 0 : if (ctx == NULL) {
1363 : /* *errmsg = "no ctx found"; */
1364 0 : return NGX_ERROR;
1365 : }
1366 :
1367 0 : if (!ctx->headers_set) {
1368 0 : if (ngx_http_lua_set_content_type(r) != NGX_OK) {
1369 : /* *errmsg = "failed to set default content type"; */
1370 0 : return NGX_ERROR;
1371 : }
1372 :
1373 0 : ctx->headers_set = 1;
1374 : }
1375 :
1376 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
1377 0 : if (llcf->transform_underscores_in_resp_headers
1378 0 : && memchr(key, '_', key_len) != NULL)
1379 : {
1380 0 : for (i = 0; i < key_len; i++) {
1381 0 : c = key[i];
1382 0 : if (c == '_') {
1383 0 : c = '-';
1384 : }
1385 :
1386 0 : key_buf[i] = c;
1387 : }
1388 :
1389 : } else {
1390 0 : key_buf = (u_char *) key;
1391 : }
1392 :
1393 0 : switch (key_len) {
1394 0 : case 14:
1395 0 : if (r->headers_out.content_length == NULL
1396 0 : && r->headers_out.content_length_n >= 0
1397 0 : && ngx_strncasecmp(key_buf, (u_char *) "Content-Length", 14) == 0)
1398 : {
1399 0 : p = ngx_palloc(r->pool, NGX_OFF_T_LEN);
1400 0 : if (p == NULL) {
1401 0 : return NGX_ERROR;
1402 : }
1403 :
1404 0 : values[0].data = p;
1405 0 : values[0].len = (int) (ngx_snprintf(p, NGX_OFF_T_LEN, "%O",
1406 : r->headers_out.content_length_n)
1407 0 : - p);
1408 0 : return 1;
1409 : }
1410 :
1411 0 : break;
1412 :
1413 0 : case 12:
1414 0 : if (r->headers_out.content_type.len
1415 0 : && ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0)
1416 : {
1417 0 : values[0].data = r->headers_out.content_type.data;
1418 0 : values[0].len = r->headers_out.content_type.len;
1419 0 : return 1;
1420 : }
1421 :
1422 0 : break;
1423 :
1424 0 : default:
1425 0 : break;
1426 : }
1427 :
1428 : dd("not a built-in output header");
1429 :
1430 : #if 1
1431 0 : if (r->headers_out.location
1432 0 : && r->headers_out.location->value.len
1433 0 : && r->headers_out.location->value.data[0] == '/')
1434 : {
1435 : /* XXX ngx_http_core_find_config_phase, for example,
1436 : * may not initialize the "key" and "hash" fields
1437 : * for a nasty optimization purpose, and
1438 : * we have to work-around it here */
1439 :
1440 0 : r->headers_out.location->hash = ngx_http_lua_location_hash;
1441 0 : ngx_str_set(&r->headers_out.location->key, "Location");
1442 : }
1443 : #endif
1444 :
1445 0 : found = 0;
1446 :
1447 0 : part = &r->headers_out.headers.part;
1448 0 : h = part->elts;
1449 :
1450 0 : for (i = 0; /* void */; i++) {
1451 :
1452 0 : if (i >= part->nelts) {
1453 0 : if (part->next == NULL) {
1454 0 : break;
1455 : }
1456 :
1457 0 : part = part->next;
1458 0 : h = part->elts;
1459 0 : i = 0;
1460 : }
1461 :
1462 0 : if (h[i].hash == 0) {
1463 0 : continue;
1464 : }
1465 :
1466 : dd("checking (%d) \"%.*s\"", (int) h[i].key.len, (int) h[i].key.len,
1467 : h[i].key.data);
1468 :
1469 0 : if (h[i].key.len == key_len
1470 0 : && ngx_strncasecmp(key_buf, h[i].key.data, key_len) == 0)
1471 : {
1472 0 : values[found].data = h[i].value.data;
1473 0 : values[found].len = (int) h[i].value.len;
1474 :
1475 0 : if (++found >= max_nvalues) {
1476 0 : break;
1477 : }
1478 : }
1479 : }
1480 :
1481 0 : return found;
1482 : }
1483 : #endif /* NGX_LUA_NO_FFI_API */
1484 :
1485 :
1486 : #if nginx_version >= 1011011
1487 : void
1488 19 : ngx_http_lua_ngx_raw_header_cleanup(void *data)
1489 : {
1490 : ngx_http_lua_main_conf_t *lmcf;
1491 :
1492 19 : lmcf = (ngx_http_lua_main_conf_t *) data;
1493 :
1494 19 : if (lmcf->busy_buf_ptrs) {
1495 0 : ngx_free(lmcf->busy_buf_ptrs);
1496 0 : lmcf->busy_buf_ptrs = NULL;
1497 : }
1498 19 : }
1499 : #endif
1500 :
1501 :
1502 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|