Commit 6af8572c7f282f458c6c63b005a85c46a14569db

Edward Thomson 2018-10-22T11:29:01

http transport: cap number of authentication replays Put a limit on the number of authentication replays in the HTTP transport. Standardize on 7 replays for authentication or redirects, which matches the behavior of the WinHTTP transport.

diff --git a/src/transports/http.c b/src/transports/http.c
index 29924a0..5c060f4 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -66,7 +66,7 @@ typedef struct {
 	unsigned sent_request : 1,
 		received_response : 1,
 		chunked : 1,
-		redirect_count : 3;
+		replay_count : 3;
 } http_stream;
 
 typedef struct {
@@ -424,6 +424,12 @@ static int on_headers_complete(http_parser *parser)
 	git_buf buf = GIT_BUF_INIT;
 	int allowed_proxy_auth_types = 0, allowed_www_auth_types = 0;
 
+	/* Enforce a reasonable cap on the number of replays */
+	if (s->replay_count++ >= GIT_HTTP_REPLAY_MAX) {
+		giterr_set(GITERR_NET, "too many redirects or authentication replays");
+		return t->parse_error = PARSE_ERROR_GENERIC;
+	}
+
 	/* Both parse_header_name and parse_header_value are populated
 	 * and ready for consumption. */
 	if (VALUE == t->last_cb)
@@ -472,11 +478,6 @@ static int on_headers_complete(http_parser *parser)
 	     parser->status_code == 308) &&
 	    t->location) {
 
-		if (s->redirect_count >= 7) {
-			giterr_set(GITERR_NET, "too many redirects");
-			return t->parse_error = PARSE_ERROR_GENERIC;
-		}
-
 		if (gitno_connection_data_from_url(&t->gitserver_data, t->location, s->service_url) < 0)
 			return t->parse_error = PARSE_ERROR_GENERIC;
 
@@ -489,8 +490,6 @@ static int on_headers_complete(http_parser *parser)
 		t->location = NULL;
 
 		t->connected = 0;
-		s->redirect_count++;
-
 		t->parse_error = PARSE_ERROR_REPLAY;
 		return 0;
 	}
diff --git a/src/transports/http.h b/src/transports/http.h
index 6c4ecc9..b094757 100644
--- a/src/transports/http.h
+++ b/src/transports/http.h
@@ -10,6 +10,8 @@
 
 #include "buffer.h"
 
+#define GIT_HTTP_REPLAY_MAX 7
+
 GIT_INLINE(int) git_http__user_agent(git_buf *buf)
 {
 	const char *ua = git_libgit2__user_agent();
diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c
index 5e7bde7..30e2ecb 100644
--- a/src/transports/winhttp.c
+++ b/src/transports/winhttp.c
@@ -932,7 +932,7 @@ static int winhttp_stream_read(
 
 replay:
 	/* Enforce a reasonable cap on the number of replays */
-	if (++replay_count >= 7) {
+	if (replay_count++ >= GIT_HTTP_REPLAY_MAX) {
 		giterr_set(GITERR_NET, "too many redirects or authentication replays");
 		return -1;
 	}