Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-16 Thread Josh Steadmon
On 2018.11.16 11:45, Junio C Hamano wrote:
> Josh Steadmon  writes:
> 
> >> What I was alludding to was a lot simpler, though.  An advert string
> >> "version=0:version=1" from a client that prefers version 0 won't be
> >> !strcmp("version=0", advert) but seeing many strcmp() in the patch
> >> made me wonder.
> >
> > Ah I see. The strcmp()s against "version=0" are special cases for where
> > it looks like the client does not understand any sort of version
> > negotiation. If we see multiple versions listed in the advert, then the
> > rest of the selection logic should do the right thing.
> 
> OK, let me try to see if I understand correctly by rephrasing.
> 
> If the client does not say anything about which version it prefers
> (because it only knows about version 0 without even realizing that
> there is a version negotiation exchange), we substitute the lack of
> proposed versions with string "version=0", and the strcmp()s I saw
> and was puzzled by are all about special casing such a client.  But
> we would end up behaving the same way (at least when judged only by
> externally visible effects) to a client that is aware of version
> negotiation and tells us it prefers version 0 (and nothing else)
> with the selection logic anyway.
> 
> Did I get it right?  If so, yeah, I think it makes sense to avoid
> two codepaths that ends up doing the same thing by removing the
> special case.

Yes, that is correct. The next version will remove the special cases
here.

> > However, I think that it might work to remove the special cases. In the
> > event that the client is so old that it doesn't understand any form of
> > version negotiation, it should just ignore the version fields /
> > environment vars. If you think it's cleaner to remove the special cases,
> > let me know.


Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-15 Thread Junio C Hamano
Josh Steadmon  writes:

>> What I was alludding to was a lot simpler, though.  An advert string
>> "version=0:version=1" from a client that prefers version 0 won't be
>> !strcmp("version=0", advert) but seeing many strcmp() in the patch
>> made me wonder.
>
> Ah I see. The strcmp()s against "version=0" are special cases for where
> it looks like the client does not understand any sort of version
> negotiation. If we see multiple versions listed in the advert, then the
> rest of the selection logic should do the right thing.

OK, let me try to see if I understand correctly by rephrasing.

If the client does not say anything about which version it prefers
(because it only knows about version 0 without even realizing that
there is a version negotiation exchange), we substitute the lack of
proposed versions with string "version=0", and the strcmp()s I saw
and was puzzled by are all about special casing such a client.  But
we would end up behaving the same way (at least when judged only by
externally visible effects) to a client that is aware of version
negotiation and tells us it prefers version 0 (and nothing else)
with the selection logic anyway.

Did I get it right?  If so, yeah, I think it makes sense to avoid
two codepaths that ends up doing the same thing by removing the
special case.

> However, I think that it might work to remove the special cases. In the
> event that the client is so old that it doesn't understand any form of
> version negotiation, it should just ignore the version fields /
> environment vars. If you think it's cleaner to remove the special cases,
> let me know.


Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-14 Thread Josh Steadmon
On 2018.11.14 11:38, Junio C Hamano wrote:
> Josh Steadmon  writes:
> 
> > On 2018.11.13 13:01, Junio C Hamano wrote:
> >> I am wondering if the code added by this patch outside this
> >> function, with if (strcmp(client_ad.buf, "version=0") sprinkled all
> >> over the place, works sensibly when the other side says "I prefer
> >> version=0 but I do not mind talking version=1".
> >
> > Depends on what you mean by "sensibly" :). In the current case, if the
> > client prefers v0, it will always end up using v0. After the fixes
> > described above, it will always use v0 unless the server no longer
> > supports v0. Is that what you would expect?
> 
> Yes, that sounds like a sensible behaviour.
> 
> What I was alludding to was a lot simpler, though.  An advert string
> "version=0:version=1" from a client that prefers version 0 won't be
> !strcmp("version=0", advert) but seeing many strcmp() in the patch
> made me wonder.

Ah I see. The strcmp()s against "version=0" are special cases for where
it looks like the client does not understand any sort of version
negotiation. If we see multiple versions listed in the advert, then the
rest of the selection logic should do the right thing.

