Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladimir Davydov <vdavydov.dev@gmail.com>
To: Kirill Shcherbatov <kshcherbatov@tarantool.org>
Cc: tarantool-patches@freelists.org
Subject: Re: [tarantool-patches] Re: [PATCH v2 1/1] http: fix httpc auto-managed headers
Date: Mon, 11 Mar 2019 13:02:21 +0300	[thread overview]
Message-ID: <20190311100221.3oudvbsfaq4gxawb@esperanza> (raw)
In-Reply-To: <d2fab5d1-1ae4-d548-524a-f9f1e618600a@tarantool.org>

On Mon, Mar 11, 2019 at 12:23:02PM +0300, Kirill Shcherbatov wrote:
> The https library intelligently sets the headers "Accept",
> "Content-Length", "Connection", "Keep-Alive: timeout".

Please remove "Content-Length" from the commit message.

> 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.
> We postponed the auto headers setup before https_exececute call.
> Now they are set only if they were not set by the user.
> 
> Closes #3955
> 
> https://github.com/tarantool/tarantool/tree/kshch/gh-3955-httpc-auto-managed-headers-redefine
> https://github.com/tarantool/tarantool/issues/3955
> ---
>  src/httpc.c                       | 36 +++++++++++++++++++------------
>  src/httpc.h                       | 21 ++++++++++++++++++
>  test/app-tap/http_client.test.lua | 16 +++++++++++++-
>  3 files changed, 58 insertions(+), 15 deletions(-)
> 
> diff --git a/src/httpc.c b/src/httpc.c
> index 04775b378..0615a32ec 100644
> --- a/src/httpc.c
> +++ b/src/httpc.c
> @@ -108,6 +108,8 @@ httpc_request_new(struct httpc_env *env, const char *method,
>  	}
>  	memset(req, 0, sizeof(*req));
>  	req->env = env;
> +	req->set_connection = true;
> +	req->set_kep_alive = true;
>  	region_create(&req->resp_headers, &cord()->slabc);
>  	region_create(&req->resp_body, &cord()->slabc);
>  
> @@ -131,8 +133,7 @@ httpc_request_new(struct httpc_env *env, const char *method,
>  		curl_easy_setopt(req->curl_request.easy, CURLOPT_POSTFIELDS, "");
>  		curl_easy_setopt(req->curl_request.easy, CURLOPT_POSTFIELDSIZE, 0);
>  		curl_easy_setopt(req->curl_request.easy, CURLOPT_CUSTOMREQUEST, method);
> -		if (httpc_set_header(req, "Accept: */*") < 0)
> -			goto error;
> +		req->set_accept_any_mime = true;
>  	} else {
>  		curl_easy_setopt(req->curl_request.easy, CURLOPT_CUSTOMREQUEST, method);
>  	}
> @@ -152,9 +153,6 @@ httpc_request_new(struct httpc_env *env, const char *method,
>  	ibuf_create(&req->body, &cord()->slabc, 1);
>  
>  	return req;
> -error:
> -	mempool_free(&env->req_pool, req);
> -	return NULL;
>  }
>  
>  void
> @@ -185,6 +183,17 @@ httpc_set_header(struct httpc_request *req, const char *fmt, ...)
>  	}
>  	va_end(ap);
>  
> +	/**
> +	 * Update flags for automanaged headers: no need to
> +	 * set them automatically later.
> +	 */
> +	if (strncasecmp(header, "Accept:", 7) == 0)
> +		req->set_accept_any_mime = false;
> +	else if (strncasecmp(header, "Connection:", 11) == 0)
> +		req->set_connection = false;
> +	else if (strncasecmp(header, "Keep-Alive:", 11) == 0)
> +		req->set_kep_alive = false;
> +

Using a constant for string length looks error-prone. Please introduce
constants for header literals and use them instead:

	strncasecmp(header, ACCEPT_HEADER, strlen(ACCEPT_HEADER))

>  	struct curl_slist *l = curl_slist_append(req->headers, header);
>  	if (l == NULL) {
>  		diag_set(OutOfMemory, strlen(header), "curl", "http header");
> @@ -223,15 +232,7 @@ httpc_set_keepalive(struct httpc_request *req, long idle, long interval)
>  		curl_easy_setopt(req->curl_request.easy, CURLOPT_TCP_KEEPALIVE, 1L);
>  		curl_easy_setopt(req->curl_request.easy, CURLOPT_TCP_KEEPIDLE, idle);
>  		curl_easy_setopt(req->curl_request.easy, CURLOPT_TCP_KEEPINTVL, interval);
> -		if (httpc_set_header(req, "Connection: Keep-Alive") < 0 ||
> -		    httpc_set_header(req, "Keep-Alive: timeout=%d",
> -				     (int) idle) < 0) {
> -			return -1;
> -		}
> -	} else {
> -		if (httpc_set_header(req, "Connection: close") < 0) {
> -			return -1;
> -		}
> +		req->idle = idle;
>  	}

