From: Junio C Hamano Date: Wed, 30 Oct 2013 19:09:53 +0000 (-0700) Subject: Merge branch 'jk/http-auth-redirects' X-Git-Tag: v1.8.5-rc0~16 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/177f0a400955f2345c73a5c8b0459d617429ffd9?ds=inline;hp=-c Merge branch 'jk/http-auth-redirects' Handle the case where http transport gets redirected during the authorization request better. * jk/http-auth-redirects: http.c: Spell the null pointer as NULL remote-curl: rewrite base url from info/refs redirects remote-curl: store url as a strbuf remote-curl: make refs_url a strbuf http: update base URLs when we see redirects http: provide effective url to callers http: hoist credential request out of handle_curl_result http: refactor options to http_get_* http_request: factor out curlinfo_strbuf http_get_file: style fixes --- 177f0a400955f2345c73a5c8b0459d617429ffd9 diff --combined http-push.c index 69200baf76,09ebb8f48c..34cb70f90e --- a/http-push.c +++ b/http-push.c @@@ -1330,7 -1330,8 +1330,7 @@@ static struct object_list **process_tre break; } - free(tree->buffer); - tree->buffer = NULL; + free_tree_buffer(tree); return p; } @@@ -1542,7 -1543,7 +1542,7 @@@ static int remote_exists(const char *pa sprintf(url, "%s%s", repo->url, path); - switch (http_get_strbuf(url, NULL, NULL, 0)) { + switch (http_get_strbuf(url, NULL, NULL)) { case HTTP_OK: ret = 1; break; @@@ -1566,7 -1567,7 +1566,7 @@@ static void fetch_symref(const char *pa url = xmalloc(strlen(repo->url) + strlen(path) + 1); sprintf(url, "%s%s", repo->url, path); - if (http_get_strbuf(url, NULL, &buffer, 0) != HTTP_OK) + if (http_get_strbuf(url, &buffer, NULL) != HTTP_OK) die("Couldn't get %s for remote symref\n%s", url, curl_errorstr); free(url); @@@ -1975,7 -1976,7 +1975,7 @@@ int main(int argc, char **argv pushing = 0; if (prepare_revision_walk(&revs)) die("revision walk setup failed"); - mark_edges_uninteresting(revs.commits, &revs, NULL); + mark_edges_uninteresting(&revs, NULL); objects_to_send = get_delta(&revs, ref_lock); finish_all_active_slots(); diff --combined http.c index 0ddb164a6f,3447945ee4..bcf54aa35f --- a/http.c +++ b/http.c @@@ -3,7 -3,6 +3,7 @@@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "urlmatch.h" #include "credential.h" #include "version.h" #include "pkt-line.h" @@@ -46,8 -45,7 +46,8 @@@ static long curl_low_speed_time = -1 static int curl_ftp_no_epsv; static const char *curl_http_proxy; static const char *curl_cookie_file; +static int curl_save_cookies; - static struct credential http_auth = CREDENTIAL_INIT; + struct credential http_auth = CREDENTIAL_INIT; static int http_proactive_auth; static const char *user_agent; @@@ -162,7 -160,8 +162,7 @@@ static int http_options(const char *var if (!strcmp("http.sslcainfo", var)) return git_config_string(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { - if (git_config_bool(var, value)) - ssl_cert_password_required = 1; + ssl_cert_password_required = git_config_bool(var, value); return 0; } if (!strcmp("http.ssltry", var)) { @@@ -201,10 -200,6 +201,10 @@@ if (!strcmp("http.cookiefile", var)) return git_config_string(&curl_cookie_file, var, value); + if (!strcmp("http.savecookies", var)) { + curl_save_cookies = git_config_bool(var, value); + return 0; + } if (!strcmp("http.postbuffer", var)) { http_post_buffer = git_config_int(var, value); @@@ -260,42 -255,6 +260,42 @@@ static int has_cert_password(void return 1; } +#if LIBCURL_VERSION_NUM >= 0x071900 +static void set_curl_keepalive(CURL *c) +{ + curl_easy_setopt(c, CURLOPT_TCP_KEEPALIVE, 1); +} + +#elif LIBCURL_VERSION_NUM >= 0x071000 +static int sockopt_callback(void *client, curl_socket_t fd, curlsocktype type) +{ + int ka = 1; + int rc; + socklen_t len = (socklen_t)sizeof(ka); + + if (type != CURLSOCKTYPE_IPCXN) + return 0; + + rc = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&ka, len); + if (rc < 0) + warning("unable to set SO_KEEPALIVE on socket %s", + strerror(errno)); + + return 0; /* CURL_SOCKOPT_OK only exists since curl 7.21.5 */ +} + +static void set_curl_keepalive(CURL *c) +{ + curl_easy_setopt(c, CURLOPT_SOCKOPTFUNCTION, sockopt_callback); +} + +#else +static void set_curl_keepalive(CURL *c) +{ + /* not supported on older curl versions */ +} +#endif + static CURL *get_curl_handle(void) { CURL *result = curl_easy_init(); @@@ -368,8 -327,6 +368,8 @@@ curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); } + set_curl_keepalive(result); + return result; } @@@ -384,20 -341,10 +384,20 @@@ void http_init(struct remote *remote, c { char *low_speed_limit; char *low_speed_time; + char *normalized_url; + struct urlmatch_config config = { STRING_LIST_INIT_DUP }; + + config.section = "http"; + config.key = NULL; + config.collect_fn = http_options; + config.cascade_fn = git_default_config; + config.cb = NULL; http_is_verbose = 0; + normalized_url = url_normalize(url, &config.url); - git_config(http_options, NULL); + git_config(urlmatch_config_entry, &config); + free(normalized_url); curl_global_init(CURL_GLOBAL_ALL); @@@ -566,8 -513,6 +566,8 @@@ struct active_request_slot *get_active_ slot->callback_data = NULL; slot->callback_func = NULL; curl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file); + if (curl_save_cookies) + curl_easy_setopt(slot->curl, CURLOPT_COOKIEJAR, curl_cookie_file); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header); curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr); curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL); @@@ -861,7 -806,6 +861,6 @@@ int handle_curl_result(struct slot_resu credential_reject(&http_auth); return HTTP_NOAUTH; } else { - credential_fill(&http_auth); return HTTP_REAUTH; } } else { @@@ -875,12 -819,25 +874,25 @@@ } } + static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf) + { + char *ptr; + CURLcode ret; + + strbuf_reset(buf); + ret = curl_easy_getinfo(curl, info, &ptr); + if (!ret && ptr) + strbuf_addstr(buf, ptr); + return ret; + } + /* http_request() targets */ #define HTTP_REQUEST_STRBUF 0 #define HTTP_REQUEST_FILE 1 - static int http_request(const char *url, struct strbuf *type, - void *result, int target, int options) + static int http_request(const char *url, + void *result, int target, + const struct http_get_options *options) { struct active_request_slot *slot; struct slot_results results; @@@ -913,9 -870,9 +925,9 @@@ } strbuf_addstr(&buf, "Pragma:"); - if (options & HTTP_NO_CACHE) + if (options && options->no_cache) strbuf_addstr(&buf, " no-cache"); - if (options & HTTP_KEEP_ERROR) + if (options && options->keep_error) curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 0); headers = curl_slist_append(headers, buf.buf); @@@ -933,13 -890,13 +945,13 @@@ ret = HTTP_START_FAILED; } - if (type) { - char *t; - strbuf_reset(type); - curl_easy_getinfo(slot->curl, CURLINFO_CONTENT_TYPE, &t); - if (t) - strbuf_addstr(type, t); - } + if (options && options->content_type) + curlinfo_strbuf(slot->curl, CURLINFO_CONTENT_TYPE, + options->content_type); + + if (options && options->effective_url) + curlinfo_strbuf(slot->curl, CURLINFO_EFFECTIVE_URL, + options->effective_url); curl_slist_free_all(headers); strbuf_release(&buf); @@@ -947,12 -904,71 +959,71 @@@ return ret; } + /* + * Update the "base" url to a more appropriate value, as deduced by + * redirects seen when requesting a URL starting with "url". + * + * The "asked" parameter is a URL that we asked curl to access, and must begin + * with "base". + * + * The "got" parameter is the URL that curl reported to us as where we ended + * up. + * + * Returns 1 if we updated the base url, 0 otherwise. + * + * Our basic strategy is to compare "base" and "asked" to find the bits + * specific to our request. We then strip those bits off of "got" to yield the + * new base. So for example, if our base is "http://example.com/foo.git", + * and we ask for "http://example.com/foo.git/info/refs", we might end up + * with "https://other.example.com/foo.git/info/refs". We would want the + * new URL to become "https://other.example.com/foo.git". + * + * Note that this assumes a sane redirect scheme. It's entirely possible + * in the example above to end up at a URL that does not even end in + * "info/refs". In such a case we simply punt, as there is not much we can + * do (and such a scheme is unlikely to represent a real git repository, + * which means we are likely about to abort anyway). + */ + static int update_url_from_redirect(struct strbuf *base, + const char *asked, + const struct strbuf *got) + { + const char *tail; + size_t tail_len; + + if (!strcmp(asked, got->buf)) + return 0; + + if (prefixcmp(asked, base->buf)) + die("BUG: update_url_from_redirect: %s is not a superset of %s", + asked, base->buf); + + tail = asked + base->len; + tail_len = strlen(tail); + + if (got->len < tail_len || + strcmp(tail, got->buf + got->len - tail_len)) + return 0; /* insane redirect scheme */ + + strbuf_reset(base); + strbuf_add(base, got->buf, got->len - tail_len); + return 1; + } + static int http_request_reauth(const char *url, - struct strbuf *type, void *result, int target, - int options) + struct http_get_options *options) { - int ret = http_request(url, type, result, target, options); + int ret = http_request(url, result, target, options); + + if (options && options->effective_url && options->base_url) { + if (update_url_from_redirect(options->base_url, + url, options->effective_url)) { + credential_from_url(&http_auth, options->base_url->buf); + url = options->effective_url->buf; + } + } + if (ret != HTTP_REAUTH) return ret; @@@ -962,7 -978,7 +1033,7 @@@ * making our next request. We only know how to do this for * the strbuf case, but that is enough to satisfy current callers. */ - if (options & HTTP_KEEP_ERROR) { + if (options && options->keep_error) { switch (target) { case HTTP_REQUEST_STRBUF: strbuf_reset(result); @@@ -971,15 -987,17 +1042,17 @@@ die("BUG: HTTP_KEEP_ERROR is only supported with strbufs"); } } - return http_request(url, type, result, target, options); + + credential_fill(&http_auth); + + return http_request(url, result, target, options); } int http_get_strbuf(const char *url, - struct strbuf *type, - struct strbuf *result, int options) + struct strbuf *result, + struct http_get_options *options) { - return http_request_reauth(url, type, result, - HTTP_REQUEST_STRBUF, options); + return http_request_reauth(url, result, HTTP_REQUEST_STRBUF, options); } /* @@@ -988,7 -1006,8 +1061,8 @@@ * If a previous interrupted download is detected (i.e. a previous temporary * file is still around) the download is resumed. */ - static int http_get_file(const char *url, const char *filename, int options) + static int http_get_file(const char *url, const char *filename, + struct http_get_options *options) { int ret; struct strbuf tmpfile = STRBUF_INIT; @@@ -996,16 -1015,16 +1070,16 @@@ strbuf_addf(&tmpfile, "%s.temp", filename); result = fopen(tmpfile.buf, "a"); - if (! result) { + if (!result) { error("Unable to open local file %s", tmpfile.buf); ret = HTTP_ERROR; goto cleanup; } - ret = http_request_reauth(url, NULL, result, HTTP_REQUEST_FILE, options); + ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options); fclose(result); - if ((ret == HTTP_OK) && move_temp_to_file(tmpfile.buf, filename)) + if (ret == HTTP_OK && move_temp_to_file(tmpfile.buf, filename)) ret = HTTP_ERROR; cleanup: strbuf_release(&tmpfile); @@@ -1014,12 -1033,15 +1088,15 @@@ int http_fetch_ref(const char *base, struct ref *ref) { + struct http_get_options options = {0}; char *url; struct strbuf buffer = STRBUF_INIT; int ret = -1; + options.no_cache = 1; + url = quote_ref_url(base, ref->name); - if (http_get_strbuf(url, NULL, &buffer, HTTP_NO_CACHE) == HTTP_OK) { + if (http_get_strbuf(url, &buffer, &options) == HTTP_OK) { strbuf_rtrim(&buffer); if (buffer.len == 40) ret = get_sha1_hex(buffer.buf, ref->old_sha1); @@@ -1050,7 -1072,7 +1127,7 @@@ static char *fetch_pack_index(unsigned strbuf_addf(&buf, "%s.temp", sha1_pack_index_name(sha1)); tmp = strbuf_detach(&buf, NULL); - if (http_get_file(url, tmp, 0) != HTTP_OK) { + if (http_get_file(url, tmp, NULL) != HTTP_OK) { error("Unable to get pack index %s", url); free(tmp); tmp = NULL; @@@ -1103,6 -1125,7 +1180,7 @@@ add_pack int http_get_info_packs(const char *base_url, struct packed_git **packs_head) { + struct http_get_options options = {0}; int ret = 0, i = 0; char *url, *data; struct strbuf buf = STRBUF_INIT; @@@ -1112,7 -1135,8 +1190,8 @@@ strbuf_addstr(&buf, "objects/info/packs"); url = strbuf_detach(&buf, NULL); - ret = http_get_strbuf(url, NULL, &buf, HTTP_NO_CACHE); + options.no_cache = 1; + ret = http_get_strbuf(url, &buf, &options); if (ret != HTTP_OK) goto cleanup; diff --combined remote-curl.c index b5ebe01800,ef1684b9df..c9b891adbf --- a/remote-curl.c +++ b/remote-curl.c @@@ -6,24 -6,23 +6,26 @@@ #include "exec_cmd.h" #include "run-command.h" #include "pkt-line.h" +#include "string-list.h" #include "sideband.h" #include "argv-array.h" + #include "credential.h" static struct remote *remote; - static const char *url; /* always ends with a trailing slash */ + /* always ends with a trailing slash */ + static struct strbuf url = STRBUF_INIT; struct options { int verbosity; unsigned long depth; unsigned progress : 1, + check_self_contained_and_connected : 1, followtags : 1, dry_run : 1, thin : 1; }; static struct options options; +static struct string_list cas_options = STRING_LIST_INIT_DUP; static int set_option(const char *name, const char *value) { @@@ -70,22 -69,6 +72,22 @@@ return -1; return 0; } + else if (!strcmp(name, "check-connectivity")) { + if (!strcmp(value, "true")) + options.check_self_contained_and_connected = 1; + else if (!strcmp(value, "false")) + options.check_self_contained_and_connected = 0; + else + return -1; + return 0; + } + else if (!strcmp(name, "cas")) { + struct strbuf val = STRBUF_INIT; + strbuf_addf(&val, "--" CAS_OPT_NAME "=%s", value); + string_list_append(&cas_options, val.buf); + strbuf_release(&val); + return 0; + } else { return 1 /* unsupported */; } @@@ -130,7 -113,8 +132,8 @@@ static struct ref *parse_info_refs(stru mid = &data[i]; if (data[i] == '\n') { if (mid - start != 40) - die("%sinfo/refs not valid: is this a git repository?", url); + die("%sinfo/refs not valid: is this a git repository?", + url.buf); data[i] = 0; ref_name = mid + 1; ref = xmalloc(sizeof(struct ref) + @@@ -149,7 -133,7 +152,7 @@@ } ref = alloc_ref("HEAD"); - if (!http_fetch_ref(url, ref) && + if (!http_fetch_ref(url.buf, ref) && !resolve_remote_symref(ref, refs)) { ref->next = refs; refs = ref; @@@ -203,40 -187,47 +206,47 @@@ static struct discovery* discover_refs( struct strbuf exp = STRBUF_INIT; struct strbuf type = STRBUF_INIT; struct strbuf buffer = STRBUF_INIT; + struct strbuf refs_url = STRBUF_INIT; + struct strbuf effective_url = STRBUF_INIT; struct discovery *last = last_discovery; - char *refs_url; int http_ret, maybe_smart = 0; + struct http_get_options options; if (last && !strcmp(service, last->service)) return last; free_discovery(last); - strbuf_addf(&buffer, "%sinfo/refs", url); - if ((!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) && + strbuf_addf(&refs_url, "%sinfo/refs", url.buf); + if ((!prefixcmp(url.buf, "http://") || !prefixcmp(url.buf, "https://")) && git_env_bool("GIT_SMART_HTTP", 1)) { maybe_smart = 1; - if (!strchr(url, '?')) - strbuf_addch(&buffer, '?'); + if (!strchr(url.buf, '?')) + strbuf_addch(&refs_url, '?'); else - strbuf_addch(&buffer, '&'); - strbuf_addf(&buffer, "service=%s", service); + strbuf_addch(&refs_url, '&'); + strbuf_addf(&refs_url, "service=%s", service); } - refs_url = strbuf_detach(&buffer, NULL); - http_ret = http_get_strbuf(refs_url, &type, &buffer, - HTTP_NO_CACHE | HTTP_KEEP_ERROR); + memset(&options, 0, sizeof(options)); + options.content_type = &type; + options.effective_url = &effective_url; + options.base_url = &url; + options.no_cache = 1; + options.keep_error = 1; + + http_ret = http_get_strbuf(refs_url.buf, &buffer, &options); switch (http_ret) { case HTTP_OK: break; case HTTP_MISSING_TARGET: show_http_message(&type, &buffer); - die("repository '%s' not found", url); + die("repository '%s' not found", url.buf); case HTTP_NOAUTH: show_http_message(&type, &buffer); - die("Authentication failed for '%s'", url); + die("Authentication failed for '%s'", url.buf); default: show_http_message(&type, &buffer); - die("unable to access '%s': %s", url, curl_errorstr); + die("unable to access '%s': %s", url.buf, curl_errorstr); } last= xcalloc(1, sizeof(*last_discovery)); @@@ -277,9 -268,10 +287,10 @@@ else last->refs = parse_info_refs(last); - free(refs_url); + strbuf_release(&refs_url); strbuf_release(&exp); strbuf_release(&type); + strbuf_release(&effective_url); strbuf_release(&buffer); last_discovery = last; return last; @@@ -463,6 -455,8 +474,8 @@@ static int post_rpc(struct rpc_state *r if (large_request) { do { err = probe_rpc(rpc); + if (err == HTTP_REAUTH) + credential_fill(&http_auth); } while (err == HTTP_REAUTH); if (err != HTTP_OK) return -1; @@@ -562,8 -556,10 +575,10 @@@ retry curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc); err = run_slot(slot); - if (err == HTTP_REAUTH && !large_request) + if (err == HTTP_REAUTH && !large_request) { + credential_fill(&http_auth); goto retry; + } if (err != HTTP_OK) err = -1; @@@ -598,7 -594,7 +613,7 @@@ static int rpc_service(struct rpc_stat rpc->out = client.out; strbuf_init(&rpc->result, 0); - strbuf_addf(&buf, "%s%s", url, svc); + strbuf_addf(&buf, "%s%s", url.buf, svc); rpc->service_url = strbuf_detach(&buf, NULL); strbuf_addf(&buf, "Content-Type: application/x-%s-request", svc); @@@ -650,7 -646,7 +665,7 @@@ static int fetch_dumb(int nr_heads, str for (i = 0; i < nr_heads; i++) targets[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1)); - walker = get_http_walker(url); + walker = get_http_walker(url.buf); walker->get_all = 1; walker->get_tree = 1; walker->get_history = 1; @@@ -673,7 -669,7 +688,7 @@@ static int fetch_git(struct discovery * struct strbuf preamble = STRBUF_INIT; char *depth_arg = NULL; int argc = 0, i, err; - const char *argv[15]; + const char *argv[16]; argv[argc++] = "fetch-pack"; argv[argc++] = "--stateless-rpc"; @@@ -687,8 -683,6 +702,8 @@@ argv[argc++] = "-v"; argv[argc++] = "-v"; } + if (options.check_self_contained_and_connected) + argv[argc++] = "--check-self-contained-and-connected"; if (!options.progress) argv[argc++] = "--no-progress"; if (options.depth) { @@@ -697,7 -691,7 +712,7 @@@ depth_arg = strbuf_detach(&buf, NULL); argv[argc++] = depth_arg; } - argv[argc++] = url; + argv[argc++] = url.buf; argv[argc++] = NULL; for (i = 0; i < nr_heads; i++) { @@@ -795,7 -789,7 +810,7 @@@ static int push_dav(int nr_spec, char * argv[argc++] = "--dry-run"; if (options.verbosity > 1) argv[argc++] = "--verbose"; - argv[argc++] = url; + argv[argc++] = url.buf; for (i = 0; i < nr_spec; i++) argv[argc++] = specs[i]; argv[argc++] = NULL; @@@ -811,7 -805,6 +826,7 @@@ static int push_git(struct discovery *h struct rpc_state rpc; int i, err; struct argv_array args; + struct string_list_item *cas_option; argv_array_init(&args); argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status", @@@ -826,9 -819,7 +841,9 @@@ else if (options.verbosity > 1) argv_array_push(&args, "--verbose"); argv_array_push(&args, options.progress ? "--progress" : "--no-progress"); + for_each_string_list_item(cas_option, &cas_options) + argv_array_push(&args, cas_option->string); - argv_array_push(&args, url); + argv_array_push(&args, url.buf); for (i = 0; i < nr_spec; i++) argv_array_push(&args, specs[i]); @@@ -909,14 -900,12 +924,12 @@@ int main(int argc, const char **argv remote = remote_get(argv[1]); if (argc > 2) { - end_url_with_slash(&buf, argv[2]); + end_url_with_slash(&url, argv[2]); } else { - end_url_with_slash(&buf, remote->url[0]); + end_url_with_slash(&url, remote->url[0]); } - url = strbuf_detach(&buf, NULL); - - http_init(remote, url, 0); + http_init(remote, url.buf, 0); do { if (strbuf_getline(&buf, stdin, '\n') == EOF) { @@@ -963,7 -952,6 +976,7 @@@ printf("fetch\n"); printf("option\n"); printf("push\n"); + printf("check-connectivity\n"); printf("\n"); fflush(stdout); } else { diff --combined t/lib-httpd.sh index 54dbbfe5ce,7059cc6c21..ad8f1ef71e --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@@ -141,11 -141,10 +141,11 @@@ stop_httpd() -f "$TEST_PATH/apache.conf" $HTTPD_PARA -k stop } -test_http_push_nonff() { +test_http_push_nonff () { REMOTE_REPO=$1 LOCAL_REPO=$2 BRANCH=$3 + EXPECT_CAS_RESULT=${4-failure} test_expect_success 'non-fast-forward push fails' ' cd "$REMOTE_REPO" && @@@ -168,22 -167,6 +168,22 @@@ test_expect_success 'non-fast-forward push shows help message' ' test_i18ngrep "Updates were rejected because" output ' + + test_expect_${EXPECT_CAS_RESULT} 'force with lease aka cas' ' + HEAD=$( cd "$REMOTE_REPO" && git rev-parse --verify HEAD ) && + test_when_finished '\'' + (cd "$REMOTE_REPO" && git update-ref HEAD "$HEAD") + '\'' && + ( + cd "$LOCAL_REPO" && + git push -v --force-with-lease=$BRANCH:$HEAD origin + ) && + git rev-parse --verify "$BRANCH" >expect && + ( + cd "$REMOTE_REPO" && git rev-parse --verify HEAD + ) >actual && + test_cmp expect actual + ' } setup_askpass_helper() { @@@ -204,7 -187,8 +204,8 @@@ set_askpass() } expect_askpass() { - dest=$HTTPD_DEST + dest=$HTTPD_DEST${3+/$3} + { case "$1" in none) diff --combined t/lib-httpd/apache.conf index 397c480401,4a261f13f5..3a03e8263d --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@@ -22,9 -22,6 +22,9 @@@ ErrorLog error.lo LoadModule version_module modules/mod_version.so + + LoadModule headers_module modules/mod_headers.so + LockFile accept.lock @@@ -90,11 -87,6 +90,11 @@@ Alias /auth/dumb/ www/auth/dumb SetEnv GIT_HTTP_EXPORT_ALL SetEnv GIT_NAMESPACE ns + + SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} + SetEnv GIT_HTTP_EXPORT_ALL + Header set Set-Cookie name=value + ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1 ScriptAlias /broken_smart/ broken-smart-http.sh/ @@@ -110,6 -102,8 +110,8 @@@ RewriteEngine on RewriteRule ^/smart-redir-perm/(.*)$ /smart/$1 [R=301] RewriteRule ^/smart-redir-temp/(.*)$ /smart/$1 [R=302] + RewriteRule ^/smart-redir-auth/(.*)$ /auth/smart/$1 [R=301] + RewriteRule ^/smart-redir-limited/(.*)/info/refs$ /smart/$1/info/refs [R=301] LoadModule ssl_module modules/mod_ssl.so diff --combined t/t5551-http-fetch.sh index 8196af19f6,1b71bb5156..fb16833f76 --- a/t/t5551-http-fetch.sh +++ b/t/t5551-http-fetch.sh @@@ -113,6 -113,10 +113,10 @@@ test_expect_success 'follow redirects ( git clone $HTTPD_URL/smart-redir-temp/repo.git --quiet repo-t ' + test_expect_success 'redirects re-root further requests' ' + git clone $HTTPD_URL/smart-redir-limited/repo.git repo-redir-limited + ' + test_expect_success 'clone from password-protected repository' ' echo two >expect && set_askpass user@host && @@@ -146,6 -150,13 +150,13 @@@ test_expect_success 'no-op half-auth fe expect_askpass none ' + test_expect_success 'redirects send auth to new location' ' + set_askpass user@host && + git -c credential.useHttpPath=true \ + clone $HTTPD_URL/smart-redir-auth/repo.git repo-redir-auth && + expect_askpass both user@host auth/smart/repo.git + ' + test_expect_success 'disable dumb http on server' ' git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ config http.getanyfile false @@@ -187,22 -198,6 +198,22 @@@ test_expect_success 'dumb clone via htt test_cmp expect actual ' +cat >cookies.txt <expect_cookies.txt < cookies_tail.txt + test_cmp expect_cookies.txt cookies_tail.txt +' + test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '