diff --git a/src/pkt.c b/src/pkt.c index 6cf4dac8e..00836bc34 100644 --- a/src/pkt.c +++ b/src/pkt.c @@ -97,6 +97,25 @@ static int comment_pkt(git_pkt **out, const char *line, size_t len) return 0; } +static int err_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_err *pkt; + + /* Remove "ERR " from the line */ + line += 4; + len -= 4; + pkt = git__malloc(sizeof(git_pkt_err) + len + 1); + GITERR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_ERR; + memcpy(pkt->error, line, len); + pkt->error[len] = '\0'; + + *out = (git_pkt *) pkt; + + return 0; +} + /* * Parse an other-ref line. */ @@ -234,6 +253,8 @@ int git_pkt_parse_line( ret = ack_pkt(head, line, len); else if (!git__prefixcmp(line, "NAK")) ret = nak_pkt(head); + else if (!git__prefixcmp(line, "ERR ")) + ret = err_pkt(head, line, len); else if (*line == '#') ret = comment_pkt(head, line, len); else diff --git a/src/pkt.h b/src/pkt.h index 7e696f70f..75442c833 100644 --- a/src/pkt.h +++ b/src/pkt.h @@ -23,6 +23,7 @@ enum git_pkt_type { GIT_PKT_NAK, GIT_PKT_PACK, GIT_PKT_COMMENT, + GIT_PKT_ERR, }; /* Used for multi-ack */ @@ -64,6 +65,11 @@ typedef struct { char comment[GIT_FLEX_ARRAY]; } git_pkt_comment; +typedef struct { + enum git_pkt_type type; + char error[GIT_FLEX_ARRAY]; +} git_pkt_err; + int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_t len); int git_pkt_buffer_flush(git_buf *buf); int git_pkt_send_flush(GIT_SOCKET s); diff --git a/src/protocol.c b/src/protocol.c index a7df961a9..a75354121 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -40,6 +40,13 @@ int git_protocol_store_refs(git_protocol *p, const char *data, size_t len) return p->error = -1; git_buf_consume(buf, line_end); + + if (pkt->type == GIT_PKT_ERR) { + giterr_set(GITERR_NET, "Remote error: %s", ((git_pkt_err *)pkt)->error); + git__free(pkt); + return -1; + } + if (git_vector_insert(refs, pkt) < 0) return p->error = -1; diff --git a/src/transports/http.c b/src/transports/http.c index 938076f90..3690f3ded 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -165,6 +165,12 @@ static int on_headers_complete(http_parser *parser) transport_http *t = (transport_http *) parser->data; git_buf *buf = &t->buf; + /* The content-type is text/plain for 404, so don't validate */ + if (parser->status_code == 404) { + git_buf_clear(buf); + return 0; + } + if (t->content_type == NULL) { t->content_type = git__strdup(git_buf_cstr(buf)); if (t->content_type == NULL) @@ -187,6 +193,10 @@ 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); } @@ -195,6 +205,12 @@ static int on_message_complete(http_parser *parser) transport_http *t = (transport_http *) parser->data; t->transfer_finished = 1; + + if (parser->status_code == 404) { + giterr_set(GITERR_NET, "Remote error: %s", git_buf_cstr(&t->buf)); + t->error = -1; + } + return 0; }