Skip to content
Permalink
4e8b4c395f
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
293 lines (266 sloc) 9.03 KB
commit 96c330c3cb2a5abc95d293854801c7ba2896d1da
Author: Thibault Charbonnier <thibaultcha@me.com>
Date: Mon Mar 23 19:40:47 2020 -0700
bugfix: prevented request smuggling in the ngx.location.capture API.
diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c
index 19a88d99..9f7036a0 100644
--- a/src/ngx_http_lua_subrequest.c
+++ b/src/ngx_http_lua_subrequest.c
@@ -57,8 +57,6 @@ static ngx_str_t ngx_http_lua_content_length_header_key =
ngx_string("Content-Length");
-static ngx_int_t ngx_http_lua_set_content_length_header(ngx_http_request_t *r,
- off_t len);
static ngx_int_t ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr,
ngx_uint_t method, int forward_body,
ngx_http_request_body_t *body, unsigned vars_action,
@@ -79,7 +77,7 @@ static void ngx_http_lua_cancel_subreq(ngx_http_request_t *r);
static ngx_int_t ngx_http_post_request_to_head(ngx_http_request_t *r);
static ngx_int_t ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r);
static ngx_int_t ngx_http_lua_copy_request_headers(ngx_http_request_t *sr,
- ngx_http_request_t *r);
+ ngx_http_request_t *pr, ngx_uint_t prcl);
enum {
@@ -634,8 +632,8 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method,
unsigned vars_action, ngx_array_t *extra_vars)
{
ngx_http_request_t *r;
- ngx_int_t rc;
ngx_http_core_main_conf_t *cmcf;
+ ngx_uint_t prcl = 0;
size_t size;
r = sr->parent;
@@ -645,46 +643,32 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method,
if (body) {
sr->request_body = body;
- rc = ngx_http_lua_set_content_length_header(sr,
- body->buf
- ? ngx_buf_size(body->buf)
- : 0);
-
- if (rc != NGX_OK) {
- return NGX_ERROR;
- }
-
} else if (!always_forward_body
&& method != NGX_HTTP_PUT
&& method != NGX_HTTP_POST
&& r->headers_in.content_length_n > 0)
{
- rc = ngx_http_lua_set_content_length_header(sr, 0);
- if (rc != NGX_OK) {
- return NGX_ERROR;
- }
-
-#if 1
sr->request_body = NULL;
-#endif
} else {
- if (ngx_http_lua_copy_request_headers(sr, r) != NGX_OK) {
- return NGX_ERROR;
+ if (!r->headers_in.chunked) {
+ prcl = 1;
}
- if (sr->request_body) {
+ if (sr->request_body && sr->request_body->temp_file) {
/* deep-copy the request body */
- if (sr->request_body->temp_file) {
- if (ngx_http_lua_copy_in_file_request_body(sr) != NGX_OK) {
- return NGX_ERROR;
- }
+ if (ngx_http_lua_copy_in_file_request_body(sr) != NGX_OK) {
+ return NGX_ERROR;
}
}
}
+ if (ngx_http_lua_copy_request_headers(sr, r, prcl) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
sr->method = method;
switch (method) {
@@ -1134,100 +1118,6 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc)
}
-static ngx_int_t
-ngx_http_lua_set_content_length_header(ngx_http_request_t *r, off_t len)
-{
- ngx_table_elt_t *h, *header;
- u_char *p;
- ngx_list_part_t *part;
- ngx_http_request_t *pr;
- ngx_uint_t i;
-
- r->headers_in.content_length_n = len;
-
- if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
- sizeof(ngx_table_elt_t)) != NGX_OK)
- {
- return NGX_ERROR;
- }
-
- h = ngx_list_push(&r->headers_in.headers);
- if (h == NULL) {
- return NGX_ERROR;
- }
-
- h->key = ngx_http_lua_content_length_header_key;
- h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
- if (h->lowcase_key == NULL) {
- return NGX_ERROR;
- }
-
- ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
-
- r->headers_in.content_length = h;
-
- p = ngx_palloc(r->pool, NGX_OFF_T_LEN);
- if (p == NULL) {
- return NGX_ERROR;
- }
-
- h->value.data = p;
-
- h->value.len = ngx_sprintf(h->value.data, "%O", len) - h->value.data;
-
- h->hash = ngx_http_lua_content_length_hash;
-
-#if 0
- dd("content length hash: %lu == %lu", (unsigned long) h->hash,
- ngx_hash_key_lc((u_char *) "Content-Length",
- sizeof("Content-Length") - 1));
-#endif
-
- dd("r content length: %.*s",
- (int) r->headers_in.content_length->value.len,
- r->headers_in.content_length->value.data);
-
- pr = r->parent;
-
- if (pr == NULL) {
- return NGX_OK;
- }
-
- /* forward the parent request's all other request headers */
-
- part = &pr->headers_in.headers.part;
- header = part->elts;
-
- for (i = 0; /* void */; i++) {
-
- if (i >= part->nelts) {
- if (part->next == NULL) {
- break;
- }
-
- part = part->next;
- header = part->elts;
- i = 0;
- }
-
- if (header[i].key.len == sizeof("Content-Length") - 1
- && ngx_strncasecmp(header[i].key.data, (u_char *) "Content-Length",
- sizeof("Content-Length") - 1) == 0)
- {
- continue;
- }
-
- if (ngx_http_lua_set_input_header(r, header[i].key,
- header[i].value, 0) == NGX_ERROR)
- {
- return NGX_ERROR;
- }
- }
-
- return NGX_OK;
-}
-
-
static void
ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r,
ngx_http_lua_ctx_t *ctx)
@@ -1742,11 +1632,17 @@ ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r)
static ngx_int_t
-ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, ngx_http_request_t *r)
+ngx_http_lua_copy_request_headers(ngx_http_request_t *sr,
+ ngx_http_request_t *pr, ngx_uint_t prcl)
{
- ngx_table_elt_t *header;
+ ngx_table_elt_t *clh, *header;
ngx_list_part_t *part;
ngx_uint_t i;
+ u_char *p;
+ off_t len;
+
+ dd("before: parent req headers count: %d",
+ (int) pr->headers_in.headers.part.nelts);
if (ngx_list_init(&sr->headers_in.headers, sr->pool, 20,
sizeof(ngx_table_elt_t)) != NGX_OK)
@@ -1754,10 +1650,46 @@ ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, ngx_http_request_t *r)
return NGX_ERROR;
}
- dd("before: parent req headers count: %d",
- (int) r->headers_in.headers.part.nelts);
+ if (sr->request_body && !prcl) {
+
+ /* craft our own Content-Length */
+
+ len = sr->request_body->buf ? ngx_buf_size(sr->request_body->buf) : 0;
+
+ clh = ngx_list_push(&sr->headers_in.headers);
+ if (clh == NULL) {
+ return NGX_ERROR;
+ }
- part = &r->headers_in.headers.part;
+ clh->hash = ngx_http_lua_content_length_hash;
+ clh->key = ngx_http_lua_content_length_header_key;
+ clh->lowcase_key = ngx_pnalloc(sr->pool, clh->key.len);
+ if (clh->lowcase_key == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_strlow(clh->lowcase_key, clh->key.data, clh->key.len);
+
+ p = ngx_palloc(sr->pool, NGX_OFF_T_LEN);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ clh->value.data = p;
+ clh->value.len = ngx_sprintf(clh->value.data, "%O", len)
+ - clh->value.data;
+
+ sr->headers_in.content_length = clh;
+ sr->headers_in.content_length_n = len;
+
+ dd("sr crafted content-length: %.*s",
+ (int) sr->headers_in.content_length->value.len,
+ sr->headers_in.content_length->value.data);
+ }
+
+ /* copy the parent request's headers */
+
+ part = &pr->headers_in.headers.part;
header = part->elts;
for (i = 0; /* void */; i++) {
@@ -1772,7 +1704,14 @@ ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, ngx_http_request_t *r)
i = 0;
}
- dd("setting request header %.*s: %.*s", (int) header[i].key.len,
+ if (!prcl && header[i].key.len == sizeof("Content-Length") - 1
+ && ngx_strncasecmp(header[i].key.data, (u_char *) "Content-Length",
+ sizeof("Content-Length") - 1) == 0)
+ {
+ continue;
+ }
+
+ dd("sr copied req header %.*s: %.*s", (int) header[i].key.len,
header[i].key.data, (int) header[i].value.len,
header[i].value.data);
@@ -1784,9 +1723,10 @@ ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, ngx_http_request_t *r)
}
dd("after: parent req headers count: %d",
- (int) r->headers_in.headers.part.nelts);
+ (int) pr->headers_in.headers.part.nelts);
return NGX_OK;
}
+
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */