diff --git a/src/httpc.c b/src/httpc.c index 950f8b32f6b54c8dfab72ce36965ba8c71bb9d06..e9f703ba1b9c036af7c9cd856b4c7f33bfdb9281 100644 --- a/src/httpc.c +++ b/src/httpc.c @@ -37,6 +37,8 @@ #include "fiber.h" #include "errinj.h" +#define MAX_HEADER_LEN 8192 + /** * libcurl callback for CURLOPT_WRITEFUNCTION * @see https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html @@ -173,9 +175,14 @@ httpc_request_delete(struct httpc_request *req) int httpc_set_header(struct httpc_request *req, const char *fmt, ...) { + static __thread char header[MAX_HEADER_LEN + 1]; va_list ap; va_start(ap, fmt); - const char *header = tt_vsprintf(fmt, ap); + int rc = vsnprintf(header, MAX_HEADER_LEN + 1, fmt, ap); + if (rc > MAX_HEADER_LEN) { + diag_set(IllegalParams, "header is too large"); + return -1; + } va_end(ap); struct curl_slist *l = curl_slist_append(req->headers, header); diff --git a/test/app-tap/http_client.test.lua b/test/app-tap/http_client.test.lua index 10a3728f8713f61e37b02afb9ca7565e94af30df..6a4ec91773e89f059388cfde6d5b1fc2f888bac6 100755 --- a/test/app-tap/http_client.test.lua +++ b/test/app-tap/http_client.test.lua @@ -206,7 +206,7 @@ local function test_errors(test) end local function test_headers(test, url, opts) - test:plan(19) + test:plan(21) local http = client:new() local r = http:get(url .. 'headers', opts) test:is(type(r.headers["set-cookie"]), 'string', "set-cookie check") @@ -231,6 +231,25 @@ local function test_headers(test, url, opts) local r = http:get(url .. 'headers', opts) test:is(r.headers["very_very_very_long_headers_name1"], "true", "truncated max_header_name_length") opts["max_header_name_length"] = nil + + -- Send large headers. + local MAX_HEADER_NAME = 8192 + local hname = 'largeheader' + + -- "${hname}: ${hvalue}" is 8192 bytes length + local hvalue = string.rep('x', MAX_HEADER_NAME - hname:len() - 2) + local headers = {[hname] = hvalue} + local r = http:post(url, nil, merge(opts, {headers = headers})) + test:is(r.headers[hname], hvalue, '8192 bytes header: success') + + -- "${hname}: ${hvalue}" is 8193 bytes length + local exp_err = 'header is too large' + local hvalue = string.rep('x', MAX_HEADER_NAME - hname:len() - 1) + local headers = {[hname] = hvalue} + local ok, err = pcall(http.post, http, url, nil, + merge(opts, {headers = headers})) + test:is_deeply({ok, tostring(err)}, {false, exp_err}, + '8193 KiB header: error') end local function test_special_methods(test, url, opts)