mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 08:11:58 +00:00
http: simple negotiation
Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>
This commit is contained in:
parent
65c86048cb
commit
e5e92c1fab
@ -350,6 +350,7 @@ int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf
|
|||||||
git_oid_fmt(oid, &head->oid);
|
git_oid_fmt(oid, &head->oid);
|
||||||
git_buf_puts(buf, WANT_PREFIX);
|
git_buf_puts(buf, WANT_PREFIX);
|
||||||
git_buf_put(buf, oid, GIT_OID_HEXSZ);
|
git_buf_put(buf, oid, GIT_OID_HEXSZ);
|
||||||
|
git_buf_putc(buf, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
return git_pkt_buffer_flush(buf);
|
return git_pkt_buffer_flush(buf);
|
||||||
|
@ -32,7 +32,8 @@ typedef struct {
|
|||||||
int error;
|
int error;
|
||||||
int transfer_finished :1,
|
int transfer_finished :1,
|
||||||
ct_found :1,
|
ct_found :1,
|
||||||
ct_finished :1;
|
ct_finished :1,
|
||||||
|
pack_ready :1;
|
||||||
enum last_cb last_cb;
|
enum last_cb last_cb;
|
||||||
http_parser parser;
|
http_parser parser;
|
||||||
char *content_type;
|
char *content_type;
|
||||||
@ -45,7 +46,8 @@ typedef struct {
|
|||||||
#endif
|
#endif
|
||||||
} transport_http;
|
} transport_http;
|
||||||
|
|
||||||
static int gen_request(git_buf *buf, const char *url, const char *host, const char *op, const char *service)
|
static int gen_request(git_buf *buf, const char *url, const char *host, const char *op,
|
||||||
|
const char *service, ssize_t content_length, int ls)
|
||||||
{
|
{
|
||||||
const char *path = url;
|
const char *path = url;
|
||||||
|
|
||||||
@ -53,12 +55,20 @@ static int gen_request(git_buf *buf, const char *url, const char *host, const ch
|
|||||||
if (path == NULL) /* Is 'git fetch http://host.com/' valid? */
|
if (path == NULL) /* Is 'git fetch http://host.com/' valid? */
|
||||||
path = "/";
|
path = "/";
|
||||||
|
|
||||||
git_buf_printf(buf, "%s %s/info/refs?service=git-%s HTTP/1.1\r\n", op, path, service);
|
if (ls) {
|
||||||
|
git_buf_printf(buf, "%s %s/info/refs?service=git-%s HTTP/1.1\r\n", op, path, service);
|
||||||
|
} else {
|
||||||
|
git_buf_printf(buf, "%s %s/git-%s HTTP/1.1\r\n", op, path, service);
|
||||||
|
}
|
||||||
git_buf_puts(buf, "User-Agent: git/1.0 (libgit2 " LIBGIT2_VERSION ")\r\n");
|
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_printf(buf, "Host: %s\r\n", host);
|
||||||
git_buf_puts(buf, "Accept: */*\r\n" "Pragma: no-cache\r\n");
|
if (content_length > 0) {
|
||||||
if (!strncmp(op, "POST", strlen("POST")))
|
git_buf_printf(buf, "Accept: application/x-git-%s-result\r\n", service);
|
||||||
git_buf_puts(buf, "Transfer-Encoding: chunked\r\n");
|
git_buf_printf(buf, "Content-Type: application/x-git-%s-request\r\n", service);
|
||||||
|
git_buf_printf(buf, "Content-Length: %zd\r\n", content_length);
|
||||||
|
} else {
|
||||||
|
git_buf_puts(buf, "Accept: */*\r\n");
|
||||||
|
}
|
||||||
git_buf_puts(buf, "\r\n");
|
git_buf_puts(buf, "\r\n");
|
||||||
|
|
||||||
if (git_buf_oom(buf))
|
if (git_buf_oom(buf))
|
||||||
@ -298,7 +308,7 @@ static int http_connect(git_transport *transport, int direction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Generate and send the HTTP request */
|
/* Generate and send the HTTP request */
|
||||||
error = gen_request(&request, url, t->host, "GET", service);
|
error = gen_request(&request, url, t->host, "GET", service, 0, 1);
|
||||||
if (error < GIT_SUCCESS) {
|
if (error < GIT_SUCCESS) {
|
||||||
error = git__throw(error, "Failed to generate request");
|
error = git__throw(error, "Failed to generate request");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -381,6 +391,11 @@ static int on_body_parse_response(http_parser *parser, const char *str, size_t l
|
|||||||
return t->error = git__throw(GIT_EOBJCORRUPTED, "Not a valid smart HTTP response");
|
return t->error = git__throw(GIT_EOBJCORRUPTED, "Not a valid smart HTTP response");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pkt->type == GIT_PKT_PACK) {
|
||||||
|
t->pack_ready = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (pkt->type == GIT_PKT_NAK)
|
if (pkt->type == GIT_PKT_NAK)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -428,7 +443,7 @@ static int parse_response(transport_http *t)
|
|||||||
|
|
||||||
gitno_consume_n(&buf, parsed);
|
gitno_consume_n(&buf, parsed);
|
||||||
|
|
||||||
if (error == 0 || t->transfer_finished)
|
if (error == 0 || t->transfer_finished || t->pack_ready)
|
||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +508,7 @@ static int http_negotiate_fetch(git_transport *transport, git_repository *repo,
|
|||||||
git_pkt_ack *pkt;
|
git_pkt_ack *pkt;
|
||||||
git_vector *common = &t->common;
|
git_vector *common = &t->common;
|
||||||
const char *prefix = "http://", *url = t->parent.url;
|
const char *prefix = "http://", *url = t->parent.url;
|
||||||
git_buf request = GIT_BUF_INIT;
|
git_buf request = GIT_BUF_INIT, data = GIT_BUF_INIT;
|
||||||
gitno_buffer_setup(&buf, buff, sizeof(buff), t->socket);
|
gitno_buffer_setup(&buf, buff, sizeof(buff), t->socket);
|
||||||
|
|
||||||
/* TODO: Store url in the transport */
|
/* TODO: Store url in the transport */
|
||||||
@ -517,7 +532,34 @@ static int http_negotiate_fetch(git_transport *transport, git_repository *repo,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = gen_request(&request, url, t->host, "POST", "upload-pack");
|
error = git_pkt_buffer_wants(wants, &t->caps, &data);
|
||||||
|
if (error < GIT_SUCCESS) {
|
||||||
|
error = git__rethrow(error, "Failed to send wants");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need to send these on each connection */
|
||||||
|
git_vector_foreach (common, i, pkt) {
|
||||||
|
error = git_pkt_buffer_have(&pkt->oid, &data);
|
||||||
|
if (error < GIT_SUCCESS) {
|
||||||
|
error = git__rethrow(error, "Failed to buffer common have");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while ((i < 20) && ((error = git_revwalk_next(&oid, walk)) == GIT_SUCCESS)) {
|
||||||
|
error = git_pkt_buffer_have(&oid, &data);
|
||||||
|
if (error < GIT_SUCCESS) {
|
||||||
|
error = git__rethrow(error, "Failed to buffer have");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
git_pkt_buffer_done(&data);
|
||||||
|
|
||||||
|
error = gen_request(&request, url, t->host, "POST", "upload-pack", data.size, 0);
|
||||||
if (error < GIT_SUCCESS) {
|
if (error < GIT_SUCCESS) {
|
||||||
error = git__rethrow(error, "Failed to generate request");
|
error = git__rethrow(error, "Failed to generate request");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -529,35 +571,23 @@ static int http_negotiate_fetch(git_transport *transport, git_repository *repo,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = git_pkt_send_wants(wants, &t->caps, t->socket, 1);
|
error = gitno_send(t->socket, data.ptr, data.size, 0);
|
||||||
if (error < GIT_SUCCESS) {
|
if (error < GIT_SUCCESS) {
|
||||||
error = git__rethrow(error, "Failed to send wants");
|
error = git__rethrow(error, "Failed to send data");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need to send these on each connection */
|
git_buf_clear(&request);
|
||||||
git_vector_foreach (common, i, pkt) {
|
git_buf_clear(&data);
|
||||||
error = git_pkt_send_have(&pkt->oid, t->socket, 1);
|
|
||||||
if (error < GIT_SUCCESS) {
|
|
||||||
error = git__rethrow(error, "Failed to send common have");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while ((i < 256) && ((error = git_revwalk_next(&oid, walk)) == GIT_SUCCESS)) {
|
|
||||||
error = git_pkt_send_have(&oid, t->socket, 1);
|
|
||||||
if (error < GIT_SUCCESS) {
|
|
||||||
error = git__rethrow(error, "Failed to send have");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (error < GIT_SUCCESS || i >= 256)
|
if (error < GIT_SUCCESS || i >= 256)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
error = parse_response(t);
|
error = parse_response(t);
|
||||||
|
|
||||||
|
if (t->pack_ready)
|
||||||
|
return 0;
|
||||||
|
|
||||||
} while(1);
|
} while(1);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
Loading…
Reference in New Issue
Block a user