Skip to content

Commit

Permalink
bugfix: we now avoid generating a Content-Type header when getting/se…
Browse files Browse the repository at this point in the history
…tting other response headers.

Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
  • Loading branch information
spacewander authored and thibaultcha committed Dec 13, 2018
1 parent ab2e271 commit 017e004
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 70 deletions.
37 changes: 37 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -4147,6 +4147,25 @@ to be returned when reading `ngx.header.Foo`.

Note that `ngx.header` is not a normal Lua table and as such, it is not possible to iterate through it using the Lua `ipairs` function.

Note: if the current response does not have a Content-Type header, but you use
`ngx.header` to attempt retrieving it, a side effect will be that a
Content-Type header will be created and returned according to your nginx
configuration.

For example:

```nginx
location = /t {
default_type text/html;
content_by_lua_block {
-- even if the response had no Content-Type header,
-- it will now have: Content-Type: text/html
ngx.say(ngx.header['Content-Type'])
}
}
```

For reading *request* headers, use the [ngx.req.get_headers](#ngxreqget_headers) function instead.

[Back to TOC](#nginx-api-for-lua)
Expand All @@ -4172,6 +4191,24 @@ Returns a Lua table holding all the current response headers for the current req
end
```

Note: if the current response does not have a Content-Type header, but you use
`ngx.resp.get_headers` to attempt retrieving it, a side effect will
be that a Content-Type header will be created and returned according to your
nginx configuration.

For example:

```nginx
location = /t {
default_type text/html;
content_by_lua_block {
-- the Content-Type header will be text/html
ngx.say(ngx.resp.get_headers()['Content-Type'])
}
}
```

This function has the same signature as [ngx.req.get_headers](#ngxreqget_headers) except getting response headers instead of request headers.

Note that a maximum of 100 response headers are parsed by default (including those with the same name) and that additional response headers are silently discarded to guard against potential denial of service attacks. Since `v0.10.13`, when the limit is exceeded, it will return a second value which is the string `"truncated"`.
Expand Down
35 changes: 35 additions & 0 deletions doc/HttpLuaModule.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -3433,6 +3433,24 @@ to be returned when reading <code>ngx.header.Foo</code>.
Note that <code>ngx.header</code> is not a normal Lua table and as such, it is not possible to iterate through it using the Lua <code>ipairs</code> function.
Note: if the current response does not have a Content-Type header, but you use
<code>ngx.header</code> to attempt retrieving it, a side effect will be that a
Content-Type header will be created and returned according to your nginx
configuration.
For example:
<geshi lang="nginx">
location = /t {
default_type text/html;
content_by_lua_block {
-- even if the response had no Content-Type header,
-- it will now have: Content-Type: text/html
ngx.say(ngx.header['Content-Type'])
}
}
</geshi>
For reading ''request'' headers, use the [[#ngx.req.get_headers|ngx.req.get_headers]] function instead.
== ngx.resp.get_headers ==
Expand All @@ -3454,6 +3472,23 @@ for k, v in pairs(h) do
end
</geshi>
Note: if the current response does not have a Content-Type header, but you use
<code>ngx.resp.get_headers</code>, a side effect will be that a Content-Type
header will be created and returned according to your nginx configuration.
For example:
<geshi lang="nginx">
location = /t {
default_type text/html;
content_by_lua_block {
-- even if the response had no Content-Type header,
-- it will now have: Content-Type: text/html
ngx.say(ngx.resp.get_headers()['Content-Type'])
}
}
</geshi>
This function has the same signature as [[#ngx.req.get_headers|ngx.req.get_headers]] except getting response headers instead of request headers.
Note that a maximum of 100 response headers are parsed by default (including those with the same name) and that additional response headers are silently discarded to guard against potential denial of service attacks. Since <code>v0.10.13</code>, when the limit is exceeded, it will return a second value which is the string `"truncated"`.
Expand Down
93 changes: 33 additions & 60 deletions src/ngx_http_lua_headers.c
Original file line number Diff line number Diff line change
Expand Up @@ -544,17 +544,6 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L)
return luaL_error(L, "no ctx found");
}

if (!ctx->headers_set) {
rc = ngx_http_lua_set_content_type(r);
if (rc != NGX_OK) {
return luaL_error(L,
"failed to set default content type: %d",
(int) rc);
}

ctx->headers_set = 1;
}

ngx_http_lua_check_fake_request(L, r);

part = &r->headers_out.headers.part;
Expand All @@ -573,6 +562,17 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L)
lua_setmetatable(L, -2);
}

if (!r->headers_out.content_type.len) {
rc = ngx_http_lua_set_content_type(r);
if (rc != NGX_OK) {
return luaL_error(L,
"failed to set default content type: %d",
(int) rc);
}

ctx->headers_set = 1;
}

#if 1
if (r->headers_out.content_type.len) {
extra++;
Expand Down Expand Up @@ -696,7 +696,6 @@ ngx_http_lua_ngx_header_get(lua_State *L)
size_t len;
ngx_http_lua_loc_conf_t *llcf;
ngx_http_lua_ctx_t *ctx;
ngx_int_t rc;

r = ngx_http_lua_get_req(L);
if (r == NULL) {
Expand Down Expand Up @@ -739,18 +738,7 @@ ngx_http_lua_ngx_header_get(lua_State *L)

key.len = len;

if (!ctx->headers_set) {
rc = ngx_http_lua_set_content_type(r);
if (rc != NGX_OK) {
return luaL_error(L,
"failed to set default content type: %d",
(int) rc);
}

ctx->headers_set = 1;
}

return ngx_http_lua_get_output_header(L, r, &key);
return ngx_http_lua_get_output_header(L, r, ctx, &key);
}


Expand Down Expand Up @@ -813,16 +801,7 @@ ngx_http_lua_ngx_header_set(lua_State *L)
}
}

if (!ctx->headers_set) {
rc = ngx_http_lua_set_content_type(r);
if (rc != NGX_OK) {
return luaL_error(L,
"failed to set default content type: %d",
(int) rc);
}

ctx->headers_set = 1;
}
ctx->headers_set = 1;

if (lua_type(L, 3) == LUA_TNIL) {
ngx_str_null(&value);
Expand Down Expand Up @@ -1244,15 +1223,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data,
}
}

if (!ctx->headers_set) {
rc = ngx_http_lua_set_content_type(r);
if (rc != NGX_OK) {
*errmsg = "failed to set default content type";
return NGX_ERROR;
}

ctx->headers_set = 1;
}
ctx->headers_set = 1;

if (is_nil) {
value.data = NULL;
Expand Down Expand Up @@ -1373,7 +1344,8 @@ ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r,
int
ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r,
const u_char *key, size_t key_len,
u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues)
u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues,
char **errmsg)
{
int found;
u_char c, *p;
Expand All @@ -1390,19 +1362,10 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r,

ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
if (ctx == NULL) {
/* *errmsg = "no ctx found"; */
*errmsg = "no ctx found";
return NGX_ERROR;
}

if (!ctx->headers_set) {
if (ngx_http_lua_set_content_type(r) != NGX_OK) {
/* *errmsg = "failed to set default content type"; */
return NGX_ERROR;
}

ctx->headers_set = 1;
}

llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
if (llcf->transform_underscores_in_resp_headers
&& memchr(key, '_', key_len) != NULL)
Expand All @@ -1428,6 +1391,7 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r,
{
p = ngx_palloc(r->pool, NGX_OFF_T_LEN);
if (p == NULL) {
*errmsg = "no memory";
return NGX_ERROR;
}

Expand All @@ -1441,12 +1405,21 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r,
break;

case 12:
if (r->headers_out.content_type.len
&& ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0)
{
values[0].data = r->headers_out.content_type.data;
values[0].len = r->headers_out.content_type.len;
return 1;
if (ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0) {
if (!r->headers_out.content_type.len) {
if (ngx_http_lua_set_content_type(r) != NGX_OK) {
*errmsg = "failed to set default content type";
return NGX_ERROR;
}

ctx->headers_set = 1;
}

if (r->headers_out.content_type.len) {
values[0].data = r->headers_out.content_type.data;
values[0].len = r->headers_out.content_type.len;
return 1;
}
}

break;
Expand Down
26 changes: 19 additions & 7 deletions src/ngx_http_lua_headers_out.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,10 +528,11 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key,

int
ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r,
ngx_str_t *key)
ngx_http_lua_ctx_t *ctx, ngx_str_t *key)
{
ngx_table_elt_t *h;
ngx_list_part_t *part;
ngx_int_t rc;
ngx_uint_t i;
unsigned found;

Expand All @@ -550,12 +551,23 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r,
break;

case 12:
if (r->headers_out.content_type.len
&& ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0)
{
lua_pushlstring(L, (char *) r->headers_out.content_type.data,
r->headers_out.content_type.len);
return 1;
if (ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0) {
if (!r->headers_out.content_type.len) {
rc = ngx_http_lua_set_content_type(r);
if (rc != NGX_OK) {
return luaL_error(L,
"failed to set default content type: %d",
(int) rc);
}

ctx->headers_set = 1;
}

if (r->headers_out.content_type.len) {
lua_pushlstring(L, (char *) r->headers_out.content_type.data,
r->headers_out.content_type.len);
return 1;
}
}

break;
Expand Down
2 changes: 1 addition & 1 deletion src/ngx_http_lua_headers_out.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key,
ngx_str_t value, unsigned override);
int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r,
ngx_str_t *key);
ngx_http_lua_ctx_t *ctx, ngx_str_t *key);


#endif /* _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ */
Expand Down
8 changes: 8 additions & 0 deletions src/ngx_http_lua_subrequest.c
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,14 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc)
dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]);

/* copy subrequest response headers */
if (ctx->headers_set) {
rc = ngx_http_lua_set_content_type(r);
if (rc != NGX_OK) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"failed to set default content type: %i", rc);
return NGX_ERROR;
}
}

pr_coctx->sr_headers[ctx->index] = &r->headers_out;

Expand Down
Loading

0 comments on commit 017e004

Please sign in to comment.