Use packet_reader instead of packet_read_line

By using and sharing a packet_reader while handling a Git pack protocol
request, the same reader option is used throughout the code. This makes
it easy to set a reader option to the request parsing code.

Signed-off-by: Masaya Suzuki <masayasuzuki@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Masaya Suzuki 2018-12-29 13:19:14 -08:00 committed by Junio C Hamano
parent b21ebb671b
commit 01f9ec64c8
6 changed files with 129 additions and 108 deletions

View File

@ -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])
@ -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);
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);
if (starts_with(reader.line, "ERR "))
die(_("remote error: %s"), reader.line + 4);
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 */

View File

@ -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"))
@ -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"))
break; /* end of cert */
strbuf_addstr(&push_cert, certbuf);
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, 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)
@ -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);
}
}
@ -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")),
@ -1986,12 +1986,14 @@ 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);
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)

View File

@ -135,38 +135,42 @@ enum ack_type {
ACK_ready
};
static void consume_shallow_list(struct fetch_pack_args *args, int fd)
static void consume_shallow_list(struct fetch_pack_args *args,
struct packet_reader *reader)
{
if (args->stateless_rpc && args->deepen) {
/* If we sent a depth we will get back "duplicate"
* shallow and unshallow commands every time there
* is a block of have lines exchanged.
*/
char *line;
while ((line = packet_read_line(fd, NULL))) {
if (starts_with(line, "shallow "))
while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
if (starts_with(reader->line, "shallow "))
continue;
if (starts_with(line, "unshallow "))
if (starts_with(reader->line, "unshallow "))
continue;
die(_("git fetch-pack: expected shallow list"));
}
if (reader->status != PACKET_READ_FLUSH)
die(_("git fetch-pack: expected a flush packet after shallow list"));
}
}
static enum ack_type get_ack(int fd, struct object_id *result_oid)
static enum ack_type get_ack(struct packet_reader *reader,
struct object_id *result_oid)
{
int len;
char *line = packet_read_line(fd, &len);
const char *arg;
if (!line)
if (packet_reader_read(reader) != PACKET_READ_NORMAL)
die(_("git fetch-pack: expected ACK/NAK, got a flush packet"));
if (!strcmp(line, "NAK"))
len = reader->pktlen;
if (!strcmp(reader->line, "NAK"))
return NAK;
if (skip_prefix(line, "ACK ", &arg)) {
if (skip_prefix(reader->line, "ACK ", &arg)) {
if (!get_oid_hex(arg, result_oid)) {
arg += 40;
len -= arg - line;
len -= arg - reader->line;
if (len < 1)
return ACK;
if (strstr(arg, "continue"))
@ -178,9 +182,9 @@ static enum ack_type get_ack(int fd, struct object_id *result_oid)
return ACK;
}
}
if (skip_prefix(line, "ERR ", &arg))
if (skip_prefix(reader->line, "ERR ", &arg))
die(_("remote error: %s"), arg);
die(_("git fetch-pack: expected ACK/NAK, got '%s'"), line);
die(_("git fetch-pack: expected ACK/NAK, got '%s'"), reader->line);
}
static void send_request(struct fetch_pack_args *args,
@ -248,10 +252,14 @@ static int find_common(struct fetch_negotiator *negotiator,
int got_ready = 0;
struct strbuf req_buf = STRBUF_INIT;
size_t state_len = 0;
struct packet_reader reader;
if (args->stateless_rpc && multi_ack == 1)
die(_("--stateless-rpc requires multi_ack_detailed"));
packet_reader_init(&reader, fd[0], NULL, 0,
PACKET_READ_CHOMP_NEWLINE);
if (!args->no_dependents) {
mark_tips(negotiator, args->negotiation_tips);
for_each_cached_alternate(negotiator, insert_one_alternate_object);
@ -336,31 +344,30 @@ static int find_common(struct fetch_negotiator *negotiator,
state_len = req_buf.len;
if (args->deepen) {
char *line;
const char *arg;
struct object_id oid;
send_request(args, fd[1], &req_buf);
while ((line = packet_read_line(fd[0], NULL))) {
if (skip_prefix(line, "shallow ", &arg)) {
while (packet_reader_read(&reader) == PACKET_READ_NORMAL) {
if (skip_prefix(reader.line, "shallow ", &arg)) {
if (get_oid_hex(arg, &oid))
die(_("invalid shallow line: %s"), line);
die(_("invalid shallow line: %s"), reader.line);
register_shallow(the_repository, &oid);
continue;
}
if (skip_prefix(line, "unshallow ", &arg)) {
if (skip_prefix(reader.line, "unshallow ", &arg)) {
if (get_oid_hex(arg, &oid))
die(_("invalid unshallow line: %s"), line);
die(_("invalid unshallow line: %s"), reader.line);
if (!lookup_object(the_repository, oid.hash))
die(_("object not found: %s"), line);
die(_("object not found: %s"), reader.line);
/* make sure that it is parsed as shallow */
if (!parse_object(the_repository, &oid))
die(_("error in object: %s"), line);
die(_("error in object: %s"), reader.line);
if (unregister_shallow(&oid))
die(_("no shallow found: %s"), line);
die(_("no shallow found: %s"), reader.line);
continue;
}
die(_("expected shallow/unshallow, got %s"), line);
die(_("expected shallow/unshallow, got %s"), reader.line);
}
} else if (!args->stateless_rpc)
send_request(args, fd[1], &req_buf);
@ -397,9 +404,9 @@ static int find_common(struct fetch_negotiator *negotiator,
if (!args->stateless_rpc && count == INITIAL_FLUSH)
continue;
consume_shallow_list(args, fd[0]);
consume_shallow_list(args, &reader);
do {
ack = get_ack(fd[0], result_oid);
ack = get_ack(&reader, result_oid);
if (ack)
print_verbose(args, _("got %s %d %s"), "ack",
ack, oid_to_hex(result_oid));
@ -469,9 +476,9 @@ done:
strbuf_release(&req_buf);
if (!got_ready || !no_done)
consume_shallow_list(args, fd[0]);
consume_shallow_list(args, &reader);
while (flushes || multi_ack) {
int ack = get_ack(fd[0], result_oid);
int ack = get_ack(&reader, result_oid);
if (ack) {
print_verbose(args, _("got %s (%d) %s"), "ack",
ack, oid_to_hex(result_oid));

View File

@ -409,28 +409,36 @@ static struct discovery *discover_refs(const char *service, int for_push)
if (maybe_smart &&
(5 <= last->len && last->buf[4] == '#') &&
!strbuf_cmp(&exp, &type)) {
char *line;
struct packet_reader reader;
packet_reader_init(&reader, -1, last->buf, last->len,
PACKET_READ_CHOMP_NEWLINE);
/*
* smart HTTP response; validate that the service
* pkt-line matches our request.
*/
line = packet_read_line_buf(&last->buf, &last->len, NULL);
if (!line)
if (packet_reader_read(&reader) != PACKET_READ_NORMAL)
die("invalid server response; expected service, got flush packet");
strbuf_reset(&exp);
strbuf_addf(&exp, "# service=%s", service);
if (strcmp(line, exp.buf))
die("invalid server response; got '%s'", line);
if (strcmp(reader.line, exp.buf))
die("invalid server response; got '%s'", reader.line);
strbuf_release(&exp);
/* The header can include additional metadata lines, up
* until a packet flush marker. Ignore these now, but
* in the future we might start to scan them.
*/
while (packet_read_line_buf(&last->buf, &last->len, NULL))
;
for (;;) {
packet_reader_read(&reader);
if (reader.pktlen <= 0) {
break;
}
}
last->buf = reader.src_buffer;
last->len = reader.src_len;
last->proto_git = 1;
} else if (maybe_smart &&

View File

@ -135,38 +135,36 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *extra, struc
return 0;
}
static int receive_unpack_status(int in)
static int receive_unpack_status(struct packet_reader *reader)
{
const char *line = packet_read_line(in, NULL);
if (!line)
if (packet_reader_read(reader) != PACKET_READ_NORMAL)
return error(_("unexpected flush packet while reading remote unpack status"));
if (!skip_prefix(line, "unpack ", &line))
return error(_("unable to parse remote unpack status: %s"), line);
if (strcmp(line, "ok"))
return error(_("remote unpack failed: %s"), line);
if (!skip_prefix(reader->line, "unpack ", &reader->line))
return error(_("unable to parse remote unpack status: %s"), reader->line);
if (strcmp(reader->line, "ok"))
return error(_("remote unpack failed: %s"), reader->line);
return 0;
}
static int receive_status(int in, struct ref *refs)
static int receive_status(struct packet_reader *reader, struct ref *refs)
{
struct ref *hint;
int ret;
hint = NULL;
ret = receive_unpack_status(in);
ret = receive_unpack_status(reader);
while (1) {
char *refname;
const char *refname;
char *msg;
char *line = packet_read_line(in, NULL);
if (!line)
if (packet_reader_read(reader) != PACKET_READ_NORMAL)
break;
if (!starts_with(line, "ok ") && !starts_with(line, "ng ")) {
error("invalid ref status from remote: %s", line);
if (!starts_with(reader->line, "ok ") && !starts_with(reader->line, "ng ")) {
error("invalid ref status from remote: %s", reader->line);
ret = -1;
break;
}
refname = line + 3;
refname = reader->line + 3;
msg = strchr(refname, ' ');
if (msg)
*msg++ = '\0';
@ -187,7 +185,7 @@ static int receive_status(int in, struct ref *refs)
continue;
}
if (line[0] == 'o' && line[1] == 'k')
if (reader->line[0] == 'o' && reader->line[1] == 'k')
hint->status = REF_STATUS_OK;
else {
hint->status = REF_STATUS_REMOTE_REJECT;
@ -390,6 +388,7 @@ int send_pack(struct send_pack_args *args,
int ret;
struct async demux;
const char *push_cert_nonce = NULL;
struct packet_reader reader;
/* Does the other end support the reporting? */
if (server_supports("report-status"))
@ -559,6 +558,8 @@ int send_pack(struct send_pack_args *args,
in = demux.out;
}
packet_reader_init(&reader, in, NULL, 0, PACKET_READ_CHOMP_NEWLINE);
if (need_pack_data && cmds_sent) {
if (pack_objects(out, remote_refs, extra_have, args) < 0) {
for (ref = remote_refs; ref; ref = ref->next)
@ -573,7 +574,7 @@ int send_pack(struct send_pack_args *args,
* are failing, and just want the error() side effects.
*/
if (status_report)
receive_unpack_status(in);
receive_unpack_status(&reader);
if (use_sideband) {
close(demux.out);
@ -590,7 +591,7 @@ int send_pack(struct send_pack_args *args,
packet_flush(out);
if (status_report && cmds_sent)
ret = receive_status(in, remote_refs);
ret = receive_status(&reader, remote_refs);
else
ret = 0;
if (args->stateless_rpc)

View File

@ -354,7 +354,8 @@ static int ok_to_give_up(const struct object_array *have_obj,
min_generation);
}
static int get_common_commits(struct object_array *have_obj,
static int get_common_commits(struct packet_reader *reader,
struct object_array *have_obj,
struct object_array *want_obj)
{
struct object_id oid;
@ -366,12 +367,11 @@ static int get_common_commits(struct object_array *have_obj,
save_commit_buffer = 0;
for (;;) {
char *line = packet_read_line(0, NULL);
const char *arg;
reset_timeout();
if (!line) {
if (packet_reader_read(reader) != PACKET_READ_NORMAL) {
if (multi_ack == 2 && got_common
&& !got_other && ok_to_give_up(have_obj, want_obj)) {
sent_ready = 1;
@ -390,7 +390,7 @@ static int get_common_commits(struct object_array *have_obj,
got_other = 0;
continue;
}
if (skip_prefix(line, "have ", &arg)) {
if (skip_prefix(reader->line, "have ", &arg)) {
switch (got_oid(arg, &oid, have_obj)) {
case -1: /* they have what we do not */
got_other = 1;
@ -416,7 +416,7 @@ static int get_common_commits(struct object_array *have_obj,
}
continue;
}
if (!strcmp(line, "done")) {
if (!strcmp(reader->line, "done")) {
if (have_obj->nr > 0) {
if (multi_ack)
packet_write_fmt(1, "ACK %s\n", last_hex);
@ -425,7 +425,7 @@ static int get_common_commits(struct object_array *have_obj,
packet_write_fmt(1, "NAK\n");
return -1;
}
die("git upload-pack: expected SHA1 list, got '%s'", line);
die("git upload-pack: expected SHA1 list, got '%s'", reader->line);
}
}
@ -826,7 +826,7 @@ static int process_deepen_not(const char *line, struct string_list *deepen_not,
return 0;
}
static void receive_needs(struct object_array *want_obj)
static void receive_needs(struct packet_reader *reader, struct object_array *want_obj)
{
struct object_array shallows = OBJECT_ARRAY_INIT;
struct string_list deepen_not = STRING_LIST_INIT_DUP;
@ -840,33 +840,32 @@ static void receive_needs(struct object_array *want_obj)
struct object *o;
const char *features;
struct object_id oid_buf;
char *line = packet_read_line(0, NULL);
const char *arg;
reset_timeout();
if (!line)
if (packet_reader_read(reader) != PACKET_READ_NORMAL)
break;
if (process_shallow(line, &shallows))
if (process_shallow(reader->line, &shallows))
continue;
if (process_deepen(line, &depth))
if (process_deepen(reader->line, &depth))
continue;
if (process_deepen_since(line, &deepen_since, &deepen_rev_list))
if (process_deepen_since(reader->line, &deepen_since, &deepen_rev_list))
continue;
if (process_deepen_not(line, &deepen_not, &deepen_rev_list))
if (process_deepen_not(reader->line, &deepen_not, &deepen_rev_list))
continue;
if (skip_prefix(line, "filter ", &arg)) {
if (skip_prefix(reader->line, "filter ", &arg)) {
if (!filter_capability_requested)
die("git upload-pack: filtering capability not negotiated");
parse_list_objects_filter(&filter_options, arg);
continue;
}
if (!skip_prefix(line, "want ", &arg) ||
if (!skip_prefix(reader->line, "want ", &arg) ||
parse_oid_hex(arg, &oid_buf, &features))
die("git upload-pack: protocol error, "
"expected to get object ID, not '%s'", line);
"expected to get object ID, not '%s'", reader->line);
if (parse_feature_request(features, "deepen-relative"))
deepen_relative = 1;
@ -1055,6 +1054,7 @@ void upload_pack(struct upload_pack_options *options)
{
struct string_list symref = STRING_LIST_INIT_DUP;
struct object_array want_obj = OBJECT_ARRAY_INIT;
struct packet_reader reader;
stateless_rpc = options->stateless_rpc;
timeout = options->timeout;
@ -1078,10 +1078,12 @@ void upload_pack(struct upload_pack_options *options)
if (options->advertise_refs)
return;
receive_needs(&want_obj);
packet_reader_init(&reader, 0, NULL, 0, PACKET_READ_CHOMP_NEWLINE);
receive_needs(&reader, &want_obj);
if (want_obj.nr) {
struct object_array have_obj = OBJECT_ARRAY_INIT;
get_common_commits(&have_obj, &want_obj);
get_common_commits(&reader, &have_obj, &want_obj);
create_pack_file(&have_obj, &want_obj);
}
}