Merge pull request #3574 from chescock/buffer-sideband-pack-data Buffer sideband packet data
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 132 133 134 135 136 137 138 139 140
diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c
index 6363378..02e1ecf 100644
--- a/src/transports/smart_protocol.c
+++ b/src/transports/smart_protocol.c
@@ -721,18 +721,39 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt)
return 0;
}
-static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt)
+static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, git_buf *data_pkt_buf)
{
git_pkt *pkt;
- const char *line = data_pkt->data, *line_end;
- size_t line_len = data_pkt->len;
+ const char *line, *line_end;
+ size_t line_len;
int error;
+ int reading_from_buf = data_pkt_buf->size > 0;
+
+ if (reading_from_buf) {
+ /* We had an existing partial packet, so add the new
+ * packet to the buffer and parse the whole thing */
+ git_buf_put(data_pkt_buf, data_pkt->data, data_pkt->len);
+ line = data_pkt_buf->ptr;
+ line_len = data_pkt_buf->size;
+ }
+ else {
+ line = data_pkt->data;
+ line_len = data_pkt->len;
+ }
while (line_len > 0) {
error = git_pkt_parse_line(&pkt, line, &line_end, line_len);
- if (error < 0)
- return error;
+ if (error == GIT_EBUFS) {
+ /* Buffer the data when the inner packet is split
+ * across multiple sideband packets */
+ if (!reading_from_buf)
+ git_buf_put(data_pkt_buf, line, line_len);
+ error = 0;
+ goto done;
+ }
+ else if (error < 0)
+ goto done;
/* Advance in the buffer */
line_len -= (line_end - line);
@@ -743,10 +764,15 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt)
git_pkt_free(pkt);
if (error < 0 && error != GIT_ITEROVER)
- return error;
+ goto done;
}
- return 0;
+ error = 0;
+
+done:
+ if (reading_from_buf)
+ git_buf_consume(data_pkt_buf, line_end);
+ return error;
}
static int parse_report(transport_smart *transport, git_push *push)
@@ -755,6 +781,7 @@ static int parse_report(transport_smart *transport, git_push *push)
const char *line_end = NULL;
gitno_buffer *buf = &transport->buffer;
int error, recvd;
+ git_buf data_pkt_buf = GIT_BUF_INIT;
for (;;) {
if (buf->offset > 0)
@@ -763,16 +790,21 @@ static int parse_report(transport_smart *transport, git_push *push)
else
error = GIT_EBUFS;
- if (error < 0 && error != GIT_EBUFS)
- return -1;
+ if (error < 0 && error != GIT_EBUFS) {
+ error = -1;
+ goto done;
+ }
if (error == GIT_EBUFS) {
- if ((recvd = gitno_recv(buf)) < 0)
- return recvd;
+ if ((recvd = gitno_recv(buf)) < 0) {
+ error = recvd;
+ goto done;
+ }
if (recvd == 0) {
giterr_set(GITERR_NET, "early EOF");
- return GIT_EEOF;
+ error = GIT_EEOF;
+ goto done;
}
continue;
}
@@ -784,7 +816,7 @@ static int parse_report(transport_smart *transport, git_push *push)
switch (pkt->type) {
case GIT_PKT_DATA:
/* This is a sideband packet which contains other packets */
- error = add_push_report_sideband_pkt(push, (git_pkt_data *)pkt);
+ error = add_push_report_sideband_pkt(push, (git_pkt_data *)pkt, &data_pkt_buf);
break;
case GIT_PKT_ERR:
giterr_set(GITERR_NET, "report-status: Error reported: %s",
@@ -805,12 +837,24 @@ static int parse_report(transport_smart *transport, git_push *push)
git_pkt_free(pkt);
/* add_push_report_pkt returns GIT_ITEROVER when it receives a flush */
- if (error == GIT_ITEROVER)
- return 0;
+ if (error == GIT_ITEROVER) {
+ error = 0;
+ if (data_pkt_buf.size > 0) {
+ /* If there was data remaining in the pack data buffer,
+ * then the server sent a partial pkt-line */
+ giterr_set(GITERR_NET, "Incomplete pack data pkt-line");
+ error = GIT_ERROR;
+ }
+ goto done;
+ }
- if (error < 0)
- return error;
+ if (error < 0) {
+ goto done;
+ }
}
+done:
+ git_buf_free(&data_pkt_buf);
+ return error;
}
static int add_ref_from_push_spec(git_vector *refs, push_spec *push_spec)