LCOV - code coverage report
Current view: top level - home/build/openresty-1.13.6.1/build/ngx_lua-0.10.11/src - ngx_http_lua_headers.c (source / functions) Hit Total Coverage
Test: coverage ngix Lines: 38 641 5.9 %
Date: 2020-03-03 04:25:50 Functions: 4 18 22.2 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.13