mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-06 09:41:04 +00:00
transport: store the refs in a common area
Instad of each transport having its own function and logic to get to its refs, store them directly in transport. Leverage the new gitno_buffer to make the parsing and storing of the refs use common code and get rid of the git_protocol struct.
This commit is contained in:
parent
b49c8f71ae
commit
ad4b5beb50
@ -71,7 +71,7 @@ static int filter_wants(git_remote *remote)
|
|||||||
if (git_repository_odb__weakptr(&p.odb, remote->repo) < 0)
|
if (git_repository_odb__weakptr(&p.odb, remote->repo) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return remote->transport->ls(remote->transport, &filter_ref__cb, &p);
|
return git_remote_ls(remote, filter_ref__cb, &p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait until we get an ack from the */
|
/* Wait until we get an ack from the */
|
||||||
|
@ -9,38 +9,36 @@
|
|||||||
#include "pkt.h"
|
#include "pkt.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
int git_protocol_store_refs(git_protocol *p, const char *data, size_t len)
|
int git_protocol_store_refs(git_transport *t, int flushes)
|
||||||
{
|
{
|
||||||
git_buf *buf = &p->buf;
|
gitno_buffer *buf = &t->buffer;
|
||||||
git_vector *refs = p->refs;
|
git_vector *refs = &t->refs;
|
||||||
int error;
|
int error, flush = 0, recvd;
|
||||||
const char *line_end, *ptr;
|
const char *line_end;
|
||||||
|
git_pkt *pkt;
|
||||||
|
|
||||||
if (len == 0) { /* EOF */
|
do {
|
||||||
if (git_buf_len(buf) != 0) {
|
if (buf->offset > 0)
|
||||||
giterr_set(GITERR_NET, "Unexpected EOF");
|
error = git_pkt_parse_line(&pkt, buf->data, &line_end, buf->offset);
|
||||||
return p->error = -1;
|
else
|
||||||
} else {
|
error = GIT_EBUFS;
|
||||||
return 0;
|
|
||||||
|
if (error < 0 && error != GIT_EBUFS)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (error == GIT_EBUFS) {
|
||||||
|
if ((recvd = gitno_recv(buf)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (recvd == 0 && !flush) {
|
||||||
|
giterr_set(GITERR_NET, "Early EOF");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
git_buf_put(buf, data, len);
|
|
||||||
ptr = buf->ptr;
|
|
||||||
while (1) {
|
|
||||||
git_pkt *pkt;
|
|
||||||
|
|
||||||
if (git_buf_len(buf) == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error = git_pkt_parse_line(&pkt, ptr, &line_end, git_buf_len(buf));
|
|
||||||
if (error == GIT_EBUFS)
|
|
||||||
return 0; /* Ask for more */
|
|
||||||
if (error < 0)
|
|
||||||
return p->error = -1;
|
|
||||||
|
|
||||||
git_buf_consume(buf, line_end);
|
|
||||||
|
|
||||||
|
gitno_consume(buf, line_end);
|
||||||
if (pkt->type == GIT_PKT_ERR) {
|
if (pkt->type == GIT_PKT_ERR) {
|
||||||
giterr_set(GITERR_NET, "Remote error: %s", ((git_pkt_err *)pkt)->error);
|
giterr_set(GITERR_NET, "Remote error: %s", ((git_pkt_err *)pkt)->error);
|
||||||
git__free(pkt);
|
git__free(pkt);
|
||||||
@ -48,13 +46,13 @@ int git_protocol_store_refs(git_protocol *p, const char *data, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (git_vector_insert(refs, pkt) < 0)
|
if (git_vector_insert(refs, pkt) < 0)
|
||||||
return p->error = -1;
|
return -1;
|
||||||
|
|
||||||
if (pkt->type == GIT_PKT_FLUSH)
|
if (pkt->type == GIT_PKT_FLUSH)
|
||||||
p->flush = 1;
|
flush++;
|
||||||
}
|
} while (flush < flushes);
|
||||||
|
|
||||||
return 0;
|
return flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_protocol_detect_caps(git_pkt_ref *pkt, git_transport_caps *caps)
|
int git_protocol_detect_caps(git_pkt_ref *pkt, git_transport_caps *caps)
|
||||||
|
@ -11,15 +11,7 @@
|
|||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "pkt.h"
|
#include "pkt.h"
|
||||||
|
|
||||||
typedef struct {
|
int git_protocol_store_refs(git_transport *t, int flushes);
|
||||||
git_transport *transport;
|
|
||||||
git_vector *refs;
|
|
||||||
git_buf buf;
|
|
||||||
int error;
|
|
||||||
unsigned int flush :1;
|
|
||||||
} git_protocol;
|
|
||||||
|
|
||||||
int git_protocol_store_refs(git_protocol *p, const char *data, size_t len);
|
|
||||||
int git_protocol_detect_caps(git_pkt_ref *pkt, git_transport_caps *caps);
|
int git_protocol_detect_caps(git_pkt_ref *pkt, git_transport_caps *caps);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
21
src/remote.c
21
src/remote.c
@ -14,6 +14,7 @@
|
|||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
#include "fetch.h"
|
#include "fetch.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
|
#include "pkt.h"
|
||||||
|
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
|
||||||
@ -401,6 +402,10 @@ on_error:
|
|||||||
|
|
||||||
int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
|
int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
|
||||||
{
|
{
|
||||||
|
git_vector *refs = &remote->transport->refs;
|
||||||
|
unsigned int i;
|
||||||
|
git_pkt *p = NULL;
|
||||||
|
|
||||||
assert(remote);
|
assert(remote);
|
||||||
|
|
||||||
if (!remote->transport || !remote->transport->connected) {
|
if (!remote->transport || !remote->transport->connected) {
|
||||||
@ -408,7 +413,21 @@ int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return remote->transport->ls(remote->transport, list_cb, payload);
|
git_vector_foreach(refs, i, p) {
|
||||||
|
git_pkt_ref *pkt = NULL;
|
||||||
|
|
||||||
|
if (p->type != GIT_PKT_REF)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pkt = (git_pkt_ref *)p;
|
||||||
|
|
||||||
|
if (list_cb(&pkt->head, payload) < 0) {
|
||||||
|
giterr_set(GITERR_NET, "User callback returned error");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats)
|
int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats)
|
||||||
|
@ -79,6 +79,7 @@ struct git_transport {
|
|||||||
#ifdef GIT_SSL
|
#ifdef GIT_SSL
|
||||||
struct gitno_ssl ssl;
|
struct gitno_ssl ssl;
|
||||||
#endif
|
#endif
|
||||||
|
git_vector refs;
|
||||||
git_vector common;
|
git_vector common;
|
||||||
gitno_buffer buffer;
|
gitno_buffer buffer;
|
||||||
GIT_SOCKET socket;
|
GIT_SOCKET socket;
|
||||||
@ -91,10 +92,6 @@ struct git_transport {
|
|||||||
* Send our side of a negotiation
|
* Send our side of a negotiation
|
||||||
*/
|
*/
|
||||||
int (*negotiation_step)(struct git_transport *transport, void *data, size_t len);
|
int (*negotiation_step)(struct git_transport *transport, void *data, size_t len);
|
||||||
/**
|
|
||||||
* Give a list of references, useful for ls-remote
|
|
||||||
*/
|
|
||||||
int (*ls)(struct git_transport *transport, git_headlist_cb list_cb, void *opaque);
|
|
||||||
/**
|
/**
|
||||||
* Push the changes over
|
* Push the changes over
|
||||||
*/
|
*/
|
||||||
@ -108,10 +105,6 @@ struct git_transport {
|
|||||||
* Download the packfile
|
* Download the packfile
|
||||||
*/
|
*/
|
||||||
int (*download_pack)(struct git_transport *transport, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats);
|
int (*download_pack)(struct git_transport *transport, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats);
|
||||||
/**
|
|
||||||
* Fetch the changes
|
|
||||||
*/
|
|
||||||
int (*fetch)(struct git_transport *transport);
|
|
||||||
/**
|
/**
|
||||||
* Close the connection
|
* Close the connection
|
||||||
*/
|
*/
|
||||||
|
@ -24,9 +24,6 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
git_transport parent;
|
git_transport parent;
|
||||||
git_protocol proto;
|
|
||||||
git_vector refs;
|
|
||||||
git_remote_head **heads;
|
|
||||||
char buff[1024];
|
char buff[1024];
|
||||||
#ifdef GIT_WIN32
|
#ifdef GIT_WIN32
|
||||||
WSADATA wsd;
|
WSADATA wsd;
|
||||||
@ -124,38 +121,6 @@ on_error:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Read from the socket and store the references in the vector
|
|
||||||
*/
|
|
||||||
static int store_refs(transport_git *t)
|
|
||||||
{
|
|
||||||
gitno_buffer *buf = &t->parent.buffer;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if ((ret = gitno_recv(buf)) < 0)
|
|
||||||
return -1;
|
|
||||||
if (ret == 0) /* Orderly shutdown, so exit */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ret = git_protocol_store_refs(&t->proto, buf->data, buf->offset);
|
|
||||||
if (ret == GIT_EBUFS) {
|
|
||||||
gitno_consume_n(buf, buf->len);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
gitno_consume_n(buf, buf->offset);
|
|
||||||
|
|
||||||
if (t->proto.flush) { /* No more refs */
|
|
||||||
t->proto.flush = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since this is a network connection, we need to parse and store the
|
* Since this is a network connection, we need to parse and store the
|
||||||
* pkt-lines at this stage and keep them there.
|
* pkt-lines at this stage and keep them there.
|
||||||
@ -170,48 +135,19 @@ static int git_connect(git_transport *transport, int direction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
t->parent.direction = direction;
|
t->parent.direction = direction;
|
||||||
if (git_vector_init(&t->refs, 16, NULL) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Connect and ask for the refs */
|
/* Connect and ask for the refs */
|
||||||
if (do_connect(t, transport->url) < 0)
|
if (do_connect(t, transport->url) < 0)
|
||||||
goto cleanup;
|
return -1;
|
||||||
|
|
||||||
gitno_buffer_setup(transport, &transport->buffer, t->buff, sizeof(t->buff));
|
gitno_buffer_setup(transport, &transport->buffer, t->buff, sizeof(t->buff));
|
||||||
|
|
||||||
t->parent.connected = 1;
|
t->parent.connected = 1;
|
||||||
if (store_refs(t) < 0)
|
if (git_protocol_store_refs(transport, 1) < 0)
|
||||||
goto cleanup;
|
return -1;
|
||||||
|
|
||||||
if (git_protocol_detect_caps(git_vector_get(&t->refs, 0), &transport->caps) < 0)
|
if (git_protocol_detect_caps(git_vector_get(&transport->refs, 0), &transport->caps) < 0)
|
||||||
goto cleanup;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
|
||||||
cleanup:
|
|
||||||
git_vector_free(&t->refs);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int git_ls(git_transport *transport, git_headlist_cb list_cb, void *opaque)
|
|
||||||
{
|
|
||||||
transport_git *t = (transport_git *) transport;
|
|
||||||
git_vector *refs = &t->refs;
|
|
||||||
unsigned int i;
|
|
||||||
git_pkt *p = NULL;
|
|
||||||
|
|
||||||
git_vector_foreach(refs, i, p) {
|
|
||||||
git_pkt_ref *pkt = NULL;
|
|
||||||
|
|
||||||
if (p->type != GIT_PKT_REF)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pkt = (git_pkt_ref *)p;
|
|
||||||
|
|
||||||
if (list_cb(&pkt->head, opaque) < 0) {
|
|
||||||
giterr_set(GITERR_NET, "User callback returned error");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -229,6 +165,7 @@ static int git_close(git_transport *t)
|
|||||||
return -1;
|
return -1;
|
||||||
/* Can't do anything if there's an error, so don't bother checking */
|
/* Can't do anything if there's an error, so don't bother checking */
|
||||||
gitno_send(t, buf.ptr, buf.size, 0);
|
gitno_send(t, buf.ptr, buf.size, 0);
|
||||||
|
git_buf_free(&buf);
|
||||||
|
|
||||||
if (gitno_close(t->socket) < 0) {
|
if (gitno_close(t->socket) < 0) {
|
||||||
giterr_set(GITERR_NET, "Failed to close socket");
|
giterr_set(GITERR_NET, "Failed to close socket");
|
||||||
@ -247,17 +184,22 @@ static int git_close(git_transport *t)
|
|||||||
static void git_free(git_transport *transport)
|
static void git_free(git_transport *transport)
|
||||||
{
|
{
|
||||||
transport_git *t = (transport_git *) transport;
|
transport_git *t = (transport_git *) transport;
|
||||||
git_vector *refs = &t->refs;
|
git_vector *refs = &transport->refs;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < refs->length; ++i) {
|
for (i = 0; i < refs->length; ++i) {
|
||||||
git_pkt *p = git_vector_get(refs, i);
|
git_pkt *p = git_vector_get(refs, i);
|
||||||
git_pkt_free(p);
|
git_pkt_free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
git_vector_free(refs);
|
git_vector_free(refs);
|
||||||
git__free(t->heads);
|
|
||||||
git_buf_free(&t->proto.buf);
|
refs = &transport->common;
|
||||||
|
for (i = 0; i < refs->length; ++i) {
|
||||||
|
git_pkt *p = git_vector_get(refs, i);
|
||||||
|
git_pkt_free(p);
|
||||||
|
}
|
||||||
|
git_vector_free(refs);
|
||||||
|
|
||||||
git__free(t->parent.url);
|
git__free(t->parent.url);
|
||||||
git__free(t);
|
git__free(t);
|
||||||
}
|
}
|
||||||
@ -273,18 +215,16 @@ int git_transport_git(git_transport **out)
|
|||||||
GITERR_CHECK_ALLOC(t);
|
GITERR_CHECK_ALLOC(t);
|
||||||
|
|
||||||
memset(t, 0x0, sizeof(transport_git));
|
memset(t, 0x0, sizeof(transport_git));
|
||||||
if (git_vector_init(&t->parent.common, 8, NULL)) {
|
if (git_vector_init(&t->parent.common, 8, NULL))
|
||||||
git__free(t);
|
goto on_error;
|
||||||
return -1;
|
|
||||||
}
|
if (git_vector_init(&t->parent.refs, 16, NULL) < 0)
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
t->parent.connect = git_connect;
|
t->parent.connect = git_connect;
|
||||||
t->parent.negotiation_step = git_negotiation_step;
|
t->parent.negotiation_step = git_negotiation_step;
|
||||||
t->parent.ls = git_ls;
|
|
||||||
t->parent.close = git_close;
|
t->parent.close = git_close;
|
||||||
t->parent.free = git_free;
|
t->parent.free = git_free;
|
||||||
t->proto.refs = &t->refs;
|
|
||||||
t->proto.transport = (git_transport *) t;
|
|
||||||
|
|
||||||
*out = (git_transport *) t;
|
*out = (git_transport *) t;
|
||||||
|
|
||||||
@ -298,4 +238,8 @@ int git_transport_git(git_transport **out)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
git__free(t);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -29,11 +29,8 @@ enum last_cb {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
git_transport parent;
|
git_transport parent;
|
||||||
git_protocol proto;
|
|
||||||
git_vector refs;
|
|
||||||
http_parser_settings settings;
|
http_parser_settings settings;
|
||||||
git_buf buf;
|
git_buf buf;
|
||||||
git_remote_head **heads;
|
|
||||||
int error;
|
int error;
|
||||||
int transfer_finished :1,
|
int transfer_finished :1,
|
||||||
ct_found :1,
|
ct_found :1,
|
||||||
@ -183,17 +180,6 @@ static int on_headers_complete(http_parser *parser)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_body_store_refs(http_parser *parser, const char *str, size_t len)
|
|
||||||
{
|
|
||||||
transport_http *t = (transport_http *) parser->data;
|
|
||||||
|
|
||||||
if (parser->status_code == 404) {
|
|
||||||
return git_buf_put(&t->buf, str, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return git_protocol_store_refs(&t->proto, str, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int on_message_complete(http_parser *parser)
|
static int on_message_complete(http_parser *parser)
|
||||||
{
|
{
|
||||||
transport_http *t = (transport_http *) parser->data;
|
transport_http *t = (transport_http *) parser->data;
|
||||||
@ -208,57 +194,64 @@ static int on_message_complete(http_parser *parser)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int store_refs(transport_http *t)
|
static int on_body_fill_buffer(http_parser *parser, const char *str, size_t len)
|
||||||
{
|
{
|
||||||
git_transport *transport = (git_transport *) t;
|
git_transport *transport = (git_transport *) parser->data;
|
||||||
http_parser_settings settings;
|
transport_http *t = (transport_http *) parser->data;
|
||||||
char buffer[1024];
|
gitno_buffer *buf = &transport->buffer;
|
||||||
gitno_buffer buf;
|
|
||||||
git_pkt *pkt;
|
if (buf->len - buf->offset < len) {
|
||||||
int ret;
|
giterr_set(GITERR_NET, "Can't fit data in the buffer");
|
||||||
|
return t->error = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf->data + buf->offset, str, len);
|
||||||
|
buf->offset += len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int http_recv_cb(gitno_buffer *buf)
|
||||||
|
{
|
||||||
|
git_transport *transport = (git_transport *) buf->cb_data;
|
||||||
|
transport_http *t = (transport_http *) transport;
|
||||||
|
size_t old_len;
|
||||||
|
gitno_buffer inner;
|
||||||
|
char buffer[2048];
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (t->transfer_finished)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
gitno_buffer_setup(transport, &inner, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
if ((error = gitno_recv(&inner)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
old_len = buf->offset;
|
||||||
|
http_parser_execute(&t->parser, &t->settings, inner.data, inner.offset);
|
||||||
|
if (t->error < 0)
|
||||||
|
return t->error;
|
||||||
|
|
||||||
|
return buf->offset - old_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up the gitno_buffer so calling gitno_recv() grabs data from the HTTP response */
|
||||||
|
static void setup_gitno_buffer(git_transport *transport)
|
||||||
|
{
|
||||||
|
transport_http *t = (transport_http *) transport;
|
||||||
|
|
||||||
http_parser_init(&t->parser, HTTP_RESPONSE);
|
http_parser_init(&t->parser, HTTP_RESPONSE);
|
||||||
t->parser.data = t;
|
t->parser.data = t;
|
||||||
memset(&settings, 0x0, sizeof(http_parser_settings));
|
t->transfer_finished = 0;
|
||||||
settings.on_header_field = on_header_field;
|
memset(&t->settings, 0x0, sizeof(http_parser_settings));
|
||||||
settings.on_header_value = on_header_value;
|
t->settings.on_header_field = on_header_field;
|
||||||
settings.on_headers_complete = on_headers_complete;
|
t->settings.on_header_value = on_header_value;
|
||||||
settings.on_body = on_body_store_refs;
|
t->settings.on_headers_complete = on_headers_complete;
|
||||||
settings.on_message_complete = on_message_complete;
|
t->settings.on_body = on_body_fill_buffer;
|
||||||
|
t->settings.on_message_complete = on_message_complete;
|
||||||
|
|
||||||
gitno_buffer_setup((git_transport *)t, &buf, buffer, sizeof(buffer));
|
gitno_buffer_setup_callback(transport, &transport->buffer, t->buffer, sizeof(t->buffer), http_recv_cb, t);
|
||||||
|
|
||||||
while(1) {
|
|
||||||
size_t parsed;
|
|
||||||
|
|
||||||
if ((ret = gitno_recv(&buf)) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
parsed = http_parser_execute(&t->parser, &settings, buf.data, buf.offset);
|
|
||||||
/* Both should happen at the same time */
|
|
||||||
if (parsed != buf.offset || t->error < 0)
|
|
||||||
return t->error;
|
|
||||||
|
|
||||||
gitno_consume_n(&buf, parsed);
|
|
||||||
|
|
||||||
if (ret == 0 || t->transfer_finished)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt = git_vector_get(&t->refs, 0);
|
|
||||||
if (pkt == NULL || pkt->type != GIT_PKT_COMMENT) {
|
|
||||||
giterr_set(GITERR_NET, "Invalid HTTP response");
|
|
||||||
return t->error = -1;
|
|
||||||
} else {
|
|
||||||
/* Remove the comment and flush pkts */
|
|
||||||
git_vector_remove(&t->refs, 0);
|
|
||||||
git_vector_remove(&t->refs, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (git_protocol_detect_caps(git_vector_get(&t->refs, 0), &transport->caps) < 0)
|
|
||||||
return t->error = -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int http_connect(git_transport *transport, int direction)
|
static int http_connect(git_transport *transport, int direction)
|
||||||
@ -269,6 +262,7 @@ static int http_connect(git_transport *transport, int direction)
|
|||||||
const char *service = "upload-pack";
|
const char *service = "upload-pack";
|
||||||
const char *url = t->parent.url, *prefix_http = "http://", *prefix_https = "https://";
|
const char *url = t->parent.url, *prefix_http = "http://", *prefix_https = "https://";
|
||||||
const char *default_port;
|
const char *default_port;
|
||||||
|
git_pkt *pkt;
|
||||||
|
|
||||||
if (direction == GIT_DIR_PUSH) {
|
if (direction == GIT_DIR_PUSH) {
|
||||||
giterr_set(GITERR_NET, "Pushing over HTTP is not implemented");
|
giterr_set(GITERR_NET, "Pushing over HTTP is not implemented");
|
||||||
@ -276,8 +270,6 @@ static int http_connect(git_transport *transport, int direction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
t->parent.direction = direction;
|
t->parent.direction = direction;
|
||||||
if (git_vector_init(&t->refs, 16, NULL) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (!git__prefixcmp(url, prefix_http)) {
|
if (!git__prefixcmp(url, prefix_http)) {
|
||||||
url = t->parent.url + strlen(prefix_http);
|
url = t->parent.url + strlen(prefix_http);
|
||||||
@ -310,7 +302,25 @@ static int http_connect(git_transport *transport, int direction)
|
|||||||
if (gitno_send(transport, request.ptr, request.size, 0) < 0)
|
if (gitno_send(transport, request.ptr, request.size, 0) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
ret = store_refs(t);
|
setup_gitno_buffer(transport);
|
||||||
|
if ((ret = git_protocol_store_refs(transport, 2)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
pkt = git_vector_get(&transport->refs, 0);
|
||||||
|
if (pkt == NULL || pkt->type != GIT_PKT_COMMENT) {
|
||||||
|
giterr_set(GITERR_NET, "Invalid HTTP response");
|
||||||
|
return t->error = -1;
|
||||||
|
} else {
|
||||||
|
/* Remove the comment and flush pkts */
|
||||||
|
git_vector_remove(&transport->refs, 0);
|
||||||
|
git__free(pkt);
|
||||||
|
pkt = git_vector_get(&transport->refs, 0);
|
||||||
|
git_vector_remove(&transport->refs, 0);
|
||||||
|
git__free(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (git_protocol_detect_caps(git_vector_get(&transport->refs, 0), &transport->caps) < 0)
|
||||||
|
return t->error = -1;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
git_buf_free(&request);
|
git_buf_free(&request);
|
||||||
@ -319,68 +329,6 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int http_ls(git_transport *transport, git_headlist_cb list_cb, void *opaque)
|
|
||||||
{
|
|
||||||
transport_http *t = (transport_http *) transport;
|
|
||||||
git_vector *refs = &t->refs;
|
|
||||||
unsigned int i;
|
|
||||||
git_pkt_ref *p;
|
|
||||||
|
|
||||||
git_vector_foreach(refs, i, p) {
|
|
||||||
if (p->type != GIT_PKT_REF)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (list_cb(&p->head, opaque) < 0) {
|
|
||||||
giterr_set(GITERR_NET, "The user callback returned error");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int on_body_fill_buffer(http_parser *parser, const char *str, size_t len)
|
|
||||||
{
|
|
||||||
git_transport *transport = (git_transport *) parser->data;
|
|
||||||
transport_http *t = (transport_http *) parser->data;
|
|
||||||
gitno_buffer *buf = &transport->buffer;
|
|
||||||
|
|
||||||
if (buf->len - buf->offset < len) {
|
|
||||||
giterr_set(GITERR_NET, "Can't fit data in the buffer");
|
|
||||||
return t->error = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(buf->data + buf->offset, str, len);
|
|
||||||
buf->offset += len;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int http_recv_cb(gitno_buffer *buf)
|
|
||||||
{
|
|
||||||
git_transport *transport = (git_transport *) buf->cb_data;
|
|
||||||
transport_http *t = (transport_http *) transport;
|
|
||||||
size_t parsed, old_len;
|
|
||||||
gitno_buffer inner;
|
|
||||||
char buffer[2048];
|
|
||||||
int error;
|
|
||||||
|
|
||||||
if (t->transfer_finished)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
gitno_buffer_setup(transport, &inner, buffer, sizeof(buffer));
|
|
||||||
|
|
||||||
if ((error = gitno_recv(&inner)) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
old_len = buf->offset;
|
|
||||||
parsed = http_parser_execute(&t->parser, &t->settings, inner.data, inner.offset);
|
|
||||||
if (t->error < 0)
|
|
||||||
return t->error;
|
|
||||||
|
|
||||||
return buf->offset - old_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int http_negotiation_step(struct git_transport *transport, void *data, size_t len)
|
static int http_negotiation_step(struct git_transport *transport, void *data, size_t len)
|
||||||
{
|
{
|
||||||
transport_http *t = (transport_http *) transport;
|
transport_http *t = (transport_http *) transport;
|
||||||
@ -403,17 +351,7 @@ static int http_negotiation_step(struct git_transport *transport, void *data, si
|
|||||||
git_buf_free(&request);
|
git_buf_free(&request);
|
||||||
|
|
||||||
/* Then we need to set up the buffer to grab data from the HTTP response */
|
/* Then we need to set up the buffer to grab data from the HTTP response */
|
||||||
http_parser_init(&t->parser, HTTP_RESPONSE);
|
setup_gitno_buffer(transport);
|
||||||
t->parser.data = t;
|
|
||||||
t->transfer_finished = 0;
|
|
||||||
memset(&t->settings, 0x0, sizeof(http_parser_settings));
|
|
||||||
t->settings.on_header_field = on_header_field;
|
|
||||||
t->settings.on_header_value = on_header_value;
|
|
||||||
t->settings.on_headers_complete = on_headers_complete;
|
|
||||||
t->settings.on_body = on_body_fill_buffer;
|
|
||||||
t->settings.on_message_complete = on_message_complete;
|
|
||||||
|
|
||||||
gitno_buffer_setup_callback(transport, &transport->buffer, t->buffer, sizeof(t->buffer), http_recv_cb, t);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -441,7 +379,7 @@ static int http_close(git_transport *transport)
|
|||||||
static void http_free(git_transport *transport)
|
static void http_free(git_transport *transport)
|
||||||
{
|
{
|
||||||
transport_http *t = (transport_http *) transport;
|
transport_http *t = (transport_http *) transport;
|
||||||
git_vector *refs = &t->refs;
|
git_vector *refs = &transport->refs;
|
||||||
git_vector *common = &transport->common;
|
git_vector *common = &transport->common;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
git_pkt *p;
|
git_pkt *p;
|
||||||
@ -463,8 +401,6 @@ static void http_free(git_transport *transport)
|
|||||||
}
|
}
|
||||||
git_vector_free(common);
|
git_vector_free(common);
|
||||||
git_buf_free(&t->buf);
|
git_buf_free(&t->buf);
|
||||||
git_buf_free(&t->proto.buf);
|
|
||||||
git__free(t->heads);
|
|
||||||
git__free(t->content_type);
|
git__free(t->content_type);
|
||||||
git__free(t->host);
|
git__free(t->host);
|
||||||
git__free(t->port);
|
git__free(t->port);
|
||||||
@ -483,13 +419,15 @@ int git_transport_http(git_transport **out)
|
|||||||
memset(t, 0x0, sizeof(transport_http));
|
memset(t, 0x0, sizeof(transport_http));
|
||||||
|
|
||||||
t->parent.connect = http_connect;
|
t->parent.connect = http_connect;
|
||||||
t->parent.ls = http_ls;
|
|
||||||
t->parent.negotiation_step = http_negotiation_step;
|
t->parent.negotiation_step = http_negotiation_step;
|
||||||
t->parent.close = http_close;
|
t->parent.close = http_close;
|
||||||
t->parent.free = http_free;
|
t->parent.free = http_free;
|
||||||
t->parent.rpc = 1;
|
t->parent.rpc = 1;
|
||||||
t->proto.refs = &t->refs;
|
|
||||||
t->proto.transport = (git_transport *) t;
|
if (git_vector_init(&t->parent.refs, 16, NULL) < 0) {
|
||||||
|
git__free(t);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef GIT_WIN32
|
#ifdef GIT_WIN32
|
||||||
/* on win32, the WSA context needs to be initialized
|
/* on win32, the WSA context needs to be initialized
|
||||||
|
@ -15,11 +15,11 @@
|
|||||||
#include "posix.h"
|
#include "posix.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
#include "pkt.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
git_transport parent;
|
git_transport parent;
|
||||||
git_repository *repo;
|
git_repository *repo;
|
||||||
git_vector refs;
|
|
||||||
} transport_local;
|
} transport_local;
|
||||||
|
|
||||||
static int add_ref(transport_local *t, const char *name)
|
static int add_ref(transport_local *t, const char *name)
|
||||||
@ -27,19 +27,32 @@ static int add_ref(transport_local *t, const char *name)
|
|||||||
const char peeled[] = "^{}";
|
const char peeled[] = "^{}";
|
||||||
git_remote_head *head;
|
git_remote_head *head;
|
||||||
git_object *obj = NULL, *target = NULL;
|
git_object *obj = NULL, *target = NULL;
|
||||||
|
git_transport *transport = (git_transport *) t;
|
||||||
git_buf buf = GIT_BUF_INIT;
|
git_buf buf = GIT_BUF_INIT;
|
||||||
|
git_pkt_ref *pkt;
|
||||||
|
|
||||||
head = git__malloc(sizeof(git_remote_head));
|
head = git__malloc(sizeof(git_remote_head));
|
||||||
GITERR_CHECK_ALLOC(head);
|
GITERR_CHECK_ALLOC(head);
|
||||||
|
pkt = git__malloc(sizeof(git_pkt_ref));
|
||||||
|
GITERR_CHECK_ALLOC(pkt);
|
||||||
|
|
||||||
head->name = git__strdup(name);
|
head->name = git__strdup(name);
|
||||||
GITERR_CHECK_ALLOC(head->name);
|
GITERR_CHECK_ALLOC(head->name);
|
||||||
|
|
||||||
if (git_reference_name_to_oid(&head->oid, t->repo, name) < 0 ||
|
if (git_reference_name_to_oid(&head->oid, t->repo, name) < 0) {
|
||||||
git_vector_insert(&t->refs, head) < 0)
|
|
||||||
{
|
|
||||||
git__free(head->name);
|
|
||||||
git__free(head);
|
git__free(head);
|
||||||
|
git__free(pkt->head.name);
|
||||||
|
git__free(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt->type = GIT_PKT_REF;
|
||||||
|
memcpy(&pkt->head, head, sizeof(git_remote_head));
|
||||||
|
git__free(head);
|
||||||
|
|
||||||
|
if (git_vector_insert(&transport->refs, pkt) < 0)
|
||||||
|
{
|
||||||
|
git__free(pkt->head.name);
|
||||||
|
git__free(pkt);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +60,7 @@ static int add_ref(transport_local *t, const char *name)
|
|||||||
if (git__prefixcmp(name, GIT_REFS_TAGS_DIR))
|
if (git__prefixcmp(name, GIT_REFS_TAGS_DIR))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJ_ANY) < 0)
|
if (git_object_lookup(&obj, t->repo, &pkt->head.oid, GIT_OBJ_ANY) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
head = NULL;
|
head = NULL;
|
||||||
@ -66,14 +79,20 @@ static int add_ref(transport_local *t, const char *name)
|
|||||||
|
|
||||||
head->name = git_buf_detach(&buf);
|
head->name = git_buf_detach(&buf);
|
||||||
|
|
||||||
|
pkt = git__malloc(sizeof(git_pkt_ref));
|
||||||
|
GITERR_CHECK_ALLOC(pkt);
|
||||||
|
pkt->type = GIT_PKT_REF;
|
||||||
|
|
||||||
if (git_tag_peel(&target, (git_tag *) obj) < 0)
|
if (git_tag_peel(&target, (git_tag *) obj) < 0)
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
|
||||||
git_oid_cpy(&head->oid, git_object_id(target));
|
git_oid_cpy(&head->oid, git_object_id(target));
|
||||||
git_object_free(obj);
|
git_object_free(obj);
|
||||||
git_object_free(target);
|
git_object_free(target);
|
||||||
|
memcpy(&pkt->head, head, sizeof(git_remote_head));
|
||||||
|
git__free(head);
|
||||||
|
|
||||||
if (git_vector_insert(&t->refs, head) < 0)
|
if (git_vector_insert(&transport->refs, pkt) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -88,11 +107,12 @@ static int store_refs(transport_local *t)
|
|||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
git_strarray ref_names = {0};
|
git_strarray ref_names = {0};
|
||||||
|
git_transport *transport = (git_transport *) t;
|
||||||
|
|
||||||
assert(t);
|
assert(t);
|
||||||
|
|
||||||
if (git_reference_list(&ref_names, t->repo, GIT_REF_LISTALL) < 0 ||
|
if (git_reference_list(&ref_names, t->repo, GIT_REF_LISTALL) < 0 ||
|
||||||
git_vector_init(&t->refs, (unsigned int)ref_names.count, NULL) < 0)
|
git_vector_init(&transport->refs, (unsigned int)ref_names.count, NULL) < 0)
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
|
||||||
/* Sort the references first */
|
/* Sort the references first */
|
||||||
@ -111,28 +131,11 @@ static int store_refs(transport_local *t)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
git_vector_free(&t->refs);
|
git_vector_free(&transport->refs);
|
||||||
git_strarray_free(&ref_names);
|
git_strarray_free(&ref_names);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *payload)
|
|
||||||
{
|
|
||||||
transport_local *t = (transport_local *) transport;
|
|
||||||
git_vector *refs = &t->refs;
|
|
||||||
unsigned int i;
|
|
||||||
git_remote_head *h;
|
|
||||||
|
|
||||||
assert(transport && transport->connected);
|
|
||||||
|
|
||||||
git_vector_foreach(refs, i, h) {
|
|
||||||
if (list_cb(h, payload) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to open the url as a git directory. The direction doesn't
|
* Try to open the url as a git directory. The direction doesn't
|
||||||
* matter in this case because we're calulating the heads ourselves.
|
* matter in this case because we're calulating the heads ourselves.
|
||||||
@ -201,14 +204,14 @@ static void local_free(git_transport *transport)
|
|||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
transport_local *t = (transport_local *) transport;
|
transport_local *t = (transport_local *) transport;
|
||||||
git_vector *vec = &t->refs;
|
git_vector *vec = &transport->refs;
|
||||||
git_remote_head *h;
|
git_pkt_ref *pkt;
|
||||||
|
|
||||||
assert(transport);
|
assert(transport);
|
||||||
|
|
||||||
git_vector_foreach (vec, i, h) {
|
git_vector_foreach (vec, i, pkt) {
|
||||||
git__free(h->name);
|
git__free(pkt->head.name);
|
||||||
git__free(h);
|
git__free(pkt);
|
||||||
}
|
}
|
||||||
git_vector_free(vec);
|
git_vector_free(vec);
|
||||||
|
|
||||||
@ -229,8 +232,8 @@ int git_transport_local(git_transport **out)
|
|||||||
|
|
||||||
memset(t, 0x0, sizeof(transport_local));
|
memset(t, 0x0, sizeof(transport_local));
|
||||||
|
|
||||||
|
t->parent.own_logic = 1;
|
||||||
t->parent.connect = local_connect;
|
t->parent.connect = local_connect;
|
||||||
t->parent.ls = local_ls;
|
|
||||||
t->parent.negotiate_fetch = local_negotiate_fetch;
|
t->parent.negotiate_fetch = local_negotiate_fetch;
|
||||||
t->parent.close = local_close;
|
t->parent.close = local_close;
|
||||||
t->parent.free = local_free;
|
t->parent.free = local_free;
|
||||||
|
Loading…
Reference in New Issue
Block a user