Commit f8683b7a by Sebastian Lackner

http: Update httpclient options when reusing an existing connection.

Httpclient internally stores a copy of the certificate_check callback and
payload. When connecting via HTTPS, and if the server sends back
"Connection: close" after the first request, the following request would
attempt to re-use the httpclient and call the (now outdated) callback. In
particular for pygit2 this is a problem, since callbacks / payloads are only
valid for the duration of a libgit2 call, leading to a ffi.from_handle()
error and crashing the Python interpreter.
parent a3841af5
...@@ -655,6 +655,7 @@ static int http_action( ...@@ -655,6 +655,7 @@ static int http_action(
{ {
http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent); http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent);
git_remote_connect_options *connect_opts = &transport->owner->connect_opts; git_remote_connect_options *connect_opts = &transport->owner->connect_opts;
git_http_client_options opts = {0};
http_stream *stream; http_stream *stream;
const http_service *service; const http_service *service;
int error; int error;
...@@ -683,14 +684,14 @@ static int http_action( ...@@ -683,14 +684,14 @@ static int http_action(
stream = git__calloc(sizeof(http_stream), 1); stream = git__calloc(sizeof(http_stream), 1);
GIT_ERROR_CHECK_ALLOC(stream); GIT_ERROR_CHECK_ALLOC(stream);
if (!transport->http_client) { opts.server_certificate_check_cb = connect_opts->callbacks.certificate_check;
git_http_client_options opts = {0}; opts.server_certificate_check_payload = connect_opts->callbacks.payload;
opts.proxy_certificate_check_cb = connect_opts->proxy_opts.certificate_check;
opts.server_certificate_check_cb = connect_opts->callbacks.certificate_check; opts.proxy_certificate_check_payload = connect_opts->proxy_opts.payload;
opts.server_certificate_check_payload = connect_opts->callbacks.payload;
opts.proxy_certificate_check_cb = connect_opts->proxy_opts.certificate_check;
opts.proxy_certificate_check_payload = connect_opts->proxy_opts.payload;
if (transport->http_client) {
git_http_client_set_options(transport->http_client, &opts);
} else {
if (git_http_client_new(&transport->http_client, &opts) < 0) if (git_http_client_new(&transport->http_client, &opts) < 0)
return -1; return -1;
} }
......
...@@ -1541,6 +1541,15 @@ int git_http_client_new( ...@@ -1541,6 +1541,15 @@ int git_http_client_new(
return 0; return 0;
} }
/* Update the options of an existing httpclient instance. */
void git_http_client_set_options(
git_http_client *client,
git_http_client_options *opts)
{
if (opts)
memcpy(&client->opts, opts, sizeof(git_http_client_options));
}
GIT_INLINE(void) http_server_close(git_http_server *server) GIT_INLINE(void) http_server_close(git_http_server *server)
{ {
if (server->stream) { if (server->stream) {
......
...@@ -88,6 +88,16 @@ extern int git_http_client_new( ...@@ -88,6 +88,16 @@ extern int git_http_client_new(
git_http_client **out, git_http_client **out,
git_http_client_options *opts); git_http_client_options *opts);
/**
* Update the options of an existing httpclient instance.
*
* @param client the httpclient instance to modify
* @param opts new options or NULL to keep existing options
*/
extern void git_http_client_set_options(
git_http_client *client,
git_http_client_options *opts);
/* /*
* Sends a request to the host specified by the request URL. If the * Sends a request to the host specified by the request URL. If the
* method is POST, either the content_length or the chunked flag must * method is POST, either the content_length or the chunked flag must
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment