Commit 40a40e8e9daa8187450258ba538c90d70eac12fe

Carlos Martín Nieto 2011-10-26T18:06:36

net: move the reference storage to common code

diff --git a/src/protocol.c b/src/protocol.c
new file mode 100644
index 0000000..1f39f10
--- /dev/null
+++ b/src/protocol.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2009-2011 the libgit2 contributors
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#include "common.h"
+#include "protocol.h"
+#include "pkt.h"
+#include "buffer.h"
+
+int git_protocol_store_refs(git_protocol *p, const char *data, size_t len)
+{
+	git_buf *buf = &p->buf;
+	git_vector *refs = p->refs;
+	int error;
+	const char *line_end, *ptr;
+
+	if (len == 0) { /* EOF */
+		if (buf->size != 0)
+			return p->error = git__throw(GIT_ERROR, "EOF and unprocessed data");
+		else
+			return 0;
+	}
+
+	git_buf_put(buf, data, len);
+	ptr = buf->ptr;
+	while (1) {
+		git_pkt *pkt;
+
+		if (buf->size == 0)
+			return 0;
+
+		error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->size);
+		if (error == GIT_ESHORTBUFFER)
+			return 0; /* Ask for more */
+		if (error < GIT_SUCCESS)
+			return p->error = git__rethrow(error, "Failed to parse pkt-line");
+
+		git_buf_consume(buf, line_end);
+		error = git_vector_insert(refs, pkt);
+		if (error < GIT_SUCCESS)
+			return p->error = git__rethrow(error, "Failed to add pkt to list");
+
+		if (pkt->type == GIT_PKT_FLUSH)
+			p->flush = 1;
+	}
+
+	return error;
+}
diff --git a/src/protocol.h b/src/protocol.h
new file mode 100644
index 0000000..e331573
--- /dev/null
+++ b/src/protocol.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2009-2011 the libgit2 contributors
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_protocol_h__
+#define INCLUDE_protocol_h__
+
+#include "transport.h"
+#include "buffer.h"
+
+typedef struct {
+	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);
+
+#endif
diff --git a/src/transports/git.c b/src/transports/git.c
index c201452..2ee2e48 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -20,9 +20,11 @@
 #include "filebuf.h"
 #include "repository.h"
 #include "fetch.h"
