summaryrefslogtreecommitdiff
path: root/http.c
diff options
context:
space:
mode:
authorTay Ray Chuan <rctay89@gmail.com>2009-06-06 08:43:59 (GMT)
committerJunio C Hamano <gitster@pobox.com>2009-06-06 18:03:11 (GMT)
commitb8caac2b8ab6482e7ab59c8ec18f1c3d90e7387d (patch)
tree173bbc81d92dc47a6c7bfac672a12fe53f9deb1d /http.c
parent9af5abd9939585bb588d537085138563922c6abe (diff)
downloadgit-b8caac2b8ab6482e7ab59c8ec18f1c3d90e7387d.zip
git-b8caac2b8ab6482e7ab59c8ec18f1c3d90e7387d.tar.gz
git-b8caac2b8ab6482e7ab59c8ec18f1c3d90e7387d.tar.bz2
http*: add http_get_info_packs
http-push.c and http-walker.c no longer have to use fetch_index or setup_index; they simply need to use http_get_info_packs, a new http method, in their fetch_indices implementations. Move fetch_index() and rename to fetch_pack_index() in http.c; this method is not meant to be used outside of http.c. It invokes end_url_with_slash with base_url; apart from that change, the code is identical. Move setup_index() and rename to fetch_and_setup_pack_index() in http.c; this method is not meant to be used outside of http.c. Do not immediately set ret to 0 in http-walker.c::fetch_indices(); instead do it in the HTTP_MISSING_TARGET case, to make it clear that the HTTP_OK and HTTP_MISSING_TARGET cases both return 0. Signed-off-by: Tay Ray Chuan <rctay89@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'http.c')
-rw-r--r--http.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/http.c b/http.c
index 2a49372..96d83d5 100644
--- a/http.c
+++ b/http.c
@@ -790,3 +790,167 @@ int http_fetch_ref(const char *base, struct ref *ref)
free(url);
return ret;
}
+
+/* Helpers for fetching packs */
+static int fetch_pack_index(unsigned char *sha1, const char *base_url)
+{
+ int ret = 0;
+ char *hex = xstrdup(sha1_to_hex(sha1));
+ char *filename;
+ char *url;
+ char tmpfile[PATH_MAX];
+ long prev_posn = 0;
+ char range[RANGE_HEADER_SIZE];
+ struct strbuf buf = STRBUF_INIT;
+ struct curl_slist *range_header = NULL;
+
+ FILE *indexfile;
+ struct active_request_slot *slot;
+ struct slot_results results;
+
+ /* Don't use the index if the pack isn't there */
+ end_url_with_slash(&buf, base_url);
+ strbuf_addf(&buf, "objects/pack/pack-%s.pack", hex);
+ url = strbuf_detach(&buf, 0);
+
+ slot = get_active_slot();
+ slot->results = &results;
+ curl_easy_setopt(slot->curl, CURLOPT_URL, url);
+ curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
+ if (start_active_slot(slot)) {
+ run_active_slot(slot);
+ if (results.curl_result != CURLE_OK) {
+ ret = error("Unable to verify pack %s is available",
+ hex);
+ goto cleanup_pack;
+ }
+ } else {
+ ret = error("Unable to start request");
+ goto cleanup_pack;
+ }
+
+ if (has_pack_index(sha1)) {
+ ret = 0;
+ goto cleanup_pack;
+ }
+
+ if (http_is_verbose)
+ fprintf(stderr, "Getting index for pack %s\n", hex);
+
+ end_url_with_slash(&buf, base_url);
+ strbuf_addf(&buf, "objects/pack/pack-%s.idx", hex);
+ url = strbuf_detach(&buf, NULL);
+
+ filename = sha1_pack_index_name(sha1);
+ snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename);
+ indexfile = fopen(tmpfile, "a");
+ if (!indexfile) {
+ ret = error("Unable to open local file %s for pack index",
+ tmpfile);
+ goto cleanup_pack;
+ }
+
+ slot = get_active_slot();
+ slot->results = &results;
+ curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
+ curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
+ curl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile);
+ curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
+ curl_easy_setopt(slot->curl, CURLOPT_URL, url);
+ curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
+ slot->local = indexfile;
+
+ /*
+ * If there is data present from a previous transfer attempt,
+ * resume where it left off
+ */
+ prev_posn = ftell(indexfile);
+ if (prev_posn>0) {
+ if (http_is_verbose)
+ fprintf(stderr,
+ "Resuming fetch of index for pack %s at byte %ld\n",
+ hex, prev_posn);
+ sprintf(range, "Range: bytes=%ld-", prev_posn);
+ range_header = curl_slist_append(range_header, range);
+ curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);
+ }
+
+ if (start_active_slot(slot)) {
+ run_active_slot(slot);
+ if (results.curl_result != CURLE_OK) {
+ ret = error("Unable to get pack index %s\n%s",
+ url, curl_errorstr);
+ goto cleanup_index;
+ }
+ } else {
+ ret = error("Unable to start request");
+ goto cleanup_index;
+ }
+
+ ret = move_temp_to_file(tmpfile, filename);
+
+cleanup_index:
+ fclose(indexfile);
+ slot->local = NULL;
+cleanup_pack:
+ free(hex);
+ free(url);
+ return ret;
+}
+
+static int fetch_and_setup_pack_index(struct packed_git **packs_head,
+ unsigned char *sha1, const char *base_url)
+{
+ struct packed_git *new_pack;
+
+ if (fetch_pack_index(sha1, base_url))
+ return -1;
+
+ new_pack = parse_pack_index(sha1);
+ if (!new_pack)
+ return -1; /* parse_pack_index() already issued error message */
+ new_pack->next = *packs_head;
+ *packs_head = new_pack;
+ return 0;
+}
+
+int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
+{
+ int ret = 0, i = 0;
+ char *url, *data;
+ struct strbuf buf = STRBUF_INIT;
+ unsigned char sha1[20];
+
+ end_url_with_slash(&buf, base_url);
+ strbuf_addstr(&buf, "objects/info/packs");
+ url = strbuf_detach(&buf, NULL);
+
+ ret = http_get_strbuf(url, &buf, HTTP_NO_CACHE);
+ if (ret != HTTP_OK)
+ goto cleanup;
+
+ data = buf.buf;
+ while (i < buf.len) {
+ switch (data[i]) {
+ case 'P':
+ i++;
+ if (i + 52 <= buf.len &&
+ !prefixcmp(data + i, " pack-") &&
+ !prefixcmp(data + i + 46, ".pack\n")) {
+ get_sha1_hex(data + i + 6, sha1);
+ fetch_and_setup_pack_index(packs_head, sha1,
+ base_url);
+ i += 51;
+ break;
+ }
+ default:
+ while (i < buf.len && data[i] != '\n')
+ i++;
+ }
+ i++;
+ }
+
+cleanup:
+ free(url);
+ return ret;
+}