otherwise noted the usual pkt-line LF rules apply: the sender SHOULD
include a LF, but the receiver MUST NOT complain if it is not present.
+An error packet is a special pkt-line that contains an error string.
+
+----
+ error-line = PKT-LINE("ERR" SP explanation-text)
+----
+
+Throughout the protocol, where `PKT-LINE(...)` is expected, an error packet MAY
+be sent. Once this packet is sent by a client or a server, the data transfer
+process defined in this protocol is terminated.
+
Transports
----------
There are three transports over which the packfile protocol is
"0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" |
nc -v example.com 9418
-If the server refuses the request for some reasons, it could abort
-gracefully with an error message.
-
-----
- error-line = PKT-LINE("ERR" SP explanation-text)
-----
-
SSH Transport
-------------
Then the server will start sending its packfile data.
----
- server-response = *ack_multi ack / nak / error-line
+ server-response = *ack_multi ack / nak
ack_multi = PKT-LINE("ACK" SP obj-id ack_status)
ack_status = "continue" / "common" / "ready"
ack = PKT-LINE("ACK" SP obj-id)
nak = PKT-LINE("NAK")
- error-line = PKT-LINE("ERR" SP explanation-text)
----
A simple clone may look like this (with no 'have' lines):
packet_write_fmt(fd[1], "argument %s\n", argv[i]);
packet_flush(fd[1]);
- packet_reader_init(&reader, fd[0], NULL, 0, PACKET_READ_CHOMP_NEWLINE);
+ packet_reader_init(&reader, fd[0], NULL, 0,
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_DIE_ON_ERR_PACKET);
if (packet_reader_read(&reader) != PACKET_READ_NORMAL)
die(_("git archive: expected ACK/NAK, got a flush packet"));
if (strcmp(reader.line, "ACK")) {
if (starts_with(reader.line, "NACK "))
die(_("git archive: NACK %s"), reader.line + 5);
- if (starts_with(reader.line, "ERR "))
- die(_("remote error: %s"), reader.line + 4);
die(_("git archive: protocol error"));
}
packet_reader_init(&reader, fd[0], NULL, 0,
PACKET_READ_CHOMP_NEWLINE |
- PACKET_READ_GENTLE_ON_EOF);
+ PACKET_READ_GENTLE_ON_EOF |
+ PACKET_READ_DIE_ON_ERR_PACKET);
switch (discover_version(&reader)) {
case protocol_v2:
if (advertise_refs)
return 0;
- packet_reader_init(&reader, 0, NULL, 0, PACKET_READ_CHOMP_NEWLINE);
+ packet_reader_init(&reader, 0, NULL, 0,
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_DIE_ON_ERR_PACKET);
if ((commands = read_head_info(&reader, &shallow)) != NULL) {
const char *unpack_status = NULL;
packet_reader_init(&reader, fd[0], NULL, 0,
PACKET_READ_CHOMP_NEWLINE |
- PACKET_READ_GENTLE_ON_EOF);
+ PACKET_READ_GENTLE_ON_EOF |
+ PACKET_READ_DIE_ON_ERR_PACKET);
switch (discover_version(&reader)) {
case protocol_v2:
struct ref **orig_list = list;
int len = 0;
enum get_remote_heads_state state = EXPECTING_FIRST_REF;
- const char *arg;
*list = NULL;
die_initial_contact(1);
case PACKET_READ_NORMAL:
len = reader->pktlen;
- if (len > 4 && skip_prefix(reader->line, "ERR ", &arg))
- die(_("remote error: %s"), arg);
break;
case PACKET_READ_FLUSH:
state = EXPECTING_DONE;
return ACK;
}
}
- if (skip_prefix(reader->line, "ERR ", &arg))
- die(_("remote error: %s"), arg);
die(_("git fetch-pack: expected ACK/NAK, got '%s'"), reader->line);
}
die(_("--stateless-rpc requires multi_ack_detailed"));
packet_reader_init(&reader, fd[0], NULL, 0,
- PACKET_READ_CHOMP_NEWLINE);
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_DIE_ON_ERR_PACKET);
if (!args->no_dependents) {
mark_tips(negotiator, args->negotiation_tips);
struct fetch_negotiator negotiator;
fetch_negotiator_init(&negotiator, negotiation_algorithm);
packet_reader_init(&reader, fd[0], NULL, 0,
- PACKET_READ_CHOMP_NEWLINE);
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_DIE_ON_ERR_PACKET);
while (state != FETCH_DONE) {
switch (state) {
return PACKET_READ_EOF;
}
+ if ((options & PACKET_READ_DIE_ON_ERR_PACKET) &&
+ starts_with(buffer, "ERR "))
+ die(_("remote error: %s"), buffer + 4);
+
if ((options & PACKET_READ_CHOMP_NEWLINE) &&
len && buffer[len-1] == '\n')
len--;
*
* If options contains PACKET_READ_CHOMP_NEWLINE, a trailing newline (if
* present) is removed from the buffer before returning.
+ *
+ * If options contains PACKET_READ_DIE_ON_ERR_PACKET, it dies when it sees an
+ * ERR packet.
*/
-#define PACKET_READ_GENTLE_ON_EOF (1u<<0)
-#define PACKET_READ_CHOMP_NEWLINE (1u<<1)
+#define PACKET_READ_GENTLE_ON_EOF (1u<<0)
+#define PACKET_READ_CHOMP_NEWLINE (1u<<1)
+#define PACKET_READ_DIE_ON_ERR_PACKET (1u<<2)
int packet_read(int fd, char **src_buffer, size_t *src_len, char
*buffer, unsigned size, int options);
packet_reader_init(&reader, -1, heads->buf, heads->len,
PACKET_READ_CHOMP_NEWLINE |
- PACKET_READ_GENTLE_ON_EOF);
+ PACKET_READ_GENTLE_ON_EOF |
+ PACKET_READ_DIE_ON_ERR_PACKET);
heads->version = discover_version(&reader);
switch (heads->version) {
!strbuf_cmp(&exp, &type)) {
struct packet_reader reader;
packet_reader_init(&reader, -1, last->buf, last->len,
- PACKET_READ_CHOMP_NEWLINE);
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_DIE_ON_ERR_PACKET);
/*
* smart HTTP response; validate that the service
p->headers = curl_slist_append(p->headers, buf.buf);
packet_reader_init(&p->reader, p->in, NULL, 0,
- PACKET_READ_GENTLE_ON_EOF);
+ PACKET_READ_GENTLE_ON_EOF |
+ PACKET_READ_DIE_ON_ERR_PACKET);
strbuf_release(&buf);
}
in = demux.out;
}
- packet_reader_init(&reader, in, NULL, 0, PACKET_READ_CHOMP_NEWLINE);
+ packet_reader_init(&reader, in, NULL, 0,
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_DIE_ON_ERR_PACKET);
if (need_pack_data && cmds_sent) {
if (pack_objects(out, remote_refs, extra_have, args) < 0) {
packet_reader_init(&reader, 0, NULL, 0,
PACKET_READ_CHOMP_NEWLINE |
- PACKET_READ_GENTLE_ON_EOF);
+ PACKET_READ_GENTLE_ON_EOF |
+ PACKET_READ_DIE_ON_ERR_PACKET);
/*
* Check to see if the client closed their end before sending another
*/
if (packet_reader_peek(&reader) == PACKET_READ_EOF)
return 1;
- reader.options = PACKET_READ_CHOMP_NEWLINE;
+ reader.options &= ~PACKET_READ_GENTLE_ON_EOF;
while (state != PROCESS_REQUEST_DONE) {
switch (packet_reader_peek(&reader)) {
cp -r "$LOCAL_PRISTINE" local &&
inconsistency master 1234567890123456789012345678901234567890 &&
test_must_fail git -C local fetch 2>err &&
- grep "ERR upload-pack: not our ref" err
+ grep "fatal: remote error: upload-pack: not our ref" err
'
test_expect_success 'server is initially ahead - ref in want' '
echo "s/master/raster/" >"$HTTPD_ROOT_PATH/one-time-sed" &&
test_must_fail git -C local fetch 2>err &&
- grep "ERR unknown ref refs/heads/raster" err
+ grep "fatal: remote error: unknown ref refs/heads/raster" err
'
stop_httpd
packet_reader_init(&reader, data->fd[0], NULL, 0,
PACKET_READ_CHOMP_NEWLINE |
- PACKET_READ_GENTLE_ON_EOF);
+ PACKET_READ_GENTLE_ON_EOF |
+ PACKET_READ_DIE_ON_ERR_PACKET);
data->version = discover_version(&reader);
switch (data->version) {
if (options->advertise_refs)
return;
- packet_reader_init(&reader, 0, NULL, 0, PACKET_READ_CHOMP_NEWLINE);
+ packet_reader_init(&reader, 0, NULL, 0,
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_DIE_ON_ERR_PACKET);
receive_needs(&reader, &want_obj);
if (want_obj.nr) {