Skip to content

Commit 017e004

Browse files
spacewanderthibaultcha
authored andcommitted
bugfix: we now avoid generating a Content-Type header when getting/setting other response headers.
Signed-off-by: Thibault Charbonnier <[email protected]>
1 parent ab2e271 commit 017e004

7 files changed

+197
-70
lines changed

README.markdown

+37
Original file line numberDiff line numberDiff line change
@@ -4147,6 +4147,25 @@ to be returned when reading `ngx.header.Foo`.
41474147

41484148
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.
41494149

4150+
Note: if the current response does not have a Content-Type header, but you use
4151+
`ngx.header` to attempt retrieving it, a side effect will be that a
4152+
Content-Type header will be created and returned according to your nginx
4153+
configuration.
4154+
4155+
For example:
4156+
4157+
```nginx
4158+
4159+
location = /t {
4160+
default_type text/html;
4161+
content_by_lua_block {
4162+
-- even if the response had no Content-Type header,
4163+
-- it will now have: Content-Type: text/html
4164+
ngx.say(ngx.header['Content-Type'])
4165+
}
4166+
}
4167+
```
4168+
41504169
For reading *request* headers, use the [ngx.req.get_headers](#ngxreqget_headers) function instead.
41514170

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

4194+
Note: if the current response does not have a Content-Type header, but you use
4195+
`ngx.resp.get_headers` to attempt retrieving it, a side effect will
4196+
be that a Content-Type header will be created and returned according to your
4197+
nginx configuration.
4198+
4199+
For example:
4200+
4201+
```nginx
4202+
4203+
location = /t {
4204+
default_type text/html;
4205+
content_by_lua_block {
4206+
-- the Content-Type header will be text/html
4207+
ngx.say(ngx.resp.get_headers()['Content-Type'])
4208+
}
4209+
}
4210+
```
4211+
41754212
This function has the same signature as [ngx.req.get_headers](#ngxreqget_headers) except getting response headers instead of request headers.
41764213

41774214
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"`.

doc/HttpLuaModule.wiki

+35
Original file line numberDiff line numberDiff line change
@@ -3433,6 +3433,24 @@ to be returned when reading <code>ngx.header.Foo</code>.
34333433
34343434
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.
34353435
3436+
Note: if the current response does not have a Content-Type header, but you use
3437+
<code>ngx.header</code> to attempt retrieving it, a side effect will be that a
3438+
Content-Type header will be created and returned according to your nginx
3439+
configuration.
3440+
3441+
For example:
3442+
3443+
<geshi lang="nginx">
3444+
location = /t {
3445+
default_type text/html;
3446+
content_by_lua_block {
3447+
-- even if the response had no Content-Type header,
3448+
-- it will now have: Content-Type: text/html
3449+
ngx.say(ngx.header['Content-Type'])
3450+
}
3451+
}
3452+
</geshi>
3453+
34363454
For reading ''request'' headers, use the [[#ngx.req.get_headers|ngx.req.get_headers]] function instead.
34373455
34383456
== ngx.resp.get_headers ==
@@ -3454,6 +3472,23 @@ for k, v in pairs(h) do
34543472
end
34553473
</geshi>
34563474
3475+
Note: if the current response does not have a Content-Type header, but you use
3476+
<code>ngx.resp.get_headers</code>, a side effect will be that a Content-Type
3477+
header will be created and returned according to your nginx configuration.
3478+
3479+
For example:
3480+
3481+
<geshi lang="nginx">
3482+
location = /t {
3483+
default_type text/html;
3484+
content_by_lua_block {
3485+
-- even if the response had no Content-Type header,
3486+
-- it will now have: Content-Type: text/html
3487+
ngx.say(ngx.resp.get_headers()['Content-Type'])
3488+
}
3489+
}
3490+
</geshi>
3491+
34573492
This function has the same signature as [[#ngx.req.get_headers|ngx.req.get_headers]] except getting response headers instead of request headers.
34583493
34593494
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"`.

src/ngx_http_lua_headers.c

+33-60
Original file line numberDiff line numberDiff line change
@@ -544,17 +544,6 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L)
544544
return luaL_error(L, "no ctx found");
545545
}
546546

547-
if (!ctx->headers_set) {
548-
rc = ngx_http_lua_set_content_type(r);
549-
if (rc != NGX_OK) {
550-
return luaL_error(L,
551-
"failed to set default content type: %d",
552-
(int) rc);
553-
}
554-
555-
ctx->headers_set = 1;
556-
}
557-
558547
ngx_http_lua_check_fake_request(L, r);
559548

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

565+
if (!r->headers_out.content_type.len) {
566+
rc = ngx_http_lua_set_content_type(r);
567+
if (rc != NGX_OK) {
568+
return luaL_error(L,
569+
"failed to set default content type: %d",
570+
(int) rc);
571+
}
572+
573+
ctx->headers_set = 1;
574+
}
575+
576576
#if 1
577577
if (r->headers_out.content_type.len) {
578578
extra++;
@@ -696,7 +696,6 @@ ngx_http_lua_ngx_header_get(lua_State *L)
696696
size_t len;
697697
ngx_http_lua_loc_conf_t *llcf;
698698
ngx_http_lua_ctx_t *ctx;
699-
ngx_int_t rc;
700699

701700
r = ngx_http_lua_get_req(L);
702701
if (r == NULL) {
@@ -739,18 +738,7 @@ ngx_http_lua_ngx_header_get(lua_State *L)
739738

740739
key.len = len;
741740

742-
if (!ctx->headers_set) {
743-
rc = ngx_http_lua_set_content_type(r);
744-
if (rc != NGX_OK) {
745-
return luaL_error(L,
746-
"failed to set default content type: %d",
747-
(int) rc);
748-
}
749-
750-
ctx->headers_set = 1;
751-
}
752-
753-
return ngx_http_lua_get_output_header(L, r, &key);
741+
return ngx_http_lua_get_output_header(L, r, ctx, &key);
754742
}
755743

756744

@@ -813,16 +801,7 @@ ngx_http_lua_ngx_header_set(lua_State *L)
813801
}
814802
}
815803

816-
if (!ctx->headers_set) {
817-
rc = ngx_http_lua_set_content_type(r);
818-
if (rc != NGX_OK) {
819-
return luaL_error(L,
820-
"failed to set default content type: %d",
821-
(int) rc);
822-
}
823-
824-
ctx->headers_set = 1;
825-
}
804+
ctx->headers_set = 1;
826805

827806
if (lua_type(L, 3) == LUA_TNIL) {
828807
ngx_str_null(&value);
@@ -1244,15 +1223,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data,
12441223
}
12451224
}
12461225

1247-
if (!ctx->headers_set) {
1248-
rc = ngx_http_lua_set_content_type(r);
1249-
if (rc != NGX_OK) {
1250-
*errmsg = "failed to set default content type";
1251-
return NGX_ERROR;
1252-
}
1253-
1254-
ctx->headers_set = 1;
1255-
}
1226+
ctx->headers_set = 1;
12561227

12571228
if (is_nil) {
12581229
value.data = NULL;
@@ -1373,7 +1344,8 @@ ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r,
13731344
int
13741345
ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r,
13751346
const u_char *key, size_t key_len,
1376-
u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues)
1347+
u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues,
1348+
char **errmsg)
13771349
{
13781350
int found;
13791351
u_char c, *p;
@@ -1390,19 +1362,10 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r,
13901362

13911363
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
13921364
if (ctx == NULL) {
1393-
/* *errmsg = "no ctx found"; */
1365+
*errmsg = "no ctx found";
13941366
return NGX_ERROR;
13951367
}
13961368

1397-
if (!ctx->headers_set) {
1398-
if (ngx_http_lua_set_content_type(r) != NGX_OK) {
1399-
/* *errmsg = "failed to set default content type"; */
1400-
return NGX_ERROR;
1401-
}
1402-
1403-
ctx->headers_set = 1;
1404-
}
1405-
14061369
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
14071370
if (llcf->transform_underscores_in_resp_headers
14081371
&& memchr(key, '_', key_len) != NULL)
@@ -1428,6 +1391,7 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r,
14281391
{
14291392
p = ngx_palloc(r->pool, NGX_OFF_T_LEN);
14301393
if (p == NULL) {
1394+
*errmsg = "no memory";
14311395
return NGX_ERROR;
14321396
}
14331397

@@ -1441,12 +1405,21 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r,
14411405
break;
14421406

14431407
case 12:
1444-
if (r->headers_out.content_type.len
1445-
&& ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0)
1446-
{
1447-
values[0].data = r->headers_out.content_type.data;
1448-
values[0].len = r->headers_out.content_type.len;
1449-
return 1;
1408+
if (ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0) {
1409+
if (!r->headers_out.content_type.len) {
1410+
if (ngx_http_lua_set_content_type(r) != NGX_OK) {
1411+
*errmsg = "failed to set default content type";
1412+
return NGX_ERROR;
1413+
}
1414+
1415+
ctx->headers_set = 1;
1416+
}
1417+
1418+
if (r->headers_out.content_type.len) {
1419+
values[0].data = r->headers_out.content_type.data;
1420+
values[0].len = r->headers_out.content_type.len;
1421+
return 1;
1422+
}
14501423
}
14511424

14521425
break;

src/ngx_http_lua_headers_out.c

+19-7
Original file line numberDiff line numberDiff line change
@@ -528,10 +528,11 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key,
528528

529529
int
530530
ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r,
531-
ngx_str_t *key)
531+
ngx_http_lua_ctx_t *ctx, ngx_str_t *key)
532532
{
533533
ngx_table_elt_t *h;
534534
ngx_list_part_t *part;
535+
ngx_int_t rc;
535536
ngx_uint_t i;
536537
unsigned found;
537538

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

552553
case 12:
553-
if (r->headers_out.content_type.len
554-
&& ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0)
555-
{
556-
lua_pushlstring(L, (char *) r->headers_out.content_type.data,
557-
r->headers_out.content_type.len);
558-
return 1;
554+
if (ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0) {
555+
if (!r->headers_out.content_type.len) {
556+
rc = ngx_http_lua_set_content_type(r);
557+
if (rc != NGX_OK) {
558+
return luaL_error(L,
559+
"failed to set default content type: %d",
560+
(int) rc);
561+
}
562+
563+
ctx->headers_set = 1;
564+
}
565+
566+
if (r->headers_out.content_type.len) {
567+
lua_pushlstring(L, (char *) r->headers_out.content_type.data,
568+
r->headers_out.content_type.len);
569+
return 1;
570+
}
559571
}
560572

561573
break;

src/ngx_http_lua_headers_out.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key,
1616
ngx_str_t value, unsigned override);
1717
int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r,
18-
ngx_str_t *key);
18+
ngx_http_lua_ctx_t *ctx, ngx_str_t *key);
1919

2020

2121
#endif /* _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ */

src/ngx_http_lua_subrequest.c

+8
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,14 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc)
10311031
dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]);
10321032

10331033
/* copy subrequest response headers */
1034+
if (ctx->headers_set) {
1035+
rc = ngx_http_lua_set_content_type(r);
1036+
if (rc != NGX_OK) {
1037+
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1038+
"failed to set default content type: %i", rc);
1039+
return NGX_ERROR;
1040+
}
1041+
}
10341042

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

0 commit comments

Comments
 (0)