+#include "protocol.h"
 
 typedef struct {
 	git_transport parent;
+	git_protocol proto;
 	GIT_SOCKET socket;
 	git_vector refs;
 	git_remote_head **heads;
@@ -126,11 +128,7 @@ static int do_connect(transport_git *t, const char *url)
 static int store_refs(transport_git *t)
 {
 	gitno_buffer *buf = &t->buf;
-	git_vector *refs = &t->refs;
 	int error = GIT_SUCCESS;
-	const char *line_end, *ptr;
-	git_pkt *pkt;
-
 
 	while (1) {
 		error = gitno_recv(buf);
@@ -139,34 +137,20 @@ static int store_refs(transport_git *t)
 		if (error == GIT_SUCCESS) /* Orderly shutdown, so exit */
 			return GIT_SUCCESS;
 
-		ptr = buf->data;
-		while (1) {
-			if (buf->offset == 0)
-				break;
-			error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
-			/*
-			 * If the error is GIT_ESHORTBUFFER, it means the buffer
-			 * isn't long enough to satisfy the request. Break out and
-			 * wait for more input.
-			 * On any other error, fail.
-			 */
-			if (error == GIT_ESHORTBUFFER) {
-				break;
-			}
-			if (error < GIT_SUCCESS) {
-				return error;
-			}
-
-			/* Get rid of the part we've used already */
-			gitno_consume(buf, line_end);
+		error = git_protocol_store_refs(&t->proto, buf->data, buf->offset);
+		if (error == GIT_ESHORTBUFFER) {
+			gitno_consume_n(buf, buf->len);
+			continue;
+		}
 
-			error = git_vector_insert(refs, pkt);
-			if (error < GIT_SUCCESS)
-				return error;
+		if (error < GIT_SUCCESS)
+			return git__rethrow(error, "Failed to store refs");
 
-			if (pkt->type == GIT_PKT_FLUSH)
-				return GIT_SUCCESS;
+		gitno_consume_n(buf, buf->offset);
 
+		if (t->proto.flush) { /* No more refs */
+			t->proto.flush = 0;
+			return GIT_SUCCESS;
 		}
 	}
 
@@ -476,6 +460,7 @@ static void git_free(git_transport *transport)
 
 	git_vector_free(refs);
 	git__free(t->heads);
+	git_buf_free(&t->proto.buf);
 	git__free(t->parent.url);
 	git__free(t);
 }
@@ -501,6 +486,8 @@ int git_transport_git(git_transport **out)
 	t->parent.download_pack = git_download_pack;
 	t->parent.close = git_close;
 	t->parent.free = git_free;
+	t->proto.refs = &t->refs;
+	t->proto.transport = (git_transport *) t;
 
 	*out = (git_transport *) t;
 
diff --git a/src/transports/http.c b/src/transports/http.c
index 66b6f25..ae0c56a 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -19,6 +19,7 @@
 #include "fetch.h"
 #include "filebuf.h"
 #include "repository.h"
+#include "protocol.h"
 
 enum last_cb {
 	NONE,
@@ -28,6 +29,7 @@ enum last_cb {
 
 typedef struct {
 	git_transport parent;
+	git_protocol proto;
 	git_vector refs;
 	git_vector common;
 	int socket;
@@ -186,47 +188,8 @@ static int on_headers_complete(http_parser *parser)
 static int on_body_store_refs(http_parser *parser, const char *str, size_t len)
 {
 	transport_http *t = (transport_http *) parser->data;
-	git_buf *buf = &t->buf;
-	git_vector *refs = &t->refs;
-	int error;
-	const char *line_end, *ptr;
-	static int first_pkt = 1;
-
-	if (len == 0) { /* EOF */
-		if (buf->size != 0)
-			return t->error = git__throw(GIT_ERROR, "EOF and unprocessed data");
-		else
-			return 0;
-	}
-
-	git_buf_put(buf, str, len);
-	ptr = buf->ptr;
-	while (1) {
-		git_pkt *pkt;
-
-		if (buf->size == 0)
-			return 0;
-
-		error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->size);
-		if (error == GIT_ESHORTBUFFER)
-			return 0; /* Ask for more */
-		if (error < GIT_SUCCESS)
-			return t->error = git__rethrow(error, "Failed to parse pkt-line");
-
-		git_buf_consume(buf, line_end);
 
-		if (first_pkt) {
-			first_pkt = 0;
-			if (pkt->type != GIT_PKT_COMMENT)
-				return t->error = git__throw(GIT_EOBJCORRUPTED, "Not a valid smart HTTP response");
-		}
-
-		error = git_vector_insert(refs, pkt);
-		if (error < GIT_SUCCESS)
-			return t->error = git__rethrow(error, "Failed to add pkt to list");
-	}
-
-	return error;
+	return git_protocol_store_refs(&t->proto, str, len);
 }
 
 static int on_message_complete(http_parser *parser)
@@ -243,6 +206,7 @@ static int store_refs(transport_http *t)
 	http_parser_settings settings;
 	char buffer[1024];
 	gitno_buffer buf;
+	git_pkt *pkt;
 
 	http_parser_init(&t->parser, HTTP_RESPONSE);
 	t->parser.data = t;
@@ -273,6 +237,12 @@ static int store_refs(transport_http *t)
 			return GIT_SUCCESS;
 	}
 
+	pkt = git_vector_get(&t->refs, 0);
+	if (pkt == NULL || pkt->type != GIT_PKT_COMMENT)
+		return t->error = git__throw(GIT_EOBJCORRUPTED, "Not a valid smart HTTP response");
+	else
+		git_vector_remove(&t->refs, 0);
+
 	return error;
 }
 
@@ -750,6 +720,7 @@ static void http_free(git_transport *transport)
 	}
 	git_vector_free(common);
 	git_buf_free(&t->buf);
+	git_buf_free(&t->proto.buf);
 	git__free(t->heads);
 	git__free(t->content_type);
 	git__free(t->host);
@@ -775,6 +746,8 @@ int git_transport_http(git_transport **out)
 	t->parent.download_pack = http_download_pack;
 	t->parent.close = http_close;
 	t->parent.free = http_free;
+	t->proto.refs = &t->refs;
+	t->proto.transport = (git_transport *) t;
 
 #ifdef GIT_WIN32
 	/* on win32, the WSA context needs to be initialized