From c3733e56410d5bc73fcca0df8e062f84a0565f90 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Fri, 4 Sep 2015 08:56:26 -0400 Subject: [PATCH 01/35] Add more headers to HTTP requests --- src/transports/http.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/transports/http.c b/src/transports/http.c index 87f3ee816..f9e5da2b1 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -54,6 +54,7 @@ typedef struct { char *redirect_url; const char *verb; char *chunk_buffer; + git_strarray *extra_headers; unsigned chunk_buffer_len; unsigned sent_request : 1, received_response : 1, @@ -193,6 +194,7 @@ static int gen_request( { http_subtransport *t = OWNING_SUBTRANSPORT(s); const char *path = t->connection_data.path ? t->connection_data.path : "/"; + size_t i; git_buf_printf(buf, "%s %s%s HTTP/1.1\r\n", s->verb, path, s->service_url); @@ -210,6 +212,13 @@ static int gen_request( } else git_buf_puts(buf, "Accept: */*\r\n"); + if (s->extra_headers) { + for (i = 0; i < s->extra_headers->count; i++) { + git_buf_puts(buf, s->extra_headers->strings[i]); + git_buf_puts(buf, "\r\n"); + } + } + /* Apply credentials to the request */ if (apply_credentials(buf, t) < 0) return -1; From 6af6e69009e207da851c2b8dff395babddb3bfa4 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Fri, 4 Sep 2015 09:18:32 -0400 Subject: [PATCH 02/35] Put the extra headers on the connection_data instead --- src/netops.h | 1 + src/transports/http.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/netops.h b/src/netops.h index b7170a0f2..ea1072518 100644 --- a/src/netops.h +++ b/src/netops.h @@ -70,6 +70,7 @@ typedef struct gitno_connection_data { char *user; char *pass; bool use_ssl; + git_strarray *extra_headers; } gitno_connection_data; /* diff --git a/src/transports/http.c b/src/transports/http.c index f9e5da2b1..d348310c1 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -54,7 +54,6 @@ typedef struct { char *redirect_url; const char *verb; char *chunk_buffer; - git_strarray *extra_headers; unsigned chunk_buffer_len; unsigned sent_request : 1, received_response : 1, @@ -212,9 +211,9 @@ static int gen_request( } else git_buf_puts(buf, "Accept: */*\r\n"); - if (s->extra_headers) { - for (i = 0; i < s->extra_headers->count; i++) { - git_buf_puts(buf, s->extra_headers->strings[i]); + if (t->connection_data.extra_headers) { + for (i = 0; i < t->connection_data.extra_headers->count; i++) { + git_buf_puts(buf, t->connection_data.extra_headers->strings[i]); git_buf_puts(buf, "\r\n"); } } From ac9b51278996b864d0a2f7d61a827f89cbd4ff23 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Fri, 4 Sep 2015 09:20:45 -0400 Subject: [PATCH 03/35] Pull extra_http_headers from the git_remote --- src/remote.c | 2 ++ src/remote.h | 1 + src/transports/http.c | 1 + 3 files changed, 4 insertions(+) diff --git a/src/remote.c b/src/remote.c index 7404bf49f..b6fb87ece 100644 --- a/src/remote.c +++ b/src/remote.c @@ -1643,6 +1643,8 @@ void git_remote_free(git_remote *remote) free_refspecs(&remote->passive_refspecs); git_vector_free(&remote->passive_refspecs); + git__free(remote->extra_http_headers); + git_push_free(remote->push); git__free(remote->url); git__free(remote->pushurl); diff --git a/src/remote.h b/src/remote.h index e696997f4..bfb20362b 100644 --- a/src/remote.h +++ b/src/remote.h @@ -32,6 +32,7 @@ struct git_remote { git_remote_autotag_option_t download_tags; int prune_refs; int passed_refspecs; + git_strarray *extra_http_headers; }; const char* git_remote__urlfordirection(struct git_remote *remote, int direction); diff --git a/src/transports/http.c b/src/transports/http.c index d348310c1..664cd80ab 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -974,6 +974,7 @@ static int http_action( if ((!t->connection_data.host || !t->connection_data.port || !t->connection_data.path) && (ret = gitno_connection_data_from_url(&t->connection_data, url, NULL)) < 0) return ret; + t->connection_data.extra_headers = t->owner->owner->extra_http_headers; if ((ret = http_connect(t)) < 0) return ret; From 59d6128e2730b71da6fdebbdf9a4d04b909e9721 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Fri, 4 Sep 2015 09:36:50 -0400 Subject: [PATCH 04/35] Allow the world to set HTTP headers for remotes --- include/git2/remote.h | 3 +++ src/remote.c | 12 +++++++++++- src/remote.h | 2 +- src/transports/http.c | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 444fe5276..40adca0ce 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -230,6 +230,9 @@ GIT_EXTERN(size_t) git_remote_refspec_count(const git_remote *remote); */ GIT_EXTERN(const git_refspec *)git_remote_get_refspec(const git_remote *remote, size_t n); +GIT_EXTERN(int) git_remote_extra_http_headers(const git_remote *remote, git_strarray *extra_http_headers); +GIT_EXTERN(int) git_remote_set_extra_http_headers(git_remote *remote, const git_strarray extra_http_headers); + /** * Open a connection to a remote * diff --git a/src/remote.c b/src/remote.c index b6fb87ece..b7d82e708 100644 --- a/src/remote.c +++ b/src/remote.c @@ -1643,7 +1643,7 @@ void git_remote_free(git_remote *remote) free_refspecs(&remote->passive_refspecs); git_vector_free(&remote->passive_refspecs); - git__free(remote->extra_http_headers); + git_strarray_free(&remote->extra_http_headers); git_push_free(remote->push); git__free(remote->url); @@ -2154,6 +2154,16 @@ size_t git_remote_refspec_count(const git_remote *remote) return remote->refspecs.length; } +int git_remote_extra_http_headers(const git_remote *remote, git_strarray *extra_http_headers) +{ + return git_strarray_copy(extra_http_headers, &remote->extra_http_headers); +} + +int git_remote_set_extra_http_headers(git_remote *remote, const git_strarray extra_http_headers) +{ + return git_strarray_copy(&remote->extra_http_headers, &extra_http_headers); +} + const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n) { return git_vector_get(&remote->refspecs, n); diff --git a/src/remote.h b/src/remote.h index bfb20362b..3a15288f3 100644 --- a/src/remote.h +++ b/src/remote.h @@ -32,7 +32,7 @@ struct git_remote { git_remote_autotag_option_t download_tags; int prune_refs; int passed_refspecs; - git_strarray *extra_http_headers; + git_strarray extra_http_headers; }; const char* git_remote__urlfordirection(struct git_remote *remote, int direction); diff --git a/src/transports/http.c b/src/transports/http.c index 664cd80ab..3cd5632f8 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -974,7 +974,7 @@ static int http_action( if ((!t->connection_data.host || !t->connection_data.port || !t->connection_data.path) && (ret = gitno_connection_data_from_url(&t->connection_data, url, NULL)) < 0) return ret; - t->connection_data.extra_headers = t->owner->owner->extra_http_headers; + t->connection_data.extra_headers = &t->owner->owner->extra_http_headers; if ((ret = http_connect(t)) < 0) return ret; From 24f5b4e155f701c86ad6daecb24b4af83aa183d6 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Tue, 8 Sep 2015 13:34:42 -0400 Subject: [PATCH 05/35] Drop extra_http_headers from git_remote --- include/git2/remote.h | 3 --- src/netops.h | 1 - src/remote.c | 12 ------------ src/remote.h | 1 - src/transports/http.c | 1 - 5 files changed, 18 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 40adca0ce..444fe5276 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -230,9 +230,6 @@ GIT_EXTERN(size_t) git_remote_refspec_count(const git_remote *remote); */ GIT_EXTERN(const git_refspec *)git_remote_get_refspec(const git_remote *remote, size_t n); -GIT_EXTERN(int) git_remote_extra_http_headers(const git_remote *remote, git_strarray *extra_http_headers); -GIT_EXTERN(int) git_remote_set_extra_http_headers(git_remote *remote, const git_strarray extra_http_headers); - /** * Open a connection to a remote * diff --git a/src/netops.h b/src/netops.h index ea1072518..b7170a0f2 100644 --- a/src/netops.h +++ b/src/netops.h @@ -70,7 +70,6 @@ typedef struct gitno_connection_data { char *user; char *pass; bool use_ssl; - git_strarray *extra_headers; } gitno_connection_data; /* diff --git a/src/remote.c b/src/remote.c index b7d82e708..7404bf49f 100644 --- a/src/remote.c +++ b/src/remote.c @@ -1643,8 +1643,6 @@ void git_remote_free(git_remote *remote) free_refspecs(&remote->passive_refspecs); git_vector_free(&remote->passive_refspecs); - git_strarray_free(&remote->extra_http_headers); - git_push_free(remote->push); git__free(remote->url); git__free(remote->pushurl); @@ -2154,16 +2152,6 @@ size_t git_remote_refspec_count(const git_remote *remote) return remote->refspecs.length; } -int git_remote_extra_http_headers(const git_remote *remote, git_strarray *extra_http_headers) -{ - return git_strarray_copy(extra_http_headers, &remote->extra_http_headers); -} - -int git_remote_set_extra_http_headers(git_remote *remote, const git_strarray extra_http_headers) -{ - return git_strarray_copy(&remote->extra_http_headers, &extra_http_headers); -} - const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n) { return git_vector_get(&remote->refspecs, n); diff --git a/src/remote.h b/src/remote.h index 3a15288f3..e696997f4 100644 --- a/src/remote.h +++ b/src/remote.h @@ -32,7 +32,6 @@ struct git_remote { git_remote_autotag_option_t download_tags; int prune_refs; int passed_refspecs; - git_strarray extra_http_headers; }; const char* git_remote__urlfordirection(struct git_remote *remote, int direction); diff --git a/src/transports/http.c b/src/transports/http.c index 3cd5632f8..d348310c1 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -974,7 +974,6 @@ static int http_action( if ((!t->connection_data.host || !t->connection_data.port || !t->connection_data.path) && (ret = gitno_connection_data_from_url(&t->connection_data, url, NULL)) < 0) return ret; - t->connection_data.extra_headers = &t->owner->owner->extra_http_headers; if ((ret = http_connect(t)) < 0) return ret; From 9da32a625564064908b61530318a1366ffff8217 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Tue, 8 Sep 2015 10:18:54 -0400 Subject: [PATCH 06/35] Add custom_headers to git_push_options --- include/git2/remote.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/git2/remote.h b/include/git2/remote.h index 444fe5276..a39e5a415 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -585,6 +585,11 @@ typedef struct { * Callbacks to use for this push operation */ git_remote_callbacks callbacks; + + /** + * Extra headers for this push operation + */ + git_strarray custom_headers; } git_push_options; #define GIT_PUSH_OPTIONS_VERSION 1 From 4f2b6093a64ead32f51a886186496821e003cee5 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Tue, 8 Sep 2015 13:53:41 -0400 Subject: [PATCH 07/35] Tell the git_transport about the custom_headers --- include/git2/remote.h | 3 ++- include/git2/sys/transport.h | 5 +++++ src/push.c | 3 ++- src/push.h | 1 + src/remote.c | 21 ++++++++++++++++----- tests/network/remote/defaultbranch.c | 6 +++--- tests/network/remote/local.c | 8 ++++---- tests/network/remote/remotes.c | 6 +++--- tests/online/fetch.c | 12 ++++++------ tests/online/push.c | 2 +- 10 files changed, 43 insertions(+), 24 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index a39e5a415..9237ca255 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -241,9 +241,10 @@ GIT_EXTERN(const git_refspec *)git_remote_get_refspec(const git_remote *remote, * @param direction GIT_DIRECTION_FETCH if you want to fetch or * GIT_DIRECTION_PUSH if you want to push * @param callbacks the callbacks to use for this connection + * @param custom_headers extra HTTP headers to use in this connection * @return 0 or an error code */ -GIT_EXTERN(int) git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks); +GIT_EXTERN(int) git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_strarray *custom_headers); /** * Get the remote repository's reference advertisement list diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h index 4a75b0832..ca8617f3f 100644 --- a/include/git2/sys/transport.h +++ b/include/git2/sys/transport.h @@ -40,6 +40,11 @@ struct git_transport { git_transport_certificate_check_cb certificate_check_cb, void *payload); + /* Set custom headers for HTTP requests */ + int (*set_custom_headers)( + git_transport *transport, + const git_strarray *custom_headers); + /* Connect the transport to the remote repository, using the given * direction. */ int (*connect)( diff --git a/src/push.c b/src/push.c index a0d8a0550..3c9fa2f1b 100644 --- a/src/push.c +++ b/src/push.c @@ -73,6 +73,7 @@ int git_push_set_options(git_push *push, const git_push_options *opts) GITERR_CHECK_VERSION(opts, GIT_PUSH_OPTIONS_VERSION, "git_push_options"); push->pb_parallelism = opts->pb_parallelism; + push->custom_headers = &opts->custom_headers; return 0; } @@ -638,7 +639,7 @@ int git_push_finish(git_push *push, const git_remote_callbacks *callbacks) int error; if (!git_remote_connected(push->remote) && - (error = git_remote_connect(push->remote, GIT_DIRECTION_PUSH, callbacks)) < 0) + (error = git_remote_connect(push->remote, GIT_DIRECTION_PUSH, callbacks, push->custom_headers)) < 0) return error; if ((error = filter_refs(push->remote)) < 0 || diff --git a/src/push.h b/src/push.h index a847ee0d0..e32ad2f4d 100644 --- a/src/push.h +++ b/src/push.h @@ -38,6 +38,7 @@ struct git_push { /* options */ unsigned pb_parallelism; + const git_strarray *custom_headers; }; /** diff --git a/src/remote.c b/src/remote.c index 7404bf49f..9e907d281 100644 --- a/src/remote.c +++ b/src/remote.c @@ -687,7 +687,15 @@ int set_transport_callbacks(git_transport *t, const git_remote_callbacks *cbs) cbs->certificate_check, cbs->payload); } -int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks) +int set_transport_custom_headers(git_transport *t, const git_strarray *custom_headers) +{ + if (!t->set_custom_headers || !custom_headers) + return 0; + + return t->set_custom_headers(t, custom_headers); +} + +int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_strarray *custom_headers) { git_transport *t; const char *url; @@ -726,6 +734,9 @@ int git_remote_connect(git_remote *remote, git_direction direction, const git_re if (!t && (error = git_transport_new(&t, remote, url)) < 0) return error; + if ((error = set_transport_custom_headers(t, custom_headers)) != 0) + goto on_error; + if ((error = set_transport_callbacks(t, callbacks)) < 0 || (error = t->connect(t, url, credentials, payload, direction, flags)) != 0) goto on_error; @@ -893,7 +904,7 @@ int git_remote_download(git_remote *remote, const git_strarray *refspecs, const } if (!git_remote_connected(remote) && - (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) < 0) + (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, NULL)) < 0) goto on_error; if (ls_to_vector(&refs, remote) < 0) @@ -966,7 +977,7 @@ int git_remote_fetch( } /* Connect and download everything */ - if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) != 0) + if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, NULL)) != 0) return error; error = git_remote_download(remote, refspecs, opts); @@ -2384,7 +2395,7 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi cbs = &opts->callbacks; if (!git_remote_connected(remote) && - (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0) + (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, &opts->custom_headers)) < 0) goto cleanup; free_refspecs(&remote->active_refspecs); @@ -2441,7 +2452,7 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_ assert(remote && refspecs); - if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0) + if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, &opts->custom_headers)) < 0) return error; if ((error = git_remote_upload(remote, refspecs, opts)) < 0) diff --git a/tests/network/remote/defaultbranch.c b/tests/network/remote/defaultbranch.c index e83755ef6..5edd79fb8 100644 --- a/tests/network/remote/defaultbranch.c +++ b/tests/network/remote/defaultbranch.c @@ -26,7 +26,7 @@ static void assert_default_branch(const char *should) { git_buf name = GIT_BUF_INIT; - cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH, NULL)); + cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH, NULL, NULL)); cl_git_pass(git_remote_default_branch(&name, g_remote)); cl_assert_equal_s(should, name.ptr); git_buf_free(&name); @@ -57,7 +57,7 @@ void test_network_remote_defaultbranch__no_default_branch(void) git_buf buf = GIT_BUF_INIT; cl_git_pass(git_remote_create(&remote_b, g_repo_b, "self", git_repository_path(g_repo_b))); - cl_git_pass(git_remote_connect(remote_b, GIT_DIRECTION_FETCH, NULL)); + cl_git_pass(git_remote_connect(remote_b, GIT_DIRECTION_FETCH, NULL, NULL)); cl_git_pass(git_remote_ls(&heads, &len, remote_b)); cl_assert_equal_i(0, len); @@ -80,7 +80,7 @@ void test_network_remote_defaultbranch__detached_sharing_nonbranch_id(void) cl_git_pass(git_reference_create(&ref, g_repo_a, "refs/foo/bar", &id, 1, NULL)); git_reference_free(ref); - cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH, NULL)); + cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH, NULL, NULL)); cl_git_fail_with(GIT_ENOTFOUND, git_remote_default_branch(&buf, g_remote)); cl_git_pass(git_clone(&cloned_repo, git_repository_path(g_repo_a), "./local-detached", NULL)); diff --git a/tests/network/remote/local.c b/tests/network/remote/local.c index 5d726c958..4d990ab71 100644 --- a/tests/network/remote/local.c +++ b/tests/network/remote/local.c @@ -40,7 +40,7 @@ static void connect_to_local_repository(const char *local_repository) git_buf_sets(&file_path_buf, cl_git_path_url(local_repository)); cl_git_pass(git_remote_create_anonymous(&remote, repo, git_buf_cstr(&file_path_buf))); - cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL)); } void test_network_remote_local__connected(void) @@ -214,7 +214,7 @@ void test_network_remote_local__push_to_bare_remote(void) /* Connect to the bare repo */ cl_git_pass(git_remote_create_anonymous(&localremote, repo, "./localbare.git")); - cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL)); + cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL, NULL)); /* Try to push */ cl_git_pass(git_remote_upload(localremote, &push_array, NULL)); @@ -253,7 +253,7 @@ void test_network_remote_local__push_to_bare_remote_with_file_url(void) /* Connect to the bare repo */ cl_git_pass(git_remote_create_anonymous(&localremote, repo, url)); - cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL)); + cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL, NULL)); /* Try to push */ cl_git_pass(git_remote_upload(localremote, &push_array, NULL)); @@ -290,7 +290,7 @@ void test_network_remote_local__push_to_non_bare_remote(void) /* Connect to the bare repo */ cl_git_pass(git_remote_create_anonymous(&localremote, repo, "./localnonbare")); - cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL)); + cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL, NULL)); /* Try to push */ cl_git_fail_with(GIT_EBAREREPO, git_remote_upload(localremote, &push_array, NULL)); diff --git a/tests/network/remote/remotes.c b/tests/network/remote/remotes.c index 2fa21d460..46abc6d33 100644 --- a/tests/network/remote/remotes.c +++ b/tests/network/remote/remotes.c @@ -93,7 +93,7 @@ void test_network_remote_remotes__error_when_no_push_available(void) cl_git_pass(git_remote_create_anonymous(&r, _repo, cl_fixture("testrepo.git"))); callbacks.transport = git_transport_local; - cl_git_pass(git_remote_connect(r, GIT_DIRECTION_PUSH, &callbacks)); + cl_git_pass(git_remote_connect(r, GIT_DIRECTION_PUSH, &callbacks, NULL)); /* Make sure that push is really not available */ r->transport->push = NULL; @@ -359,7 +359,7 @@ void test_network_remote_remotes__can_load_with_an_empty_url(void) cl_assert(remote->url == NULL); cl_assert(remote->pushurl == NULL); - cl_git_fail(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL)); + cl_git_fail(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL)); cl_assert(giterr_last() != NULL); cl_assert(giterr_last()->klass == GITERR_INVALID); @@ -376,7 +376,7 @@ void test_network_remote_remotes__can_load_with_only_an_empty_pushurl(void) cl_assert(remote->url == NULL); cl_assert(remote->pushurl == NULL); - cl_git_fail(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL)); + cl_git_fail(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL)); git_remote_free(remote); } diff --git a/tests/online/fetch.c b/tests/online/fetch.c index 72e7c24e3..c12df069f 100644 --- a/tests/online/fetch.c +++ b/tests/online/fetch.c @@ -81,11 +81,11 @@ void test_online_fetch__fetch_twice(void) { git_remote *remote; cl_git_pass(git_remote_create(&remote, _repo, "test", "git://github.com/libgit2/TestGitRepository.git")); - cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL)); cl_git_pass(git_remote_download(remote, NULL, NULL)); git_remote_disconnect(remote); - git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL); + git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL); cl_git_pass(git_remote_download(remote, NULL, NULL)); git_remote_disconnect(remote); @@ -117,7 +117,7 @@ void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date cl_git_pass(git_repository_open(&_repository, "./fetch/lg2")); cl_git_pass(git_remote_lookup(&remote, _repository, "origin")); - cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL)); cl_assert_equal_i(false, invoked); @@ -155,7 +155,7 @@ void test_online_fetch__can_cancel(void) options.callbacks.transfer_progress = cancel_at_half; options.callbacks.payload = &bytes_received; - cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL)); cl_git_fail_with(git_remote_download(remote, NULL, &options), -4321); git_remote_disconnect(remote); git_remote_free(remote); @@ -169,7 +169,7 @@ void test_online_fetch__ls_disconnected(void) cl_git_pass(git_remote_create(&remote, _repo, "test", "http://github.com/libgit2/TestGitRepository.git")); - cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL)); cl_git_pass(git_remote_ls(&refs, &refs_len_before, remote)); git_remote_disconnect(remote); cl_git_pass(git_remote_ls(&refs, &refs_len_after, remote)); @@ -187,7 +187,7 @@ void test_online_fetch__remote_symrefs(void) cl_git_pass(git_remote_create(&remote, _repo, "test", "http://github.com/libgit2/TestGitRepository.git")); - cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL)); git_remote_disconnect(remote); cl_git_pass(git_remote_ls(&refs, &refs_len, remote)); diff --git a/tests/online/push.c b/tests/online/push.c index 0b0892c97..13d364d30 100644 --- a/tests/online/push.c +++ b/tests/online/push.c @@ -373,7 +373,7 @@ void test_online_push__initialize(void) record_callbacks_data_clear(&_record_cbs_data); - cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH, &_record_cbs)); + cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH, &_record_cbs, NULL)); /* Clean up previously pushed branches. Fails if receive.denyDeletes is * set on the remote. Also, on Git 1.7.0 and newer, you must run From 276f6aa08d4cb35ad647b24bfa254b99af89e076 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Tue, 8 Sep 2015 14:00:37 -0400 Subject: [PATCH 08/35] Hook up the custom_headers to the http transport --- src/transports/http.c | 7 +++---- src/transports/smart.c | 12 ++++++++++++ src/transports/smart.h | 1 + 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/transports/http.c b/src/transports/http.c index d348310c1..764c6a97e 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -211,10 +211,9 @@ static int gen_request( } else git_buf_puts(buf, "Accept: */*\r\n"); - if (t->connection_data.extra_headers) { - for (i = 0; i < t->connection_data.extra_headers->count; i++) { - git_buf_puts(buf, t->connection_data.extra_headers->strings[i]); - git_buf_puts(buf, "\r\n"); + if (t->owner->custom_headers) { + for (i = 0; i < t->owner->custom_headers->count; i++) { + git_buf_printf(buf, "%s\r\n", t->owner->custom_headers->strings[i]); } } diff --git a/src/transports/smart.c b/src/transports/smart.c index 31a2dec7b..15f45e11c 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -66,6 +66,17 @@ static int git_smart__set_callbacks( return 0; } +static int git_smart__set_custom_headers( + git_transport *transport, + const git_strarray *custom_headers) +{ + transport_smart *t = (transport_smart *)transport; + + t->custom_headers = custom_headers; + + return 0; +} + int git_smart__update_heads(transport_smart *t, git_vector *symrefs) { size_t i; @@ -399,6 +410,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) t->parent.version = GIT_TRANSPORT_VERSION; t->parent.set_callbacks = git_smart__set_callbacks; + t->parent.set_custom_headers = git_smart__set_custom_headers; t->parent.connect = git_smart__connect; t->parent.close = git_smart__close; t->parent.free = git_smart__free; diff --git a/src/transports/smart.h b/src/transports/smart.h index 4c728c7cc..2c87e0200 100644 --- a/src/transports/smart.h +++ b/src/transports/smart.h @@ -139,6 +139,7 @@ typedef struct { git_transport_message_cb error_cb; git_transport_certificate_check_cb certificate_check_cb; void *message_cb_payload; + const git_strarray *custom_headers; git_smart_subtransport *wrapped; git_smart_subtransport_stream *current_stream; transport_smart_caps caps; From 80ee25434d076b87d1a34e2dee467600013ae4ee Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Tue, 8 Sep 2015 13:38:22 -0400 Subject: [PATCH 09/35] Teach winhttp about the extra headers --- src/transports/winhttp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 0c43c4b0b..d28762db1 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -409,6 +409,23 @@ static int winhttp_stream_connect(winhttp_stream *s) } } + if (t->owner->custom_headers) { + for (i = 0; i < t->owner->custom_headers->count; i++) { + git_buf_clear(&buf); + git_buf_puts(&buf, t->owner->custom_headers->strings[i]); + if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) { + giterr_set(GITERR_OS, "Failed to convert custom header to wide characters"); + goto on_error; + } + + if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L, + WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { + giterr_set(GITERR_OS, "Failed to add a header to the request"); + goto on_error; + } + } + } + /* If requested, disable certificate validation */ if (t->connection_data.use_ssl) { int flags; From 5d7cd57f9950fca5c60176c5b5a3673358386a05 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Tue, 8 Sep 2015 14:15:29 -0400 Subject: [PATCH 10/35] Update another call to git_remote_connect --- examples/network/ls-remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/network/ls-remote.c b/examples/network/ls-remote.c index 21026562f..c9da79f5f 100644 --- a/examples/network/ls-remote.c +++ b/examples/network/ls-remote.c @@ -26,7 +26,7 @@ static int use_remote(git_repository *repo, char *name) */ callbacks.credentials = cred_acquire_cb; - error = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks); + error = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks, NULL); if (error < 0) goto cleanup; From c82c2ba60f63095a3b418424d858277f5800b914 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Tue, 8 Sep 2015 14:17:59 -0400 Subject: [PATCH 11/35] o i --- src/transports/winhttp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index d28762db1..8e2bdd44f 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -277,6 +277,7 @@ static int winhttp_stream_connect(winhttp_stream *s) unsigned long disable_redirects = WINHTTP_DISABLE_REDIRECTS; int default_timeout = TIMEOUT_INFINITE; int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT; + int i; /* Prepare URL */ git_buf_printf(&buf, "%s%s", t->connection_data.path, s->service_url); From c49126c87f1124d0928d68d9191535e5ef4ecd25 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Thu, 10 Sep 2015 08:34:35 -0400 Subject: [PATCH 12/35] Accept custom headers for fetch too --- include/git2/remote.h | 5 +++++ src/remote.c | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 9237ca255..c42d96710 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -547,6 +547,11 @@ typedef struct { * The default is to auto-follow tags. */ git_remote_autotag_option_t download_tags; + + /** + * Extra headers for this fetch operation + */ + git_strarray custom_headers; } git_fetch_options; #define GIT_FETCH_OPTIONS_VERSION 1 diff --git a/src/remote.c b/src/remote.c index 9e907d281..a374a84b3 100644 --- a/src/remote.c +++ b/src/remote.c @@ -895,16 +895,18 @@ int git_remote_download(git_remote *remote, const git_strarray *refspecs, const size_t i; git_vector *to_active, specs = GIT_VECTOR_INIT, refs = GIT_VECTOR_INIT; const git_remote_callbacks *cbs = NULL; + const git_strarray *custom_headers = NULL; assert(remote); if (opts) { GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks"); cbs = &opts->callbacks; + custom_headers = &opts->custom_headers; } if (!git_remote_connected(remote) && - (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, NULL)) < 0) + (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, custom_headers)) < 0) goto on_error; if (ls_to_vector(&refs, remote) < 0) @@ -968,16 +970,18 @@ int git_remote_fetch( bool prune = false; git_buf reflog_msg_buf = GIT_BUF_INIT; const git_remote_callbacks *cbs = NULL; + const git_strarray *custom_headers = NULL; if (opts) { GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks"); cbs = &opts->callbacks; + custom_headers = &opts->custom_headers; update_fetchhead = opts->update_fetchhead; tagopt = opts->download_tags; } /* Connect and download everything */ - if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, NULL)) != 0) + if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, custom_headers)) != 0) return error; error = git_remote_download(remote, refspecs, opts); From 35969c6839c0659ed3ced67bfc5b963662a721f2 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Thu, 10 Sep 2015 08:58:23 -0400 Subject: [PATCH 13/35] Ignore NULL headers --- src/transports/http.c | 3 ++- src/transports/winhttp.c | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/transports/http.c b/src/transports/http.c index 764c6a97e..73ea05043 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -213,7 +213,8 @@ static int gen_request( if (t->owner->custom_headers) { for (i = 0; i < t->owner->custom_headers->count; i++) { - git_buf_printf(buf, "%s\r\n", t->owner->custom_headers->strings[i]); + if (t->owner->custom_headers->strings[i]) + git_buf_printf(buf, "%s\r\n", t->owner->custom_headers->strings[i]); } } diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 8e2bdd44f..5b00d9091 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -412,17 +412,19 @@ static int winhttp_stream_connect(winhttp_stream *s) if (t->owner->custom_headers) { for (i = 0; i < t->owner->custom_headers->count; i++) { - git_buf_clear(&buf); - git_buf_puts(&buf, t->owner->custom_headers->strings[i]); - if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) { - giterr_set(GITERR_OS, "Failed to convert custom header to wide characters"); - goto on_error; - } + if (t->owner->custom_headers->strings[i]) { + git_buf_clear(&buf); + git_buf_puts(&buf, t->owner->custom_headers->strings[i]); + if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) { + giterr_set(GITERR_OS, "Failed to convert custom header to wide characters"); + goto on_error; + } - if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L, - WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { - giterr_set(GITERR_OS, "Failed to add a header to the request"); - goto on_error; + if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L, + WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { + giterr_set(GITERR_OS, "Failed to add a header to the request"); + goto on_error; + } } } } From 8c876fa91d0783bf4e1f0e624b2dfa86574de4e3 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Thu, 10 Sep 2015 09:11:16 -0400 Subject: [PATCH 14/35] Validate custom http headers --- src/transports/smart.c | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/transports/smart.c b/src/transports/smart.c index 15f45e11c..ee49729aa 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -66,11 +66,64 @@ static int git_smart__set_callbacks( return 0; } +bool is_valid(const char *custom_header) +{ + const char *c; + int name_len; + + if (custom_header == NULL) + return true; + + // Disallow \r and \n + c = strchr(custom_header, '\r'); + if (c != NULL) + return false; + c = strchr(custom_header, '\n'); + if (c != NULL) + return false; + + // Require a header name followed by : + c = strchr(custom_header, ':'); + if (c == NULL) + return false; + name_len = c - custom_header; + if (name_len < 1) + return false; + + // Disallow headers that we set + return git__strncmp("User-Agent", custom_header, name_len) == 0 && + git__strncmp("Host", custom_header, name_len) == 0 && + git__strncmp("Accept", custom_header, name_len) == 0 && + git__strncmp("Content-Type", custom_header, name_len) == 0 && + git__strncmp("Transfer-Encoding", custom_header, name_len) == 0 && + git__strncmp("Content-Length", custom_header, name_len) == 0; +} + +const char *find_invalid_header(const git_strarray *custom_headers) +{ + size_t i; + + if (custom_headers == NULL || custom_headers->count == 0) + return NULL; + + for (i = 0; i < custom_headers->count; i++) + if (!is_valid(custom_headers->strings[i])) + return custom_headers->strings[i]; + + return NULL; +} + static int git_smart__set_custom_headers( git_transport *transport, const git_strarray *custom_headers) { transport_smart *t = (transport_smart *)transport; + const char *invalid_header = find_invalid_header(custom_headers); + + if (invalid_header != NULL) { + giterr_set(GITERR_INVALID, "Illegal HTTP header '%s'", invalid_header); + return -1; + } t->custom_headers = custom_headers; From 66d90e7098ee2da76ff3351a305a17a38fb9282b Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Thu, 10 Sep 2015 09:14:20 -0400 Subject: [PATCH 15/35] More specific names --- src/transports/smart.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/transports/smart.c b/src/transports/smart.c index ee49729aa..b4f8578db 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -66,7 +66,7 @@ static int git_smart__set_callbacks( return 0; } -bool is_valid(const char *custom_header) +bool is_valid_custom_header(const char *custom_header) { const char *c; int name_len; @@ -99,7 +99,7 @@ bool is_valid(const char *custom_header) git__strncmp("Content-Length", custom_header, name_len) == 0; } -const char *find_invalid_header(const git_strarray *custom_headers) +const char *find_invalid_custom_header(const git_strarray *custom_headers) { size_t i; @@ -107,7 +107,7 @@ const char *find_invalid_header(const git_strarray *custom_headers) return NULL; for (i = 0; i < custom_headers->count; i++) - if (!is_valid(custom_headers->strings[i])) + if (!is_valid_custom_header(custom_headers->strings[i])) return custom_headers->strings[i]; return NULL; @@ -118,7 +118,7 @@ static int git_smart__set_custom_headers( const git_strarray *custom_headers) { transport_smart *t = (transport_smart *)transport; - const char *invalid_header = find_invalid_header(custom_headers); + const char *invalid_header = find_invalid_custom_header(custom_headers); if (invalid_header != NULL) { giterr_set(GITERR_INVALID, "Illegal HTTP header '%s'", invalid_header); From 3245896bb7527cb42d48faf68f33858c887f2b3d Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Thu, 10 Sep 2015 13:18:26 -0400 Subject: [PATCH 16/35] Add a test for custom header validation Also, *some* custom headers actually are valid. --- src/transports/smart.c | 18 ++++++++++++------ tests/online/clone.c | 27 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/transports/smart.c b/src/transports/smart.c index b4f8578db..8388d9dc5 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -66,6 +66,10 @@ static int git_smart__set_callbacks( return 0; } +#define forbid_custom_header(disallowed_name) \ + if (strncmp(disallowed_name, custom_header, name_len) == 0) \ + return false + bool is_valid_custom_header(const char *custom_header) { const char *c; @@ -91,12 +95,14 @@ bool is_valid_custom_header(const char *custom_header) return false; // Disallow headers that we set - return git__strncmp("User-Agent", custom_header, name_len) == 0 && - git__strncmp("Host", custom_header, name_len) == 0 && - git__strncmp("Accept", custom_header, name_len) == 0 && - git__strncmp("Content-Type", custom_header, name_len) == 0 && - git__strncmp("Transfer-Encoding", custom_header, name_len) == 0 && - git__strncmp("Content-Length", custom_header, name_len) == 0; + forbid_custom_header("User-Agent"); + forbid_custom_header("Host"); + forbid_custom_header("Accept"); + forbid_custom_header("Content-Type"); + forbid_custom_header("Transfer-Encoding"); + forbid_custom_header("Content-Length"); + + return true; } const char *find_invalid_custom_header(const git_strarray *custom_headers) diff --git a/tests/online/clone.c b/tests/online/clone.c index 225b3abe2..b84be405c 100644 --- a/tests/online/clone.c +++ b/tests/online/clone.c @@ -213,6 +213,33 @@ void test_online_clone__custom_remote_callbacks(void) cl_assert(callcount > 0); } +void test_online_clone__custom_headers(void) +{ + char *empty_header = ""; + char *unnamed_header = "this is a header about nothing"; + char *newlines = "X-Custom: almost OK\n"; + char *conflict = "Accept: defined-by-git"; + char *ok = "X-Custom: this should be ok"; + + g_options.fetch_opts.custom_headers.count = 1; + + g_options.fetch_opts.custom_headers.strings = &empty_header; + cl_git_fail(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); + + g_options.fetch_opts.custom_headers.strings = &unnamed_header; + cl_git_fail(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); + + g_options.fetch_opts.custom_headers.strings = &newlines; + cl_git_fail(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); + + g_options.fetch_opts.custom_headers.strings = &conflict; + cl_git_fail(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); + + /* Finally, we got it right! */ + g_options.fetch_opts.custom_headers.strings = &ok; + cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); +} + static int cred_failure_cb( git_cred **cred, const char *url, From d29c5412aa91b279b1b2db4fe57dd6fe71272b91 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Thu, 10 Sep 2015 14:16:39 -0400 Subject: [PATCH 17/35] Avoid segfault when opts == NULL --- src/remote.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/remote.c b/src/remote.c index a374a84b3..ce6e13b3d 100644 --- a/src/remote.c +++ b/src/remote.c @@ -2392,14 +2392,17 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi git_push *push; git_refspec *spec; const git_remote_callbacks *cbs = NULL; + const git_strarray *custom_headers = NULL; assert(remote); - if (opts) + if (opts) { cbs = &opts->callbacks; + custom_headers = &opts->custom_headers; + } if (!git_remote_connected(remote) && - (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, &opts->custom_headers)) < 0) + (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, custom_headers)) < 0) goto cleanup; free_refspecs(&remote->active_refspecs); @@ -2448,15 +2451,17 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_ { int error; const git_remote_callbacks *cbs = NULL; + const git_strarray *custom_headers = NULL; if (opts) { GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks"); cbs = &opts->callbacks; + custom_headers = &opts->custom_headers; } assert(remote && refspecs); - if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, &opts->custom_headers)) < 0) + if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, custom_headers)) < 0) return error; if ((error = git_remote_upload(remote, refspecs, opts)) < 0) From e8ddd8d76c119903677b5d0c638c875023ae6784 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 17 Sep 2015 17:49:32 -0400 Subject: [PATCH 18/35] repo::reservedname: test a submodule update Test an initial submodule update, where we are trying to checkout the submodule for the first time, and placing a file within the submodule working directory with the same name as the submodule (and consequently, the same name as the repository itself). --- tests/repo/reservedname.c | 24 ++++++++++++++++++ tests/resources/sub.git/HEAD | Bin 0 -> 23 bytes tests/resources/sub.git/config | Bin 0 -> 157 bytes tests/resources/sub.git/index | Bin 0 -> 405 bytes tests/resources/sub.git/logs/HEAD | Bin 0 -> 174 bytes .../resources/sub.git/logs/refs/heads/master | Bin 0 -> 174 bytes .../10/ddd6d257e01349d514541981aeecea6b2e741d | Bin 0 -> 22 bytes .../17/6a458f94e0ea5272ce67c36bf30b6be9caf623 | Bin 0 -> 28 bytes .../94/c7d78d85c933d1d95b56bc2de01833ba8559fb | Bin 0 -> 132 bytes .../b7/a59b3f4ea13b985f8a1e0d3757d5cd3331add8 | Bin 0 -> 139 bytes .../d0/ee23c41b28746d7e822511d7838bce784ae773 | Bin 0 -> 54 bytes tests/resources/sub.git/refs/heads/master | Bin 0 -> 41 bytes tests/resources/super/.gitted/COMMIT_EDITMSG | Bin 0 -> 10 bytes tests/resources/super/.gitted/HEAD | Bin 0 -> 23 bytes tests/resources/super/.gitted/config | Bin 0 -> 193 bytes tests/resources/super/.gitted/index | Bin 0 -> 217 bytes .../51/589c218bf77a8da9e9d8dbc097d76a742726c4 | Bin 0 -> 90 bytes .../79/d0d58ca6aa1688a073d280169908454cad5b91 | Bin 0 -> 132 bytes .../d7/57768b570a83e80d02edcc1032db14573e5034 | Bin 0 -> 87 bytes .../resources/super/.gitted/refs/heads/master | Bin 0 -> 41 bytes tests/resources/super/gitmodules | Bin 0 -> 48 bytes tests/submodule/submodule_helpers.c | 16 ++++++++++++ tests/submodule/submodule_helpers.h | 1 + 23 files changed, 41 insertions(+) create mode 100644 tests/resources/sub.git/HEAD create mode 100644 tests/resources/sub.git/config create mode 100644 tests/resources/sub.git/index create mode 100644 tests/resources/sub.git/logs/HEAD create mode 100644 tests/resources/sub.git/logs/refs/heads/master create mode 100644 tests/resources/sub.git/objects/10/ddd6d257e01349d514541981aeecea6b2e741d create mode 100644 tests/resources/sub.git/objects/17/6a458f94e0ea5272ce67c36bf30b6be9caf623 create mode 100644 tests/resources/sub.git/objects/94/c7d78d85c933d1d95b56bc2de01833ba8559fb create mode 100644 tests/resources/sub.git/objects/b7/a59b3f4ea13b985f8a1e0d3757d5cd3331add8 create mode 100644 tests/resources/sub.git/objects/d0/ee23c41b28746d7e822511d7838bce784ae773 create mode 100644 tests/resources/sub.git/refs/heads/master create mode 100644 tests/resources/super/.gitted/COMMIT_EDITMSG create mode 100644 tests/resources/super/.gitted/HEAD create mode 100644 tests/resources/super/.gitted/config create mode 100644 tests/resources/super/.gitted/index create mode 100644 tests/resources/super/.gitted/objects/51/589c218bf77a8da9e9d8dbc097d76a742726c4 create mode 100644 tests/resources/super/.gitted/objects/79/d0d58ca6aa1688a073d280169908454cad5b91 create mode 100644 tests/resources/super/.gitted/objects/d7/57768b570a83e80d02edcc1032db14573e5034 create mode 100644 tests/resources/super/.gitted/refs/heads/master create mode 100644 tests/resources/super/gitmodules diff --git a/tests/repo/reservedname.c b/tests/repo/reservedname.c index faea0cc2b..2a5b38239 100644 --- a/tests/repo/reservedname.c +++ b/tests/repo/reservedname.c @@ -106,3 +106,27 @@ void test_repo_reservedname__submodule_pointer(void) git_repository_free(sub_repo); #endif } + +/* Like the `submodule_pointer` test (above), this ensures that we do not + * follow the gitlink to the submodule's repository location and treat that + * as a reserved name. This tests at an initial submodule update, where the + * submodule repo is being created. + */ +void test_repo_reservedname__submodule_pointer_during_create(void) +{ + git_repository *repo; + git_submodule *sm; + git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT; + git_buf url = GIT_BUF_INIT; + + repo = setup_fixture_super(); + + cl_git_pass(git_buf_joinpath(&url, clar_sandbox_path(), "sub.git")); + cl_repo_set_string(repo, "submodule.sub.url", url.ptr); + + cl_git_pass(git_submodule_lookup(&sm, repo, "sub")); + cl_git_pass(git_submodule_update(sm, 1, &update_options)); + + git_submodule_free(sm); + git_buf_free(&url); +} diff --git a/tests/resources/sub.git/HEAD b/tests/resources/sub.git/HEAD new file mode 100644 index 0000000000000000000000000000000000000000..cb089cd89a7d7686d284d8761201649346b5aa1c GIT binary patch literal 23 ecmXR)O|w!cN=+-)&qz&7Db~+TEG|hc;sO9;xClW2 literal 0 HcmV?d00001 diff --git a/tests/resources/sub.git/config b/tests/resources/sub.git/config new file mode 100644 index 0000000000000000000000000000000000000000..78387c50b472d8c0cdaeca4b56bf23c5b7f791df GIT binary patch literal 157 zcmYj~F%H5o3`OVU6g@&Oz=mM#0T6>}oMPd`mF*(s_9TLV@qN9ge_KWI9)sd8MlRa2 zXaRqt8cCf_(;P!4#v%zjWnjY?9-x23vH`PVKK2BT);-swYt{-=eU0H4(pLN73O4eu U^rVDm@k>7$ViLcSFO^&T0N7wQ1ONa4 literal 0 HcmV?d00001 diff --git a/tests/resources/sub.git/index b/tests/resources/sub.git/index new file mode 100644 index 0000000000000000000000000000000000000000..54be69e33e1917169be0a3fbaba5fd61746ea15a GIT binary patch literal 405 zcmZ?q402{*U|<4bmeAiS$AL5hkUj;X5ukAig3Z7yp5@v<<-x0SOTvLu;?`=J4eDP*<*dE;n62`k)BYy+6Fc>Nra9wz(d_-EKB)6_f kRq%Rq_qhtM=fz>Ee_l3S@LMBvbgC8SC8;G(PQUH}02WnsssI20 literal 0 HcmV?d00001 diff --git a/tests/resources/sub.git/logs/HEAD b/tests/resources/sub.git/logs/HEAD new file mode 100644 index 0000000000000000000000000000000000000000..f636268f6fd72e083ae31c48aa7ad90d6e238f08 GIT binary patch literal 174 zcma*bK?*`45P;!zonn@?DAZB(MMRqx?Yn?FN&~5&Qr9nd7wBJo{6hQ}1nbQbFze(c zhQ*oeyi9`78cQY;B1%u>;6@+c2_DZ@Myqg6bJewQ>}|9>kFk{tNUfDo3YCI`&_Zl} XxA24=SDx%&`xD$(K~HZU-0JoVU8^zE literal 0 HcmV?d00001 diff --git a/tests/resources/sub.git/logs/refs/heads/master b/tests/resources/sub.git/logs/refs/heads/master new file mode 100644 index 0000000000000000000000000000000000000000..f636268f6fd72e083ae31c48aa7ad90d6e238f08 GIT binary patch literal 174 zcma*bK?*`45P;!zonn@?DAZB(MMRqx?Yn?FN&~5&Qr9nd7wBJo{6hQ}1nbQbFze(c zhQ*oeyi9`78cQY;B1%u>;6@+c2_DZ@Myqg6bJewQ>}|9>kFk{tNUfDo3YCI`&_Zl} XxA24=SDx%&`xD$(K~HZU-0JoVU8^zE literal 0 HcmV?d00001 diff --git a/tests/resources/sub.git/objects/10/ddd6d257e01349d514541981aeecea6b2e741d b/tests/resources/sub.git/objects/10/ddd6d257e01349d514541981aeecea6b2e741d new file mode 100644 index 0000000000000000000000000000000000000000..a095b3fb822e3cde46d5d39ff21528c1e1fc70cf GIT binary patch literal 22 ecmb7F=sF|FfcPQQP4}zEJ-XWDauSLElDkA5YKY$pYq^UP|>;c z!`Yv?vtOS2rVLe?n3rFYky@lzQc=PnaQE7!@CU-4S4Bc38`r&gm91AI3sshunUjiB mjfnveC={0_F?TvpB(Aj# zP#zDX=M3Jai6%!5lQ)JGd5n0DNmG`}854s;^h*@sHCFC$qfh7rkCp4j4d%StA6;un toi|>_DRI4kvR0$kMr$}qE2Y@&J|6jxgt)gdN_axg@3Iwc;tNWyL3_OFJ+1%% literal 0 HcmV?d00001 diff --git a/tests/resources/sub.git/objects/d0/ee23c41b28746d7e822511d7838bce784ae773 b/tests/resources/sub.git/objects/d0/ee23c41b28746d7e822511d7838bce784ae773 new file mode 100644 index 0000000000000000000000000000000000000000..d9bb9c84d8053600309e1bd6393d26b61c47bd78 GIT binary patch literal 54 zcmV-60LlM&0V^p=O;s>9XD~D{Ff%bxNY2R2Nzp5*C}9w|d+k#A17XjrA|aBE>)yP| M)+><(08@Jq$s_(2XaE2J literal 0 HcmV?d00001 diff --git a/tests/resources/sub.git/refs/heads/master b/tests/resources/sub.git/refs/heads/master new file mode 100644 index 0000000000000000000000000000000000000000..0e4d6e2a7897e667e388557d25a9c64e9bf2096f GIT binary patch literal 41 ucmV~$!4Uu;2m`Rc)5z5xFb-JUe*}~EVm98HGIR!Cl+6~LE?xn!l45=I^9x=8 literal 0 HcmV?d00001 diff --git a/tests/resources/super/.gitted/COMMIT_EDITMSG b/tests/resources/super/.gitted/COMMIT_EDITMSG new file mode 100644 index 0000000000000000000000000000000000000000..e2d6b8987e3c26ce8b4444db8fe855acf8644936 GIT binary patch literal 10 RcmXReP0GzrDa}dc0st2(1KR)q literal 0 HcmV?d00001 diff --git a/tests/resources/super/.gitted/HEAD b/tests/resources/super/.gitted/HEAD new file mode 100644 index 0000000000000000000000000000000000000000..cb089cd89a7d7686d284d8761201649346b5aa1c GIT binary patch literal 23 ecmXR)O|w!cN=+-)&qz&7Db~+TEG|hc;sO9;xClW2 literal 0 HcmV?d00001 diff --git a/tests/resources/super/.gitted/config b/tests/resources/super/.gitted/config new file mode 100644 index 0000000000000000000000000000000000000000..06a8b77907e29ad26fcf19724b9c70d364c639fd GIT binary patch literal 193 zcmYk0K@NgI3`N(>DF_EZFW}DT(gP3|1Jl9AG9_(?gxg!93wQlL@8@-xSl}5Nft3}F zWzQ^2v<*a&OM7Y0p~*-50|0K8oKE=iM{R9FHCS{ySd~56Wbl_QD_f?*3rF{pzZwZ{Ld=nOy8e8_cL1f08=GFZU6uP literal 0 HcmV?d00001 diff --git a/tests/resources/super/.gitted/index b/tests/resources/super/.gitted/index new file mode 100644 index 0000000000000000000000000000000000000000..cc2ffffb980f6eade02621e7431faffc830c96e9 GIT binary patch literal 217 zcmZ?q402{*U|<5_(BFmvK$-zYgV+$zxCF)m(!qfda}>M3SM{!ZdE@qh>DRML)YXnK zaOp0i)X@;dTKg{30SZ^EfSPb1kPO Nt$y+J!W`S|A^_*II9C7w literal 0 HcmV?d00001 diff --git a/tests/resources/super/.gitted/objects/51/589c218bf77a8da9e9d8dbc097d76a742726c4 b/tests/resources/super/.gitted/objects/51/589c218bf77a8da9e9d8dbc097d76a742726c4 new file mode 100644 index 0000000000000000000000000000000000000000..727d3a696894fe8d07899ae0b520da02596720cd GIT binary patch literal 90 zcmV-g0HyzU0ZYosPg1ZjW{55>P0GzrDa}b$Py#ZQV!1dA5=$}^Y!!e!F3!@T93V5< wDkdg9vm_=aCo>618|fOy#FV5KmlVgu6r~pDmlh?b0+~P!dO%q&0A7+GCFlAeGXMYp literal 0 HcmV?d00001 diff --git a/tests/resources/super/.gitted/objects/79/d0d58ca6aa1688a073d280169908454cad5b91 b/tests/resources/super/.gitted/objects/79/d0d58ca6aa1688a073d280169908454cad5b91 new file mode 100644 index 0000000000000000000000000000000000000000..7fd889d5f1cfe79f0b769d2682e3f5a888f0fa3b GIT binary patch literal 132 zcmV-~0DJ#<0i}&e3IZ_@06pgw{Q;%3nFxb;@dth&Nw>^^u^|h7-|-FJiaJyksdXEm zV?2z;3>16_=a_xK6fH+2G)$#vw1%>FK3Mi>ol0}8(%?>?)CeA{)GlvWc(*^g)vYw? m@*Jlk^$OZKAU@$Z=Ff%bx&`ZxO$<0qG%}Fh02#lDc*!{h#cje0)w+~Fe to>ii*cEr%k00$tl#o29h3`5|2fC0kl5aFs~UyWIQVG`1<2i3UdGe literal 0 HcmV?d00001 diff --git a/tests/resources/super/gitmodules b/tests/resources/super/gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..a3d8f7f5afa24d79f145cf902746e684d1446290 GIT binary patch literal 48 ycmazpE=|hKPbtkwRZs#lm14O#3ld8*6l@iMJTA`Cq8uPoPfs7n(@W1R;Q|1ItPb)3 literal 0 HcmV?d00001 diff --git a/tests/submodule/submodule_helpers.c b/tests/submodule/submodule_helpers.c index 1dc687231..cde69d92d 100644 --- a/tests/submodule/submodule_helpers.c +++ b/tests/submodule/submodule_helpers.c @@ -126,6 +126,22 @@ git_repository *setup_fixture_submod2(void) return repo; } +git_repository *setup_fixture_super(void) +{ + git_repository *repo = cl_git_sandbox_init("super"); + + cl_fixture_sandbox("sub.git"); + p_mkdir("super/sub", 0777); + + rewrite_gitmodules(git_repository_workdir(repo)); + + cl_set_cleanup(cleanup_fixture_submodules, "sub.git"); + + cl_git_pass(git_repository_reinit_filesystem(repo, 1)); + + return repo; +} + git_repository *setup_fixture_submodule_simple(void) { git_repository *repo = cl_git_sandbox_init("submodule_simple"); diff --git a/tests/submodule/submodule_helpers.h b/tests/submodule/submodule_helpers.h index 1493f245f..1191ab35b 100644 --- a/tests/submodule/submodule_helpers.h +++ b/tests/submodule/submodule_helpers.h @@ -4,6 +4,7 @@ extern void rewrite_gitmodules(const char *workdir); extern git_repository *setup_fixture_submodules(void); extern git_repository *setup_fixture_submod2(void); extern git_repository *setup_fixture_submodule_simple(void); +extern git_repository *setup_fixture_super(void); extern unsigned int get_submodule_status(git_repository *, const char *); From 538dfc8816087f3952f499212f1564336b2cba87 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 17 Sep 2015 18:12:05 -0400 Subject: [PATCH 19/35] repository: only reserve repo dirs in the workdir Check that the repository directory is beneath the workdir before adding it to the list of reserved paths. If it is not, then there is no possibility of checking out files into it, and it should not be a reserved word. This is a particular problem with submodules where the repo directory may be in the super's .git directory. --- src/repository.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/repository.c b/src/repository.c index 0f37cfbfe..cbdfd5826 100644 --- a/src/repository.c +++ b/src/repository.c @@ -908,12 +908,28 @@ bool git_repository__reserved_names( buf->size = git_repository__reserved_names_win32[i].size; } - /* Try to add any repo-specific reserved names */ + /* Try to add any repo-specific reserved names - the gitlink file + * within a submodule or the repository (if the repository directory + * is beneath the workdir). These are typically `.git`, but should + * be protected in case they are not. Note, repo and workdir paths + * are always prettified to end in `/`, so a prefixcmp is safe. + */ if (!repo->is_bare) { - const char *reserved_path = repo->path_gitlink ? - repo->path_gitlink : repo->path_repository; + int (*prefixcmp)(const char *, const char *); + int error, ignorecase; - if (reserved_names_add8dot3(repo, reserved_path) < 0) + error = git_repository__cvar( + &ignorecase, repo, GIT_CVAR_IGNORECASE); + prefixcmp = (error || ignorecase) ? git__prefixcmp_icase : + git__prefixcmp; + + if (repo->path_gitlink && + reserved_names_add8dot3(repo, repo->path_gitlink) < 0) + goto on_error; + + if (repo->path_repository && + prefixcmp(repo->path_repository, repo->workdir) == 0 && + reserved_names_add8dot3(repo, repo->path_repository) < 0) goto on_error; } } From 92a47824d8d4dc62728ebb4ec1962ec03ae92d85 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 22 Sep 2015 23:10:56 -0400 Subject: [PATCH 20/35] win32: propogate filename too long errors --- src/win32/path_w32.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/win32/path_w32.c b/src/win32/path_w32.c index 118e8bcc5..40b95c33b 100644 --- a/src/win32/path_w32.c +++ b/src/win32/path_w32.c @@ -198,13 +198,13 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) /* See if this is an absolute path (beginning with a drive letter) */ if (path__is_absolute(src)) { if (git__utf8_to_16(dest, MAX_PATH, src) < 0) - return -1; + goto on_error; } /* File-prefixed NT-style paths beginning with \\?\ */ else if (path__is_nt_namespace(src)) { /* Skip the NT prefix, the destination already contains it */ if (git__utf8_to_16(dest, MAX_PATH, src + PATH__NT_NAMESPACE_LEN) < 0) - return -1; + goto on_error; } /* UNC paths */ else if (path__is_unc(src)) { @@ -213,36 +213,43 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) /* Skip the leading "\\" */ if (git__utf8_to_16(dest, MAX_PATH - 2, src + 2) < 0) - return -1; + goto on_error; } /* Absolute paths omitting the drive letter */ else if (src[0] == '\\' || src[0] == '/') { if (path__cwd(dest, MAX_PATH) < 0) - return -1; + goto on_error; if (!path__is_absolute(dest)) { errno = ENOENT; - return -1; + goto on_error; } /* Skip the drive letter specification ("C:") */ if (git__utf8_to_16(dest + 2, MAX_PATH - 2, src) < 0) - return -1; + goto on_error; } /* Relative paths */ else { int cwd_len; if ((cwd_len = git_win32_path__cwd(dest, MAX_PATH)) < 0) - return -1; + goto on_error; dest[cwd_len++] = L'\\'; if (git__utf8_to_16(dest + cwd_len, MAX_PATH - cwd_len, src) < 0) - return -1; + goto on_error; } return git_win32_path_canonicalize(out); + +on_error: + /* set windows error code so we can use its error message */ + if (errno == ENAMETOOLONG) + SetLastError(ERROR_FILENAME_EXCED_RANGE); + + return -1; } int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src) From 9768ebb1f385a1e26c317814951042089f6a65e9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 22 Sep 2015 23:24:30 -0400 Subject: [PATCH 21/35] win32: test checkout msg on long path err --- tests/win32/longpath.c | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 tests/win32/longpath.c diff --git a/tests/win32/longpath.c b/tests/win32/longpath.c new file mode 100644 index 000000000..4fe851c2a --- /dev/null +++ b/tests/win32/longpath.c @@ -0,0 +1,62 @@ +#include "clar_libgit2.h" + +#include "git2/clone.h" +#include "clone.h" +#include "buffer.h" +#include "fileops.h" + +static git_buf path = GIT_BUF_INIT; + +void test_win32_longpath__initialize(void) +{ +#ifdef GIT_WIN32 + const char *base = clar_sandbox_path(); + size_t base_len = strlen(base); + size_t remain = MAX_PATH - base_len; + size_t i; + + git_buf_clear(&path); + git_buf_puts(&path, base); + git_buf_putc(&path, '/'); + + cl_assert(remain < (MAX_PATH - 5)); + + for (i = 0; i < (remain - 5); i++) + git_buf_putc(&path, 'a'); + + printf("%s %" PRIuZ "\n", path.ptr, path.size); +#endif +} + +void test_win32_longpath__cleanup(void) +{ + git_buf_free(&path); +} + +#ifdef GIT_WIN32 +void assert_name_too_long(void) +{ + const git_error *err; + size_t expected_len, actual_len; + const char *expected_msg; + + err = giterr_last(); + actual_len = strlen(err->message); + + expected_msg = git_win32_get_error_message(ERROR_FILENAME_EXCED_RANGE); + expected_len = strlen(expected_msg); + + /* check the suffix */ + cl_assert_equal_s(expected_msg, err->message + (actual_len - expected_len)); +} +#endif + +void test_win32_longpath__errmsg_on_checkout(void) +{ +#ifdef GIT_WIN32 + git_repository *repo; + + cl_git_fail(git_clone(&repo, cl_fixture("testrepo.git"), path.ptr, NULL)); + assert_name_too_long(); +#endif +} From ab8f2c669a2a0bb66d5473f83ecb47ad805a7078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 23 Sep 2015 15:09:19 +0200 Subject: [PATCH 22/35] submodule: plug a few leaks --- src/submodule.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/submodule.c b/src/submodule.c index 1d73dc24e..998ef91fd 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -170,7 +170,7 @@ static int name_from_path(git_buf *out, git_config *cfg, const char *path) git_buf_clear(out); git_buf_put(out, fdot + 1, ldot - fdot - 1); - return 0; + goto cleanup; } if (error == GIT_ITEROVER) { @@ -178,6 +178,8 @@ static int name_from_path(git_buf *out, git_config *cfg, const char *path) error = GIT_ENOTFOUND; } +cleanup: + git_config_iterator_free(iter); return error; } @@ -1701,7 +1703,7 @@ static int submodule_read_config(git_submodule *sm, git_config *cfg) GITERR_CHECK_ALLOC(sm->path); } } else if (error != GIT_ENOTFOUND) { - return error; + goto cleanup; } if ((error = get_value(&value, cfg, &key, sm->name, "url")) == 0) { @@ -1709,7 +1711,7 @@ static int submodule_read_config(git_submodule *sm, git_config *cfg) sm->url = git__strdup(value); GITERR_CHECK_ALLOC(sm->url); } else if (error != GIT_ENOTFOUND) { - return error; + goto cleanup; } if ((error = get_value(&value, cfg, &key, sm->name, "branch")) == 0) { @@ -1717,40 +1719,44 @@ static int submodule_read_config(git_submodule *sm, git_config *cfg) sm->branch = git__strdup(value); GITERR_CHECK_ALLOC(sm->branch); } else if (error != GIT_ENOTFOUND) { - return error; + goto cleanup; } if ((error = get_value(&value, cfg, &key, sm->name, "update")) == 0) { in_config = 1; if ((error = git_submodule_parse_update(&sm->update, value)) < 0) - return error; + goto cleanup; sm->update_default = sm->update; } else if (error != GIT_ENOTFOUND) { - return error; + goto cleanup; } if ((error = get_value(&value, cfg, &key, sm->name, "fetchRecurseSubmodules")) == 0) { in_config = 1; if ((error = git_submodule_parse_recurse(&sm->fetch_recurse, value)) < 0) - return error; + goto cleanup; sm->fetch_recurse_default = sm->fetch_recurse; } else if (error != GIT_ENOTFOUND) { - return error; + goto cleanup; } if ((error = get_value(&value, cfg, &key, sm->name, "ignore")) == 0) { in_config = 1; if ((error = git_submodule_parse_ignore(&sm->ignore, value)) < 0) - return error; + goto cleanup; sm->ignore_default = sm->ignore; } else if (error != GIT_ENOTFOUND) { - return error; + goto cleanup; } if (in_config) sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG; - return 0; + error = 0; + +cleanup: + git_buf_free(&key); + return error; } static int submodule_load_each(const git_config_entry *entry, void *payload) @@ -1784,8 +1790,10 @@ static int submodule_load_each(const git_config_entry *entry, void *payload) * already inserted, we've already loaded it, so we skip. */ pos = git_strmap_lookup_index(map, name.ptr); - if (git_strmap_valid_index(map, pos)) - return 0; + if (git_strmap_valid_index(map, pos)) { + error = 0; + goto done; + } if ((error = submodule_alloc(&sm, data->repo, name.ptr)) < 0) goto done; From 098f1e6e2506b3ca6376617751f877bee6fb5d20 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Thu, 24 Sep 2015 09:09:48 -0400 Subject: [PATCH 23/35] Use an array of forbidden custom headers --- src/transports/smart.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/transports/smart.c b/src/transports/smart.c index 8388d9dc5..1ff39b48e 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -66,14 +66,20 @@ static int git_smart__set_callbacks( return 0; } -#define forbid_custom_header(disallowed_name) \ - if (strncmp(disallowed_name, custom_header, name_len) == 0) \ - return false +static char *forbidden_custom_headers[] = { + "User-Agent", + "Host", + "Accept", + "Content-Type", + "Transfer-Encoding", + "Content-Length", +}; bool is_valid_custom_header(const char *custom_header) { const char *c; int name_len; + unsigned long i; if (custom_header == NULL) return true; @@ -95,12 +101,9 @@ bool is_valid_custom_header(const char *custom_header) return false; // Disallow headers that we set - forbid_custom_header("User-Agent"); - forbid_custom_header("Host"); - forbid_custom_header("Accept"); - forbid_custom_header("Content-Type"); - forbid_custom_header("Transfer-Encoding"); - forbid_custom_header("Content-Length"); + for (i = 0; i < ARRAY_SIZE(forbidden_custom_headers); i++) + if (strncmp(forbidden_custom_headers[i], custom_header, name_len) == 0) + return false; return true; } From 63cc57232cebab60ad193731582e24e83ea5b3b9 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Thu, 24 Sep 2015 09:13:05 -0400 Subject: [PATCH 24/35] Don't null-check --- src/transports/smart.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/transports/smart.c b/src/transports/smart.c index 1ff39b48e..fc7630c49 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -81,9 +81,6 @@ bool is_valid_custom_header(const char *custom_header) int name_len; unsigned long i; - if (custom_header == NULL) - return true; - // Disallow \r and \n c = strchr(custom_header, '\r'); if (c != NULL) From e60db3c79a82459aff9bd90fc97ff9d5fb886a04 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Thu, 24 Sep 2015 09:24:10 -0400 Subject: [PATCH 25/35] Revise custom header error messages If the header doesn't look like a header (e.g. if it doesn't have a ":" or if it has newlines), report "custom HTTP header '%s' is malformed". If the header has the same name as a header already set by libgit2 (e.g. "Host"), report "HTTP header '%s' is already set by libgit2". --- src/transports/smart.c | 86 ++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/src/transports/smart.c b/src/transports/smart.c index fc7630c49..f0f212ca3 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -66,57 +66,55 @@ static int git_smart__set_callbacks( return 0; } -static char *forbidden_custom_headers[] = { - "User-Agent", - "Host", - "Accept", - "Content-Type", - "Transfer-Encoding", - "Content-Length", -}; +int http_header_name_length(const char *http_header) +{ + const char *colon = strchr(http_header, ':'); + if (!colon) + return 0; + return colon - http_header; +} -bool is_valid_custom_header(const char *custom_header) +bool is_malformed_http_header(const char *http_header) { const char *c; int name_len; - unsigned long i; // Disallow \r and \n - c = strchr(custom_header, '\r'); - if (c != NULL) - return false; - c = strchr(custom_header, '\n'); - if (c != NULL) - return false; + c = strchr(http_header, '\r'); + if (c) + return true; + c = strchr(http_header, '\n'); + if (c) + return true; // Require a header name followed by : - c = strchr(custom_header, ':'); - if (c == NULL) - return false; - name_len = c - custom_header; + name_len = http_header_name_length(http_header); if (name_len < 1) - return false; + return true; + + return false; +} + +static char *forbidden_custom_headers[] = { + "User-Agent", + "Host", + "Accept", + "Content-Type", + "Transfer-Encoding", + "Content-Length", +}; + +bool is_forbidden_custom_header(const char *custom_header) +{ + unsigned long i; + int name_len = http_header_name_length(custom_header); // Disallow headers that we set for (i = 0; i < ARRAY_SIZE(forbidden_custom_headers); i++) if (strncmp(forbidden_custom_headers[i], custom_header, name_len) == 0) - return false; + return true; - return true; -} - -const char *find_invalid_custom_header(const git_strarray *custom_headers) -{ - size_t i; - - if (custom_headers == NULL || custom_headers->count == 0) - return NULL; - - for (i = 0; i < custom_headers->count; i++) - if (!is_valid_custom_header(custom_headers->strings[i])) - return custom_headers->strings[i]; - - return NULL; + return false; } static int git_smart__set_custom_headers( @@ -124,11 +122,17 @@ static int git_smart__set_custom_headers( const git_strarray *custom_headers) { transport_smart *t = (transport_smart *)transport; - const char *invalid_header = find_invalid_custom_header(custom_headers); + size_t i; - if (invalid_header != NULL) { - giterr_set(GITERR_INVALID, "Illegal HTTP header '%s'", invalid_header); - return -1; + for (i = 0; i < custom_headers->count; i++) { + if (is_malformed_http_header(custom_headers->strings[i])) { + giterr_set(GITERR_INVALID, "custom HTTP header '%s' is malformed", custom_headers->strings[i]); + return -1; + } + if (is_forbidden_custom_header(custom_headers->strings[i])) { + giterr_set(GITERR_INVALID, "custom HTTP header '%s' is already set by libgit2", custom_headers->strings[i]); + return -1; + } } t->custom_headers = custom_headers; From d16c1b978fa3498a8a800d80ef6ed8a1e39ca314 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Thu, 24 Sep 2015 10:30:37 -0400 Subject: [PATCH 26/35] These can be static --- src/remote.c | 2 +- src/transports/smart.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/remote.c b/src/remote.c index ce6e13b3d..84b8d590f 100644 --- a/src/remote.c +++ b/src/remote.c @@ -687,7 +687,7 @@ int set_transport_callbacks(git_transport *t, const git_remote_callbacks *cbs) cbs->certificate_check, cbs->payload); } -int set_transport_custom_headers(git_transport *t, const git_strarray *custom_headers) +static int set_transport_custom_headers(git_transport *t, const git_strarray *custom_headers) { if (!t->set_custom_headers || !custom_headers) return 0; diff --git a/src/transports/smart.c b/src/transports/smart.c index f0f212ca3..8c5bc89e8 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -66,7 +66,7 @@ static int git_smart__set_callbacks( return 0; } -int http_header_name_length(const char *http_header) +static int http_header_name_length(const char *http_header) { const char *colon = strchr(http_header, ':'); if (!colon) @@ -74,7 +74,7 @@ int http_header_name_length(const char *http_header) return colon - http_header; } -bool is_malformed_http_header(const char *http_header) +static bool is_malformed_http_header(const char *http_header) { const char *c; int name_len; @@ -104,7 +104,7 @@ static char *forbidden_custom_headers[] = { "Content-Length", }; -bool is_forbidden_custom_header(const char *custom_header) +static bool is_forbidden_custom_header(const char *custom_header) { unsigned long i; int name_len = http_header_name_length(custom_header); From d7375662e7b4c885ea4865403e4db4c130e79198 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Fri, 25 Sep 2015 10:16:16 -0400 Subject: [PATCH 27/35] Copy custom_headers insteach of referencing the caller's copy --- src/remote.c | 2 +- src/transports/http.c | 8 +++----- src/transports/smart.c | 12 +++++++++--- src/transports/smart.h | 2 +- src/transports/winhttp.c | 26 ++++++++++++-------------- 5 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/remote.c b/src/remote.c index 84b8d590f..2f8ffcb37 100644 --- a/src/remote.c +++ b/src/remote.c @@ -689,7 +689,7 @@ int set_transport_callbacks(git_transport *t, const git_remote_callbacks *cbs) static int set_transport_custom_headers(git_transport *t, const git_strarray *custom_headers) { - if (!t->set_custom_headers || !custom_headers) + if (!t->set_custom_headers) return 0; return t->set_custom_headers(t, custom_headers); diff --git a/src/transports/http.c b/src/transports/http.c index 73ea05043..e5f2b9f28 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -211,11 +211,9 @@ static int gen_request( } else git_buf_puts(buf, "Accept: */*\r\n"); - if (t->owner->custom_headers) { - for (i = 0; i < t->owner->custom_headers->count; i++) { - if (t->owner->custom_headers->strings[i]) - git_buf_printf(buf, "%s\r\n", t->owner->custom_headers->strings[i]); - } + for (i = 0; i < t->owner->custom_headers.count; i++) { + if (t->owner->custom_headers.strings[i]) + git_buf_printf(buf, "%s\r\n", t->owner->custom_headers.strings[i]); } /* Apply credentials to the request */ diff --git a/src/transports/smart.c b/src/transports/smart.c index 8c5bc89e8..b0611c35e 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -124,6 +124,12 @@ static int git_smart__set_custom_headers( transport_smart *t = (transport_smart *)transport; size_t i; + if (t->custom_headers.count) + git_strarray_free(&t->custom_headers); + + if (!custom_headers) + return 0; + for (i = 0; i < custom_headers->count; i++) { if (is_malformed_http_header(custom_headers->strings[i])) { giterr_set(GITERR_INVALID, "custom HTTP header '%s' is malformed", custom_headers->strings[i]); @@ -135,9 +141,7 @@ static int git_smart__set_custom_headers( } } - t->custom_headers = custom_headers; - - return 0; + return git_strarray_copy(&t->custom_headers, custom_headers); } int git_smart__update_heads(transport_smart *t, git_vector *symrefs) @@ -436,6 +440,8 @@ static void git_smart__free(git_transport *transport) git_vector_free(refs); + git_strarray_free(&t->custom_headers); + git__free(t); } diff --git a/src/transports/smart.h b/src/transports/smart.h index 2c87e0200..800466adf 100644 --- a/src/transports/smart.h +++ b/src/transports/smart.h @@ -139,7 +139,7 @@ typedef struct { git_transport_message_cb error_cb; git_transport_certificate_check_cb certificate_check_cb; void *message_cb_payload; - const git_strarray *custom_headers; + git_strarray custom_headers; git_smart_subtransport *wrapped; git_smart_subtransport_stream *current_stream; transport_smart_caps caps; diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 5b00d9091..b364e906e 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -410,21 +410,19 @@ static int winhttp_stream_connect(winhttp_stream *s) } } - if (t->owner->custom_headers) { - for (i = 0; i < t->owner->custom_headers->count; i++) { - if (t->owner->custom_headers->strings[i]) { - git_buf_clear(&buf); - git_buf_puts(&buf, t->owner->custom_headers->strings[i]); - if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) { - giterr_set(GITERR_OS, "Failed to convert custom header to wide characters"); - goto on_error; - } + for (i = 0; i < t->owner->custom_headers.count; i++) { + if (t->owner->custom_headers.strings[i]) { + git_buf_clear(&buf); + git_buf_puts(&buf, t->owner->custom_headers.strings[i]); + if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) { + giterr_set(GITERR_OS, "Failed to convert custom header to wide characters"); + goto on_error; + } - if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L, - WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { - giterr_set(GITERR_OS, "Failed to add a header to the request"); - goto on_error; - } + if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L, + WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { + giterr_set(GITERR_OS, "Failed to add a header to the request"); + goto on_error; } } } From e4b2b919bb35d94d6dbcb5f7a31805788f2e335b Mon Sep 17 00:00:00 2001 From: Guille -bisho- Date: Fri, 25 Sep 2015 10:37:41 -0700 Subject: [PATCH 28/35] Fix binary diffs git expects an empty line after the binary data: literal X ...binary data... The last literal block of the generated patches were not containing the required empty line. Example: diff --git a/binary_file b/binary_file index 3f1b3f9098131cfecea4a50ff8afab349ea66d22..86e5c1008b5ce635d3e3fffa4434c5eccd8f00b6 100644 GIT binary patch literal 8 Pc${NM&PdElPvrst3ey5{ literal 6 Nc${NM%g@i}0ssZ|0lokL diff --git a/binary_file2 b/binary_file2 index 31be99be19470da4af5b28b21e27896a2f2f9ee2..86e5c1008b5ce635d3e3fffa4434c5eccd8f00b6 100644 GIT binary patch literal 8 Pc${NM&PdElPvrst3ey5{ literal 13 Sc${NMEKbZyOexL+Qd|HZV+4u- git apply of that diff results in: error: corrupt binary patch at line 9: diff --git a/binary_file2 b/binary_file2 fatal: patch with only garbage at line 10 The proper formating is: diff --git a/binary_file b/binary_file index 3f1b3f9098131cfecea4a50ff8afab349ea66d22..86e5c1008b5ce635d3e3fffa4434c5eccd8f00b6 100644 GIT binary patch literal 8 Pc${NM&PdElPvrst3ey5{ literal 6 Nc${NM%g@i}0ssZ|0lokL diff --git a/binary_file2 b/binary_file2 index 31be99be19470da4af5b28b21e27896a2f2f9ee2..86e5c1008b5ce635d3e3fffa4434c5eccd8f00b6 100644 GIT binary patch literal 8 Pc${NM&PdElPvrst3ey5{ literal 13 Sc${NMEKbZyOexL+Qd|HZV+4u- --- src/diff_print.c | 2 +- tests/diff/binary.c | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/diff_print.c b/src/diff_print.c index d406a441a..bc2d6fab0 100644 --- a/src/diff_print.c +++ b/src/diff_print.c @@ -358,6 +358,7 @@ static int format_binary( scan += chunk_len; pi->line.num_lines++; } + git_buf_putc(pi->buf, '\n'); return 0; } @@ -416,7 +417,6 @@ static int diff_print_patch_file_binary( if ((error = format_binary(pi, binary->new_file.type, binary->new_file.data, binary->new_file.datalen, binary->new_file.inflatedlen)) < 0 || - (error = git_buf_putc(pi->buf, '\n')) < 0 || (error = format_binary(pi, binary->old_file.type, binary->old_file.data, binary->old_file.datalen, binary->old_file.inflatedlen)) < 0) { diff --git a/tests/diff/binary.c b/tests/diff/binary.c index 5298e9ebb..173a5994e 100644 --- a/tests/diff/binary.c +++ b/tests/diff/binary.c @@ -96,7 +96,8 @@ void test_diff_binary__add(void) "Kc${Nk-~s>u4FC%O\n" "\n" \ "literal 0\n" \ - "Hc$@u4FC%O\n"; + "Kc${Nk-~s>u4FC%O\n" \ + "\n"; opts.flags = GIT_DIFF_SHOW_BINARY; @@ -177,7 +179,8 @@ void test_diff_binary__delete(void) "Hc$@u4FC%O\n"; + "Kc${Nk-~s>u4FC%O\n" \ + "\n"; opts.flags = GIT_DIFF_SHOW_BINARY; opts.id_abbrev = GIT_OID_HEXSZ; @@ -208,7 +211,8 @@ void test_diff_binary__delta(void) "delta 198\n" \ "zc$}LmI8{(0BqLQJI6p64AwNwaIJGP_Pr*5}Br~;mqJ$PQ;Y(X&QMK*C5^Br3bjG4d=XI^5@\n" \ - "JfH567LIF3FM2!Fd\n"; + "JfH567LIF3FM2!Fd\n" \ + "\n"; opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY; opts.id_abbrev = GIT_OID_HEXSZ; @@ -249,7 +253,8 @@ void test_diff_binary__delta_append(void) "nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \ "\n" \ "delta 7\n" \ - "Oc%18D`@*{63ljhg(E~C7\n"; + "Oc%18D`@*{63ljhg(E~C7\n" \ + "\n"; opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY; opts.id_abbrev = GIT_OID_HEXSZ; @@ -314,7 +319,8 @@ void test_diff_binary__index_to_workdir(void) "nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \ "\n" \ "delta 7\n" \ - "Oc%18D`@*{63ljhg(E~C7\n"; + "Oc%18D`@*{63ljhg(E~C7\n" \ + "\n"; opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY; opts.id_abbrev = GIT_OID_HEXSZ; @@ -379,7 +385,8 @@ void test_diff_binary__print_patch_from_diff(void) "nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \ "\n" \ "delta 7\n" \ - "Oc%18D`@*{63ljhg(E~C7\n"; + "Oc%18D`@*{63ljhg(E~C7\n" \ + "\n"; opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY; opts.id_abbrev = GIT_OID_HEXSZ; From 53a2870514fb06b7aebfd1c55c19a61704906596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sun, 27 Sep 2015 22:48:39 +0200 Subject: [PATCH 29/35] net: add tests against badssl.com These provide bad X.509 certificates, which we should refuse to connect to by default. --- tests/online/badssl.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/online/badssl.c diff --git a/tests/online/badssl.c b/tests/online/badssl.c new file mode 100644 index 000000000..850468320 --- /dev/null +++ b/tests/online/badssl.c @@ -0,0 +1,27 @@ +#include "clar_libgit2.h" + +#include "git2/clone.h" + +static git_repository *g_repo; + +#if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT) + +void test_online_badssl__expired(void) +{ + cl_git_fail_with(GIT_ECERTIFICATE, + git_clone(&g_repo, "https://expired.badssl.com/fake.git", "./fake", NULL)); +} + +void test_online_badssl__wrong_host(void) +{ + cl_git_fail_with(GIT_ECERTIFICATE, + git_clone(&g_repo, "https://wrong.host.badssl.com/fake.git", "./fake", NULL)); +} + +void test_online_badssl__self_signed(void) +{ + cl_git_fail_with(GIT_ECERTIFICATE, + git_clone(&g_repo, "https://self-signed.badssl.com/fake.git", "./fake", NULL)); +} + +#endif From 5c5df666b0b2ed4433c6fb931280f9641e967a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sun, 27 Sep 2015 23:32:20 +0200 Subject: [PATCH 30/35] Plug some leaks --- src/submodule.c | 3 +++ tests/core/mkdir.c | 2 ++ tests/index/rename.c | 5 +++++ 3 files changed, 10 insertions(+) diff --git a/src/submodule.c b/src/submodule.c index 998ef91fd..3fd338843 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -229,6 +229,7 @@ int git_submodule_lookup( if (error < 0) { git_submodule_free(sm); + git_buf_free(&path); return error; } @@ -1699,6 +1700,8 @@ static int submodule_read_config(git_submodule *sm, git_config *cfg) * should be strcasecmp */ if (strcmp(sm->name, value) != 0) { + if (sm->path != sm->name) + git__free(sm->path); sm->path = git__strdup(value); GITERR_CHECK_ALLOC(sm->path); } diff --git a/tests/core/mkdir.c b/tests/core/mkdir.c index 5e6a06002..96c972396 100644 --- a/tests/core/mkdir.c +++ b/tests/core/mkdir.c @@ -48,6 +48,8 @@ void test_core_mkdir__absolute(void) cl_assert(!git_path_isdir(path.ptr)); cl_git_fail(git_futils_mkdir(path.ptr, 0755, 0)); cl_assert(!git_path_isdir(path.ptr)); + + git_buf_free(&path); } void test_core_mkdir__basic(void) diff --git a/tests/index/rename.c b/tests/index/rename.c index ebaa9b740..86eaf0053 100644 --- a/tests/index/rename.c +++ b/tests/index/rename.c @@ -77,5 +77,10 @@ void test_index_rename__casechanging(void) cl_assert_equal_i(1, git_index_entrycount(index)); else cl_assert_equal_i(2, git_index_entrycount(index)); + + git_index_free(index); + git_repository_free(repo); + + cl_fixture_cleanup("rename"); } From ea467e74871830da77bec3e351172a637c139823 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 28 Sep 2015 16:46:09 -0400 Subject: [PATCH 31/35] win32::longpath: don't print path --- tests/win32/longpath.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/win32/longpath.c b/tests/win32/longpath.c index 4fe851c2a..6de7d389a 100644 --- a/tests/win32/longpath.c +++ b/tests/win32/longpath.c @@ -23,8 +23,6 @@ void test_win32_longpath__initialize(void) for (i = 0; i < (remain - 5); i++) git_buf_putc(&path, 'a'); - - printf("%s %" PRIuZ "\n", path.ptr, path.size); #endif } From 146a96de82aebeca5e9b5bfe7fc69456f2bf2d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 30 Sep 2015 09:41:25 +0200 Subject: [PATCH 32/35] openssl: don't try to teardown an unconnected SSL context SSL_shutdown() does not like it when we pass an unitialized ssl context to it. This means that when we fail to connect to a host, we hide the error message saying so with OpenSSL's indecipherable error message. --- src/openssl_stream.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/openssl_stream.c b/src/openssl_stream.c index 8ff53d4b1..54dd761ca 100644 --- a/src/openssl_stream.c +++ b/src/openssl_stream.c @@ -302,6 +302,7 @@ cert_fail_name: typedef struct { git_stream parent; git_stream *io; + bool connected; char *host; SSL *ssl; git_cert_x509 cert_info; @@ -318,6 +319,8 @@ int openssl_connect(git_stream *stream) if ((ret = git_stream_connect(st->io)) < 0) return ret; + st->connected = true; + bio = BIO_new(&git_stream_bio_method); GITERR_CHECK_ALLOC(bio); bio->ptr = st->io; @@ -406,9 +409,11 @@ int openssl_close(git_stream *stream) openssl_stream *st = (openssl_stream *) stream; int ret; - if ((ret = ssl_teardown(st->ssl)) < 0) + if (st->connected && (ret = ssl_teardown(st->ssl)) < 0) return -1; + st->connected = false; + return git_stream_close(st->io); } From 8649dfd8df4f0d840a64c1d6c5fc80b8e94a68d1 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 29 Sep 2015 13:36:37 -0400 Subject: [PATCH 33/35] p_futimes: support using futimens when available --- CMakeLists.txt | 6 ++++++ src/unix/posix.h | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c03c718c..a0ef89f76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ CMAKE_POLICY(SET CMP0015 NEW) SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/") INCLUDE(CheckLibraryExists) +INCLUDE(CheckFunctionExists) INCLUDE(AddCFlagIfSupported) INCLUDE(FindPkgConfig) @@ -431,6 +432,11 @@ ELSE () ADD_C_FLAG_IF_SUPPORTED(-Wno-unused-const-variable) ADD_C_FLAG_IF_SUPPORTED(-Wno-unused-function) + CHECK_FUNCTION_EXISTS(futimens HAVE_FUTIMENS) + IF (HAVE_FUTIMENS) + ADD_DEFINITIONS(-DHAVE_FUTIMENS) + ENDIF () + IF (APPLE) # Apple deprecated OpenSSL ADD_C_FLAG_IF_SUPPORTED(-Wno-deprecated-declarations) ENDIF() diff --git a/src/unix/posix.h b/src/unix/posix.h index 777350990..6633689bc 100644 --- a/src/unix/posix.h +++ b/src/unix/posix.h @@ -22,7 +22,6 @@ typedef int GIT_SOCKET; #define p_stat(p,b) stat(p, b) #define p_utimes(f, t) utimes(f, t) -#define p_futimes(f, t) futimes(f, t) #define p_readlink(a, b, c) readlink(a, b, c) #define p_symlink(o,n) symlink(o, n) @@ -53,4 +52,18 @@ extern char *p_realpath(const char *, char *); #define p_localtime_r(c, r) localtime_r(c, r) #define p_gmtime_r(c, r) gmtime_r(c, r) +#ifdef HAVE_FUTIMENS +GIT_INLINE(int) p_futimes(int f, const struct timeval t[2]) +{ + struct timespec s[2]; + s[0].tv_sec = t[0].tv_sec; + s[0].tv_nsec = t[0].tv_usec * 1000; + s[1].tv_sec = t[1].tv_sec; + s[1].tv_nsec = t[1].tv_usec * 1000; + return futimens(f, s); +} +#else +# define p_futimes futimes +#endif + #endif From e683d15247ef7231143b46580f07113ecae43773 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 30 Sep 2015 05:49:04 -0400 Subject: [PATCH 34/35] qsort_r/qsort_s: detect their support --- CMakeLists.txt | 20 +++++++++++++++----- src/util.c | 21 ++++++++------------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0ef89f76..e6c06413b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,11 +432,6 @@ ELSE () ADD_C_FLAG_IF_SUPPORTED(-Wno-unused-const-variable) ADD_C_FLAG_IF_SUPPORTED(-Wno-unused-function) - CHECK_FUNCTION_EXISTS(futimens HAVE_FUTIMENS) - IF (HAVE_FUTIMENS) - ADD_DEFINITIONS(-DHAVE_FUTIMENS) - ENDIF () - IF (APPLE) # Apple deprecated OpenSSL ADD_C_FLAG_IF_SUPPORTED(-Wno-deprecated-declarations) ENDIF() @@ -447,6 +442,21 @@ ELSE () ENDIF () ENDIF() +CHECK_FUNCTION_EXISTS(futimens HAVE_FUTIMENS) +IF (HAVE_FUTIMENS) + ADD_DEFINITIONS(-DHAVE_FUTIMENS) +ENDIF () + +CHECK_FUNCTION_EXISTS(qsort_r HAVE_QSORT_R) +IF (HAVE_QSORT_R) + ADD_DEFINITIONS(-DHAVE_QSORT_R) +ENDIF () + +CHECK_FUNCTION_EXISTS(qsort_s HAVE_QSORT_S) +IF (HAVE_QSORT_S) + ADD_DEFINITIONS(-DHAVE_QSORT_S) +ENDIF () + IF( NOT CMAKE_CONFIGURATION_TYPES ) # Build Debug by default IF (NOT CMAKE_BUILD_TYPE) diff --git a/src/util.c b/src/util.c index b3929bca2..9e67f4347 100644 --- a/src/util.c +++ b/src/util.c @@ -611,7 +611,7 @@ size_t git__unescape(char *str) return (pos - str); } -#if defined(GIT_WIN32) || defined(BSD) +#if defined(HAVE_QSORT_S) || (defined(HAVE_QSORT_R) && defined(BSD)) typedef struct { git__sort_r_cmp cmp; void *payload; @@ -628,21 +628,16 @@ static int GIT_STDLIB_CALL git__qsort_r_glue_cmp( void git__qsort_r( void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload) { -#if defined(__MINGW32__) || defined(AMIGA) || \ - defined(__OpenBSD__) || defined(__NetBSD__) || \ - defined(__gnu_hurd__) || defined(__ANDROID_API__) || \ - defined(__sun) || defined(__CYGWIN__) || \ - (__GLIBC__ == 2 && __GLIBC_MINOR__ < 8) || \ - (defined(_MSC_VER) && _MSC_VER < 1500) - git__insertsort_r(els, nel, elsize, NULL, cmp, payload); -#elif defined(GIT_WIN32) - git__qsort_r_glue glue = { cmp, payload }; - qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue); -#elif defined(BSD) +#if defined(HAVE_QSORT_R) && defined(BSD) git__qsort_r_glue glue = { cmp, payload }; qsort_r(els, nel, elsize, &glue, git__qsort_r_glue_cmp); -#else +#elif defined(HAVE_QSORT_R) && defined(__GLIBC__) qsort_r(els, nel, elsize, cmp, payload); +#elif defined(HAVE_QSORT_S) + git__qsort_r_glue glue = { cmp, payload }; + qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue); +#else + git__insertsort_r(els, nel, elsize, NULL, cmp, payload); #endif } From d3b29fb94bf1c1d0caec39b4a2c3d2061c63efec Mon Sep 17 00:00:00 2001 From: Arthur Schreiber Date: Thu, 1 Oct 2015 00:50:37 +0200 Subject: [PATCH 35/35] refdb and odb backends must provide `free` function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As refdb and odb backends can be allocated by client code, libgit2 can’t know whether an alternative memory allocator was used, and thus should not try to call `git__free` on those objects. Instead, odb and refdb backend implementations must always provide their own `free` functions to ensure memory gets freed correctly. --- include/git2/sys/odb_backend.h | 4 ++++ include/git2/sys/refdb_backend.h | 4 ++-- src/odb.c | 3 +-- src/refdb.c | 8 ++------ tests/odb/sorting.c | 1 + 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/git2/sys/odb_backend.h b/include/git2/sys/odb_backend.h index fe102ff3c..e423a9236 100644 --- a/include/git2/sys/odb_backend.h +++ b/include/git2/sys/odb_backend.h @@ -83,6 +83,10 @@ struct git_odb_backend { git_odb_writepack **, git_odb_backend *, git_odb *odb, git_transfer_progress_cb progress_cb, void *progress_payload); + /** + * Frees any resources held by the odb (including the `git_odb_backend` + * itself). An odb backend implementation must provide this function. + */ void (* free)(git_odb_backend *); }; diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h index 01fce8009..5129ad84a 100644 --- a/include/git2/sys/refdb_backend.h +++ b/include/git2/sys/refdb_backend.h @@ -130,8 +130,8 @@ struct git_refdb_backend { int (*ensure_log)(git_refdb_backend *backend, const char *refname); /** - * Frees any resources held by the refdb. A refdb implementation may - * provide this function; if it is not provided, nothing will be done. + * Frees any resources held by the refdb (including the `git_refdb_backend` + * itself). A refdb backend implementation must provide this function. */ void (*free)(git_refdb_backend *backend); diff --git a/src/odb.c b/src/odb.c index b2d635109..2b2c35fe8 100644 --- a/src/odb.c +++ b/src/odb.c @@ -600,8 +600,7 @@ static void odb_free(git_odb *db) backend_internal *internal = git_vector_get(&db->backends, i); git_odb_backend *backend = internal->backend; - if (backend->free) backend->free(backend); - else git__free(backend); + backend->free(backend); git__free(internal); } diff --git a/src/refdb.c b/src/refdb.c index 16fb519a6..debba1276 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -61,12 +61,8 @@ int git_refdb_open(git_refdb **out, git_repository *repo) static void refdb_free_backend(git_refdb *db) { - if (db->backend) { - if (db->backend->free) - db->backend->free(db->backend); - else - git__free(db->backend); - } + if (db->backend) + db->backend->free(db->backend); } int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend) diff --git a/tests/odb/sorting.c b/tests/odb/sorting.c index 147a160c8..d24c49c69 100644 --- a/tests/odb/sorting.c +++ b/tests/odb/sorting.c @@ -14,6 +14,7 @@ static git_odb_backend *new_backend(size_t position) if (b == NULL) return NULL; + b->base.free = (void (*)(git_odb_backend *)) git__free; b->base.version = GIT_ODB_BACKEND_VERSION; b->position = position; return (git_odb_backend *)b;