From: Kirill Shcherbatov <kshcherbatov@tarantool.org> To: tarantool-patches@freelists.org, Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Subject: [tarantool-patches] Re: [PATCH v1 1/1] http: fix httpc auto-managed headers Date: Fri, 22 Feb 2019 10:39:51 +0300 [thread overview] Message-ID: <80130a1b-84ad-5f90-9422-95bb0a1e67cb@tarantool.org> (raw) In-Reply-To: <9099f8a339c278e3a5dac683923d13c7ee470ce9.1550761676.git.kshcherbatov@tarantool.org> Perhaps even better here is so: diff --git a/src/httpc.c b/src/httpc.c index b4ca6cfce..f2df069e5 100644 --- a/src/httpc.c +++ b/src/httpc.c @@ -184,23 +184,24 @@ httpc_managed_headers_mask_update(uint8_t *auto_headers_mask, static struct { const char *header_name; uint32_t header_name_len; - int8_t bit_index; } httpc_managed_headers[] = { - {"Connection", 10, 1}, - {"Keep-Alive", 10, 2}, - {"Content-Length", 14, 4}, - {"Accept", 6, 8}, + {"Connection", 10}, + {"Keep-Alive", 10}, + {"Content-Length", 14}, + {"Accept", 6}, }; uint32_t httpc_managed_headers_cnt = sizeof(httpc_managed_headers)/sizeof(httpc_managed_headers[0]); + assert(httpc_managed_headers_cnt < + sizeof(*auto_headers_mask) * CHAR_BIT); for (uint32_t i = 0; i < httpc_managed_headers_cnt; i++) { if (strncasecmp(header, httpc_managed_headers[i].header_name, httpc_managed_headers[i].header_name_len) != 0) continue; - if ((*auto_headers_mask & - httpc_managed_headers[i].bit_index) != 0) + int8_t bit_index = 1 << i; + if ((*auto_headers_mask & bit_index) != 0) return -1; - *auto_headers_mask |= httpc_managed_headers[i].bit_index; + *auto_headers_mask |= bit_index; return 0; } return 0; =========================================== ntent-Length", "Connection", "Keep-Alive: timeout". However, when the user explicitly specified them in the header options section of the call argument, they could be written to the HTTP request twice. Was introduced service http c_managed_header_mask mask in which the bits corresponding to the http auto-manager headers, set 1 when referenced. When the bit is set, the new value is not applied. In this way, we prefer user-defined value for all httpc-managed headers. Closes #3955 --- src/httpc.c | 42 +++++++++++++++++++++++++++++++ src/httpc.h | 8 ++++++ test/app-tap/http_client.test.lua | 12 ++++++++- 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/httpc.c b/src/httpc.c index 950f8b32f..f2df069e5 100644 --- a/src/httpc.c +++ b/src/httpc.c @@ -170,6 +170,43 @@ httpc_request_delete(struct httpc_request *req) mempool_free(&req->env->req_pool, req); } +/** + * Update bitmask of the http request headers that httpc may set + * automatically. In case of reserved pattern is found in header, + * routine sets corresponding bit in auto_headers_mask. + * Returns -1 when header is reserved and it's bit is already set + * in auto_headers_mask; 0 otherwise, +*/ +static int +httpc_managed_headers_mask_update(uint8_t *auto_headers_mask, + const char *header) +{ + static struct { + const char *header_name; + uint32_t header_name_len; + } httpc_managed_headers[] = { + {"Connection", 10}, + {"Keep-Alive", 10}, + {"Content-Length", 14}, + {"Accept", 6}, + }; + uint32_t httpc_managed_headers_cnt = + sizeof(httpc_managed_headers)/sizeof(httpc_managed_headers[0]); + assert(httpc_managed_headers_cnt < + sizeof(*auto_headers_mask) * CHAR_BIT); + for (uint32_t i = 0; i < httpc_managed_headers_cnt; i++) { + if (strncasecmp(header, httpc_managed_headers[i].header_name, + httpc_managed_headers[i].header_name_len) != 0) + continue; + int8_t bit_index = 1 << i; + if ((*auto_headers_mask & bit_index) != 0) + return -1; + *auto_headers_mask |= bit_index; + return 0; + } + return 0; +} + int httpc_set_header(struct httpc_request *req, const char *fmt, ...) { @@ -178,6 +215,11 @@ httpc_set_header(struct httpc_request *req, const char *fmt, ...) const char *header = tt_vsprintf(fmt, ap); va_end(ap); + if (httpc_managed_headers_mask_update(&req->auto_headers_mask, + header) != 0) { + /* Do not add extra header to list. */ + return 0; + } struct curl_slist *l = curl_slist_append(req->headers, header); if (l == NULL) { diag_set(OutOfMemory, strlen(header), "curl", "http header"); diff --git a/src/httpc.h b/src/httpc.h index dc709e6fa..d30343be1 100644 --- a/src/httpc.h +++ b/src/httpc.h @@ -109,6 +109,14 @@ struct httpc_request { struct region resp_headers; /** buffer of body */ struct region resp_body; + /** + * A bitmask of the http request headers from among + * the headers that httpc can set automatically. + * This allows to prevent settings such headers twice. + * Read httpc_managed_headers_mask_update definition for + * more details. + */ + uint8_t auto_headers_mask; }; /** diff --git a/test/app-tap/http_client.test.lua b/test/app-tap/http_client.test.lua index 10a3728f8..8d1c50549 100755 --- a/test/app-tap/http_client.test.lua +++ b/test/app-tap/http_client.test.lua @@ -79,6 +79,14 @@ local function test_http_client(test, url, opts) test:is(r.status, 200, 'request') end +local function test_http_client_headers_redefine(test, url, opts) + test:plan(2) + opts.headers={['Connection'] = 'Keep-Alive'} + local r = client.get(url, opts) + test:is(r.status, 200, 'simple 200') + test:is(r.headers["connection"], 'Keep-Alive', 'redefined Connection header') +end + local function test_cancel_and_errinj(test, url, opts) test:plan(3) local ch = fiber.channel(1) @@ -397,9 +405,11 @@ local function test_concurrent(test, url, opts) end function run_tests(test, sock_family, sock_addr) - test:plan(9) + test:plan(10) local server, url, opts = start_server(test, sock_family, sock_addr) test:test("http.client", test_http_client, url, opts) + test:test("http.client headers redefine", test_http_client_headers_redefine, + url, opts) test:test("cancel and errinj", test_cancel_and_errinj, url .. 'long_query', opts) test:test("basic http post/get", test_post_and_get, url, opts) test:test("errors", test_errors) -- 2.20.1
next prev parent reply other threads:[~2019-02-22 7:39 UTC|newest] Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-02-21 15:09 [tarantool-patches] " Kirill Shcherbatov 2019-02-22 7:39 ` Kirill Shcherbatov [this message] 2019-02-25 7:52 ` [tarantool-patches] " Kirill Shcherbatov 2019-02-25 14:17 ` Vladislav Shpilevoy 2019-02-25 15:21 ` Kirill Shcherbatov 2019-03-07 13:51 ` Vladimir Davydov 2019-03-07 14:07 ` Kirill Shcherbatov 2019-03-07 14:32 ` Vladimir Davydov 2019-03-07 14:48 ` Kirill Shcherbatov 2019-03-07 14:53 ` Vladimir Davydov 2019-03-11 9:23 ` [tarantool-patches] Re: [PATCH v2 " Kirill Shcherbatov 2019-03-11 10:02 ` Vladimir Davydov 2019-03-11 15:57 ` Kirill Shcherbatov 2019-03-12 8:54 ` Vladimir Davydov 2019-03-07 14:07 ` [tarantool-patches] Re: [PATCH v1 " Vladislav Shpilevoy
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=80130a1b-84ad-5f90-9422-95bb0a1e67cb@tarantool.org \ --to=kshcherbatov@tarantool.org \ --cc=tarantool-patches@freelists.org \ --cc=v.shpilevoy@tarantool.org \ --subject='[tarantool-patches] Re: [PATCH v1 1/1] http: fix httpc auto-managed headers' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox