Jonathan Tan <[email protected]> writes:
> Currently, get_remote_heads() parses the ref advertisement in one loop,
> allowing refs and shallow lines to intersperse, despite this not being
> allowed by the specification. Refactor get_remote_heads() to use two
> loops instead, enforcing that refs come first, and then shallows.
>
> This also makes it easier to teach get_remote_heads() to interpret other
> lines in the ref advertisement, which will be done in a subsequent
> patch.
>
> As part of this change, this patch interprets capabilities only on the
> first line in the ref advertisement, ignoring all others.
>
> Signed-off-by: Jonathan Tan <[email protected]>
> ---
> I've updated state transitions to occur in get_remote_heads() instead,
> as suggested. I didn't want to do that previously because each step in
> the state machine needed to communicate if (i) the line is "consumed"
> and (ii) the state needed to be advanced, but with Junio's suggestion to
> reorganize the methods, that is no longer true.
>
> As Junio said, the free(server_capabilities) can be removed.
>
> As for whether how capabilities on subsequent lines are handled, I think
> it's better to ignore them - they are behind NULs, after all.
Not even a diagnosis? When the other side clearly wants to tell us
something and we deliberately ignore, I'd think we want to at least
know about it---that may lead us to notify the implementators of the
other side of a protocol violation, or rethink the design decision
(i.e. only the first one matters) ourselves.
> This change does have the side effect that if the server sends a ref
> advertisement with "shallow"s only (and no refs), things will still
> work, and the server can even tuck capabilities on the first "shallow"
> line. I think that's fine, and it does make the client code cleaner.
I am ambivalent on this aspect of the change.
The change makes the resulting state transition logic quite easy to
follow. Very nicely done.
> + while ((len = read_remote_ref(in, &src_buf, &src_len, &responded))) {
> + switch (state) {
> + case EXPECTING_FIRST_REF:
> + process_capabilities(len);
> + if (process_dummy_ref()) {
> + state = EXPECTING_SHALLOW;
> + break;
> + }
> + state = EXPECTING_REF;
> + /* fallthrough */
> + case EXPECTING_REF:
> + if (process_ref(&list, flags, extra_have))
> + break;
> + state = EXPECTING_SHALLOW;
> + /* fallthrough */
> + case EXPECTING_SHALLOW:
> + if (process_shallow(shallow_points))
> + break;
> + die("protocol error: unexpected '%s'", packet_buffer);
> + default:
> + die("unexpected state %d", state);
> }
> }