However, I think that it might work to remove the special cases. In the
event that the client is so old that it doesn't understand any form of
version negotiation, it should just ignore the version fields /
environment vars. If you think it's cleaner to remove the special cases,
let me know.


Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-14 Thread SZEDER Gábor
On Wed, Nov 14, 2018 at 11:44:51AM +0900, Junio C Hamano wrote:
> SZEDER Gábor  writes:
> 
> >> +  if (tmp_allowed_versions[0] != config_version)
> >> +  for (int i = 1; i < nr_allowed_versions; i++)
> >
> > We don't do C99 yet, thus the declaration of a loop variable like this
> > is not allowed and triggers compiler errors.
> 
> I thought we did a weather-balloon to see if this bothers people who
> build on minority platforms but
> 
>   git grep 'for (int'
> 
> is coming up empty.
> 
> We have been trying designated initializers with weather-balloon
> changes (both arrays and struct fields) and I somehow thought that
> we already were trying this out, but apparently that is not the
> case.

I thought so as well, and I run the exact same 'git grep' command
before replying to Josh :)

There was a discussion about such a weather-balloon patch [1] (which
happened to use an unsigned loop variable, so our grep wouldn't have
found it anyway), but it wasn't picked up because it required new
options in CFLAGS and there was no standard way to do so [2].

[1] https://public-inbox.org/git/20170719181956.15845-1-sbel...@google.com/
[2] 
https://public-inbox.org/git/20170724170813.scceigybl5d3f...@sigill.intra.peff.net/



Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-13 Thread Junio C Hamano
SZEDER Gábor  writes:

>> +if (tmp_allowed_versions[0] != config_version)
>> +for (int i = 1; i < nr_allowed_versions; i++)
>
> We don't do C99 yet, thus the declaration of a loop variable like this
> is not allowed and triggers compiler errors.

I thought we did a weather-balloon to see if this bothers people who
build on minority platforms but

git grep 'for (int'

is coming up empty.

We have been trying designated initializers with weather-balloon
changes (both arrays and struct fields) and I somehow thought that
we already were trying this out, but apparently that is not the
case.  Also trailing comma in the enum definition was what we
discussed earlier but I do not know if we had weather-balloon for it
or not offhand.  

Perhaps we should write these down in CodingGuidelines.


Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-13 Thread Junio C Hamano
Josh Steadmon  writes:

> On 2018.11.13 13:01, Junio C Hamano wrote:
>> stead...@google.com writes:
>> 
>> > Currently the client advertises that it supports the wire protocol
>> > version set in the protocol.version config. However, not all services
>> > support the same set of protocol versions. When connecting to
>> > git-receive-pack, the client automatically downgrades to v0 if
>> > config.protocol is set to v2, but this check is not performed for other
>> > services.
>> 
>> "downgrades to v0 even if ... is set to v2" you mean?  Otherwise it
>> is unclear why asking for v2 leads to using v0.
>
> The downgrade on push happens only when the the configured version is
> v2. If v1 is requested, no downgrade is triggered. I'll clarify the
> commit message in the next version.

OK, then it will still be confusing unless "we downgrade v2 to v0
because ..."gives the reason.

> In any case, the ordering of the server's allowed versions won't matter;
> we'll pick the the first version in the client's list which is also
> allowed on the server.

That sounds like a very sensible semantics.

>
>> I am wondering if the code added by this patch outside this
>> function, with if (strcmp(client_ad.buf, "version=0") sprinkled all
>> over the place, works sensibly when the other side says "I prefer
>> version=0 but I do not mind talking version=1".
>
> Depends on what you mean by "sensibly" :). In the current case, if the
> client prefers v0, it will always end up using v0. After the fixes
> described above, it will always use v0 unless the server no longer
> supports v0. Is that what you would expect?

Yes, that sounds like a sensible behaviour.

What I was alludding to was a lot simpler, though.  An advert string
"version=0:version=1" from a client that prefers version 0 won't be
!strcmp("version=0", advert) but seeing many strcmp() in the patch
made me wonder.


