@matheusbsbs / matheus-bagliano / commits / 42653c09c8
Fork 0

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://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>

Scott Chacon committed Apr 1, 2010 at 15:14 UTC 42653c09c85015addc6fa8dd4d49cb250253412e
3 files changed +24 -2
http.c
+20 -2
@@ -815,7 +815,21 @@ static int http_request(const char *url, void *result, int target, int options)
815 ret = HTTP_OK;
816 else if (missing_target(&results))
817 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
833 ret = HTTP_ERROR;
834 } else {
835 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)
845
846 int http_get_strbuf(const char *url, struct strbuf *result, int options)
847 {
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;
853 }
854
855 /*
http.h
+2
@@ -126,6 +126,8 @@ extern char *get_remote_object_url(const char *url, const char *hex,
126 #define HTTP_MISSING_TARGET 1
127 #define HTTP_ERROR 2
128 #define HTTP_START_FAILED 3
129 +#define HTTP_REAUTH 4
130 +#define HTTP_NOAUTH 5
131
132 /*
133 * Requests an url and stores the result in a strbuf.
remote-curl.c
+2
@@ -132,6 +132,8 @@ static struct discovery* discover_refs(const char *service)
132 case HTTP_MISSING_TARGET:
133 die("%s not found: did you run git update-server-info on the"
134 " server?", refs_url);
135 + case HTTP_NOAUTH:
136 + die("Authentication failed");
137 default:
138 http_error(refs_url, http_ret);
139 die("HTTP request failed");