summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Lackner <sebastian.lackner@sysmagine.com>2022-10-06 05:04:38 +0200
committerSebastian Lackner <sebastian.lackner@sysmagine.com>2022-10-20 03:04:56 +0200
commitf8683b7a93c54db3df510fbb8593082c2667bfcd (patch)
tree4b1712d15d44d7bc8607de092fc665a32067c63f
parenta3841af5eecc6301e87f8302c7fdce6555e39247 (diff)
downloadlibgit2-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.c15
-rw-r--r--src/libgit2/transports/httpclient.c9
-rw-r--r--src/libgit2/transports/httpclient.h10
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