From a7bece2014ec043cfe58418dc13e982f79dcfcba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 11 May 2015 16:35:24 +0200 Subject: [PATCH 01/14] proxy: introduce a proxy options struct It is currently unused; it will go into the remote's options. --- include/git2.h | 1 + include/git2/proxy.h | 91 ++++++++++++++++++++++++++++++++++++++++++++ src/proxy.c | 16 ++++++++ 3 files changed, 108 insertions(+) create mode 100644 include/git2/proxy.h create mode 100644 src/proxy.c diff --git a/include/git2.h b/include/git2.h index ac4a63160..bc4333cc9 100644 --- a/include/git2.h +++ b/include/git2.h @@ -40,6 +40,7 @@ #include "git2/pack.h" #include "git2/patch.h" #include "git2/pathspec.h" +#include "git2/proxy.h" #include "git2/rebase.h" #include "git2/refdb.h" #include "git2/reflog.h" diff --git a/include/git2/proxy.h b/include/git2/proxy.h new file mode 100644 index 000000000..2a3ce8f3e --- /dev/null +++ b/include/git2/proxy.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git_proxy_h__ +#define INCLUDE_git_proxy_h__ + +#include "common.h" +#include "transport.h" + +GIT_BEGIN_DECL + +/** + * The type of proxy to use. + */ +typedef enum { + /** + * Do not attempt to connect through a proxy + */ + GIT_PROXY_NONE, + /** + * Try to auto-detect the proxy from the git configuration. + */ + GIT_PROXY_AUTO, + /** + * Connect through a HTTP proxy + */ + GIT_PROXY_HTTP, + /** + * Connect through a SOCKS v4 proxy + */ + GIT_PROXY_SOCKS4, + /** + * Connect through a SOCKS v5 proxy + */ + GIT_PROXY_SOCKS5, +} git_proxy_t; + +/** + * Options for connecting through a proxy + * + * Note that not all types may be supported, depending on the platform + * and compilation options. + */ +typedef struct { + unsigned int version; + + /** + * The type of proxy to use, by URL, auto-detect. + */ + git_proxy_t type; + + /** + * The URL of the proxy. + */ + const char *url; + + /** + * This will be called if the remote host requires + * authentication in order to connect to it. + * + * Returning GIT_PASSTHROUGH will make libgit2 behave as + * though this field isn't set. + */ + git_cred_acquire_cb credentials; + + /** + * If cert verification fails, this will be called to let the + * user make the final decision of whether to allow the + * connection to proceed. Returns 1 to allow the connection, 0 + * to disallow it or a negative value to indicate an error. + */ + git_transport_certificate_check_cb certificate_check; +} git_proxy_options; + +#define GIT_PROXY_OPTIONS_VERSION 1 +#define GIT_PROXY_OPTIONS_INIT {GIT_PROXY_OPTIONS_VERSION} + +/** + * Initialize a proxy options structure + * + * @param opts the options struct to initialize + * @param version the version of the struct, use `GIT_PROXY_OPTIONS_VERSION` + */ +GIT_EXTERN(int) git_proxy_init_options(git_proxy_options *opts, unsigned int version); + +GIT_END_DECL + +#endif diff --git a/src/proxy.c b/src/proxy.c new file mode 100644 index 000000000..2112596e9 --- /dev/null +++ b/src/proxy.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" +#include "git2/proxy.h" + +int git_proxy_init_options(git_proxy_options *opts, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, version, git_proxy_options, GIT_PROXY_OPTIONS_INIT); + return 0; +} From 07bd3e57d9a9930727695be690c8757f79117d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 7 May 2015 12:57:56 +0200 Subject: [PATCH 02/14] proxy: ask the user for credentials if necessary --- examples/network/ls-remote.c | 2 +- include/git2/remote.h | 19 +++- include/git2/sys/transport.h | 4 +- src/proxy.c | 16 ++++ src/proxy.h | 14 +++ src/push.c | 2 +- src/remote.c | 26 ++++-- src/transports/local.c | 5 +- src/transports/smart.c | 5 ++ src/transports/smart.h | 1 + src/transports/winhttp.c | 128 ++++++++++++++++++++++++--- tests/network/remote/defaultbranch.c | 6 +- tests/network/remote/local.c | 8 +- tests/network/remote/remotes.c | 6 +- tests/online/clone.c | 45 ++++++++++ tests/online/fetch.c | 12 +-- tests/online/push.c | 2 +- 17 files changed, 260 insertions(+), 41 deletions(-) create mode 100644 src/proxy.h diff --git a/examples/network/ls-remote.c b/examples/network/ls-remote.c index c9da79f5f..9329da5d9 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, NULL); + error = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks, NULL, NULL); if (error < 0) goto cleanup; diff --git a/include/git2/remote.h b/include/git2/remote.h index 4f345d30c..c459f42cc 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -15,6 +15,7 @@ #include "strarray.h" #include "transport.h" #include "pack.h" +#include "proxy.h" /** * @file git2/remote.h @@ -241,10 +242,11 @@ 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 proxy_opts proxy settings * @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, const git_strarray *custom_headers); +GIT_EXTERN(int) git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_proxy_options *proxy_opts, const git_strarray *custom_headers); /** * Get the remote repository's reference advertisement list @@ -548,6 +550,11 @@ typedef struct { */ git_remote_autotag_option_t download_tags; + /** + * Proxy options to use, by default no proxy is used. + */ + git_proxy_options proxy_opts; + /** * Extra headers for this fetch operation */ @@ -555,7 +562,8 @@ typedef struct { } git_fetch_options; #define GIT_FETCH_OPTIONS_VERSION 1 -#define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 1 } +#define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 1, \ + GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT } /** * Initializes a `git_fetch_options` with default values. Equivalent to @@ -592,6 +600,11 @@ typedef struct { */ git_remote_callbacks callbacks; + /** + * Proxy options to use, by default no proxy is used. + */ + git_proxy_options proxy_opts; + /** * Extra headers for this push operation */ @@ -599,7 +612,7 @@ typedef struct { } git_push_options; #define GIT_PUSH_OPTIONS_VERSION 1 -#define GIT_PUSH_OPTIONS_INIT { GIT_PUSH_OPTIONS_VERSION, 0, GIT_REMOTE_CALLBACKS_INIT } +#define GIT_PUSH_OPTIONS_INIT { GIT_PUSH_OPTIONS_VERSION, 0, GIT_REMOTE_CALLBACKS_INIT, GIT_PROXY_OPTIONS_INIT } /** * Initializes a `git_push_options` with default values. Equivalent to diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h index ce0234a18..60e38b21a 100644 --- a/include/git2/sys/transport.h +++ b/include/git2/sys/transport.h @@ -11,6 +11,7 @@ #include "git2/net.h" #include "git2/types.h" #include "git2/strarray.h" +#include "git2/proxy.h" /** * @file git2/sys/transport.h @@ -53,6 +54,7 @@ struct git_transport { const char *url, git_cred_acquire_cb cred_acquire_cb, void *cred_acquire_payload, + const git_proxy_options *proxy_opts, int direction, int flags); @@ -65,7 +67,7 @@ struct git_transport { git_transport *transport); /* Executes the push whose context is in the git_push object. */ - int (*push)(git_transport *transport, git_push *push, const git_remote_callbacks *callbacks); + int(*push)(git_transport *transport, git_push *push, const git_remote_callbacks *callbacks); /* This function may be called after a successful call to connect(), when * the direction is FETCH. The function performs a negotiation to calculate diff --git a/src/proxy.c b/src/proxy.c index 2112596e9..f53ac1151 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -14,3 +14,19 @@ int git_proxy_init_options(git_proxy_options *opts, unsigned int version) opts, version, git_proxy_options, GIT_PROXY_OPTIONS_INIT); return 0; } + +int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src) +{ + if (!src) { + git_proxy_init_options(tgt, GIT_PROXY_OPTIONS_VERSION); + return 0; + } + + memcpy(tgt, src, sizeof(git_proxy_options)); + if (src->url) { + tgt->url = git__strdup(src->url); + GITERR_CHECK_ALLOC(tgt->url); + } + + return 0; +} diff --git a/src/proxy.h b/src/proxy.h new file mode 100644 index 000000000..bf9382737 --- /dev/null +++ b/src/proxy.h @@ -0,0 +1,14 @@ +/* +* Copyright (C) the libgit2 contributors. All rights reserved. +* +* This file is part of libgit2, distributed under the GNU GPL v2 with +* a Linking Exception. For full terms see the included COPYING file. +*/ +#ifndef INCLUDE_proxy_h__ +#define INCLUDE_proxy_h__ + +#include "git2/proxy.h" + +extern int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src); + +#endif \ No newline at end of file diff --git a/src/push.c b/src/push.c index 0747259c8..b4901388b 100644 --- a/src/push.c +++ b/src/push.c @@ -639,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, push->custom_headers)) < 0) + (error = git_remote_connect(push->remote, GIT_DIRECTION_PUSH, callbacks, NULL, push->custom_headers)) < 0) return error; if ((error = filter_refs(push->remote)) < 0 || diff --git a/src/remote.c b/src/remote.c index 8b7203ee2..5ff7f6826 100644 --- a/src/remote.c +++ b/src/remote.c @@ -695,7 +695,7 @@ static int set_transport_custom_headers(git_transport *t, const git_strarray *cu 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) +int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_proxy_options *proxy, const git_strarray *custom_headers) { git_transport *t; const char *url; @@ -714,6 +714,9 @@ int git_remote_connect(git_remote *remote, git_direction direction, const git_re payload = callbacks->payload; } + if (proxy) + GITERR_CHECK_VERSION(proxy, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options"); + t = remote->transport; url = git_remote__urlfordirection(remote, direction); @@ -738,7 +741,7 @@ int git_remote_connect(git_remote *remote, git_direction direction, const git_re goto on_error; if ((error = set_transport_callbacks(t, callbacks)) < 0 || - (error = t->connect(t, url, credentials, payload, direction, flags)) != 0) + (error = t->connect(t, url, credentials, payload, proxy, direction, flags)) != 0) goto on_error; remote->transport = t; @@ -896,6 +899,7 @@ int git_remote_download(git_remote *remote, const git_strarray *refspecs, const git_vector *to_active, specs = GIT_VECTOR_INIT, refs = GIT_VECTOR_INIT; const git_remote_callbacks *cbs = NULL; const git_strarray *custom_headers = NULL; + const git_proxy_options *proxy = NULL; assert(remote); @@ -903,10 +907,12 @@ int git_remote_download(git_remote *remote, const git_strarray *refspecs, const GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks"); cbs = &opts->callbacks; custom_headers = &opts->custom_headers; + GITERR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options"); + proxy = &opts->proxy_opts; } if (!git_remote_connected(remote) && - (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, custom_headers)) < 0) + (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, proxy, custom_headers)) < 0) goto on_error; if (ls_to_vector(&refs, remote) < 0) @@ -971,6 +977,7 @@ int git_remote_fetch( git_buf reflog_msg_buf = GIT_BUF_INIT; const git_remote_callbacks *cbs = NULL; const git_strarray *custom_headers = NULL; + const git_proxy_options *proxy = NULL; if (opts) { GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks"); @@ -978,10 +985,12 @@ int git_remote_fetch( custom_headers = &opts->custom_headers; update_fetchhead = opts->update_fetchhead; tagopt = opts->download_tags; + GITERR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options"); + proxy = &opts->proxy_opts; } /* Connect and download everything */ - if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, custom_headers)) != 0) + if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, proxy, custom_headers)) != 0) return error; error = git_remote_download(remote, refspecs, opts); @@ -2393,16 +2402,18 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi git_refspec *spec; const git_remote_callbacks *cbs = NULL; const git_strarray *custom_headers = NULL; + const git_proxy_options *proxy = NULL; assert(remote); if (opts) { cbs = &opts->callbacks; custom_headers = &opts->custom_headers; + proxy = &opts->proxy_opts; } if (!git_remote_connected(remote) && - (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, custom_headers)) < 0) + (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0) goto cleanup; free_refspecs(&remote->active_refspecs); @@ -2452,16 +2463,19 @@ 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; + const git_proxy_options *proxy = NULL; if (opts) { GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks"); cbs = &opts->callbacks; custom_headers = &opts->custom_headers; + GITERR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options"); + proxy = &opts->proxy_opts; } assert(remote && refspecs); - if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, custom_headers)) < 0) + if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0) return error; if ((error = git_remote_upload(remote, refspecs, opts)) < 0) diff --git a/src/transports/local.c b/src/transports/local.c index 1c6e5f01e..4eae9dead 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -25,6 +25,7 @@ #include "odb.h" #include "push.h" #include "remote.h" +#include "proxy.h" typedef struct { git_transport parent; @@ -199,6 +200,7 @@ static int local_connect( const char *url, git_cred_acquire_cb cred_acquire_cb, void *cred_acquire_payload, + const git_proxy_options *proxy, int direction, int flags) { git_repository *repo; @@ -209,6 +211,7 @@ static int local_connect( GIT_UNUSED(cred_acquire_cb); GIT_UNUSED(cred_acquire_payload); + GIT_UNUSED(proxy); if (t->connected) return 0; @@ -439,7 +442,7 @@ static int local_push( if (!url || t->parent.close(&t->parent) < 0 || t->parent.connect(&t->parent, url, - NULL, NULL, GIT_DIRECTION_PUSH, flags)) + NULL, NULL, NULL, GIT_DIRECTION_PUSH, flags)) goto on_error; } diff --git a/src/transports/smart.c b/src/transports/smart.c index b0611c35e..a78b57218 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -8,6 +8,7 @@ #include "smart.h" #include "refs.h" #include "refspec.h" +#include "proxy.h" static int git_smart__recv_cb(gitno_buffer *buf) { @@ -199,6 +200,7 @@ static int git_smart__connect( const char *url, git_cred_acquire_cb cred_acquire_cb, void *cred_acquire_payload, + const git_proxy_options *proxy, int direction, int flags) { @@ -216,6 +218,9 @@ static int git_smart__connect( t->url = git__strdup(url); GITERR_CHECK_ALLOC(t->url); + if (git_proxy_options_dup(&t->proxy, proxy) < 0) + return -1; + t->direction = direction; t->flags = flags; t->cred_acquire_cb = cred_acquire_cb; diff --git a/src/transports/smart.h b/src/transports/smart.h index 800466adf..0a0c3fc1b 100644 --- a/src/transports/smart.h +++ b/src/transports/smart.h @@ -133,6 +133,7 @@ typedef struct { char *url; git_cred_acquire_cb cred_acquire_cb; void *cred_acquire_payload; + git_proxy_options proxy; int direction; int flags; git_transport_message_cb progress_cb; diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 32b838084..22be39c6c 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -91,13 +91,39 @@ typedef struct { git_smart_subtransport parent; transport_smart *owner; gitno_connection_data connection_data; + gitno_connection_data proxy_connection_data; git_cred *cred; git_cred *url_cred; + git_cred *proxy_cred; int auth_mechanism; HINTERNET session; HINTERNET connection; } winhttp_subtransport; +static int apply_basic_credential_proxy(HINTERNET request, git_cred *cred) +{ + git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; + wchar_t *user, *pass; + int error; + + if ((error = git__utf8_to_16_alloc(&user, c->username)) < 0) + return error; + + if ((error = git__utf8_to_16_alloc(&pass, c->password)) < 0) + return error; + + if (!WinHttpSetCredentials(request, WINHTTP_AUTH_TARGET_PROXY, WINHTTP_AUTH_SCHEME_BASIC, + user, pass, NULL)) { + giterr_set(GITERR_OS, "failed to set proxy auth"); + error = -1; + } + + git__free(user); + git__free(pass); + + return error; +} + static int apply_basic_credential(HINTERNET request, git_cred *cred) { git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; @@ -271,6 +297,34 @@ static void winhttp_stream_close(winhttp_stream *s) s->sent_request = 0; } +/** + * Extract the url and password from a URL. The outputs are pointers + * into the input. + */ +static int userpass_from_url(wchar_t **user, int *user_len, + wchar_t **pass, int *pass_len, + const wchar_t *url, int url_len) +{ + URL_COMPONENTS components = { 0 }; + + components.dwStructSize = sizeof(components); + /* These tell WinHttpCrackUrl that we're interested in the fields */ + components.dwUserNameLength = 1; + components.dwPasswordLength = 1; + + if (!WinHttpCrackUrl(url, url_len, 0, &components)) { + giterr_set(GITERR_OS, "failed to extract user/pass from url"); + return -1; + } + + *user = components.lpszUserName; + *user_len = components.dwUserNameLength; + *pass = components.lpszPassword; + *pass_len = components.dwPasswordLength; + + return 0; +} + static int winhttp_stream_connect(winhttp_stream *s) { winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); @@ -284,6 +338,7 @@ static int winhttp_stream_connect(winhttp_stream *s) int default_timeout = TIMEOUT_INFINITE; int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT; size_t i; + const git_proxy_options *proxy_opts; /* Prepare URL */ git_buf_printf(&buf, "%s%s", t->connection_data.path, s->service_url); @@ -317,26 +372,49 @@ static int winhttp_stream_connect(winhttp_stream *s) goto on_error; } - /* Set proxy if necessary */ - if (git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &proxy_url) < 0) - goto on_error; + proxy_opts = &t->owner->proxy; + if (proxy_opts->type == GIT_PROXY_AUTO) { + /* Set proxy if necessary */ + if (git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &proxy_url) < 0) + goto on_error; + } + else if (proxy_opts->type == GIT_PROXY_HTTP) { + proxy_url = git__strdup(proxy_opts->url); + GITERR_CHECK_ALLOC(proxy_url); + } if (proxy_url) { + git_buf processed_url = GIT_BUF_INIT; WINHTTP_PROXY_INFO proxy_info; wchar_t *proxy_wide; - /* Convert URL to wide characters */ - int proxy_wide_len = git__utf8_to_16_alloc(&proxy_wide, proxy_url); + if ((error = gitno_connection_data_from_url(&t->proxy_connection_data, proxy_url, NULL)) < 0) + goto on_error; - if (proxy_wide_len < 0) { - giterr_set(GITERR_OS, "Failed to convert string to wide form"); + if (t->proxy_connection_data.user && t->proxy_connection_data.pass) { + if ((error = git_cred_userpass_plaintext_new(&t->proxy_cred, t->proxy_connection_data.user, t->proxy_connection_data.pass)) < 0) + goto on_error; + } + + if (t->proxy_connection_data.use_ssl) + git_buf_puts(&processed_url, "https://"); + else + git_buf_puts(&processed_url, "http://"); + + git_buf_puts(&processed_url, t->proxy_connection_data.host); + if (t->proxy_connection_data.port) + git_buf_printf(&processed_url, ":%s", t->proxy_connection_data.port); + + if (git_buf_oom(&processed_url)) { + giterr_set_oom(); + error = -1; goto on_error; } - /* Strip any trailing forward slash on the proxy URL; - * WinHTTP doesn't like it if one is present */ - if (proxy_wide_len > 1 && L'/' == proxy_wide[proxy_wide_len - 2]) - proxy_wide[proxy_wide_len - 2] = L'\0'; + /* Convert URL to wide characters */ + if ((error = git__utf8_to_16_alloc(&proxy_wide, processed_url.ptr)) < 0) + goto on_error; + proxy_info.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; proxy_info.lpszProxy = proxy_wide; @@ -352,6 +430,14 @@ static int winhttp_stream_connect(winhttp_stream *s) } git__free(proxy_wide); + + if (t->proxy_cred) { + if (t->proxy_cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT) { + if ((error = apply_basic_credential_proxy(s->request, t->proxy_cred)) < 0) + goto on_error; + } + } + } /* Disable WinHTTP redirects so we can handle them manually. Why, you ask? @@ -919,6 +1005,26 @@ replay: goto replay; } + /* Handle proxy authentication failures */ + if (status_code == HTTP_STATUS_PROXY_AUTH_REQ) { + int allowed_types; + + if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanism) < 0) + return -1; + + /* TODO: extract the username from the url, no payload? */ + if (t->owner->proxy.credentials) { + int cred_error = 1; + cred_error = t->owner->proxy.credentials(&t->proxy_cred, t->owner->proxy.url, NULL, allowed_types, NULL); + + if (cred_error < 0) + return cred_error; + } + + winhttp_stream_close(s); + goto replay; + } + /* Handle authentication failures */ if (HTTP_STATUS_DENIED == status_code && get_verb == s->verb) { int allowed_types; diff --git a/tests/network/remote/defaultbranch.c b/tests/network/remote/defaultbranch.c index 5edd79fb8..9ab0d4095 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, NULL)); + cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH, NULL, 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, NULL)); + cl_git_pass(git_remote_connect(remote_b, GIT_DIRECTION_FETCH, NULL, 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, NULL)); + cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH, NULL, 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 4d990ab71..6194802af 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, NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, 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, NULL)); + cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL, 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, NULL)); + cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL, 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, NULL)); + cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL, 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 46abc6d33..9c7e6b299 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, NULL)); + cl_git_pass(git_remote_connect(r, GIT_DIRECTION_PUSH, &callbacks, NULL, 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, NULL)); + cl_git_fail(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, 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, NULL)); + cl_git_fail(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); git_remote_free(remote); } diff --git a/tests/online/clone.c b/tests/online/clone.c index b84be405c..cc4d2fe04 100644 --- a/tests/online/clone.c +++ b/tests/online/clone.c @@ -24,6 +24,9 @@ static char *_remote_ssh_pubkey = NULL; static char *_remote_ssh_privkey = NULL; static char *_remote_ssh_passphrase = NULL; static char *_remote_ssh_fingerprint = NULL; +static char *_remote_proxy_url = NULL; +static char *_remote_proxy_user = NULL; +static char *_remote_proxy_pass = NULL; void test_online_clone__initialize(void) @@ -46,6 +49,9 @@ void test_online_clone__initialize(void) _remote_ssh_privkey = cl_getenv("GITTEST_REMOTE_SSH_KEY"); _remote_ssh_passphrase = cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE"); _remote_ssh_fingerprint = cl_getenv("GITTEST_REMOTE_SSH_FINGERPRINT"); + _remote_proxy_url = cl_getenv("GITTEST_REMOTE_PROXY_URL"); + _remote_proxy_user = cl_getenv("GITTEST_REMOTE_PROXY_USER"); + _remote_proxy_pass = cl_getenv("GITTEST_REMOTE_PROXY_PASS"); } void test_online_clone__cleanup(void) @@ -63,6 +69,9 @@ void test_online_clone__cleanup(void) git__free(_remote_ssh_privkey); git__free(_remote_ssh_passphrase); git__free(_remote_ssh_fingerprint); + git__free(_remote_proxy_url); + git__free(_remote_proxy_user); + git__free(_remote_proxy_pass); } void test_online_clone__network_full(void) @@ -653,3 +662,39 @@ void test_online_clone__start_with_http(void) cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); } + +static int called_proxy_creds; +static int proxy_creds(git_cred **out, const char *url, const char *username, unsigned int allowed, void *payload) +{ + GIT_UNUSED(payload); + GIT_UNUSED(username); + + called_proxy_creds = 1; + return git_cred_userpass_plaintext_new(out, _remote_proxy_user, _remote_proxy_pass); +} + +void test_online_clone__proxy_credentials_request(void) +{ + if (!_remote_proxy_url || !_remote_proxy_user || !_remote_proxy_pass) + cl_skip(); + + g_options.fetch_opts.proxy_opts.type = GIT_PROXY_HTTP; + g_options.fetch_opts.proxy_opts.url = _remote_proxy_url; + g_options.fetch_opts.proxy_opts.credentials = proxy_creds; + called_proxy_creds = 0; + cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); + cl_assert(called_proxy_creds); +} + +void test_online_clone__proxy_credentials_in_url(void) +{ + if (!_remote_proxy_url) + cl_skip(); + + g_options.fetch_opts.proxy_opts.type = GIT_PROXY_HTTP; + g_options.fetch_opts.proxy_opts.url = _remote_proxy_url; + g_options.fetch_opts.proxy_opts.credentials = proxy_creds; + called_proxy_creds = 0; + cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); + cl_assert(called_proxy_creds == 0); +} diff --git a/tests/online/fetch.c b/tests/online/fetch.c index c12df069f..827cb23c1 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, NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); cl_git_pass(git_remote_download(remote, NULL, NULL)); git_remote_disconnect(remote); - git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL); + git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, 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, NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, 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, NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, 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, NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, 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, NULL)); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, 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 77c437622..f72b4f8cb 100644 --- a/tests/online/push.c +++ b/tests/online/push.c @@ -372,7 +372,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, NULL)); + cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH, &_record_cbs, NULL, 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 b117721dd8aa039e074c6bd46b18a526ac9cb2f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 29 Jul 2015 21:23:56 +0200 Subject: [PATCH 03/14] proxy: use poxy to test our Windows proxy support --- appveyor.yml | 10 ++++++++++ src/transports/smart.c | 1 + tests/online/clone.c | 1 - 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 5ba8aaabd..50152adb2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,6 +19,7 @@ environment: cache: - i686-4.9.2-release-win32-sjlj-rt_v3-rev1.7z - x86_64-4.9.2-release-win32-seh-rt_v3-rev1.7z + build_script: - ps: | mkdir build @@ -26,6 +27,7 @@ build_script: if ($env:GENERATOR -ne "MSYS Makefiles") { cmake -D ENABLE_TRACE=ON -D BUILD_CLAR=ON -D MSVC_CRTDBG=ON .. -G"$env:GENERATOR" cmake --build . --config Debug + Invoke-WebRequest https://github.com/ethomson/poxyproxy/releases/download/v0.1.0/poxyproxy-0.1.0.jar -OutFile poxyproxy.jar } - cmd: | if "%GENERATOR%"=="MSYS Makefiles" (C:\MinGW\msys\1.0\bin\sh --login /c/projects/libgit2/script/appveyor-mingw.sh) @@ -36,3 +38,11 @@ test_script: $env:GITTEST_REMOTE_URL="https://github.com/libgit2/non-existent" $env:GITTEST_REMOTE_USER="libgit2test" ctest -V -R libgit2_clar-cred_callback + Start-Job { java -jar $Env:APPVEYOR_BUILD_FOLDER\build\poxyproxy.jar -d --port 8080 --credentials foo:bar } + ctest -V . + $env:GITTEST_REMOTE_PROXY_URL = "http://foo:bar@localhost:8080/" + .\Debug\libgit2_clar.exe -sonline::clone::proxy_credentials_in_url + $env:GITTEST_REMOTE_PROXY_URL = "http://localhost:8080/" + $env:GITTEST_REMOTE_PROXY_USER = "foo" + $env:GITTEST_REMOTE_PROXY_PASS = "bar" + .\Debug\libgit2_clar.exe -sonline::clone::proxy_credentials_request diff --git a/src/transports/smart.c b/src/transports/smart.c index a78b57218..11b4b09a4 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -444,6 +444,7 @@ static void git_smart__free(git_transport *transport) git_pkt_free(p); git_vector_free(refs); + git__free(t->proxy.url); git_strarray_free(&t->custom_headers); diff --git a/tests/online/clone.c b/tests/online/clone.c index cc4d2fe04..d2a5928da 100644 --- a/tests/online/clone.c +++ b/tests/online/clone.c @@ -693,7 +693,6 @@ void test_online_clone__proxy_credentials_in_url(void) g_options.fetch_opts.proxy_opts.type = GIT_PROXY_HTTP; g_options.fetch_opts.proxy_opts.url = _remote_proxy_url; - g_options.fetch_opts.proxy_opts.credentials = proxy_creds; called_proxy_creds = 0; cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); cl_assert(called_proxy_creds == 0); From 4e01741390d1bed120a44456236ef70d9304380b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 21 Sep 2015 21:11:02 +0200 Subject: [PATCH 04/14] netops: make the path optional in URLs When we're dealing with proxy addresses, we only want a hostname and port, and the user would not provide a path, so make it optional so we can use this same function to parse git as well as proxy URLs. --- src/netops.c | 22 ++++++++++++---------- tests/network/urlparse.c | 9 +++++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/netops.c b/src/netops.c index c4241989f..90326ea59 100644 --- a/src/netops.c +++ b/src/netops.c @@ -257,16 +257,18 @@ int gitno_extract_url_parts( *port = git__strdup(default_port); GITERR_CHECK_ALLOC(*port); - if (u.field_set & (1 << UF_PATH)) { - *path = git__substrdup(_path, u.field_data[UF_PATH].len); - GITERR_CHECK_ALLOC(*path); - } else { - git__free(*port); - *port = NULL; - git__free(*host); - *host = NULL; - giterr_set(GITERR_NET, "invalid url, missing path"); - return GIT_EINVALIDSPEC; + if (path) { + if (u.field_set & (1 << UF_PATH)) { + *path = git__substrdup(_path, u.field_data[UF_PATH].len); + GITERR_CHECK_ALLOC(*path); + } else { + git__free(*port); + *port = NULL; + git__free(*host); + *host = NULL; + giterr_set(GITERR_NET, "invalid url, missing path"); + return GIT_EINVALIDSPEC; + } } if (u.field_set & (1 << UF_USERINFO)) { diff --git a/tests/network/urlparse.c b/tests/network/urlparse.c index b3ac8ae60..4a3096baa 100644 --- a/tests/network/urlparse.c +++ b/tests/network/urlparse.c @@ -121,6 +121,15 @@ void test_network_urlparse__user_pass_port(void) cl_assert_equal_s(pass, "pass"); } +void test_network_urlparse__optional_path(void) +{ + cl_git_fail(gitno_extract_url_parts(&host, &port, &path, &user, &pass, + "https://user:pass@example.com:9191", "8080")); + + cl_git_pass(gitno_extract_url_parts(&host, &port, NULL, &user, &pass, + "https://user:pass@example.com:9191", "8080")); +} + void test_network_urlparse__connection_data_http(void) { cl_git_pass(gitno_connection_data_from_url(&conndata, From 2f3f1ee08532b10993b7e9270e5fe61f08f795ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 21 Sep 2015 21:40:37 +0200 Subject: [PATCH 05/14] proxy: test proxy support on Travis --- script/cibuild.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/script/cibuild.sh b/script/cibuild.sh index 00cde0ada..b2a928a65 100755 --- a/script/cibuild.sh +++ b/script/cibuild.sh @@ -49,12 +49,26 @@ export GITTEST_REMOTE_SSH_KEY="$HOME/.ssh/id_rsa" export GITTEST_REMOTE_SSH_PUBKEY="$HOME/.ssh/id_rsa.pub" export GITTEST_REMOTE_SSH_PASSPHRASE="" + +# Can we ask Travis to cache this file? +curl -L https://github.com/ethomson/poxyproxy/releases/download/v0.1.0/poxyproxy-0.1.0.jar >poxyproxy.jar || exit $? + if [ -e ./libgit2_clar ]; then ./libgit2_clar -sonline::push -sonline::clone::ssh_cert && ./libgit2_clar -sonline::clone::ssh_with_paths || exit $? if [ "$TRAVIS_OS_NAME" = "linux" ]; then ./libgit2_clar -sonline::clone::cred_callback || exit $? fi + + java -jar poxyproxy.jar -d --port 8080 --credentials foo:bar & + + export GITTEST_REMOTE_PROXY_URL="http://foo:bar@localhost:8080/" + ./libgit2_clar -sonline::clone::proxy_credentials_in_url + export GITTEST_REMOTE_PROXY_URL="http://localhost:8080/" + export GITTEST_REMOTE_PROXY_USER="foo" + export GITTEST_REMOTE_PROXY_PASS="bar" + ./libgit2_clar -sonline::clone::proxy_credentials_request + fi export GITTEST_REMOTE_URL="https://github.com/libgit2/non-existent" From 22e6aa0d4fc7a619472aa8da69163dc210781956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 23 Sep 2015 04:39:05 +0200 Subject: [PATCH 06/14] proxy: don't require the trailing slash on WinHTTP The path is not something that you use for proxies, so make use of the new optionality of the path when extracting URL parts. --- appveyor.yml | 4 ++-- src/transports/winhttp.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 50152adb2..4c58df6b3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -40,9 +40,9 @@ test_script: ctest -V -R libgit2_clar-cred_callback Start-Job { java -jar $Env:APPVEYOR_BUILD_FOLDER\build\poxyproxy.jar -d --port 8080 --credentials foo:bar } ctest -V . - $env:GITTEST_REMOTE_PROXY_URL = "http://foo:bar@localhost:8080/" + $env:GITTEST_REMOTE_PROXY_URL = "http://foo:bar@localhost:8080" .\Debug\libgit2_clar.exe -sonline::clone::proxy_credentials_in_url - $env:GITTEST_REMOTE_PROXY_URL = "http://localhost:8080/" + $env:GITTEST_REMOTE_PROXY_URL = "http://localhost:8080" $env:GITTEST_REMOTE_PROXY_USER = "foo" $env:GITTEST_REMOTE_PROXY_PASS = "bar" .\Debug\libgit2_clar.exe -sonline::clone::proxy_credentials_request diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 22be39c6c..5a506d20d 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -388,7 +388,8 @@ static int winhttp_stream_connect(winhttp_stream *s) WINHTTP_PROXY_INFO proxy_info; wchar_t *proxy_wide; - if ((error = gitno_connection_data_from_url(&t->proxy_connection_data, proxy_url, NULL)) < 0) + if ((error = gitno_extract_url_parts(&t->proxy_connection_data.host, &t->proxy_connection_data.port, NULL, + &t->proxy_connection_data.user, &t->proxy_connection_data.pass, proxy_url, NULL)) < 0) goto on_error; if (t->proxy_connection_data.user && t->proxy_connection_data.pass) { From b373e9a6ba11b3b82ad6c74996488176d22920a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 21 Sep 2015 22:38:50 +0200 Subject: [PATCH 07/14] net: use proxy options struct in the stream config --- include/git2/sys/stream.h | 3 ++- src/curl_stream.c | 10 ++++++++-- src/openssl_stream.c | 4 ++-- src/stream.h | 4 ++-- src/transports/http.c | 41 ++++++++++++++++++++++++++++++--------- 5 files changed, 46 insertions(+), 16 deletions(-) diff --git a/include/git2/sys/stream.h b/include/git2/sys/stream.h index 2b4ff7fd8..eeeb68dae 100644 --- a/include/git2/sys/stream.h +++ b/include/git2/sys/stream.h @@ -9,6 +9,7 @@ #include "git2/common.h" #include "git2/types.h" +#include "git2/proxy.h" GIT_BEGIN_DECL @@ -32,7 +33,7 @@ typedef struct git_stream { int proxy_support; int (*connect)(struct git_stream *); int (*certificate)(git_cert **, struct git_stream *); - int (*set_proxy)(struct git_stream *, const char *proxy_url); + int (*set_proxy)(struct git_stream *, const git_proxy_options *proxy_opts); ssize_t (*read)(struct git_stream *, void *, size_t); ssize_t (*write)(struct git_stream *, const char *, size_t, int); int (*close)(struct git_stream *); diff --git a/src/curl_stream.c b/src/curl_stream.c index 9963d94cc..f48dd2249 100644 --- a/src/curl_stream.c +++ b/src/curl_stream.c @@ -13,6 +13,7 @@ #include "git2/transport.h" #include "buffer.h" #include "vector.h" +#include "proxy.h" typedef struct { git_stream parent; @@ -21,6 +22,7 @@ typedef struct { char curl_error[CURL_ERROR_SIZE + 1]; git_cert_x509 cert_info; git_strarray cert_info_strings; + git_proxy_options proxy; } curl_stream; static int seterr_curl(curl_stream *s) @@ -95,12 +97,16 @@ static int curls_certificate(git_cert **out, git_stream *stream) return 0; } -static int curls_set_proxy(git_stream *stream, const char *proxy_url) +static int curls_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts) { + int error; CURLcode res; curl_stream *s = (curl_stream *) stream; - if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXY, proxy_url)) != CURLE_OK) + if ((error = git_proxy_options_dup(&s->proxy, proxy_opts)) < 0) + return error; + + if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXY, s->proxy.url)) != CURLE_OK) return seterr_curl(s); return 0; diff --git a/src/openssl_stream.c b/src/openssl_stream.c index a65f5586e..edea8fef7 100644 --- a/src/openssl_stream.c +++ b/src/openssl_stream.c @@ -496,11 +496,11 @@ int openssl_certificate(git_cert **out, git_stream *stream) return 0; } -static int openssl_set_proxy(git_stream *stream, const char *proxy_url) +static int openssl_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts) { openssl_stream *st = (openssl_stream *) stream; - return git_stream_set_proxy(st->io, proxy_url); + return git_stream_set_proxy(st->io, proxy_opts); } ssize_t openssl_write(git_stream *stream, const char *data, size_t len, int flags) diff --git a/src/stream.h b/src/stream.h index 4692c7115..d35477591 100644 --- a/src/stream.h +++ b/src/stream.h @@ -35,14 +35,14 @@ GIT_INLINE(int) git_stream_supports_proxy(git_stream *st) return st->proxy_support; } -GIT_INLINE(int) git_stream_set_proxy(git_stream *st, const char *proxy_url) +GIT_INLINE(int) git_stream_set_proxy(git_stream *st, const git_proxy_options *proxy_opts) { if (!st->proxy_support) { giterr_set(GITERR_INVALID, "proxy not supported on this stream"); return -1; } - return st->set_proxy(st, proxy_url); + return st->set_proxy(st, proxy_opts); } GIT_INLINE(ssize_t) git_stream_read(git_stream *st, void *data, size_t len) diff --git a/src/transports/http.c b/src/transports/http.c index 88b124bf7..03a16da98 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -555,10 +555,40 @@ static int write_chunk(git_stream *io, const char *buffer, size_t len) return 0; } +static int apply_proxy_config(http_subtransport *t) +{ + int error; + git_proxy_t proxy_type; + + if (!git_stream_supports_proxy(t->io)) + return 0; + + proxy_type = t->owner->proxy.type; + + if (proxy_type == GIT_PROXY_NONE) + return 0; + + if (proxy_type == GIT_PROXY_AUTO) { + char *url; + git_proxy_options opts = GIT_PROXY_OPTIONS_INIT; + + if ((error = git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &url)) < 0) + return error; + + opts.type = GIT_PROXY_HTTP; + opts.url = url; + error = git_stream_set_proxy(t->io, &opts); + git__free(url); + + return error; + } + + return git_stream_set_proxy(t->io, &t->owner->proxy); +} + static int http_connect(http_subtransport *t) { int error; - char *proxy_url; if (t->connected && http_should_keep_alive(&t->parser) && @@ -586,14 +616,7 @@ static int http_connect(http_subtransport *t) GITERR_CHECK_VERSION(t->io, GIT_STREAM_VERSION, "git_stream"); - if (git_stream_supports_proxy(t->io) && - !git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &proxy_url)) { - error = git_stream_set_proxy(t->io, proxy_url); - git__free(proxy_url); - - if (error < 0) - return error; - } + apply_proxy_config(t); error = git_stream_connect(t->io); From 60d717c6f1238f810402956779dcebb10f0cf175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 2 Oct 2015 10:10:13 +0200 Subject: [PATCH 08/14] proxy: add a payload field for the proxy options I don't quite recall what we do in the other places where we use this, but we should pass this payload to the callbacks. --- include/git2/proxy.h | 6 ++++++ include/git2/sys/remote.h | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 include/git2/sys/remote.h diff --git a/include/git2/proxy.h b/include/git2/proxy.h index 2a3ce8f3e..b45b55b3b 100644 --- a/include/git2/proxy.h +++ b/include/git2/proxy.h @@ -73,6 +73,12 @@ typedef struct { * to disallow it or a negative value to indicate an error. */ git_transport_certificate_check_cb certificate_check; + + /** + * Payload to be provided to the credentials and certificate + * check callbacks. + */ + void *payload; } git_proxy_options; #define GIT_PROXY_OPTIONS_VERSION 1 diff --git a/include/git2/sys/remote.h b/include/git2/sys/remote.h new file mode 100644 index 000000000..3037b411c --- /dev/null +++ b/include/git2/sys/remote.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_sys_git_transport_h +#define INCLUDE_sys_git_transport_h + +#include "git2/net.h" +#include "git2/types.h" + +GIT_BEGIN_DECL + +GIT_END_DECL From 467e2cb1d71b9ec01878e05f71d50e87f110ec89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 2 Oct 2015 10:11:43 +0200 Subject: [PATCH 09/14] curl: ask for proxy credentials --- src/curl_stream.c | 85 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 4 deletions(-) diff --git a/src/curl_stream.c b/src/curl_stream.c index f48dd2249..98de187dd 100644 --- a/src/curl_stream.c +++ b/src/curl_stream.c @@ -23,6 +23,7 @@ typedef struct { git_cert_x509 cert_info; git_strarray cert_info_strings; git_proxy_options proxy; + git_cred *proxy_cred; } curl_stream; static int seterr_curl(curl_stream *s) @@ -31,21 +32,94 @@ static int seterr_curl(curl_stream *s) return -1; } +GIT_INLINE(int) error_no_credentials(void) +{ + giterr_set(GITERR_NET, "proxy authentication required, but no callback provided"); + return GIT_EAUTH; +} + +static int apply_proxy_creds(curl_stream *s) +{ + CURLcode res; + git_cred_userpass_plaintext *userpass; + + if (!s->proxy_cred) + return GIT_ENOTFOUND; + + userpass = (git_cred_userpass_plaintext *) s->proxy_cred; + if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYUSERNAME, userpass->username)) != CURLE_OK) + return seterr_curl(s); + if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYPASSWORD, userpass->password)) != CURLE_OK) + return seterr_curl(s); + + return 0; +} + +static int ask_and_apply_proxy_creds(curl_stream *s) +{ + int error; + git_proxy_options *opts = &s->proxy; + + if (!opts->credentials) + return error_no_credentials(); + + /* TODO: see if PROXYAUTH_AVAIL helps us here */ + git_cred_free(s->proxy_cred); + s->proxy_cred = NULL; + giterr_clear(); + error = opts->credentials(&s->proxy_cred, opts->url, NULL, GIT_CREDTYPE_USERPASS_PLAINTEXT, opts->payload); + if (error == GIT_PASSTHROUGH) + return error_no_credentials(); + if (error < 0) { + if (!giterr_last()) + giterr_set(GITERR_NET, "proxy authentication was aborted by the user"); + return error; + } + + if (s->proxy_cred->credtype != GIT_CREDTYPE_USERPASS_PLAINTEXT) { + giterr_set(GITERR_NET, "credentials callback returned invalid credential type"); + return -1; + } + + return apply_proxy_creds(s); +} + static int curls_connect(git_stream *stream) { curl_stream *s = (curl_stream *) stream; - long sockextr; - int failed_cert = 0; + long sockextr, connect_last = 0; + int failed_cert = 0, error; + bool retry_connect; CURLcode res; - res = curl_easy_perform(s->handle); + + /* Apply any credentials we've already established */ + error = apply_proxy_creds(s); + if (error < 0 && error != GIT_ENOTFOUND) + return seterr_curl(s); + + do { + retry_connect = 0; + res = curl_easy_perform(s->handle); + + curl_easy_getinfo(s->handle, CURLINFO_HTTP_CONNECTCODE, &connect_last); + + /* HTTP 407 Proxy Authentication Required */ + if (connect_last == 407) { + if ((error = ask_and_apply_proxy_creds(s)) < 0) + return error; + + retry_connect = true; + } + } while (retry_connect); if (res != CURLE_OK && res != CURLE_PEER_FAILED_VERIFICATION) return seterr_curl(s); if (res == CURLE_PEER_FAILED_VERIFICATION) failed_cert = 1; - if ((res = curl_easy_getinfo(s->handle, CURLINFO_LASTSOCKET, &sockextr)) != CURLE_OK) + if ((res = curl_easy_getinfo(s->handle, CURLINFO_LASTSOCKET, &sockextr)) != CURLE_OK) { return seterr_curl(s); + } s->socket = sockextr; @@ -109,6 +183,9 @@ static int curls_set_proxy(git_stream *stream, const git_proxy_options *proxy_op if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXY, s->proxy.url)) != CURLE_OK) return seterr_curl(s); + if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY)) != CURLE_OK) + return seterr_curl(s); + return 0; } From bf6f7ad2974fc3088b2d9f3b0afe41febefbb209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 30 Sep 2015 17:42:53 +0200 Subject: [PATCH 10/14] winhttp: correctly detect HTTPS usage --- src/transports/winhttp.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 5a506d20d..d9f38c826 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -325,6 +325,9 @@ static int userpass_from_url(wchar_t **user, int *user_len, return 0; } +#define SCHEME_HTTP "http://" +#define SCHEME_HTTPS "https://" + static int winhttp_stream_connect(winhttp_stream *s) { winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); @@ -388,6 +391,15 @@ static int winhttp_stream_connect(winhttp_stream *s) WINHTTP_PROXY_INFO proxy_info; wchar_t *proxy_wide; + if (!git__prefixcmp(proxy_url, SCHEME_HTTP)) { + t->proxy_connection_data.use_ssl = false; + } else if (!git__prefixcmp(proxy_url, SCHEME_HTTPS)) { + t->proxy_connection_data.use_ssl = true; + } else { + giterr_set(GITERR_NET, "invalid URL: '%s'", proxy_url); + return -1; + } + if ((error = gitno_extract_url_parts(&t->proxy_connection_data.host, &t->proxy_connection_data.port, NULL, &t->proxy_connection_data.user, &t->proxy_connection_data.pass, proxy_url, NULL)) < 0) goto on_error; @@ -398,9 +410,9 @@ static int winhttp_stream_connect(winhttp_stream *s) } if (t->proxy_connection_data.use_ssl) - git_buf_puts(&processed_url, "https://"); + git_buf_PUTS(&processed_url, SCHEME_HTTPS); else - git_buf_puts(&processed_url, "http://"); + git_buf_PUTS(&processed_url, SCHEME_HTTP); git_buf_puts(&processed_url, t->proxy_connection_data.host); if (t->proxy_connection_data.port) From db01724fd969a7d01711e1b8e6f8d763873c9245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 14 Mar 2016 13:42:10 +0100 Subject: [PATCH 11/14] CI: start the proxy before the build so it's ready It takes a bit for the propxy to get ready to accept connections, so start it before the build so we can be reasonably sure that it's going to be ready in time. --- appveyor.yml | 4 ++-- script/cibuild.sh | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 4c58df6b3..b3bd3994d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,12 +34,12 @@ build_script: test_script: - ps: | $ErrorActionPreference="Stop" + # Run this early so we know it's ready by the time we need it + Start-Job { java -jar $Env:APPVEYOR_BUILD_FOLDER\build\poxyproxy.jar -d --port 8080 --credentials foo:bar } ctest -V -R libgit2_clar $env:GITTEST_REMOTE_URL="https://github.com/libgit2/non-existent" $env:GITTEST_REMOTE_USER="libgit2test" ctest -V -R libgit2_clar-cred_callback - Start-Job { java -jar $Env:APPVEYOR_BUILD_FOLDER\build\poxyproxy.jar -d --port 8080 --credentials foo:bar } - ctest -V . $env:GITTEST_REMOTE_PROXY_URL = "http://foo:bar@localhost:8080" .\Debug\libgit2_clar.exe -sonline::clone::proxy_credentials_in_url $env:GITTEST_REMOTE_PROXY_URL = "http://localhost:8080" diff --git a/script/cibuild.sh b/script/cibuild.sh index b2a928a65..92e926490 100755 --- a/script/cibuild.sh +++ b/script/cibuild.sh @@ -6,6 +6,11 @@ then exit $?; fi +# Should we ask Travis to cache this file? +curl -L https://github.com/ethomson/poxyproxy/releases/download/v0.1.0/poxyproxy-0.1.0.jar >poxyproxy.jar || exit $? +# Run this early so we know it's ready by the time we need it +java -jar poxyproxy.jar -d --port 8080 --credentials foo:bar & + mkdir _build cd _build # shellcheck disable=SC2086 @@ -50,9 +55,6 @@ export GITTEST_REMOTE_SSH_PUBKEY="$HOME/.ssh/id_rsa.pub" export GITTEST_REMOTE_SSH_PASSPHRASE="" -# Can we ask Travis to cache this file? -curl -L https://github.com/ethomson/poxyproxy/releases/download/v0.1.0/poxyproxy-0.1.0.jar >poxyproxy.jar || exit $? - if [ -e ./libgit2_clar ]; then ./libgit2_clar -sonline::push -sonline::clone::ssh_cert && ./libgit2_clar -sonline::clone::ssh_with_paths || exit $? @@ -60,14 +62,13 @@ if [ -e ./libgit2_clar ]; then ./libgit2_clar -sonline::clone::cred_callback || exit $? fi - java -jar poxyproxy.jar -d --port 8080 --credentials foo:bar & - + # Use the proxy we started at the beginning export GITTEST_REMOTE_PROXY_URL="http://foo:bar@localhost:8080/" - ./libgit2_clar -sonline::clone::proxy_credentials_in_url + ./libgit2_clar -sonline::clone::proxy_credentials_in_url || exit $? export GITTEST_REMOTE_PROXY_URL="http://localhost:8080/" export GITTEST_REMOTE_PROXY_USER="foo" export GITTEST_REMOTE_PROXY_PASS="bar" - ./libgit2_clar -sonline::clone::proxy_credentials_request + ./libgit2_clar -sonline::clone::proxy_credentials_request || exit $? fi From 0d72f67f28d52b3d7fb2760484fb51c014273bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 14 Mar 2016 17:36:04 +0100 Subject: [PATCH 12/14] proxy: don't specify the protocol in the type We leave this up to the scheme in the url field. The type should only tell us about whether we want a proxy and whether we want to auto-detect it. --- include/git2/proxy.h | 15 +++++---------- src/transports/http.c | 2 +- src/transports/winhttp.c | 2 +- tests/online/clone.c | 4 ++-- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/include/git2/proxy.h b/include/git2/proxy.h index b45b55b3b..dcd615633 100644 --- a/include/git2/proxy.h +++ b/include/git2/proxy.h @@ -18,6 +18,9 @@ GIT_BEGIN_DECL typedef enum { /** * Do not attempt to connect through a proxy + * + * If built against lbicurl, it itself may attempt to connect + * to a proxy if the environment variables specify it. */ GIT_PROXY_NONE, /** @@ -25,17 +28,9 @@ typedef enum { */ GIT_PROXY_AUTO, /** - * Connect through a HTTP proxy + * Connect via the URL given in the options */ - GIT_PROXY_HTTP, - /** - * Connect through a SOCKS v4 proxy - */ - GIT_PROXY_SOCKS4, - /** - * Connect through a SOCKS v5 proxy - */ - GIT_PROXY_SOCKS5, + GIT_PROXY_SPECIFIED, } git_proxy_t; /** diff --git a/src/transports/http.c b/src/transports/http.c index 03a16da98..7bb3374a0 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -575,7 +575,7 @@ static int apply_proxy_config(http_subtransport *t) if ((error = git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &url)) < 0) return error; - opts.type = GIT_PROXY_HTTP; + opts.type = GIT_PROXY_SPECIFIED; opts.url = url; error = git_stream_set_proxy(t->io, &opts); git__free(url); diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index d9f38c826..580c3b91b 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -381,7 +381,7 @@ static int winhttp_stream_connect(winhttp_stream *s) if (git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &proxy_url) < 0) goto on_error; } - else if (proxy_opts->type == GIT_PROXY_HTTP) { + else if (proxy_opts->type == GIT_PROXY_SPECIFIED) { proxy_url = git__strdup(proxy_opts->url); GITERR_CHECK_ALLOC(proxy_url); } diff --git a/tests/online/clone.c b/tests/online/clone.c index d2a5928da..0fc8d4271 100644 --- a/tests/online/clone.c +++ b/tests/online/clone.c @@ -678,7 +678,7 @@ void test_online_clone__proxy_credentials_request(void) if (!_remote_proxy_url || !_remote_proxy_user || !_remote_proxy_pass) cl_skip(); - g_options.fetch_opts.proxy_opts.type = GIT_PROXY_HTTP; + g_options.fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED; g_options.fetch_opts.proxy_opts.url = _remote_proxy_url; g_options.fetch_opts.proxy_opts.credentials = proxy_creds; called_proxy_creds = 0; @@ -691,7 +691,7 @@ void test_online_clone__proxy_credentials_in_url(void) if (!_remote_proxy_url) cl_skip(); - g_options.fetch_opts.proxy_opts.type = GIT_PROXY_HTTP; + g_options.fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED; g_options.fetch_opts.proxy_opts.url = _remote_proxy_url; called_proxy_creds = 0; cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options)); From b8353236bc9aff0ea0501e46e7912383cb6e574c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 19 Apr 2016 10:50:30 +0200 Subject: [PATCH 13/14] CI: run proxy tests with ctest Running clar directly on appveyor makes it think the command returned failure, so it stops the tests. Running it via ctest lets it go through. --- CMakeLists.txt | 2 ++ appveyor.yml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 17b5fba7b..ba3a5184a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -690,6 +690,8 @@ IF (BUILD_CLAR) # Add a test target which runs the cred callback tests, to be # called after setting the url and user ADD_TEST(libgit2_clar-cred_callback libgit2_clar -v -sonline::clone::cred_callback) + ADD_TEST(libgit2_clar-proxy_credentials_in_url libgit2_clar -v -sonline::clone::proxy_credentials_in_url) + ADD_TEST(libgit2_clar-proxy_credentials_request libgit2_clar -v -sonline::clone::proxy_credentials_request) ENDIF () IF (TAGS) diff --git a/appveyor.yml b/appveyor.yml index b3bd3994d..fece95ea7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -41,8 +41,8 @@ test_script: $env:GITTEST_REMOTE_USER="libgit2test" ctest -V -R libgit2_clar-cred_callback $env:GITTEST_REMOTE_PROXY_URL = "http://foo:bar@localhost:8080" - .\Debug\libgit2_clar.exe -sonline::clone::proxy_credentials_in_url + ctest -V -R libgit2_clar-proxy_credentials_in_url $env:GITTEST_REMOTE_PROXY_URL = "http://localhost:8080" $env:GITTEST_REMOTE_PROXY_USER = "foo" $env:GITTEST_REMOTE_PROXY_PASS = "bar" - .\Debug\libgit2_clar.exe -sonline::clone::proxy_credentials_request + ctest -V -R libgit2_clar-proxy_credentials_request From 2638df771172a18dc5da89f039076fcc05ceb4ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 19 Apr 2016 23:05:16 +0200 Subject: [PATCH 14/14] CI: download the proxy jar also on mingw We were downloading the jar from within an block which only runs for MSVC. Move the download to the start of the test so it gets downloaded for both. --- appveyor.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index fece95ea7..4f51aa89c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,19 +27,20 @@ build_script: if ($env:GENERATOR -ne "MSYS Makefiles") { cmake -D ENABLE_TRACE=ON -D BUILD_CLAR=ON -D MSVC_CRTDBG=ON .. -G"$env:GENERATOR" cmake --build . --config Debug - Invoke-WebRequest https://github.com/ethomson/poxyproxy/releases/download/v0.1.0/poxyproxy-0.1.0.jar -OutFile poxyproxy.jar } - cmd: | if "%GENERATOR%"=="MSYS Makefiles" (C:\MinGW\msys\1.0\bin\sh --login /c/projects/libgit2/script/appveyor-mingw.sh) test_script: - ps: | $ErrorActionPreference="Stop" + Invoke-WebRequest https://github.com/ethomson/poxyproxy/releases/download/v0.1.0/poxyproxy-0.1.0.jar -OutFile poxyproxy.jar # Run this early so we know it's ready by the time we need it - Start-Job { java -jar $Env:APPVEYOR_BUILD_FOLDER\build\poxyproxy.jar -d --port 8080 --credentials foo:bar } + $proxyJob = Start-Job { java -jar $Env:APPVEYOR_BUILD_FOLDER\build\poxyproxy.jar -d --port 8080 --credentials foo:bar } ctest -V -R libgit2_clar $env:GITTEST_REMOTE_URL="https://github.com/libgit2/non-existent" $env:GITTEST_REMOTE_USER="libgit2test" ctest -V -R libgit2_clar-cred_callback + Receive-Job -Job $proxyJob $env:GITTEST_REMOTE_PROXY_URL = "http://foo:bar@localhost:8080" ctest -V -R libgit2_clar-proxy_credentials_in_url $env:GITTEST_REMOTE_PROXY_URL = "http://localhost:8080"