Re: Re* [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-13 Thread Junio C Hamano
Stefan Beller  writes:

> "Nobody reads documentation any more, we have too much of it."

Maybe, but spelling it out and writing it down, you can point at it
(or hope that other people point at it without making a bad or incorrect
rephrase).

> I would have hoped to have a .cocci patch in the bad style category,
> i.e. disallowing the _() function inside the context of BUG().
>
> That said, I like the patch below. Thanks for writing it.

That was a mere weather-baloon, and too early to thank about.
Hopefully people can pick nits and come to a final version that can
be applied.

I have a few things in it that I think may be debatable.  I am not
sure if we should talk about being careful not to send localized
strings over the wire in that comment, for example.




Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-13 Thread SZEDER Gábor
On Tue, Nov 13, 2018 at 03:03:47PM -0800, Josh Steadmon wrote:
> > > + for (int i = 1; i < nr_allowed_versions; i++)
> > 
> > We don't do C99 yet, thus the declaration of a loop variable like this
> > is not allowed and triggers compiler errors.

> Sorry about that. Will fix in v4. Out of curiousity, do you have a
> config.mak snippet that will make these into errors? I played around
> with adding combinations of -ansi, -std=c89, and -pedantic to CFLAGS,
> but I couldn't get anything that detect the problem without also
> breaking on other parts of the build.

Unfortunately, I don't have such an universal CFLAGS.

With gcc-4.8 the default CFLAGS is sufficient:

  $ make V=1 CC=gcc-4.8 protocol.o
  gcc-4.8 -o protocol.o -c -MF ./.depend/protocol.o.d -MQ protocol.o -MMD -MP  
-g -O2 -Wall -I. -DHAVE_SYSINFO -DGIT_HOST_CPU="\"x86_64\"" -DHAVE_ALLOCA_H 
-DUSE_CURL_FOR_IMAP_SEND -DSHA1_DC -DSHA1DC_NO_STANDARD_INCLUDES 
-DSHA1DC_INIT_SAFE_HASH_DEFAULT=0 -DSHA1DC_CUSTOM_INCLUDE_SHA1_C="\"cache.h\"" 
-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="\"git-compat-util.h\""  -DHAVE_PATHS_H 
-DHAVE_DEV_TTY -DHAVE_CLOCK_GETTIME -DHAVE_CLOCK_MONOTONIC -DHAVE_GETDELIM 
'-DPROCFS_EXECUTABLE_PATH="/proc/self/exe"'  -DFREAD_READS_DIRECTORIES 
-DNO_STRLCPY -DSHELL_PATH='"/bin/sh"' -DPAGER_ENV='"LESS=FRX LV=-c"'  protocol.c
  protocol.c: In function ‘get_client_protocol_version_advertisement’:
  protocol.c:112:3: error: ‘for’ loop initial declarations are only allowed in 
C99 mode
 for (int i = 1; i < nr_allowed_versions; i++)
 ^
  < ... snip ... >

I couldn't get this error with any newer GCC or Clang, and using
options like -std=c89 trigger many other errors as well, just like you
mentioned.




Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-13 Thread Josh Steadmon
On 2018.11.13 19:28, SZEDER Gábor wrote:
> On Mon, Nov 12, 2018 at 01:49:05PM -0800, stead...@google.com wrote:
> 
> > diff --git a/protocol.c b/protocol.c
> > index 5e636785d1..54d2ab991b 100644
> > --- a/protocol.c
> > +++ b/protocol.c
> 
> > +void get_client_protocol_version_advertisement(struct strbuf *advert)
> > +{
> > +   int tmp_nr = nr_allowed_versions;
> > +   enum protocol_version *tmp_allowed_versions, config_version;
> > +   strbuf_reset(advert);
> > +
> > +   have_advertised_versions_already = 1;
> > +
> > +   config_version = get_protocol_version_config();
> > +   if (config_version == protocol_v0) {
> > +   strbuf_addstr(advert, "version=0");
> > +   return;
> > +   }
> > +
> > +   if (tmp_nr > 0) {
> > +   ALLOC_ARRAY(tmp_allowed_versions, tmp_nr);
> > +   copy_array(tmp_allowed_versions, allowed_versions, tmp_nr,
> > +  sizeof(enum protocol_version));
> > +   } else {
> > +   ALLOC_ARRAY(tmp_allowed_versions, 1);
> > +   tmp_nr = 1;
> > +   tmp_allowed_versions[0] = config_version;
> > +   }
> > +
> > +   if (tmp_allowed_versions[0] != config_version)
> > +   for (int i = 1; i < nr_allowed_versions; i++)
> 
> We don't do C99 yet, thus the declaration of a loop variable like this
> is not allowed and triggers compiler errors.
> 
> > +   if (tmp_allowed_versions[i] == config_version) {
> > +   enum protocol_version swap =
> > +   tmp_allowed_versions[0];
> > +   tmp_allowed_versions[0] =
> > +   tmp_allowed_versions[i];
> > +   tmp_allowed_versions[i] = swap;
> > +   }
> > +
> > +   strbuf_addf(advert, "version=%s",
> > +   format_protocol_version(tmp_allowed_versions[0]));
> > +   for (int i = 1; i < tmp_nr; i++)
> 
> Likewise.
> 
> > +   strbuf_addf(advert, ":version=%s",
> > +   format_protocol_version(tmp_allowed_versions[i]));
> > +}

Sorry about that. Will fix in v4. Out of curiousity, do you have a
config.mak snippet that will make these into errors? I played around
with adding combinations of -ansi, -std=c89, and -pedantic to CFLAGS,
but I couldn't get anything that detect the problem without also
breaking on other parts of the build.


Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-13 Thread Josh Steadmon
On 2018.11.13 13:01, Junio C Hamano wrote:
> stead...@google.com writes:
> 
> > Currently the client advertises that it supports the wire protocol
> > version set in the protocol.version config. However, not all services
> > support the same set of protocol versions. When connecting to
> > git-receive-pack, the client automatically downgrades to v0 if
> > config.protocol is set to v2, but this check is not performed for other
> > services.
> 
> "downgrades to v0 even if ... is set to v2" you mean?  Otherwise it
> is unclear why asking for v2 leads to using v0.

The downgrade on push happens only when the the configured version is
v2. If v1 is requested, no downgrade is triggered. I'll clarify the
commit message in the next version.

> > This patch creates a protocol version registry. Individual operations
> > register all the protocol versions they support prior to communicating
> > with a server. Versions should be listed in preference order; the
> > version specified in protocol.version will automatically be moved to the
> > front of the registry.
> >
> > The protocol version registry is passed to remote helpers via the
> > GIT_PROTOCOL environment variable.
> >
> > Clients now advertise the full list of registered versions. Servers
> > select the first recognized version from this advertisement.
> 
> Makes sense.
> 
> > +void get_client_protocol_version_advertisement(struct strbuf *advert)
> > +{
> > +   int tmp_nr = nr_allowed_versions;
> > +   enum protocol_version *tmp_allowed_versions, config_version;
> > +   strbuf_reset(advert);
> > +
> > +   have_advertised_versions_already = 1;
> > +
> > +   config_version = get_protocol_version_config();
> > +   if (config_version == protocol_v0) {
> > +   strbuf_addstr(advert, "version=0");
> > +   return;
> > +   }
> > +
> > +   if (tmp_nr > 0) {
> > +   ALLOC_ARRAY(tmp_allowed_versions, tmp_nr);
> > +   copy_array(tmp_allowed_versions, allowed_versions, tmp_nr,
> > +  sizeof(enum protocol_version));
> > +   } else {
> > +   ALLOC_ARRAY(tmp_allowed_versions, 1);
> > +   tmp_nr = 1;
> > +   tmp_allowed_versions[0] = config_version;
> > +   }
> > +
> > +   if (tmp_allowed_versions[0] != config_version)
> > +   for (int i = 1; i < nr_allowed_versions; i++)
> > +   if (tmp_allowed_versions[i] == config_version) {
> > +   enum protocol_version swap =
> > +   tmp_allowed_versions[0];
> > +   tmp_allowed_versions[0] =
> > +   tmp_allowed_versions[i];
> > +   tmp_allowed_versions[i] = swap;
> > +   }
> > +
> > +   strbuf_addf(advert, "version=%s",
> > +   format_protocol_version(tmp_allowed_versions[0]));
> > +   for (int i = 1; i < tmp_nr; i++)
> > +   strbuf_addf(advert, ":version=%s",
> > +   format_protocol_version(tmp_allowed_versions[i]));
> > +}
> > +
> 
> So the idea is that the protocols the other end can talk come in
> advert in their preferred order, and we take an intersection of them
> and our "allowed-versions", but the preference is further skewed
> with the "swap" thing if we have our own preference specified via
> config?

We currently don't intersect with our own allowed list, we just accept
the first version that we recognize. This introduces its own version
negotiation bug; if we add v2 push in the future, a new client
talking to an old server would try to use v2 even though the server may
not have the corresponding v2 push implementation. I'll fix this in the
next version.

In any case, the ordering of the server's allowed versions won't matter;
we'll pick the the first version in the client's list which is also
allowed on the server.

> I am wondering if the code added by this patch outside this
> function, with if (strcmp(client_ad.buf, "version=0") sprinkled all
> over the place, works sensibly when the other side says "I prefer
> version=0 but I do not mind talking version=1".

Depends on what you mean by "sensibly" :). In the current case, if the
client prefers v0, it will always end up using v0. After the fixes
described above, it will always use v0 unless the server no longer
supports v0. Is that what you would expect?

> Isn't tmp_allowed_versions[] leaking when we return from this
> function?

Yes, sorry about that. Will fix.


Re: Re* [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-13 Thread Stefan Beller
On Mon, Nov 12, 2018 at 7:24 PM Junio C Hamano  wrote:
>
> Stefan Beller  writes:
>
> >> +   if (have_advertised_versions_already)
> >> +   BUG(_("attempting to register an allowed protocol version 
> >> after advertisement"));
> >
> > If this is a real BUG (due to wrong program flow) instead of bad user input,
> > we would not want to burden the translators with this message.
> >
> > If it is a message that the user is intended to see upon bad input
> > we'd rather go with die(_("translatable text here"));
>
> Yeah, good suggestion.
>
> Perhaps we should spell it out in docstrings for BUG/die with the
> above rationale.  A weatherbaloon patch follows.

"Nobody reads documentation any more, we have too much of it." [1]
[1] c.f. https://quoteinvestigator.com/2014/08/29/too-crowded/

I would have hoped to have a .cocci patch in the bad style category,
i.e. disallowing the _() function inside the context of BUG().

That said, I like the patch below. Thanks for writing it.

>  git-compat-util.h | 22 +-
>  1 file changed, 21 insertions(+), 1 deletion(-)
>
> diff --git a/git-compat-util.h b/git-compat-util.h
> index 96a3f86d8e..a1cf68cbbc 100644
> --- a/git-compat-util.h
> +++ b/git-compat-util.h
> @@ -420,7 +420,16 @@ static inline char *git_find_last_dir_sep(const char 
> *path)
>
>  struct strbuf;
>
> -/* General helper functions */
> +/*
> + * General helper functions
> + *
> + * Note that these are to produce end-user facing messages, and most
> + * of them should be marked for translation (the exception is
> + * messages generated to be sent over the wire---as we currently do not
> + * have a mechanism to notice and honor locale settings used on the
> + * other end, leave them untranslated.  We should *not* send messages
> + * that are localized for our end).
> + */
>  extern void vreportf(const char *prefix, const char *err, va_list params);
>  extern NORETURN void usage(const char *err);
>  extern NORETURN void usagef(const char *err, ...) __attribute__((format 
> (printf, 1, 2)));
> @@ -1142,6 +1151,17 @@ static inline int regexec_buf(const regex_t *preg, 
> const char *buf, size_t size,
>  /* usage.c: only to be used for testing BUG() implementation (see test-tool) 
> */
>  extern int BUG_exit_code;
>
> +/*
> + * BUG(fmt, ...) is to be used when the problem of reaching that point
> + * in code can only be caused by a program error.  To abort with a
> + * message to report impossible-to-continue condition due to external
> + * factors like end-user input, environment settings, data it was fed
> + * over the wire, use die(_(fmt),...).
> + *
> + * Note that the message from BUG() should not be marked for
> + * translation while the message from die() is in general end-user
> + * facing and should be marked for translation.
> + */
>  #ifdef HAVE_VARIADIC_MACROS
>  __attribute__((format (printf, 3, 4))) NORETURN
>  void BUG_fl(const char *file, int line, const char *fmt, ...);


Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-13 Thread SZEDER Gábor
On Mon, Nov 12, 2018 at 01:49:05PM -0800, stead...@google.com wrote:

> diff --git a/protocol.c b/protocol.c
> index 5e636785d1..54d2ab991b 100644
> --- a/protocol.c
> +++ b/protocol.c

> +void get_client_protocol_version_advertisement(struct strbuf *advert)
> +{
> + int tmp_nr = nr_allowed_versions;
> + enum protocol_version *tmp_allowed_versions, config_version;
> + strbuf_reset(advert);
> +
> + have_advertised_versions_already = 1;
> +
> + config_version = get_protocol_version_config();
> + if (config_version == protocol_v0) {
> + strbuf_addstr(advert, "version=0");
> + return;
> + }
> +
> + if (tmp_nr > 0) {
> + ALLOC_ARRAY(tmp_allowed_versions, tmp_nr);
> + copy_array(tmp_allowed_versions, allowed_versions, tmp_nr,
> +sizeof(enum protocol_version));
> + } else {
> + ALLOC_ARRAY(tmp_allowed_versions, 1);
> + tmp_nr = 1;
> + tmp_allowed_versions[0] = config_version;
> + }
> +
> + if (tmp_allowed_versions[0] != config_version)
> + for (int i = 1; i < nr_allowed_versions; i++)

We don't do C99 yet, thus the declaration of a loop variable like this
is not allowed and triggers compiler errors.

> + if (tmp_allowed_versions[i] == config_version) {
> + enum protocol_version swap =
> + tmp_allowed_versions[0];
> + tmp_allowed_versions[0] =
> + tmp_allowed_versions[i];
> + tmp_allowed_versions[i] = swap;
> + }
> +
> + strbuf_addf(advert, "version=%s",
> + format_protocol_version(tmp_allowed_versions[0]));
> + for (int i = 1; i < tmp_nr; i++)

Likewise.

> + strbuf_addf(advert, ":version=%s",
> + format_protocol_version(tmp_allowed_versions[i]));
> +}


Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-13 Thread Junio C Hamano
stead...@google.com writes:

> + if (tmp_allowed_versions[0] != config_version)
> + for (int i = 1; i < nr_allowed_versions; i++)
> + if (tmp_allowed_versions[i] == config_version) {
> + enum protocol_version swap =
> + tmp_allowed_versions[0];
> + tmp_allowed_versions[0] =
> + tmp_allowed_versions[i];
> + tmp_allowed_versions[i] = swap;
> + }

Here is what coccicheck suggests.

diff -u -p a/protocol.c b/protocol.c
--- a/protocol.c
+++ b/protocol.c
@@ -111,11 +111,8 @@ void get_client_protocol_version_adverti
if (tmp_allowed_versions[0] != config_version)
for (int i = 1; i < nr_allowed_versions; i++)
if (tmp_allowed_versions[i] == config_version) {
-   enum protocol_version swap =
-   tmp_allowed_versions[0];
-   tmp_allowed_versions[0] =
-   tmp_allowed_versions[i];
-   tmp_allowed_versions[i] = swap;
+   SWAP(tmp_allowed_versions[0],
+tmp_allowed_versions[i]);
}
 
strbuf_addf(advert, "version=%s",


Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-12 Thread Junio C Hamano
stead...@google.com writes:

> Currently the client advertises that it supports the wire protocol
> version set in the protocol.version config. However, not all services
> support the same set of protocol versions. When connecting to
> git-receive-pack, the client automatically downgrades to v0 if
> config.protocol is set to v2, but this check is not performed for other
> services.

"downgrades to v0 even if ... is set to v2" you mean?  Otherwise it
is unclear why asking for v2 leads to using v0.

> This patch creates a protocol version registry. Individual operations
> register all the protocol versions they support prior to communicating
> with a server. Versions should be listed in preference order; the
> version specified in protocol.version will automatically be moved to the
> front of the registry.
>
> The protocol version registry is passed to remote helpers via the
> GIT_PROTOCOL environment variable.
>
> Clients now advertise the full list of registered versions. Servers
> select the first recognized version from this advertisement.

Makes sense.

> +void get_client_protocol_version_advertisement(struct strbuf *advert)
> +{
> + int tmp_nr = nr_allowed_versions;
> + enum protocol_version *tmp_allowed_versions, config_version;
> + strbuf_reset(advert);
> +
> + have_advertised_versions_already = 1;
> +
> + config_version = get_protocol_version_config();
> + if (config_version == protocol_v0) {
> + strbuf_addstr(advert, "version=0");
> + return;
> + }
> +
> + if (tmp_nr > 0) {
> + ALLOC_ARRAY(tmp_allowed_versions, tmp_nr);
> + copy_array(tmp_allowed_versions, allowed_versions, tmp_nr,
> +sizeof(enum protocol_version));
> + } else {
> + ALLOC_ARRAY(tmp_allowed_versions, 1);
> + tmp_nr = 1;
> + tmp_allowed_versions[0] = config_version;
> + }
> +
> + if (tmp_allowed_versions[0] != config_version)
> + for (int i = 1; i < nr_allowed_versions; i++)
> + if (tmp_allowed_versions[i] == config_version) {
> + enum protocol_version swap =
> + tmp_allowed_versions[0];
> + tmp_allowed_versions[0] =
> + tmp_allowed_versions[i];
> + tmp_allowed_versions[i] = swap;
> + }
> +
> + strbuf_addf(advert, "version=%s",
> + format_protocol_version(tmp_allowed_versions[0]));
> + for (int i = 1; i < tmp_nr; i++)
> + strbuf_addf(advert, ":version=%s",
> + format_protocol_version(tmp_allowed_versions[i]));
> +}
> +

So the idea is that the protocols the other end can talk come in
advert in their preferred order, and we take an intersection of them
and our "allowed-versions", but the preference is further skewed
with the "swap" thing if we have our own preference specified via
config?

I am wondering if the code added by this patch outside this
function, with if (strcmp(client_ad.buf, "version=0") sprinkled all
over the place, works sensibly when the other side says "I prefer
version=0 but I do not mind talking version=1".

Isn't tmp_allowed_versions[] leaking when we return from this
function?


Re* [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-12 Thread Junio C Hamano
Stefan Beller  writes:

>> +   if (have_advertised_versions_already)
>> +   BUG(_("attempting to register an allowed protocol version 
>> after advertisement"));
>
> If this is a real BUG (due to wrong program flow) instead of bad user input,
> we would not want to burden the translators with this message.
>
> If it is a message that the user is intended to see upon bad input
> we'd rather go with die(_("translatable text here"));

Yeah, good suggestion.  

Perhaps we should spell it out in docstrings for BUG/die with the
above rationale.  A weatherbaloon patch follows.

 git-compat-util.h | 22 +-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/git-compat-util.h b/git-compat-util.h
index 96a3f86d8e..a1cf68cbbc 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -420,7 +420,16 @@ static inline char *git_find_last_dir_sep(const char *path)
 
 struct strbuf;
 
-/* General helper functions */
+/*
+ * General helper functions
+ *
+ * Note that these are to produce end-user facing messages, and most
+ * of them should be marked for translation (the exception is
+ * messages generated to be sent over the wire---as we currently do not
+ * have a mechanism to notice and honor locale settings used on the
+ * other end, leave them untranslated.  We should *not* send messages
+ * that are localized for our end).
+ */
 extern void vreportf(const char *prefix, const char *err, va_list params);
 extern NORETURN void usage(const char *err);
 extern NORETURN void usagef(const char *err, ...) __attribute__((format 
(printf, 1, 2)));
@@ -1142,6 +1151,17 @@ static inline int regexec_buf(const regex_t *preg, const 
char *buf, size_t size,
 /* usage.c: only to be used for testing BUG() implementation (see test-tool) */
 extern int BUG_exit_code;
 
+/*
+ * BUG(fmt, ...) is to be used when the problem of reaching that point
+ * in code can only be caused by a program error.  To abort with a
+ * message to report impossible-to-continue condition due to external
+ * factors like end-user input, environment settings, data it was fed
+ * over the wire, use die(_(fmt),...).
+ * 
+ * Note that the message from BUG() should not be marked for
+ * translation while the message from die() is in general end-user
+ * facing and should be marked for translation.
+ */
 #ifdef HAVE_VARIADIC_MACROS
 __attribute__((format (printf, 3, 4))) NORETURN
 void BUG_fl(const char *file, int line, const char *fmt, ...);


Re: [PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-12 Thread Stefan Beller
On Mon, Nov 12, 2018 at 1:49 PM  wrote:
>
> Currently the client advertises that it supports the wire protocol
> version set in the protocol.version config. However, not all services
> support the same set of protocol versions. When connecting to
> git-receive-pack, the client automatically downgrades to v0 if
> config.protocol is set to v2, but this check is not performed for other
> services.
>
> This patch creates a protocol version registry. Individual operations
> register all the protocol versions they support prior to communicating
> with a server. Versions should be listed in preference order; the
> version specified in protocol.version will automatically be moved to the
> front of the registry.
>
> The protocol version registry is passed to remote helpers via the
> GIT_PROTOCOL environment variable.
>
> Clients now advertise the full list of registered versions. Servers
> select the first recognized version from this advertisement.
>
> Signed-off-by: Josh Steadmon 

Thanks for resending this patch!

+cc Jonathan Tan, who works a lot on the protocol side of things.

> +void register_allowed_protocol_version(enum protocol_version version)
> +{
> +   if (have_advertised_versions_already)
> +   BUG(_("attempting to register an allowed protocol version 
> after advertisement"));

If this is a real BUG (due to wrong program flow) instead of bad user input,
we would not want to burden the translators with this message.

If it is a message that the user is intended to see upon bad input
we'd rather go with die(_("translatable text here"));


> diff --git a/protocol.h b/protocol.h
> index 2ad35e433c..b67b2259de 100644
> --- a/protocol.h
> +++ b/protocol.h
> @@ -16,6 +16,23 @@ enum protocol_version {
>   */
>  extern enum protocol_version get_protocol_version_config(void);
>
> +/*
> + * Register an allowable protocol version for a given operation. Registration
> + * must occur before attempting to advertise a version to a server process.
> + */
> +extern void register_allowed_protocol_version(enum protocol_version version);

We keep extern here as to imitate the file-local style, although
Documentation/CodingGuidelines would prefer to not have the extern keywords.
Okay.

Bonus points for converting the file to omit all extern keywords in a
resend. :-)
(I think there is no other series currently in flight touching this header file,
so it is safe to convert it "while at it", `git log --grep "while at
it"` is shorter
than expected.)

All that said, it's only nits that I contributed to this code review;
the code/design
looks good to me, and if I were maintainer I'd include it as-is, as it
fixes a long(ish)
standing protocol error.

Thanks,
Stefan


[PATCH v3 1/1] protocol: advertise multiple supported versions

2018-11-12 Thread steadmon
Currently the client advertises that it supports the wire protocol
version set in the protocol.version config. However, not all services
support the same set of protocol versions. When connecting to
git-receive-pack, the client automatically downgrades to v0 if
config.protocol is set to v2, but this check is not performed for other
services.

This patch creates a protocol version registry. Individual operations
register all the protocol versions they support prior to communicating
with a server. Versions should be listed in preference order; the
version specified in protocol.version will automatically be moved to the
front of the registry.

The protocol version registry is passed to remote helpers via the
GIT_PROTOCOL environment variable.

Clients now advertise the full list of registered versions. Servers
select the first recognized version from this advertisement.

Signed-off-by: Josh Steadmon 
---
 builtin/archive.c  |   3 ++
 builtin/clone.c|   4 ++
 builtin/fetch-pack.c   |   4 ++
 builtin/fetch.c|   5 ++
 builtin/ls-remote.c|   5 ++
 builtin/pull.c |   5 ++
 builtin/push.c |   4 ++
 builtin/send-pack.c|   3 ++
 connect.c  |  47 -
 protocol.c | 112 ++---
 protocol.h |  17 +++
 remote-curl.c  |  28 +++
 t/t5570-git-daemon.sh  |   2 +-
 t/t5700-protocol-v1.sh |   8 +--
 t/t5702-protocol-v2.sh |  16 +++---
 transport-helper.c |   6 +++
 16 files changed, 214 insertions(+), 55 deletions(-)

diff --git a/builtin/archive.c b/builtin/archive.c
index e74f675390..8adb9f381b 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -8,6 +8,7 @@
 #include "transport.h"
 #include "parse-options.h"
 #include "pkt-line.h"
+#include "protocol.h"
 #include "sideband.h"
 
 static void create_output_file(const char *output_file)
@@ -94,6 +95,8 @@ int cmd_archive(int argc, const char **argv, const char 
*prefix)
OPT_END()
};
 
+   register_allowed_protocol_version(protocol_v0);
+
argc = parse_options(argc, argv, prefix, local_opts, NULL,
 PARSE_OPT_KEEP_ALL);
 
diff --git a/builtin/clone.c b/builtin/clone.c
index fd2c3ef090..1651a950b6 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -900,6 +900,10 @@ int cmd_clone(int argc, const char **argv, const char 
*prefix)
struct refspec rs = REFSPEC_INIT_FETCH;
struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 
+   register_allowed_protocol_version(protocol_v2);
+   register_allowed_protocol_version(protocol_v1);
+   register_allowed_protocol_version(protocol_v0);
+
fetch_if_missing = 0;
 
packet_trace_identity("clone");
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index 1a1bc63566..cba935e4d3 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -57,6 +57,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char 
*prefix)
 
fetch_if_missing = 0;
 
+   register_allowed_protocol_version(protocol_v2);
+   register_allowed_protocol_version(protocol_v1);
+   register_allowed_protocol_version(protocol_v0);
+
packet_trace_identity("fetch-pack");
 
memset(, 0, sizeof(args));
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 61bec5d213..2a20cf8bfd 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -21,6 +21,7 @@
 #include "argv-array.h"
 #include "utf8.h"
 #include "packfile.h"
+#include "protocol.h"
 #include "list-objects-filter-options.h"
 
 static const char * const builtin_fetch_usage[] = {
@@ -1476,6 +1477,10 @@ int cmd_fetch(int argc, const char **argv, const char 
*prefix)
int prune_tags_ok = 1;
struct argv_array argv_gc_auto = ARGV_ARRAY_INIT;
 
+   register_allowed_protocol_version(protocol_v2);
+   register_allowed_protocol_version(protocol_v1);
+   register_allowed_protocol_version(protocol_v0);
+
packet_trace_identity("fetch");
 
fetch_if_missing = 0;
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 1a25df7ee1..ea685e8bb9 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "cache.h"
+#include "protocol.h"
 #include "transport.h"
 #include "ref-filter.h"
 #include "remote.h"
@@ -80,6 +81,10 @@ int cmd_ls_remote(int argc, const char **argv, const char 
*prefix)
 
memset(_array, 0, sizeof(ref_array));
 
+   register_allowed_protocol_version(protocol_v2);
+   register_allowed_protocol_version(protocol_v1);
+   register_allowed_protocol_version(protocol_v0);
+
argc = parse_options(argc, argv, prefix, options, ls_remote_usage,
 PARSE_OPT_STOP_AT_NON_OPTION);
dest = argv[0];
diff --git a/builtin/pull.c b/builtin/pull.c
index 681c127a07..cb64146834 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -9,6 +9,7 @@
 #include "config.h"
 #include "builtin.h"
 #include