Skip to content

Commit

Permalink
Prompt for a username when an HTTP request 401s
Browse files Browse the repository at this point in the history
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://user@host.com/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 <schacon@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
schacon authored and gitster committed Apr 2, 2010
1 parent 890a13a commit 42653c0
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 2 deletions.
22 changes: 20 additions & 2 deletions http.c
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,21 @@ static int http_request(const char *url, void *result, int target, int options)
ret = HTTP_OK;
else if (missing_target(&results))
ret = HTTP_MISSING_TARGET;
else
else if (results.http_code == 401) {
if (user_name) {
ret = HTTP_NOAUTH;
} else {
/*
* git_getpass is needed here because its very likely stdin/stdout are
* pipes to our parent process. So we instead need to use /dev/tty,
* but that is non-portable. Using git_getpass() can at least be stubbed
* on other platforms with a different implementation if/when necessary.
*/
user_name = xstrdup(git_getpass("Username: "));
init_curl_http_auth(slot->curl);
ret = HTTP_REAUTH;
}
} else
ret = HTTP_ERROR;
} else {
error("Unable to start HTTP request for %s", url);
Expand All @@ -831,7 +845,11 @@ static int http_request(const char *url, void *result, int target, int options)

int http_get_strbuf(const char *url, struct strbuf *result, int options)
{
return http_request(url, result, HTTP_REQUEST_STRBUF, options);
int http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
if (http_ret == HTTP_REAUTH) {
http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
}
return http_ret;
}

/*
Expand Down
2 changes: 2 additions & 0 deletions http.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ extern char *get_remote_object_url(const char *url, const char *hex,
#define HTTP_MISSING_TARGET 1
#define HTTP_ERROR 2
#define HTTP_START_FAILED 3
#define HTTP_REAUTH 4
#define HTTP_NOAUTH 5

/*
* Requests an url and stores the result in a strbuf.
Expand Down
2 changes: 2 additions & 0 deletions remote-curl.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ static struct discovery* discover_refs(const char *service)
case HTTP_MISSING_TARGET:
die("%s not found: did you run git update-server-info on the"
" server?", refs_url);
case HTTP_NOAUTH:
die("Authentication failed");
default:
http_error(refs_url, http_ret);
die("HTTP request failed");
Expand Down

0 comments on commit 42653c0

Please sign in to comment.