Skip to content

Commit 110cb41

Browse files
author
Junio C Hamano
committed
Merge branch 'nh/http' into next
* nh/http: http-fetch: add optional DAV-based pack list cvsimport: use git-update-ref when updating
2 parents afb28f2 + 8d9fbe5 commit 110cb41

File tree

3 files changed

+285
-6
lines changed

3 files changed

+285
-6
lines changed

Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,11 @@ exec_cmd.o: exec_cmd.c
513513
http.o: http.c
514514
$(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $<
515515

516+
ifdef NO_EXPAT
517+
http-fetch.o: http-fetch.c
518+
$(CC) -o $*.o -c $(ALL_CFLAGS) -DNO_EXPAT $<
519+
endif
520+
516521
git-%$X: %.o $(GITLIBS)
517522
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
518523

@@ -535,7 +540,7 @@ git-imap-send$X: imap-send.o $(LIB_FILE)
535540

536541
git-http-fetch$X: fetch.o http.o http-fetch.o $(LIB_FILE)
537542
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
538-
$(LIBS) $(CURL_LIBCURL)
543+
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
539544

540545
git-http-push$X: revision.o http.o http-push.o $(LIB_FILE)
541546
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \

git-cvsimport.perl

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -677,11 +677,7 @@ ($$)
677677
waitpid($pid,0);
678678
die "Error running git-commit-tree: $?\n" if $?;
679679

680-
open(C,">$git_dir/refs/heads/$branch")
681-
or die "Cannot open branch $branch for update: $!\n";
682-
print C "$cid\n"
683-
or die "Cannot write branch $branch for update: $!\n";
684-
close(C)
680+
system("git-update-ref refs/heads/$branch $cid") == 0
685681
or die "Cannot write branch $branch for update: $!\n";
686682

687683
if($tag) {

http-fetch.c

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,35 @@
44
#include "fetch.h"
55
#include "http.h"
66

7+
#ifndef NO_EXPAT
8+
#include <expat.h>
9+
10+
/* Definitions for DAV requests */
11+
#define DAV_PROPFIND "PROPFIND"
12+
#define DAV_PROPFIND_RESP ".multistatus.response"
13+
#define DAV_PROPFIND_NAME ".multistatus.response.href"
14+
#define DAV_PROPFIND_COLLECTION ".multistatus.response.propstat.prop.resourcetype.collection"
15+
#define PROPFIND_ALL_REQUEST "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:propfind xmlns:D=\"DAV:\">\n<D:allprop/>\n</D:propfind>"
16+
17+
/* Definitions for processing XML DAV responses */
18+
#ifndef XML_STATUS_OK
19+
enum XML_Status {
20+
XML_STATUS_OK = 1,
21+
XML_STATUS_ERROR = 0
22+
};
23+
#define XML_STATUS_OK 1
24+
#define XML_STATUS_ERROR 0
25+
#endif
26+
27+
/* Flags that control remote_ls processing */
28+
#define PROCESS_FILES (1u << 0)
29+
#define PROCESS_DIRS (1u << 1)
30+
#define RECURSIVE (1u << 2)
31+
32+
/* Flags that remote_ls passes to callback functions */
33+
#define IS_DIR (1u << 0)
34+
#endif
35+
736
#define PREV_BUF_SIZE 4096
837
#define RANGE_HEADER_SIZE 30
938

@@ -15,6 +44,7 @@ static struct curl_slist *no_pragma_header;
1544
struct alt_base
1645
{
1746
char *base;
47+
int path_len;
1848
int got_indices;
1949
struct packed_git *packs;
2050
struct alt_base *next;
@@ -58,6 +88,30 @@ struct alternates_request {
5888
int http_specific;
5989
};
6090

91+
#ifndef NO_EXPAT
92+
struct xml_ctx
93+
{
94+
char *name;
95+
int len;
96+
char *cdata;
97+
void (*userFunc)(struct xml_ctx *ctx, int tag_closed);
98+
void *userData;
99+
};
100+
101+
struct remote_ls_ctx
102+
{
103+
struct alt_base *repo;
104+
char *path;
105+
void (*userFunc)(struct remote_ls_ctx *ls);
106+
void *userData;
107+
int flags;
108+
char *dentry_name;
109+
int dentry_flags;
110+
int rc;
111+
struct remote_ls_ctx *parent;
112+
};
113+
#endif
114+
61115
static struct object_request *object_queue_head = NULL;
62116

63117
static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
@@ -500,6 +554,7 @@ static void process_alternates_response(void *callback_data)
500554
int serverlen = 0;
501555
struct alt_base *newalt;
502556
char *target = NULL;
557+
char *path;
503558
if (data[i] == '/') {
504559
serverlen = strchr(base + 8, '/') - base;
505560
okay = 1;
@@ -540,6 +595,13 @@ static void process_alternates_response(void *callback_data)
540595
newalt->base = target;
541596
newalt->got_indices = 0;
542597
newalt->packs = NULL;
598+
path = strstr(target, "//");
599+
if (path) {
600+
path = index(path+2, '/');
601+
if (path)
602+
newalt->path_len = strlen(path);
603+
}
604+
543605
while (tail->next != NULL)
544606
tail = tail->next;
545607
tail->next = newalt;
@@ -611,6 +673,209 @@ static void fetch_alternates(char *base)
611673
free(url);
612674
}
613675

676+
#ifndef NO_EXPAT
677+
static void
678+
xml_start_tag(void *userData, const char *name, const char **atts)
679+
{
680+
struct xml_ctx *ctx = (struct xml_ctx *)userData;
681+
const char *c = index(name, ':');
682+
int new_len;
683+
684+
if (c == NULL)
685+
c = name;
686+
else
687+
c++;
688+
689+
new_len = strlen(ctx->name) + strlen(c) + 2;
690+
691+
if (new_len > ctx->len) {
692+
ctx->name = xrealloc(ctx->name, new_len);
693+
ctx->len = new_len;
694+
}
695+
strcat(ctx->name, ".");
696+
strcat(ctx->name, c);
697+
698+
if (ctx->cdata) {
699+
free(ctx->cdata);
700+
ctx->cdata = NULL;
701+
}
702+
703+
ctx->userFunc(ctx, 0);
704+
}
705+
706+
static void
707+
xml_end_tag(void *userData, const char *name)
708+
{
709+
struct xml_ctx *ctx = (struct xml_ctx *)userData;
710+
const char *c = index(name, ':');
711+
char *ep;
712+
713+
ctx->userFunc(ctx, 1);
714+
715+
if (c == NULL)
716+
c = name;
717+
else
718+
c++;
719+
720+
ep = ctx->name + strlen(ctx->name) - strlen(c) - 1;
721+
*ep = 0;
722+
}
723+
724+
static void
725+
xml_cdata(void *userData, const XML_Char *s, int len)
726+
{
727+
struct xml_ctx *ctx = (struct xml_ctx *)userData;
728+
if (ctx->cdata)
729+
free(ctx->cdata);
730+
ctx->cdata = xcalloc(len+1, 1);
731+
strncpy(ctx->cdata, s, len);
732+
}
733+
734+
static int remote_ls(struct alt_base *repo, const char *path, int flags,
735+
void (*userFunc)(struct remote_ls_ctx *ls),
736+
void *userData);
737+
738+
static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)
739+
{
740+
struct remote_ls_ctx *ls = (struct remote_ls_ctx *)ctx->userData;
741+
742+
if (tag_closed) {
743+
if (!strcmp(ctx->name, DAV_PROPFIND_RESP) && ls->dentry_name) {
744+
if (ls->dentry_flags & IS_DIR) {
745+
if (ls->flags & PROCESS_DIRS) {
746+
ls->userFunc(ls);
747+
}
748+
if (strcmp(ls->dentry_name, ls->path) &&
749+
ls->flags & RECURSIVE) {
750+
ls->rc = remote_ls(ls->repo,
751+
ls->dentry_name,
752+
ls->flags,
753+
ls->userFunc,
754+
ls->userData);
755+
}
756+
} else if (ls->flags & PROCESS_FILES) {
757+
ls->userFunc(ls);
758+
}
759+
} else if (!strcmp(ctx->name, DAV_PROPFIND_NAME) && ctx->cdata) {
760+
ls->dentry_name = xmalloc(strlen(ctx->cdata) -
761+
ls->repo->path_len + 1);
762+
strcpy(ls->dentry_name, ctx->cdata + ls->repo->path_len);
763+
} else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {
764+
ls->dentry_flags |= IS_DIR;
765+
}
766+
} else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {
767+
if (ls->dentry_name) {
768+
free(ls->dentry_name);
769+
}
770+
ls->dentry_name = NULL;
771+
ls->dentry_flags = 0;
772+
}
773+
}
774+
775+
static int remote_ls(struct alt_base *repo, const char *path, int flags,
776+
void (*userFunc)(struct remote_ls_ctx *ls),
777+
void *userData)
778+
{
779+
char *url = xmalloc(strlen(repo->base) + strlen(path) + 1);
780+
struct active_request_slot *slot;
781+
struct slot_results results;
782+
struct buffer in_buffer;
783+
struct buffer out_buffer;
784+
char *in_data;
785+
char *out_data;
786+
XML_Parser parser = XML_ParserCreate(NULL);
787+
enum XML_Status result;
788+
struct curl_slist *dav_headers = NULL;
789+
struct xml_ctx ctx;
790+
struct remote_ls_ctx ls;
791+
792+
ls.flags = flags;
793+
ls.repo = repo;
794+
ls.path = strdup(path);
795+
ls.dentry_name = NULL;
796+
ls.dentry_flags = 0;
797+
ls.userData = userData;
798+
ls.userFunc = userFunc;
799+
ls.rc = 0;
800+
801+
sprintf(url, "%s%s", repo->base, path);
802+
803+
out_buffer.size = strlen(PROPFIND_ALL_REQUEST);
804+
out_data = xmalloc(out_buffer.size + 1);
805+
snprintf(out_data, out_buffer.size + 1, PROPFIND_ALL_REQUEST);
806+
out_buffer.posn = 0;
807+
out_buffer.buffer = out_data;
808+
809+
in_buffer.size = 4096;
810+
in_data = xmalloc(in_buffer.size);
811+
in_buffer.posn = 0;
812+
in_buffer.buffer = in_data;
813+
814+
dav_headers = curl_slist_append(dav_headers, "Depth: 1");
815+
dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
816+
817+
slot = get_active_slot();
818+
slot->results = &results;
819+
curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
820+
curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
821+
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
822+
curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
823+
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
824+
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
825+
curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
826+
curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PROPFIND);
827+
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
828+
829+
if (start_active_slot(slot)) {
830+
run_active_slot(slot);
831+
if (results.curl_result == CURLE_OK) {
832+
ctx.name = xcalloc(10, 1);
833+
ctx.len = 0;
834+
ctx.cdata = NULL;
835+
ctx.userFunc = handle_remote_ls_ctx;
836+
ctx.userData = &ls;
837+
XML_SetUserData(parser, &ctx);
838+
XML_SetElementHandler(parser, xml_start_tag,
839+
xml_end_tag);
840+
XML_SetCharacterDataHandler(parser, xml_cdata);
841+
result = XML_Parse(parser, in_buffer.buffer,
842+
in_buffer.posn, 1);
843+
free(ctx.name);
844+
845+
if (result != XML_STATUS_OK) {
846+
ls.rc = error("XML error: %s",
847+
XML_ErrorString(
848+
XML_GetErrorCode(parser)));
849+
}
850+
} else {
851+
ls.rc = -1;
852+
}
853+
} else {
854+
ls.rc = error("Unable to start PROPFIND request");
855+
}
856+
857+
free(ls.path);
858+
free(url);
859+
free(out_data);
860+
free(in_buffer.buffer);
861+
curl_slist_free_all(dav_headers);
862+
863+
return ls.rc;
864+
}
865+
866+
static void process_ls_pack(struct remote_ls_ctx *ls)
867+
{
868+
unsigned char sha1[20];
869+
870+
if (strlen(ls->dentry_name) == 63 &&
871+
!strncmp(ls->dentry_name, "objects/pack/pack-", 18) &&
872+
!strncmp(ls->dentry_name+58, ".pack", 5)) {
873+
get_sha1_hex(ls->dentry_name + 18, sha1);
874+
setup_index(ls->repo, sha1);
875+
}
876+
}
877+
#endif
878+
614879
static int fetch_indices(struct alt_base *repo)
615880
{
616881
unsigned char sha1[20];
@@ -633,6 +898,12 @@ static int fetch_indices(struct alt_base *repo)
633898
if (get_verbosely)
634899
fprintf(stderr, "Getting pack list for %s\n", repo->base);
635900

901+
#ifndef NO_EXPAT
902+
if (remote_ls(repo, "objects/pack/", PROCESS_FILES,
903+
process_ls_pack, NULL) == 0)
904+
return 0;
905+
#endif
906+
636907
url = xmalloc(strlen(repo->base) + 21);
637908
sprintf(url, "%s/objects/info/packs", repo->base);
638909

@@ -947,6 +1218,7 @@ int main(int argc, char **argv)
9471218
{
9481219
char *commit_id;
9491220
char *url;
1221+
char *path;
9501222
int arg = 1;
9511223
int rc = 0;
9521224

@@ -987,6 +1259,12 @@ int main(int argc, char **argv)
9871259
alt->got_indices = 0;
9881260
alt->packs = NULL;
9891261
alt->next = NULL;
1262+
path = strstr(url, "//");
1263+
if (path) {
1264+
path = index(path+2, '/');
1265+
if (path)
1266+
alt->path_len = strlen(path);
1267+
}
9901268

9911269
if (pull(commit_id))
9921270
rc = 1;

0 commit comments

Comments
 (0)