Skip to content

Commit 42653c0

Browse files
schacongitster
authored andcommitted
Prompt for a username when an HTTP request 401s
When an HTTP request returns a 401, Git will currently fail with a confusing message saying that it got a 401, which is not very descriptive. Currently if a user wants to use Git over HTTP, they have to use one URL with the username in the URL (e.g. "http://[email protected]/repo.git") for write access and another without the username for unauthenticated read access (unless they want to be prompted for the password each time). However, since the HTTP servers will return a 401 if an action requires authentication, we can prompt for username and password if we see this, allowing us to use a single URL for both purposes. This patch changes http_request to prompt for the username and password, then return HTTP_REAUTH so http_get_strbuf can try again. If it gets a 401 even when a user/pass is supplied, http_request will now return HTTP_NOAUTH which remote_curl can then use to display a more intelligent error message that is less confusing. Signed-off-by: Scott Chacon <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 890a13a commit 42653c0

File tree

3 files changed

+24
-2
lines changed

3 files changed

+24
-2
lines changed

http.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,21 @@ static int http_request(const char *url, void *result, int target, int options)
815815
ret = HTTP_OK;
816816
else if (missing_target(&results))
817817
ret = HTTP_MISSING_TARGET;
818-
else
818+
else if (results.http_code == 401) {
819+
if (user_name) {
820+
ret = HTTP_NOAUTH;
821+
} else {
822+
/*
823+
* git_getpass is needed here because its very likely stdin/stdout are
824+
* pipes to our parent process. So we instead need to use /dev/tty,
825+
* but that is non-portable. Using git_getpass() can at least be stubbed
826+
* on other platforms with a different implementation if/when necessary.
827+
*/
828+
user_name = xstrdup(git_getpass("Username: "));
829+
init_curl_http_auth(slot->curl);
830+
ret = HTTP_REAUTH;
831+
}
832+
} else
819833
ret = HTTP_ERROR;
820834
} else {
821835
error("Unable to start HTTP request for %s", url);
@@ -831,7 +845,11 @@ static int http_request(const char *url, void *result, int target, int options)
831845

832846
int http_get_strbuf(const char *url, struct strbuf *result, int options)
833847
{
834-
return http_request(url, result, HTTP_REQUEST_STRBUF, options);
848+
int http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
849+
if (http_ret == HTTP_REAUTH) {
850+
http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
851+
}
852+
return http_ret;
835853
}
836854

837855
/*

http.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ extern char *get_remote_object_url(const char *url, const char *hex,
126126
#define HTTP_MISSING_TARGET 1
127127
#define HTTP_ERROR 2
128128
#define HTTP_START_FAILED 3
129+
#define HTTP_REAUTH 4
130+
#define HTTP_NOAUTH 5
129131

130132
/*
131133
* Requests an url and stores the result in a strbuf.

remote-curl.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ static struct discovery* discover_refs(const char *service)
132132
case HTTP_MISSING_TARGET:
133133
die("%s not found: did you run git update-server-info on the"
134134
" server?", refs_url);
135+
case HTTP_NOAUTH:
136+
die("Authentication failed");
135137
default:
136138
http_error(refs_url, http_ret);
137139
die("HTTP request failed");

0 commit comments

Comments
 (0)