diff options
author | Sebastian Lackner <sebastian.lackner@sysmagine.com> | 2022-10-06 05:04:38 +0200 |
---|---|---|
committer | Sebastian Lackner <sebastian.lackner@sysmagine.com> | 2022-10-20 03:04:56 +0200 |
commit | f8683b7a93c54db3df510fbb8593082c2667bfcd (patch) | |
tree | 4b1712d15d44d7bc8607de092fc665a32067c63f | |
parent | a3841af5eecc6301e87f8302c7fdce6555e39247 (diff) | |
download | libgit2-f8683b7a93c54db3df510fbb8593082c2667bfcd.tar.gz |
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.
-rw-r--r-- | src/libgit2/transports/http.c | 15 | ||||
-rw-r--r-- | src/libgit2/transports/httpclient.c | 9 | ||||
-rw-r--r-- | src/libgit2/transports/httpclient.h | 10 |
3 files changed, 27 insertions, 7 deletions
diff --git a/src/libgit2/transports/http.c b/src/libgit2/transports/http.c index 7db5582ca..cda76ae61 100644 --- a/src/libgit2/transports/http.c +++ b/src/libgit2/transports/http.c @@ -655,6 +655,7 @@ static int http_action( { http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent); git_remote_connect_options *connect_opts = &transport->owner->connect_opts; + git_http_client_options opts = {0}; http_stream *stream; const http_service *service; int error; @@ -683,14 +684,14 @@ static int http_action( stream = git__calloc(sizeof(http_stream), 1); GIT_ERROR_CHECK_ALLOC(stream); - if (!transport->http_client) { - git_http_client_options opts = {0}; - - opts.server_certificate_check_cb = connect_opts->callbacks.certificate_check; - 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; + opts.server_certificate_check_cb = connect_opts->callbacks.certificate_check; + 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) return -1; } diff --git a/src/libgit2/transports/httpclient.c b/src/libgit2/transports/httpclient.c index f07923ef2..0ad6cd4dc 100644 --- a/src/libgit2/transports/httpclient.c +++ b/src/libgit2/transports/httpclient.c @@ -1541,6 +1541,15 @@ int git_http_client_new( 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) { if (server->stream) { diff --git a/src/libgit2/transports/httpclient.h b/src/libgit2/transports/httpclient.h index 6d0ef9edb..22c4dd093 100644 --- a/src/libgit2/transports/httpclient.h +++ b/src/libgit2/transports/httpclient.h @@ -88,6 +88,16 @@ extern int git_http_client_new( git_http_client **out, 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 * method is POST, either the content_length or the chunked flag must |