about summary refs log tree commit homepage
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:54:43 -0700
commit883653babd8ee7ea23e6a5c392bb739348b1eb61 (patch)
treedae67a63b5f2398f1aaccebd83dee3c99d6da30a
parent60a6bf5f53635005f4f68d8b8a33172309193623 (diff)
downloadgit-svn-1.4.2.1.tar.gz
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 de5fc44e66..259292d4de 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);