httpc_set_keepalive never fails after this patch. Please remove the
return value from the function signature.

>  #else
>  	(void) req;
> @@ -322,6 +323,13 @@ int
>  httpc_execute(struct httpc_request *req, double timeout)
>  {
>  	struct httpc_env *env = req->env;
> +	if (req->set_connection &&
> +	    httpc_set_header(req, "Connection: %s",
> +			     req->idle > 0 ? "Keep-Alive" : "close") != 0)
> +		return -1;
> +	if (req->set_kep_alive && req->idle > 0 &&
> +	    httpc_set_header(req, "Keep-Alive: timeout=%d", (int)req->idle) < 0)

Please use %ld rather than (int) type conversion.

> +		return -1;

Where do you set "Accept" header?

>  
>  	curl_easy_setopt(req->curl_request.easy, CURLOPT_WRITEDATA, (void *) req);
>  	curl_easy_setopt(req->curl_request.easy, CURLOPT_HEADERDATA, (void *) req);
> diff --git a/src/httpc.h b/src/httpc.h
> index b675d5f26..5c6bcc8a5 100644
> --- a/src/httpc.h
> +++ b/src/httpc.h
> @@ -109,6 +109,27 @@ struct httpc_request {
>  	struct region resp_headers;
>  	/** buffer of body */
>  	struct region resp_body;
> +	/**
> +	 * Idle delay, in seconds, that the operating system will
> +	 * wait while the connection is idle before sending
> +	 * keepalive probes.
> +	 */
> +	long idle;

keep_alive_timeout

> +	/**
> +	 * True when connection header must be set before
> +	 * execution automatically.
> +	 */
> +	bool set_connection;

set_connection_header

> +	/**
> +	 * True when accept Any MIME header must be set
> +	 * before execution automatically.
> +	 */
> +	bool set_accept_any_mime;

set_accept_header

> +	/**
> +	 * True when Keep-Alive header must be set before
> +	 * execution automatically.
> +	 */
> +	bool set_kep_alive;

s/set_kep_alive/set_keep_alive_header

>  };
>  
>  /**
> diff --git a/test/app-tap/http_client.test.lua b/test/app-tap/http_client.test.lua
> index 3cecb47ed..563f1f67e 100755
> --- a/test/app-tap/http_client.test.lua
> +++ b/test/app-tap/http_client.test.lua
> @@ -80,6 +80,18 @@ local function test_http_client(test, url, opts)
>      test:is(r.status, 200, 'request')
>  end
>  
> +--
> +-- gh-3955: Fix httpc auto-managed headers.
> +--

Bad comment as it says nothing about what the test actually checks.
Should be

  Check that httpc module doesn't redefine http headers set explicitly
  by the caller.

> +local function test_http_client_headers_redefine(test, url, opts)
> +    test:plan(3)
> +    opts.headers={['Connection'] = 'Keep-Alive', ['Accept'] = 'text/html'}
> +    local r = client.get(url, opts)
> +    test:is(r.status, 200, 'simple 200')
> +    test:is(r.headers["accept"], 'text/html', 'redefined Accept header')
> +    test:is(r.headers["connection"], 'Keep-Alive', 'redefined Connection header')
> +end
> +

Please add more test cases. In particular, you must check that if
keepalive option contradicts http headers provided by the caller,
httpc uses user-provided headers; if the user doesn't provide any
headers, the defaults are used.

>  local function test_cancel_and_errinj(test, url, opts)
>      test:plan(3)
>      local ch = fiber.channel(1)
> @@ -493,9 +505,11 @@ local function test_concurrent(test, url, opts)
>  end
>  
>  function run_tests(test, sock_family, sock_addr)
> -    test:plan(10)
> +    test:plan(11)
>      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)

  reply	other threads:[~2019-03-11 10:02 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-02-21 15:09 [tarantool-patches] [PATCH v1 " Kirill Shcherbatov
2019-02-22  7:39 ` [tarantool-patches] " Kirill Shcherbatov
2019-02-25  7:52   ` 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 [this message]
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=20190311100221.3oudvbsfaq4gxawb@esperanza \
    --to=vdavydov.dev@gmail.com \
    --cc=kshcherbatov@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --subject='Re: [tarantool-patches] Re: [PATCH v2 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