diff options
Diffstat (limited to 'src/transports')
-rw-r--r-- | src/transports/smart_protocol.c | 78 |
1 files changed, 61 insertions, 17 deletions
diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 6363378ec..02e1ecf74 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) |