Skip to content

Commit

Permalink
Merge branch 'ms/packet-err-check' into jt/fetch-v2-sideband
Browse files Browse the repository at this point in the history
* ms/packet-err-check:
  pack-protocol.txt: accept error packets in any context
  Use packet_reader instead of packet_read_line
  • Loading branch information
gitster committed Jan 14, 2019
2 parents ecbdaf0 + 2d103c3 commit 17069c7
Show file tree
Hide file tree
Showing 15 changed files with 174 additions and 133 deletions.
20 changes: 11 additions & 9 deletions Documentation/technical/pack-protocol.txt
Expand Up @@ -22,6 +22,16 @@ protocol-common.txt. When the grammar indicate `PKT-LINE(...)`, unless
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
Expand Down Expand Up @@ -89,13 +99,6 @@ process on the server side over the Git protocol is this:
"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
-------------
Expand Down Expand Up @@ -398,12 +401,11 @@ from the client).
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):
Expand Down
19 changes: 10 additions & 9 deletions builtin/archive.c
Expand Up @@ -27,10 +27,10 @@ static int run_remote_archiver(int argc, const char **argv,
const char *remote, const char *exec,
const char *name_hint)
{
char *buf;
int fd[2], i, rv;
struct transport *transport;
struct remote *_remote;
struct packet_reader reader;

_remote = remote_get(remote);
if (!_remote->url[0])
Expand All @@ -53,18 +53,19 @@ static int run_remote_archiver(int argc, const char **argv,
packet_write_fmt(fd[1], "argument %s\n", argv[i]);
packet_flush(fd[1]);

buf = packet_read_line(fd[0], NULL);
if (!buf)
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(buf, "ACK")) {
if (starts_with(buf, "NACK "))
die(_("git archive: NACK %s"), buf + 5);
if (starts_with(buf, "ERR "))
die(_("remote error: %s"), buf + 4);
if (strcmp(reader.line, "ACK")) {
if (starts_with(reader.line, "NACK "))
die(_("git archive: NACK %s"), reader.line + 5);
die(_("git archive: protocol error"));
}

if (packet_read_line(fd[0], NULL))
if (packet_reader_read(&reader) != PACKET_READ_FLUSH)
die(_("git archive: expected a flush"));

/* Now, start reading from fd[0] and spit it out to stdout */
Expand Down
3 changes: 2 additions & 1 deletion builtin/fetch-pack.c
Expand Up @@ -217,7 +217,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)

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:
Expand Down
62 changes: 33 additions & 29 deletions builtin/receive-pack.c
Expand Up @@ -1569,30 +1569,29 @@ static void queue_commands_from_cert(struct command **tail,
}
}

static struct command *read_head_info(struct oid_array *shallow)
static struct command *read_head_info(struct packet_reader *reader,
struct oid_array *shallow)
{
struct command *commands = NULL;
struct command **p = &commands;
for (;;) {
char *line;
int len, linelen;
int linelen;

line = packet_read_line(0, &len);
if (!line)
if (packet_reader_read(reader) != PACKET_READ_NORMAL)
break;

if (len > 8 && starts_with(line, "shallow ")) {
if (reader->pktlen > 8 && starts_with(reader->line, "shallow ")) {
struct object_id oid;
if (get_oid_hex(line + 8, &oid))
if (get_oid_hex(reader->line + 8, &oid))
die("protocol error: expected shallow sha, got '%s'",
line + 8);
reader->line + 8);
oid_array_append(shallow, &oid);
continue;
}

linelen = strlen(line);
if (linelen < len) {
const char *feature_list = line + linelen + 1;
linelen = strlen(reader->line);
if (linelen < reader->pktlen) {
const char *feature_list = reader->line + linelen + 1;
if (parse_feature_request(feature_list, "report-status"))
report_status = 1;
if (parse_feature_request(feature_list, "side-band-64k"))
Expand All @@ -1607,28 +1606,32 @@ static struct command *read_head_info(struct oid_array *shallow)
use_push_options = 1;
}

if (!strcmp(line, "push-cert")) {
if (!strcmp(reader->line, "push-cert")) {
int true_flush = 0;
char certbuf[1024];
int saved_options = reader->options;
reader->options &= ~PACKET_READ_CHOMP_NEWLINE;

for (;;) {
len = packet_read(0, NULL, NULL,
certbuf, sizeof(certbuf), 0);
if (!len) {
packet_reader_read(reader);
if (reader->status == PACKET_READ_FLUSH) {
true_flush = 1;
break;
}
if (!strcmp(certbuf, "push-cert-end\n"))
if (reader->status != PACKET_READ_NORMAL) {
die("protocol error: got an unexpected packet");
}
if (!strcmp(reader->line, "push-cert-end\n"))
break; /* end of cert */
strbuf_addstr(&push_cert, certbuf);
strbuf_addstr(&push_cert, reader->line);
}
reader->options = saved_options;

if (true_flush)
break;
continue;
}

p = queue_command(p, line, linelen);
p = queue_command(p, reader->line, linelen);
}

if (push_cert.len)
Expand All @@ -1637,18 +1640,14 @@ static struct command *read_head_info(struct oid_array *shallow)
return commands;
}

static void read_push_options(struct string_list *options)
static void read_push_options(struct packet_reader *reader,
struct string_list *options)
{
while (1) {
char *line;
int len;

line = packet_read_line(0, &len);

if (!line)
if (packet_reader_read(reader) != PACKET_READ_NORMAL)
break;

string_list_append(options, line);
string_list_append(options, reader->line);
}
}

Expand Down Expand Up @@ -1924,6 +1923,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
struct oid_array shallow = OID_ARRAY_INIT;
struct oid_array ref = OID_ARRAY_INIT;
struct shallow_info si;
struct packet_reader reader;

struct option options[] = {
OPT__QUIET(&quiet, N_("quiet")),
Expand Down Expand Up @@ -1986,12 +1986,16 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
if (advertise_refs)
return 0;

if ((commands = read_head_info(&shallow)) != NULL) {
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;
struct string_list push_options = STRING_LIST_INIT_DUP;

if (use_push_options)
read_push_options(&push_options);
read_push_options(&reader, &push_options);
if (!check_cert_push_options(&push_options)) {
struct command *cmd;
for (cmd = commands; cmd; cmd = cmd->next)
Expand Down
3 changes: 2 additions & 1 deletion builtin/send-pack.c
Expand Up @@ -250,7 +250,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)

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:
Expand Down
3 changes: 0 additions & 3 deletions connect.c
Expand Up @@ -296,7 +296,6 @@ struct ref **get_remote_heads(struct packet_reader *reader,
struct ref **orig_list = list;
int len = 0;
enum get_remote_heads_state state = EXPECTING_FIRST_REF;
const char *arg;

*list = NULL;

Expand All @@ -306,8 +305,6 @@ struct ref **get_remote_heads(struct packet_reader *reader,
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;
Expand Down

0 comments on commit 17069c7

Please sign in to comment.