summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2006-09-12 23:53:27 -0700
committerJunio C Hamano <junkio@cox.net>2006-09-13 00:33:14 -0700
commit5df1e0d05cc42aeef9bf2fce243375fb6dac2121 (patch)
tree13b3c830cc345cdc9eb54c99578380b51e26f61e
parentcdad8bbe92a447233133be8f9f3015c1bd7e10eb (diff)
downloadgit-5df1e0d05cc42aeef9bf2fce243375fb6dac2121.tar.gz
http-fetch: fix alternates handling.
Fetch over http from a repository that uses alternates to borrow from neighbouring repositories were quite broken, apparently for some time now. We parse input and count bytes to allocate the new buffer, and when we copy into that buffer we know exactly how many bytes we want to copy from where. Using strlcpy for it was simply stupid, and the code forgot to take it into account that strlcpy terminated the string with NUL. Signed-off-by: Junio C Hamano <junkio@cox.net>
-rw-r--r--http-fetch.c39
1 files changed, 34 insertions, 5 deletions
diff --git a/http-fetch.c b/http-fetch.c
index fac17607b4..a113bb8c4b 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -559,9 +559,36 @@ static void process_alternates_response(void *callback_data)
char *target = NULL;
char *path;
if (data[i] == '/') {
- serverlen = strchr(base + 8, '/') - base;
- okay = 1;
+ /* This counts
+ * http://git.host/pub/scm/linux.git/
+ * -----------here^
+ * so memcpy(dst, base, serverlen) will
+ * copy up to "...git.host".
+ */
+ const char *colon_ss = strstr(base,"://");
+ if (colon_ss) {
+ serverlen = (strchr(colon_ss + 3, '/')
+ - base);
+ okay = 1;
+ }
} else if (!memcmp(data + i, "../", 3)) {
+ /* Relative URL; chop the corresponding
+ * number of subpath from base (and ../
+ * from data), and concatenate the result.
+ *
+ * The code first drops ../ from data, and
+ * then drops one ../ from data and one path
+ * from base. IOW, one extra ../ is dropped
+ * from data than path is dropped from base.
+ *
+ * This is not wrong. The alternate in
+ * http://git.host/pub/scm/linux.git/
+ * to borrow from
+ * http://git.host/pub/scm/linus.git/
+ * is ../../linus.git/objects/. You need
+ * two ../../ to borrow from your direct
+ * neighbour.
+ */
i += 3;
serverlen = strlen(base);
while (i + 2 < posn &&
@@ -583,11 +610,13 @@ static void process_alternates_response(void *callback_data)
okay = 1;
}
}
- /* skip 'objects' at end */
+ /* skip "objects\n" at end */
if (okay) {
target = xmalloc(serverlen + posn - i - 6);
- strlcpy(target, base, serverlen);
- strlcpy(target + serverlen, data + i, posn - i - 6);
+ memcpy(target, base, serverlen);
+ memcpy(target + serverlen, data + i,
+ posn - i - 7);
+ target[serverlen + posn - i - 7] = 0;
if (get_verbosely)
fprintf(stderr,
"Also look at %s\n", target);