Commit 0328eef6aad7861f9dbcb2e5b8e276fe65f98c09

Edward Thomson 2018-10-22T11:14:06

http transport: further refactor credential handling Prepare credential handling to understand both git server and proxy server authentication.

diff --git a/src/transports/http.c b/src/transports/http.c
index 6f46094..57aa9f7 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -87,6 +87,7 @@ typedef struct {
 	char parse_buffer_data[NETIO_BUFSIZE];
 	char *content_type;
 	char *location;
+	git_vector proxy_authenticate;
 	git_vector www_authenticate;
 	enum last_cb last_cb;
 	int parse_error;
@@ -292,6 +293,12 @@ static int on_header_ready(http_subtransport *t)
 			GITERR_CHECK_ALLOC(t->content_type);
 		}
 	}
+	else if (!strcasecmp("Proxy-Authenticate", git_buf_cstr(name))) {
+		char *dup = git__strdup(git_buf_cstr(value));
+		GITERR_CHECK_ALLOC(dup);
+
+		git_vector_insert(&t->proxy_authenticate, dup);
+	}
 	else if (!strcasecmp("WWW-Authenticate", git_buf_cstr(name))) {
 		char *dup = git__strdup(git_buf_cstr(value));
 		GITERR_CHECK_ALLOC(dup);
@@ -346,7 +353,14 @@ static int on_header_value(http_parser *parser, const char *str, size_t len)
 	return 0;
 }
 
-static int on_auth_required(http_parser *parser, int allowed_types)
+static int on_auth_required(
+	git_cred **creds,
+	http_parser *parser,
+	const char *url,
+	git_cred_acquire_cb callback,
+	void *callback_payload,
+	const char *username,
+	int allowed_types)
 {
 	parser_context *ctx = (parser_context *) parser->data;
 	http_subtransport *t = ctx->t;
@@ -358,17 +372,13 @@ static int on_auth_required(http_parser *parser, int allowed_types)
 		return t->parse_error;
 	}
 
-	if (t->owner->cred_acquire_cb) {
-		if (t->cred) {
-			t->cred->free(t->cred);
-			t->cred = NULL;
+	if (callback) {
+		if (*creds) {
+			(*creds)->free(*creds);
+			*creds = NULL;
 		}
 
-		ret = t->owner->cred_acquire_cb(&t->cred,
-				  t->owner->url,
-				  t->gitserver_data.user,
-				  allowed_types,
-				  t->owner->cred_acquire_payload);
+		ret = callback(creds, url, username, allowed_types, callback_payload);
 
 		if (ret == GIT_PASSTHROUGH) {
 			/* treat GIT_PASSTHROUGH as if callback isn't set */
@@ -377,9 +387,9 @@ static int on_auth_required(http_parser *parser, int allowed_types)
 			t->parse_error = PARSE_ERROR_EXT;
 			return t->parse_error;
 		} else {
-			assert(t->cred);
+			assert(*creds);
 
-			if (!(t->cred->credtype & allowed_types)) {
+			if (!((*creds)->credtype & allowed_types)) {
 				giterr_set(GITERR_NET, "credential provider returned an invalid cred type");
 				t->parse_error = PARSE_ERROR_GENERIC;
 				return t->parse_error;
@@ -421,7 +431,13 @@ static int on_headers_complete(http_parser *parser)
 
 	/* Check for an authentication failure. */
 	if (parser->status_code == 401 && get_verb == s->verb)
-		return on_auth_required(parser, allowed_www_auth_types);
+		return on_auth_required(&t->cred,
+		    parser,
+		    t->owner->url,
+		    t->owner->cred_acquire_cb,
+		    t->owner->cred_acquire_payload,
+		    t->gitserver_data.user,
+		    allowed_www_auth_types);
 
 	/* Check for a redirect.
 	 * Right now we only permit a redirect to the same hostname. */
@@ -554,6 +570,7 @@ static void clear_parser_state(http_subtransport *t)
 	git__free(t->location);
 	t->location = NULL;
 
+	git_vector_free_deep(&t->proxy_authenticate);
 	git_vector_free_deep(&t->www_authenticate);
 }
 
@@ -1076,10 +1093,8 @@ static int http_action(
 
 	assert(t->gitserver_data.host && t->gitserver_data.port && t->gitserver_data.path);
 
-	if ((ret = load_proxy_config(t)) < 0)
-		return ret;
-
-	if ((ret = http_connect(t)) < 0)
+	if ((ret = load_proxy_config(t)) < 0 ||
+		(ret = http_connect(t)) < 0)
 		return ret;
 
 	switch (action) {