http: Start negotiate_fetch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
diff --git a/src/transport-http.c b/src/transport-http.c
index cc12939..109c9ee 100644
--- a/src/transport-http.c
+++ b/src/transport-http.c
@@ -14,6 +14,7 @@
#include "netops.h"
#include "buffer.h"
#include "pkt.h"
+#include "refs.h"
enum last_cb {
NONE,
@@ -37,6 +38,7 @@ typedef struct {
char *host;
char *port;
char *service;
+ git_transport_caps caps;
#ifdef GIT_WIN32
WSADATA wsd;
#endif
@@ -54,6 +56,8 @@ static int gen_request(git_buf *buf, const char *url, const char *host, const ch
git_buf_puts(buf, "User-Agent: git/1.0 (libgit2 " LIBGIT2_VERSION ")\r\n");
git_buf_printf(buf, "Host: %s\r\n", host);
git_buf_puts(buf, "Accept: */*\r\n" "Pragma: no-cache\r\n\r\n");
+ if (strncmp(service, "POST", strlen("POST")))
+ git_buf_puts(buf, "Content-Encoding: chunked");
if (git_buf_oom(buf))
return GIT_ENOMEM;
@@ -337,6 +341,92 @@ static int http_ls(git_transport *transport, git_headarray *array)
return GIT_SUCCESS;
}
+static int http_send_wants(git_transport *transport, git_headarray *array)
+{
+ transport_http *t = (transport_http *) transport;
+ const char *prefix = "http://", *url = t->parent.url;
+ git_buf request = GIT_BUF_INIT;
+ int error;
+
+ /* TODO: Store url in the transport */
+ if (!git__prefixcmp(url, prefix))
+ url += strlen(prefix);
+
+ error = do_connect(t, t->host, t->port);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Faile to connect to host");
+
+ error = gen_request(&request, url, t->host, "POST", "upload-pack");
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to generate request");
+
+ error = gitno_send(t->socket, request.ptr, request.size, 0);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to send request");
+
+ return git_pkt_send_wants(array, &t->caps, t->socket, 1);
+}
+
+static int http_negotiate_fetch(git_transport *transport, git_repository *repo, git_headarray *GIT_UNUSED(list))
+{
+ transport_http *t = (transport_http *) transport;
+ GIT_UNUSED_ARG(list);
+ int error;
+ unsigned int i;
+ char buff[128];
+ gitno_buffer buf;
+ git_strarray refs;
+ git_revwalk *walk;
+ git_reference *ref;
+ git_oid oid;
+
+ gitno_buffer_setup(&buf, buff, sizeof(buff), t->socket);
+
+ error = git_reference_listall(&refs, repo, GIT_REF_LISTALL);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to list references");
+
+ error = git_revwalk_new(&walk, repo);
+ if (error < GIT_ERROR) {
+ error = git__rethrow(error, "Failed to list all references");
+ goto cleanup;
+ }
+ git_revwalk_sorting(walk, GIT_SORT_TIME);
+
+ for (i = 0; i < refs.count; ++i) {
+ /* No tags */
+ if (!git__prefixcmp(refs.strings[i], GIT_REFS_TAGS_DIR))
+ continue;
+
+ error = git_reference_lookup(&ref, repo, refs.strings[i]);
+ if (error < GIT_ERROR) {
+ error = git__rethrow(error, "Failed to lookup %s", refs.strings[i]);
+ goto cleanup;
+ }
+
+ if (git_reference_type(ref) == GIT_REF_SYMBOLIC)
+ continue;
+ error = git_revwalk_push(walk, git_reference_oid(ref));
+ if (error < GIT_ERROR) {
+ error = git__rethrow(error, "Failed to push %s", refs.strings[i]);
+ goto cleanup;
+ }
+ }
+ git_strarray_free(&refs);
+
+ i = 0;
+ while ((error = git_revwalk_next(&oid, walk)) == GIT_SUCCESS) {
+ error = git_pkt_send_have(&oid, t->socket, 1);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to send have");
+ i++;
+ }
+
+cleanup:
+ git_revwalk_free(walk);
+ return error;
+}
+
static int http_close(git_transport *transport)
{
transport_http *t = (transport_http *) transport;
@@ -391,6 +481,8 @@ int git_transport_http(git_transport **out)
t->parent.connect = http_connect;
t->parent.ls = http_ls;
+ t->parent.send_wants = http_send_wants;
+ t->parent.negotiate_fetch = http_negotiate_fetch;
t->parent.close = http_close;
t->parent.free = http_free;