This is a refactoring of what a callback in serve.c needs to do to
aquire config. Currently two of them want that, and grab it in ad-hoc
ways themselves, now they can insted configure a "configure" callback
along with the existing "advertise" and "command", by the time they're
called their config will already be read with their callback.
I split this prep work off from an upcoming series where I wanted to
add a new capability, but I think this stands nicely on its own, and
simplifies the existing code.
The line count increase is mostly converting things to designated
initializers.
Ævar Arnfjörð Bjarmason (5):
serve: mark has_capability() as static
transport: rename "fetch" in transport_vtable to "fetch_refs"
transport: use designated initializers
serve: use designated initializers
serve: add support for a git_config() callback
ls-refs.c | 55 +++++++++++---------------------
ls-refs.h | 1 +
serve.c | 76 ++++++++++++++++++++++++++++++++++++++------
serve.h | 3 --
transport-helper.c | 18 +++++------
transport-internal.h | 2 +-
transport.c | 32 ++++++++-----------
7 files changed, 108 insertions(+), 79 deletions(-)
--
2.32.0.576.g59759b6ca7d
The has_capability() function introduced in ed10cb952d3 (serve:
introduce git-serve, 2018-03-15) has never been used anywhere except
serve.c, so let's mark it as static.
It was later changed from "extern" in 554544276a6 (*.[ch]: remove
extern from function declarations using spatch, 2019-04-29), but we
could have simply marked it as "static" instead.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 4 ++--
serve.h | 3 ---
2 files changed, 2 insertions(+), 5 deletions(-)
From: Eric Sunshine <hidden> Date: 2021-06-16 16:28:14
On Wed, Jun 16, 2021 at 10:16 AM Ævar Arnfjörð Bjarmason
[off-list ref] wrote:
quoted hunk
The has_capability() function introduced in ed10cb952d3 (serve:
introduce git-serve, 2018-03-15) has never been used anywhere except
serve.c, so let's mark it as static.
It was later changed from "extern" in 554544276a6 (*.[ch]: remove
extern from function declarations using spatch, 2019-04-29), but we
could have simply marked it as "static" instead.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
Rename the "fetch" member of the transport_vtable to "fetch_refs" for
consistency with the existing "push_refs". Neither of them just push
"refs" but refs and objects, but having the two match makes the code
more readable than having it be inconsistent, especially since
"fetch_refs" is a lot easier to grep for than "fetch".
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
transport-helper.c | 8 ++++----
transport-internal.h | 2 +-
transport.c | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
@@ -671,8 +671,8 @@ static int connect_helper(struct transport *transport, const char *name,staticstructref*get_refs_list_using_list(structtransport*transport,intfor_push);-staticintfetch(structtransport*transport,-intnr_heads,structref**to_fetch)+staticintfetch_refs(structtransport*transport,+intnr_heads,structref**to_fetch){structhelper_data*data=transport->data;inti,count;
@@ -681,7 +681,7 @@ static int fetch(struct transport *transport,if(process_connect(transport,0)){do_take_over(transport);-returntransport->vtable->fetch(transport,nr_heads,to_fetch);+returntransport->vtable->fetch_refs(transport,nr_heads,to_fetch);}/*
@@ -1263,7 +1263,7 @@ static struct ref *get_refs_list_using_list(struct transport *transport,staticstructtransport_vtablevtable={set_helper_option,get_refs_list,-fetch,+fetch_refs,push_refs,connect_helper,release_helper
Change the assignments to the various transport_vtables to use
designated initializers, this makes the code easier to read and
maintain.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
transport-helper.c | 12 ++++++------
transport.c | 30 ++++++++++++------------------
2 files changed, 18 insertions(+), 24 deletions(-)
@@ -880,12 +880,10 @@ static int disconnect_git(struct transport *transport)}staticstructtransport_vtabletaken_over_vtable={-NULL,-get_refs_via_connect,-fetch_refs_via_pack,-git_transport_push,-NULL,-disconnect_git+.get_refs_list=get_refs_via_connect,+.fetch_refs=fetch_refs_via_pack,+.push_refs=git_transport_push,+.disconnect=disconnect_git};voidtransport_take_over(structtransport*transport,
Since the introduction of serve.c we've added git_config() callbacks
and other config reading for capabilities in the following commits:
- e20b4192a37 (upload-pack: support hidden refs with protocol v2, 2018-12-18)
- 59e1205d167 (ls-refs: report unborn targets of symrefs, 2021-02-05)
- 6b5b6e422ee (serve: advertise session ID in v2 capabilities, 2020-11-11)
This code can be simplified by simply adding support to serve.c itself
for reading config at the right time before the capability is
called. In particular the ensure_config_read() function being gone
makes this whole thing much simpler.
A behavior change here is that we're eagerly doing the configuration
for all our capabilities regardless of which one we end up serving,
whereas before we'd defer it until the point where we were processing
the specific command.
We could try to be more lazy here and only read the config if we find
out that we're serving "ls-refs" or "session-id", but it's just a fast
git_config() callback, I think in this case simplicity trumps a
premature optimization.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
ls-refs.c | 55 ++++++++++++++++++-------------------------------------
ls-refs.h | 1 +
serve.c | 34 +++++++++++++++++++++++++++++++++-
3 files changed, 52 insertions(+), 38 deletions(-)
@@ -7,38 +7,9 @@#include"pkt-line.h"#include"config.h"-staticintconfig_read;-staticintadvertise_unborn;-staticintallow_unborn;--staticvoidensure_config_read(void)-{-constchar*str=NULL;--if(config_read)-return;--if(repo_config_get_string_tmp(the_repository,"lsrefs.unborn",&str)){-/*-*Ifthereisnosuchconfig,advertiseandallowitby-*default.-*/-advertise_unborn=1;-allow_unborn=1;-}else{-if(!strcmp(str,"advertise")){-advertise_unborn=1;-allow_unborn=1;-}elseif(!strcmp(str,"allow")){-allow_unborn=1;-}elseif(!strcmp(str,"ignore")){-/* do nothing */-}else{-die(_("invalid value '%s' for lsrefs.unborn"),str);-}-}-config_read=1;-}+/* "unborn" is on by default if there's no lsrefs.unborn config */+staticintadvertise_unborn=1;+staticintallow_unborn=1;/**Checkifoneoftheprefixesisaprefixoftheref.
@@ -128,8 +99,22 @@ static void send_possibly_unborn_head(struct ls_refs_data *data)strbuf_release(&namespaced);}-staticintls_refs_config(constchar*var,constchar*value,void*data)+intls_refs_configure(constchar*var,constchar*value,void*data){+if(!strcmp(var,"lsrefs.unborn")){+if(!strcmp(value,"advertise")){+/* Allowed and advertised by default */+}elseif(!strcmp(value,"allow")){+advertise_unborn=0;+allow_unborn=1;+}elseif(!strcmp(value,"ignore")){+advertise_unborn=0;+allow_unborn=0;+}else{+die(_("invalid value '%s' for lsrefs.unborn"),value);+}+}+/**Weonlyservefetchesoverv2fornow,sorespectonly"uploadpack"*config.Thismayneedtoeventuallybeexpandedto"receive",butwe
@@ -303,7 +335,7 @@ static int process_request(void)/* Main serve loop for protocol version 2 */voidserve(structserve_options*options){-git_config_get_bool("transfer.advertisesid",&advertise_sid);+git_config(git_serve_config,NULL);if(options->advertise_capabilities||!options->stateless_rpc){/* serve by default supports v2 */
From: Jeff King <hidden> Date: 2021-06-16 16:23:02
On Wed, Jun 16, 2021 at 04:16:21PM +0200, Ævar Arnfjörð Bjarmason wrote:
Since the introduction of serve.c we've added git_config() callbacks
and other config reading for capabilities in the following commits:
- e20b4192a37 (upload-pack: support hidden refs with protocol v2, 2018-12-18)
- 59e1205d167 (ls-refs: report unborn targets of symrefs, 2021-02-05)
- 6b5b6e422ee (serve: advertise session ID in v2 capabilities, 2020-11-11)
This code can be simplified by simply adding support to serve.c itself
for reading config at the right time before the capability is
called. In particular the ensure_config_read() function being gone
makes this whole thing much simpler.
A behavior change here is that we're eagerly doing the configuration
for all our capabilities regardless of which one we end up serving,
whereas before we'd defer it until the point where we were processing
the specific command.
Hmm. I like simplifying things, but what's the plan for when we have a
v2 receive-pack? We'll need different config based on whether we're
serving a fetch or a push.
While working on e20b4192a37, I had originally proposed patches that
would pass that context into the serve mechanism (based on whether we
were called by upload-pack or receive-pack). But the review there
indicated that v2 receive-pack would probably involve an extra
capability argument passed by the client to ls-refs.
So we'd eventually need to parse config _after_ we've received the
actual ls-refs command. To be clear, this patch isn't breaking anything
now. But I think it's painting us into a corner that we'll regret later.
Of course there are ways around this. E.g., we could read config for
both operations ahead of time, and then decide which to use later. But
that definitely isn't how it works now, and we'd have to refactor the
whole ref_is_hidden() system to fix that. Definitely do-able, but given
the relatively limited upside of this patch, I'm not sure if it's worth
it.
I'd also note that this patch doesn't touch upload_pack_v2() at all,
which also reads config. That one is extra-weird because it reads the
config fresh for every round of interaction with the client, and then
cleans it up. Which led to fixes like the one in 08450ef791
(upload-pack: clear filter_options for each v2 fetch command,
2020-05-08).
Doing a single config read would probably make that simpler. But the
config setup is shared between the v0 and v2 functions, so extracting it
into serve() would potentially be awkward.
In particular the ensure_config_read() function being gone
makes this whole thing much simpler.
I do agree this is awkward. The two calls for that function seem to come
from the "should we advertise ls-refs" and "actually do ls-refs"
functions. Should we be able to assume that the former ran if we are in
the latter? I'm not sure if that's true or not (i.e., because it's
rare but possible for a client to make two separate HTTP requests, one
to discover our v2 capabilities and another to actually issue ls-refs).
-Peff
Change the declaration of the protocol_capability struct to use
designated initializers, this makes this more verbose now, but a
follow-up commit will add a new field. At that point these lines would
be too dense to be on one line comfortably.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 38 +++++++++++++++++++++++++++++++-------
1 file changed, 31 insertions(+), 7 deletions(-)
From: Jeff King <hidden> Date: 2021-06-16 16:23:42
On Wed, Jun 16, 2021 at 04:16:16PM +0200, Ævar Arnfjörð Bjarmason wrote:
This is a refactoring of what a callback in serve.c needs to do to
aquire config. Currently two of them want that, and grab it in ad-hoc
ways themselves, now they can insted configure a "configure" callback
along with the existing "advertise" and "command", by the time they're
called their config will already be read with their callback.
I split this prep work off from an upcoming series where I wanted to
add a new capability, but I think this stands nicely on its own, and
simplifies the existing code.
The first four seem like obviously-good cleanups. I'm not so sure
about the last one, though. I left some comments there.
-Peff
As Jeff pointed out on v1 the control flow around serve.c was more
subtle than I expected, i.e. we might process N requests:
http://lore.kernel.org/git/YMolS8iJAMgbbg9D@coredump.intra.peff.net
This v2 has a 1-4/8 that's a trivially improved version of what Junio
picked up for "seen", the only change is addressing Eric's feedback
that the "struct strvec;" could also be removed.
Then 5-6/8 is a new trivial refactoring of the various callback
invocations into a rapper function, allowing us to add a trace2 region
for the advertisements & command we run.
After that 7-8/8 is a new approach of doing this "configure" callback,
I was on the fence about whether it should be another series on top,
but decided to submit it as one thing.
Now instead of there being a "configure" we explicitly have a
"startup_config" where we expect to stick all our config that doesn't
change, won't be different depending on what "mode" or "command" we
operate as, and in the case of upload-pack doesn't depend on anything
in "upload_pack_data".
As the diffstat shows it doesn't make the code shorter, but I think it
makes it easier to read and maintain, as we now clearly separate the
types of config we're reading.
Ævar Arnfjörð Bjarmason (8):
serve: mark has_capability() as static
transport: rename "fetch" in transport_vtable to "fetch_refs"
transport: use designated initializers
serve: use designated initializers
serve.c: add call_{advertise,command}() indirection
serve.c: add trace2 regions for advertise & command
serve: add support for a "startup" git_config() callback
upload-pack.c: convert to new serve.c "startup" config cb
ls-refs.c | 42 +++-----
ls-refs.h | 1 +
serve.c | 138 +++++++++++++++++++++----
serve.h | 4 -
t/t5705-session-id-in-capabilities.sh | 16 ++-
transport-helper.c | 18 ++--
transport-internal.h | 2 +-
transport.c | 32 +++---
upload-pack.c | 139 +++++++++++++++-----------
upload-pack.h | 2 +
10 files changed, 255 insertions(+), 139 deletions(-)
Range-diff against v1:
1: 4f74d7d34c4 ! 1: fdb0c5f4df1 serve: mark has_capability() as static
@@ serve.c: static int is_command(const char *key, struct protocol_capability **com
## serve.h ##
@@
+ #ifndef SERVE_H
#define SERVE_H
- struct strvec;
+-struct strvec;
-int has_capability(const struct strvec *keys, const char *capability,
- const char **value);
-
2: c6720d1bf33 = 2: 7b8101dca71 transport: rename "fetch" in transport_vtable to "fetch_refs"
3: 369efe0eed5 = 3: 766045e5f1d transport: use designated initializers
4: 8e97412d584 = 4: bd920de1629 serve: use designated initializers
-: ----------- > 5: d0b02aa0c7d serve.c: add call_{advertise,command}() indirection
-: ----------- > 6: baeee6539ad serve.c: add trace2 regions for advertise & command
5: c8625025125 ! 7: 0a4fb01ae38 serve: add support for a git_config() callback
@@ Metadata
Author: Ævar Arnfjörð Bjarmason [off-list ref]
## Commit message ##
- serve: add support for a git_config() callback
+ serve: add support for a "startup" git_config() callback
Since the introduction of serve.c we've added git_config() callbacks
and other config reading for capabilities in the following commits:
- e20b4192a37 (upload-pack: support hidden refs with protocol v2, 2018-12-18)
- - 59e1205d167 (ls-refs: report unborn targets of symrefs, 2021-02-05)
+ - 08450ef7918 (upload-pack: clear filter_options for each v2 fetch command, 2020-05-08)
- 6b5b6e422ee (serve: advertise session ID in v2 capabilities, 2020-11-11)
+ - 59e1205d167 (ls-refs: report unborn targets of symrefs, 2021-02-05)
- This code can be simplified by simply adding support to serve.c itself
- for reading config at the right time before the capability is
- called. In particular the ensure_config_read() function being gone
- makes this whole thing much simpler.
+ Of these 08450ef7918 fixed code that needed to read config on a
+ per-request basis, whereas most of the config reading just wants to
+ check if we've enabled one semi-static config variable or other. We'd
+ like to re-read that value eventually, but from request-to-request
+ it's OK if we retain the old one, and it isn't impacted by other
+ request data.
- A behavior change here is that we're eagerly doing the configuration
- for all our capabilities regardless of which one we end up serving,
- whereas before we'd defer it until the point where we were processing
- the specific command.
+ So let's support this common pattern as a "startup_config" callback,
+ making use of our recently added "call_{advertise,command}()"
+ functions. This allows us to simplify e.g. the "ensure_config_read()"
+ function added in 59e1205d167 (ls-refs: report unborn targets of
+ symrefs, 2021-02-05).
- We could try to be more lazy here and only read the config if we find
- out that we're serving "ls-refs" or "session-id", but it's just a fast
- git_config() callback, I think in this case simplicity trumps a
- premature optimization.
+ We could read all the config for all the protocol capabilities, but
+ let's do it one callback at a time in anticipation that some won't be
+ called at all, and that some might be more expensive than others in
+ the future.
+
+ I'm not migrating over the code in the upload_pack_v2 function in
+ upload-pack.c yet, that case is more complex since it deals with both
+ v1 and v2. It will be dealt with in a code a subsequent commit.
Signed-off-by: Ævar Arnfjörð Bjarmason [off-list ref]
@@ ls-refs.c
-static int config_read;
-static int advertise_unborn;
-static int allow_unborn;
--
++/* "unborn" is on by default if there's no lsrefs.unborn config */
++static int advertise_unborn = 1;
++static int allow_unborn = 1;
+
-static void ensure_config_read(void)
--{
++int ls_refs_startup_config(const char *var, const char *value, void *data)
+ {
- const char *str = NULL;
-
- if (config_read)
@@ ls-refs.c
- } else {
- if (!strcmp(str, "advertise")) {
- advertise_unborn = 1;
-- allow_unborn = 1;
-- } else if (!strcmp(str, "allow")) {
-- allow_unborn = 1;
-- } else if (!strcmp(str, "ignore")) {
-- /* do nothing */
-- } else {
-- die(_("invalid value '%s' for lsrefs.unborn"), str);
-- }
-- }
-- config_read = 1;
--}
-+/* "unborn" is on by default if there's no lsrefs.unborn config */
-+static int advertise_unborn = 1;
-+static int allow_unborn = 1;
-
- /*
- * Check if one of the prefixes is a prefix of the ref.
-@@ ls-refs.c: static void send_possibly_unborn_head(struct ls_refs_data *data)
- strbuf_release(&namespaced);
- }
-
--static int ls_refs_config(const char *var, const char *value, void *data)
-+int ls_refs_configure(const char *var, const char *value, void *data)
- {
+ if (!strcmp(var, "lsrefs.unborn")) {
+ if (!strcmp(value, "advertise")) {
+ /* Allowed and advertised by default */
+ } else if (!strcmp(value, "allow")) {
+ advertise_unborn = 0;
-+ allow_unborn = 1;
+ allow_unborn = 1;
+- } else if (!strcmp(str, "allow")) {
+- allow_unborn = 1;
+- } else if (!strcmp(str, "ignore")) {
+- /* do nothing */
+ } else if (!strcmp(value, "ignore")) {
+ advertise_unborn = 0;
+ allow_unborn = 0;
-+ } else {
+ } else {
+- die(_("invalid value '%s' for lsrefs.unborn"), str);
+ die(_("invalid value '%s' for lsrefs.unborn"), value);
-+ }
-+ }
-+
- /*
- * We only serve fetches over v2 for now, so respect only "uploadpack"
- * config. This may need to eventually be expanded to "receive", but we
+ }
+ }
+- config_read = 1;
++ return 0;
+ }
+
+ /*
@@ ls-refs.c: int ls_refs(struct repository *r, struct strvec *keys,
+
memset(&data, 0, sizeof(data));
strvec_init(&data.prefixes);
-
-- ensure_config_read();
-- git_config(ls_refs_config, NULL);
-
+- ensure_config_read();
+ git_config(ls_refs_config, NULL);
+
while (packet_reader_read(request) == PACKET_READ_NORMAL) {
- const char *arg = request->line;
- const char *out;
@@ ls-refs.c: int ls_refs(struct repository *r, struct strvec *keys,
int ls_refs_advertise(struct repository *r, struct strbuf *value)
{
@@ ls-refs.h: struct strvec;
struct packet_reader;
int ls_refs(struct repository *r, struct strvec *keys,
struct packet_reader *request);
-+int ls_refs_configure(const char *var, const char *value, void *data);
++int ls_refs_startup_config(const char *var, const char *value, void *data);
int ls_refs_advertise(struct repository *r, struct strbuf *value);
#endif /* LS_REFS_H */
@@ serve.c: static int object_format_advertise(struct repository *r,
return 1;
}
-+static int session_id_configure(const char *var, const char *value, void *data)
++static int session_id_startup_config(const char *var, const char *value, void *data)
+{
+ if (!strcmp(var, "transfer.advertisesid"))
+ advertise_sid = git_config_bool(var, value);
@@ serve.c: struct protocol_capability {
const char *name;
+ /*
-+ * A git_config() callback. If defined it'll be dispatched too
-+ * sometime before the other functions are called, giving the
-+ * capability a chance to configure itself.
++ * A git_config() callback that'll be called only once for the
++ * lifetime of the process, possibly over many different
++ * requests. Used for reading config that's expected to be
++ * static.
++ *
++ * The "command" or "advertise" callbacks themselves are
++ * expected to read config that needs to be more current than
++ * that, or which is dependent on request data.
+ */
-+ int (*configure)(const char *var, const char *value, void *data);
++ int (*startup_config)(const char *var, const char *value, void *data);
++
++ /*
++ * A boolean to check if we've called our "startup_config"
++ * callback.
++ */
++ int have_startup_config;
+
/*
* Function queried to see if a capability should be advertised.
@@ serve.c: static struct protocol_capability capabilities[] = {
},
{
.name = "ls-refs",
-+ .configure = ls_refs_configure,
++ .startup_config = ls_refs_startup_config,
.advertise = ls_refs_advertise,
.command = ls_refs,
},
@@ serve.c: static struct protocol_capability capabilities[] = {
},
{
.name = "session-id",
-+ .configure = session_id_configure,
++ .startup_config = session_id_startup_config,
.advertise = session_id_advertise,
},
{
@@ serve.c: static struct protocol_capability capabilities[] = {
},
};
-+static int git_serve_config(const char *var, const char *value, void *data)
++static void read_startup_config(struct protocol_capability *command)
+{
-+ int i;
-+ for (i = 0; i < ARRAY_SIZE(capabilities); i++) {
-+ struct protocol_capability *c = &capabilities[i];
-+ config_fn_t fn = c->configure;
-+ int ret;
-+ if (!fn)
-+ continue;
-+ ret = fn(var, value, data);
-+ if (ret)
-+ return ret;
-+ }
-+ return 0;
++ if (!command->startup_config)
++ return;
++ if (command->have_startup_config++)
++ return;
++ git_config(command->startup_config, NULL);
+}
+
- static void advertise_capabilities(void)
+ static int call_advertise(struct protocol_capability *command,
+ struct repository *r, struct strbuf *value)
{
- struct strbuf capability = STRBUF_INIT;
+@@ serve.c: static int call_advertise(struct protocol_capability *command,
+ struct strbuf sb = STRBUF_INIT;
+ const char *msg;
+
++ read_startup_config(command);
++
+ strbuf_addf(&sb, "advertise/%s", command->name);
+ trace2_region_enter("serve", sb.buf, r);
+ ret = command->advertise(r, value);
+@@ serve.c: static int call_command(struct protocol_capability *command,
+ int ret;
+ struct strbuf sb = STRBUF_INIT;
+
++ read_startup_config(command);
++
+ strbuf_addf(&sb, "command/%s", command->name);
+ trace2_region_enter("serve", sb.buf, r);
+ ret = command->command(r, keys, request);
@@ serve.c: static int process_request(void)
/* Main serve loop for protocol version 2 */
void serve(struct serve_options *options)
{
- git_config_get_bool("transfer.advertisesid", &advertise_sid);
-+ git_config(git_serve_config, NULL);
-
+-
if (options->advertise_capabilities || !options->stateless_rpc) {
/* serve by default supports v2 */
+ packet_write_fmt(1, "version 2\n");
-: ----------- > 8: 9fd6138aa62 upload-pack.c: convert to new serve.c "startup" config cb
--
2.32.0.611.gd4a17395dfa
The has_capability() function introduced in ed10cb952d3 (serve:
introduce git-serve, 2018-03-15) has never been used anywhere except
serve.c, so let's mark it as static.
It was later changed from "extern" in 554544276a6 (*.[ch]: remove
extern from function declarations using spatch, 2019-04-29), but we
could have simply marked it as "static" instead.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 4 ++--
serve.h | 4 ----
2 files changed, 2 insertions(+), 6 deletions(-)
Change the assignments to the various transport_vtables to use
designated initializers, this makes the code easier to read and
maintain.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
transport-helper.c | 12 ++++++------
transport.c | 30 ++++++++++++------------------
2 files changed, 18 insertions(+), 24 deletions(-)
@@ -880,12 +880,10 @@ static int disconnect_git(struct transport *transport)}staticstructtransport_vtabletaken_over_vtable={-NULL,-get_refs_via_connect,-fetch_refs_via_pack,-git_transport_push,-NULL,-disconnect_git+.get_refs_list=get_refs_via_connect,+.fetch_refs=fetch_refs_via_pack,+.push_refs=git_transport_push,+.disconnect=disconnect_git};voidtransport_take_over(structtransport*transport,
Rename the "fetch" member of the transport_vtable to "fetch_refs" for
consistency with the existing "push_refs". Neither of them just push
"refs" but refs and objects, but having the two match makes the code
more readable than having it be inconsistent, especially since
"fetch_refs" is a lot easier to grep for than "fetch".
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
transport-helper.c | 8 ++++----
transport-internal.h | 2 +-
transport.c | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
@@ -671,8 +671,8 @@ static int connect_helper(struct transport *transport, const char *name,staticstructref*get_refs_list_using_list(structtransport*transport,intfor_push);-staticintfetch(structtransport*transport,-intnr_heads,structref**to_fetch)+staticintfetch_refs(structtransport*transport,+intnr_heads,structref**to_fetch){structhelper_data*data=transport->data;inti,count;
@@ -681,7 +681,7 @@ static int fetch(struct transport *transport,if(process_connect(transport,0)){do_take_over(transport);-returntransport->vtable->fetch(transport,nr_heads,to_fetch);+returntransport->vtable->fetch_refs(transport,nr_heads,to_fetch);}/*
@@ -1263,7 +1263,7 @@ static struct ref *get_refs_list_using_list(struct transport *transport,staticstructtransport_vtablevtable={set_helper_option,get_refs_list,-fetch,+fetch_refs,push_refs,connect_helper,release_helper
Instead of directly calling the callbacks defined in the "struct
protocol_capability", let's call them via new
"call_{advertise,command}()" functions. There's no use in this
indirection now, but it'll be used in a subsequent commit to ensure
that config is read before they're called.
See ed10cb952d3 (serve: introduce git-serve, 2018-03-15) for the
introduction of the code being changed here.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 33 ++++++++++++++++++++++++---------
1 file changed, 24 insertions(+), 9 deletions(-)
Change the declaration of the protocol_capability struct to use
designated initializers, this makes this more verbose now, but a
follow-up commit will add a new field. At that point these lines would
be too dense to be on one line comfortably.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 38 +++++++++++++++++++++++++++++++-------
1 file changed, 31 insertions(+), 7 deletions(-)
Since the introduction of serve.c we've added git_config() callbacks
and other config reading for capabilities in the following commits:
- e20b4192a37 (upload-pack: support hidden refs with protocol v2, 2018-12-18)
- 08450ef7918 (upload-pack: clear filter_options for each v2 fetch command, 2020-05-08)
- 6b5b6e422ee (serve: advertise session ID in v2 capabilities, 2020-11-11)
- 59e1205d167 (ls-refs: report unborn targets of symrefs, 2021-02-05)
Of these 08450ef7918 fixed code that needed to read config on a
per-request basis, whereas most of the config reading just wants to
check if we've enabled one semi-static config variable or other. We'd
like to re-read that value eventually, but from request-to-request
it's OK if we retain the old one, and it isn't impacted by other
request data.
So let's support this common pattern as a "startup_config" callback,
making use of our recently added "call_{advertise,command}()"
functions. This allows us to simplify e.g. the "ensure_config_read()"
function added in 59e1205d167 (ls-refs: report unborn targets of
symrefs, 2021-02-05).
We could read all the config for all the protocol capabilities, but
let's do it one callback at a time in anticipation that some won't be
called at all, and that some might be more expensive than others in
the future.
I'm not migrating over the code in the upload_pack_v2 function in
upload-pack.c yet, that case is more complex since it deals with both
v1 and v2. It will be dealt with in a code a subsequent commit.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
ls-refs.c | 42 ++++++++++++++----------------------------
ls-refs.h | 1 +
serve.c | 42 ++++++++++++++++++++++++++++++++++++++++--
3 files changed, 55 insertions(+), 30 deletions(-)
@@ -7,37 +7,26 @@#include"pkt-line.h"#include"config.h"-staticintconfig_read;-staticintadvertise_unborn;-staticintallow_unborn;+/* "unborn" is on by default if there's no lsrefs.unborn config */+staticintadvertise_unborn=1;+staticintallow_unborn=1;-staticvoidensure_config_read(void)+intls_refs_startup_config(constchar*var,constchar*value,void*data){-constchar*str=NULL;--if(config_read)-return;--if(repo_config_get_string_tmp(the_repository,"lsrefs.unborn",&str)){-/*-*Ifthereisnosuchconfig,advertiseandallowitby-*default.-*/-advertise_unborn=1;-allow_unborn=1;-}else{-if(!strcmp(str,"advertise")){-advertise_unborn=1;+if(!strcmp(var,"lsrefs.unborn")){+if(!strcmp(value,"advertise")){+/* Allowed and advertised by default */+}elseif(!strcmp(value,"allow")){+advertise_unborn=0;allow_unborn=1;-}elseif(!strcmp(str,"allow")){-allow_unborn=1;-}elseif(!strcmp(str,"ignore")){-/* do nothing */+}elseif(!strcmp(value,"ignore")){+advertise_unborn=0;+allow_unborn=0;}else{-die(_("invalid value '%s' for lsrefs.unborn"),str);+die(_("invalid value '%s' for lsrefs.unborn"),value);}}-config_read=1;+return0;}/*
@@ -115,6 +151,8 @@ static int call_advertise(struct protocol_capability *command,structstrbufsb=STRBUF_INIT;constchar*msg;+read_startup_config(command);+strbuf_addf(&sb,"advertise/%s",command->name);trace2_region_enter("serve",sb.buf,r);ret=command->advertise(r,value);
@@ -132,6 +170,8 @@ static int call_command(struct protocol_capability *command,intret;structstrbufsb=STRBUF_INIT;+read_startup_config(command);+strbuf_addf(&sb,"command/%s",command->name);trace2_region_enter("serve",sb.buf,r);ret=command->command(r,keys,request);
@@ -338,8 +378,6 @@ static int process_request(void)/* Main serve loop for protocol version 2 */voidserve(structserve_options*options){-git_config_get_bool("transfer.advertisesid",&advertise_sid);-if(options->advertise_capabilities||!options->stateless_rpc){/* serve by default supports v2 */packet_write_fmt(1,"version 2\n");
From: Jeff King <hidden> Date: 2021-07-01 16:43:45
On Mon, Jun 28, 2021 at 09:19:24PM +0200, Ævar Arnfjörð Bjarmason wrote:
So let's support this common pattern as a "startup_config" callback,
making use of our recently added "call_{advertise,command}()"
functions. This allows us to simplify e.g. the "ensure_config_read()"
function added in 59e1205d167 (ls-refs: report unborn targets of
symrefs, 2021-02-05).
We could read all the config for all the protocol capabilities, but
let's do it one callback at a time in anticipation that some won't be
called at all, and that some might be more expensive than others in
the future.
Sadly I don't think this addresses my "v2 receive-pack" concern. The
ls_refs_startup_config() function will get called after we've received a
request for "ls-refs", which is good. But:
+static void read_startup_config(struct protocol_capability *command)
+{
+ if (!command->startup_config)
+ return;
+ if (command->have_startup_config++)
+ return;
+ git_config(command->startup_config, NULL);
+}
...we don't pass any context to the config callback here. I thought
passing "command" might work, but looking at the ls_refs() function, it
is the one who actually reads the pkt-lines that will tell us "hey, I'm
doing an ls-refs for a push".
So none of the serve() infrastructure can help us there; we need to read
pkt-lines and _then_ read config.
I dunno. Maybe the solution is for ls_refs() to just do a separate
config call to pick up the operation-specific bits, like:
@@ -161,8 +161,12 @@ int ls_refs(struct repository *r, struct strvec *keys,strvec_push(&data.prefixes,out);elseif(!strcmp("unborn",arg))data.unborn=allow_unborn;+elseif(!strcmp("for-push",arg))/* imagine this exists */+data.for_push=1;}+git_config(ls_refs_config,&data);+if(request->status!=PACKET_READ_FLUSH)die(_("expected flush after ls-refs arguments"));
And then it is a separate thing entirely from your "serve will read
config" code. It's arguably more confusing, because now config is read
in two places, but that is already true because of this
ensure_config_read() thing.
The patch above obviously makes no sense until we're working on v2
receive-pack. But I think it illustrates that your patch here is not
getting in the way (though technically I think that would also be true
of your v1, I do like this version better).
-Peff
From: Jeff King <hidden> Date: 2021-07-01 16:47:29
On Thu, Jul 01, 2021 at 12:43:43PM -0400, Jeff King wrote:
I dunno. Maybe the solution is for ls_refs() to just do a separate
config call to pick up the operation-specific bits, like:
By the way, I think both currently and after the patch I showed,
ls_refs() has the same "bug" that we fixed for upload_pack_v2() a while
ago: in a v2 world, a client could request "ls-refs" over and over, and
each time we'd load the hiderefs config, appending duplicate config to
the list each time.
In practice this doesn't happen because unlike "fetch", which clients
must do many rounds of, clients usually issue only a single ls-refs. So
it may not be worth worrying too much about. I guess a malicious client
could convince us to very slowly allocate an arbitrary amount of memory.
-Peff
On Mon, Jun 28, 2021 at 09:19:24PM +0200, Ævar Arnfjörð Bjarmason wrote:
quoted
So let's support this common pattern as a "startup_config" callback,
making use of our recently added "call_{advertise,command}()"
functions. This allows us to simplify e.g. the "ensure_config_read()"
function added in 59e1205d167 (ls-refs: report unborn targets of
symrefs, 2021-02-05).
We could read all the config for all the protocol capabilities, but
let's do it one callback at a time in anticipation that some won't be
called at all, and that some might be more expensive than others in
the future.
Sadly I don't think this addresses my "v2 receive-pack" concern. The
ls_refs_startup_config() function will get called after we've received a
request for "ls-refs", which is good. But:
I think it does in that you rightly objected to us moving all config to
such a callback, because for some of it we don't have the information
needed to look it up yet, we do that in the request handler.
But for a lot of our config it's fine to do it early, hence "startup"
config.
Yes I've moved the ls-refs handling into the "startup" because /right
now/ it's only handling fetches, it'll need to be moved out if and when
we start handling pushes.
But isn't it going to be obvious that we'll need to do that then? Since
we'll have the example of upload-pack.c doing that exact thing?
I.e. do you not want to have the "startup config" concept at all, or
would just prefer to have the ls-refs part of it pre-emotively moved out
of it in anticipation of handling pushes some day, even if we can do
that on "startup" now?
(More below)
quoted hunk
quoted
+static void read_startup_config(struct protocol_capability *command)
+{
+ if (!command->startup_config)
+ return;
+ if (command->have_startup_config++)
+ return;
+ git_config(command->startup_config, NULL);
+}
...we don't pass any context to the config callback here. I thought
passing "command" might work, but looking at the ls_refs() function, it
is the one who actually reads the pkt-lines that will tell us "hey, I'm
doing an ls-refs for a push".
So none of the serve() infrastructure can help us there; we need to read
pkt-lines and _then_ read config.
I dunno. Maybe the solution is for ls_refs() to just do a separate
config call to pick up the operation-specific bits, like:
@@ -161,8 +161,12 @@ int ls_refs(struct repository *r, struct strvec *keys,strvec_push(&data.prefixes,out);elseif(!strcmp("unborn",arg))data.unborn=allow_unborn;+elseif(!strcmp("for-push",arg))/* imagine this exists */+data.for_push=1;}+git_config(ls_refs_config,&data);+if(request->status!=PACKET_READ_FLUSH)die(_("expected flush after ls-refs arguments"));
And then it is a separate thing entirely from your "serve will read
config" code. It's arguably more confusing, because now config is read
in two places, but that is already true because of this
ensure_config_read() thing.
This suggests to me you'd like to preemptively move it out of "startup",
correct?
Anyway, I can do that if that addresses your concern. I thought the v1
objection was mainly "the config flow won't work that way in all cases",
which you're right that I incorrectly assumed.
I just thought preemptively doing it for "ls-refs" wouldn't be needed,
since we'd notice in testing such a feature that "do it once" would
break in obvious ways for multi-requests, especially with the comment
for the "startup_config" callback explicitly calling out that case.
The patch above obviously makes no sense until we're working on v2
receive-pack. But I think it illustrates that your patch here is not
getting in the way (though technically I think that would also be true
of your v1, I do like this version better).
From: Jeff King <hidden> Date: 2021-07-02 21:13:32
On Fri, Jul 02, 2021 at 02:55:38PM +0200, Ævar Arnfjörð Bjarmason wrote:
quoted
Sadly I don't think this addresses my "v2 receive-pack" concern. The
ls_refs_startup_config() function will get called after we've received a
request for "ls-refs", which is good. But:
I think it does in that you rightly objected to us moving all config to
such a callback, because for some of it we don't have the information
needed to look it up yet, we do that in the request handler.
But for a lot of our config it's fine to do it early, hence "startup"
config.
So I think your patch is OK, but just to lay out my thinking, it was
this. The v2 serve code basically does:
1. Somebody calls serve().
2. It reads a capability/operation name, then dispatches to the
appropriate function.
3. That function reads operation-specific data, like options.
Your first patch read config at step 1. This one reads at step 2.
But from past discussions, the hide-refs config could only be read (or
interpreted) after step 3, because that's when we'd see an option saying
"this is for pushing".
So anything except step 3 is "too late". But that doesn't stop us from
having some early config and some operation-specific late config.
Yes I've moved the ls-refs handling into the "startup" because /right
now/ it's only handling fetches, it'll need to be moved out if and when
we start handling pushes.
But isn't it going to be obvious that we'll need to do that then? Since
we'll have the example of upload-pack.c doing that exact thing?
I.e. do you not want to have the "startup config" concept at all, or
would just prefer to have the ls-refs part of it pre-emotively moved out
of it in anticipation of handling pushes some day, even if we can do
that on "startup" now?
Sorry to be so confusing. About halfway through writing my previous
email I had realized "well, I guess we can have two phases of
config-reading, and that's not so bad". So I'm OK with this direction.
I don't think anything else needs to happen on top of your patch here.
The "late" phase for ls-refs config reading already happens totally
separately (it's in the git_config(ls_refs_config) call, which is
already separate from the ensure_config_read() thing. And your patch
leaves that line untouched.
quoted
And then it is a separate thing entirely from your "serve will read
config" code. It's arguably more confusing, because now config is read
in two places, but that is already true because of this
ensure_config_read() thing.
This suggests to me you'd like to preemptively move it out of "startup",
correct?
It's already out of the startup, so I think we are OK.
My big question here was: is the concept of "startup config" and "other
config we read after seeing the options" too confusing? But probably
not.
I just thought preemptively doing it for "ls-refs" wouldn't be needed,
since we'd notice in testing such a feature that "do it once" would
break in obvious ways for multi-requests, especially with the comment
for the "startup_config" callback explicitly calling out that case.
Yeah, we'd definitely notice. I was just wondering if we'd end up
needing to back out these changes to accommodate it. But the two-phase
thing solves that.
-Peff
On Mon, Jun 28, 2021 at 9:19 PM Ævar Arnfjörð Bjarmason
[off-list ref] wrote:
So let's support this common pattern as a "startup_config" callback,
making use of our recently added "call_{advertise,command}()"
I think this is an improvement over ensure_config_read(), but I don't
understand the whole picture. If you want to control configuration and
be sure it is set early, isn't it more natural to put this in struct
serve_options? With your patch, there are still two routes to
injecting configuration: 'struct serve_options' and the git config.
IMO the former is more principled, and the control flow (serve_options
is an argument to serve()) ensures that the options are read only
once.
+ /*
+ * A git_config() callback that'll be called only once for the
+ * lifetime of the process, possibly over many different
Putting it in a struct supplied by the caller provides more
flexibility for testing: you could test multiple behaviors from a
single process, by calling serve multiple times supplying different
arguments.
--
Han-Wen Nienhuys - Google Munich
I work 80%. Don't expect answers from me on Fridays.
--
Google Germany GmbH, Erika-Mann-Strasse 33, 80636 Munich
Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg
Geschäftsführer: Paul Manicle, Halimah DeLaine Prado
On Mon, Jun 28, 2021 at 9:19 PM Ævar Arnfjörð Bjarmason
[off-list ref] wrote:
/* Main serve loop for protocol version 2 */
void serve(struct serve_options *options)
side note: this is a very short name for a globally visible symbol.
Would be nice if this were something like protocol_v2_serve_loop() .
Then one could drop the comment.
--
Han-Wen Nienhuys - Google Munich
I work 80%. Don't expect answers from me on Fridays.
--
Google Germany GmbH, Erika-Mann-Strasse 33, 80636 Munich
Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg
Geschäftsführer: Paul Manicle, Halimah DeLaine Prado
Now that we've factored out "call_{advertise,command}()" in a
preceding commit it becomes easy to trace all these callbacks with
trace2. Let's do that. As the tests demonstrate there's no v2 push
protocol, which the tests assert.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 24 ++++++++++++++++++++++--
t/t5705-session-id-in-capabilities.sh | 16 ++++++++++++++--
2 files changed, 36 insertions(+), 4 deletions(-)
From: Jeff King <hidden> Date: 2021-07-01 16:30:06
On Mon, Jun 28, 2021 at 09:19:23PM +0200, Ævar Arnfjörð Bjarmason wrote:
Now that we've factored out "call_{advertise,command}()" in a
preceding commit it becomes easy to trace all these callbacks with
trace2. Let's do that. As the tests demonstrate there's no v2 push
protocol, which the tests assert.
Seems reasonable. I haven't ever wanted these myself, but it seems like
a natural spot to mention when debugging server-side actions (especially
because we may get multiple rounds of "fetch" for a single upload-pack
invocation).
We'll do these allocations even if trace2 isn't enabled. I guess that's
probably not that big a deal in practice. I think:
if (trace2_is_enabled())
strbuf_addf(&sb, "advertise/%s", command->name);
would work (everything else is cheap and handles the unallocated state
fine), but it might not be worth the readability hit (and it's probably
premature optimization anyway).
-Peff
On Mon, Jun 28, 2021 at 09:19:23PM +0200, Ævar Arnfjörð Bjarmason wrote:
quoted
Now that we've factored out "call_{advertise,command}()" in a
preceding commit it becomes easy to trace all these callbacks with
trace2. Let's do that. As the tests demonstrate there's no v2 push
protocol, which the tests assert.
Seems reasonable. I haven't ever wanted these myself, but it seems like
a natural spot to mention when debugging server-side actions (especially
because we may get multiple rounds of "fetch" for a single upload-pack
invocation).
We'll do these allocations even if trace2 isn't enabled. I guess that's
probably not that big a deal in practice. I think:
if (trace2_is_enabled())
strbuf_addf(&sb, "advertise/%s", command->name);
would work (everything else is cheap and handles the unallocated state
fine), but it might not be worth the readability hit (and it's probably
premature optimization anyway).
Will change it to be conditional, pending further discussion...
On Mon, Jun 28, 2021 at 9:19 PM Ævar Arnfjörð Bjarmason
[off-list ref] wrote:
Now that we've factored out "call_{advertise,command}()" in a
preceding commit it becomes easy to trace all these callbacks with
trace2. Let's do that. As the tests demonstrate there's no v2 push
protocol, which the tests assert.
code looks good, but confused about the objective. This isn't
necessary for the rest of the series, is it?
cleanup changes leading up to here LGTM.
--
Han-Wen Nienhuys - Google Munich
I work 80%. Don't expect answers from me on Fridays.
--
Google Germany GmbH, Erika-Mann-Strasse 33, 80636 Munich
Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg
Geschäftsführer: Paul Manicle, Halimah DeLaine Prado
Convert the config reading code in upload-pack.c to use the new
"startup_config" callback when we're using the v2 protocol, and
lightly fake up the same when we're using v0 and v1.
Before the series that fixed 08450ef7918 (upload-pack: clear
filter_options for each v2 fetch command, 2020-05-08) landed, most of
what's now "struct upload_pack_data" used to be static variables at
the top of this file.
This moves some of them back. See f203a88cf14 (upload-pack: move
keepalive to upload_pack_data, 2020-06-04), f1514c6aad0 (upload-pack:
move allow_unadvertised_object_request to upload_pack_data,
2020-06-11) etc.
I think this makes it easier to understand the this code, as we're now
clearly separating data and config that changes on a
request-to-request basis (see 08450ef7918), and the sort of config
that serve.c's "startup_config" is aimed at.
Thus it's clear that the "allow_uor" passed to functions like
"is_our_ref()" is constant after startup (usually it'll never change
for a given server's configuration, or change once).
This requires a very light compatibly layer with the serve.c callback
mechanism in the form of "upload_pack" for the v0 and v1 protocols.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 1 +
upload-pack.c | 139 ++++++++++++++++++++++++++++++--------------------
upload-pack.h | 2 +
3 files changed, 86 insertions(+), 56 deletions(-)
@@ -703,13 +702,13 @@ static int get_reachable_list(struct upload_pack_data *data,return0;}-staticinthas_unreachable(structobject_array*src,enumallow_uorallow_uor)+staticinthas_unreachable(structobject_array*src){structchild_processcmd=CHILD_PROCESS_INIT;charbuf[1];inti;-if(do_reachable_revlist(&cmd,src,NULL,allow_uor)<0)+if(do_reachable_revlist(&cmd,src,NULL)<0)return1;/*
@@ -748,9 +747,9 @@ static void check_non_tip(struct upload_pack_data *data)*uploadpack.allowReachableSHA1InWant,*non-tiprequestscanneverhappen.*/-if(!data->stateless_rpc&&!(data->allow_uor&ALLOW_REACHABLE_SHA1))+if(!data->stateless_rpc&&!(config_allow_uor&ALLOW_REACHABLE_SHA1))gotoerror;-if(!has_unreachable(&data->want_obj,data->allow_uor))+if(!has_unreachable(&data->want_obj))/* All the non-tip ones are ancestors of what we advertised */return;
@@ -758,7 +757,7 @@ static void check_non_tip(struct upload_pack_data *data)/* Pick one of them (we know there at least is one) */for(i=0;i<data->want_obj.nr;i++){structobject*o=data->want_obj.objects[i].item;-if(!is_our_ref(o,data->allow_uor)){+if(!is_our_ref(o)){packet_writer_error(&data->writer,"upload-pack: not our ref %s",oid_to_hex(&o->oid));
On Mon, Jun 28, 2021 at 9:19 PM Ævar Arnfjörð Bjarmason
[off-list ref] wrote:
Convert the config reading code in upload-pack.c to use the new
"startup_config" callback when we're using the v2 protocol, and
lightly fake up the same when we're using v0 and v1.
I'm not a fan creating more global variables rather, but I'll it leave
to someone else to decide what's best. This change looks consistent
with its predecessor, and OK modulo a few nits below.
Thus it's clear that the "allow_uor" passed to functions like
"is_our_ref()" is constant after startup (usually it'll never change
for a given server's configuration, or change once).
This requires a very light compatibly layer with the serve.c callback
typo.
+/*
+ * "Global" configuration that won't be affected by the type of
+ * request we're doing, or by other request data in "struct
+ * upload_pack_data" below.
+ */
+static int v1_have_startup_config;
+static int config_keepalive = 5;
could this include a unit? config_keepalive_secs , I think?
+ int ret;
+ ret = upload_pack_startup_config(var, value, data);
+ if (ret)
+ return ret;
+ ret = upload_pack_startup_config_v2_only(var, value, data);
+ if (ret)
+ return ret;
Neither of these config readers ever return -1. Do you foresee this
ever happening? Or could this return void?
+ if (!v1_have_startup_config++)
+ git_config(upload_pack_startup_config, NULL);
See comment in previous patch about ++ for boolean values.
--
Han-Wen Nienhuys - Google Munich
I work 80%. Don't expect answers from me on Fridays.
--
Google Germany GmbH, Erika-Mann-Strasse 33, 80636 Munich
Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg
Geschäftsführer: Paul Manicle, Halimah DeLaine Prado
The has_capability() function introduced in ed10cb952d3 (serve:
introduce git-serve, 2018-03-15) has never been used anywhere except
serve.c, so let's mark it as static.
It was later changed from "extern" in 554544276a6 (*.[ch]: remove
extern from function declarations using spatch, 2019-04-29), but we
could have simply marked it as "static" instead.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 4 ++--
serve.h | 4 ----
2 files changed, 2 insertions(+), 6 deletions(-)
Rename the "fetch" member of the transport_vtable to "fetch_refs" for
consistency with the existing "push_refs". Neither of them just push
"refs" but refs and objects, but having the two match makes the code
more readable than having it be inconsistent, especially since
"fetch_refs" is a lot easier to grep for than "fetch".
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
transport-helper.c | 8 ++++----
transport-internal.h | 2 +-
transport.c | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
@@ -671,8 +671,8 @@ static int connect_helper(struct transport *transport, const char *name,staticstructref*get_refs_list_using_list(structtransport*transport,intfor_push);-staticintfetch(structtransport*transport,-intnr_heads,structref**to_fetch)+staticintfetch_refs(structtransport*transport,+intnr_heads,structref**to_fetch){structhelper_data*data=transport->data;inti,count;
@@ -681,7 +681,7 @@ static int fetch(struct transport *transport,if(process_connect(transport,0)){do_take_over(transport);-returntransport->vtable->fetch(transport,nr_heads,to_fetch);+returntransport->vtable->fetch_refs(transport,nr_heads,to_fetch);}/*
@@ -1263,7 +1263,7 @@ static struct ref *get_refs_list_using_list(struct transport *transport,staticstructtransport_vtablevtable={set_helper_option,get_refs_list,-fetch,+fetch_refs,push_refs,connect_helper,release_helper
Change the assignments to the various transport_vtables to use
designated initializers, this makes the code easier to read and
maintain.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
transport-helper.c | 12 ++++++------
transport.c | 30 ++++++++++++------------------
2 files changed, 18 insertions(+), 24 deletions(-)
@@ -883,12 +883,10 @@ static int disconnect_git(struct transport *transport)}staticstructtransport_vtabletaken_over_vtable={-NULL,-get_refs_via_connect,-fetch_refs_via_pack,-git_transport_push,-NULL,-disconnect_git+.get_refs_list=get_refs_via_connect,+.fetch_refs=fetch_refs_via_pack,+.push_refs=git_transport_push,+.disconnect=disconnect_git};voidtransport_take_over(structtransport*transport,
Change the declaration of the protocol_capability struct to use
designated initializers, this makes this more verbose now, but a
follow-up commit will add a new field. At that point these lines would
be too dense to be on one line comfortably.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 38 +++++++++++++++++++++++++++++++-------
1 file changed, 31 insertions(+), 7 deletions(-)
Instead of directly calling the callbacks defined in the "struct
protocol_capability", let's call them via new
"call_{advertise,command}()" functions. There's no use in this
indirection now, but it'll be used in a subsequent commit to ensure
that config is read before they're called.
See ed10cb952d3 (serve: introduce git-serve, 2018-03-15) for the
introduction of the code being changed here.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 33 ++++++++++++++++++++++++---------
1 file changed, 24 insertions(+), 9 deletions(-)
Since the introduction of serve.c we've added git_config() callbacks
and other config reading for capabilities in the following commits:
- e20b4192a37 (upload-pack: support hidden refs with protocol v2, 2018-12-18)
- 08450ef7918 (upload-pack: clear filter_options for each v2 fetch command, 2020-05-08)
- 6b5b6e422ee (serve: advertise session ID in v2 capabilities, 2020-11-11)
- 59e1205d167 (ls-refs: report unborn targets of symrefs, 2021-02-05)
Of these 08450ef7918 fixed code that needed to read config on a
per-request basis, whereas most of the config reading just wants to
check if we've enabled one semi-static config variable or other. We'd
like to re-read that value eventually, but from request-to-request
it's OK if we retain the old one, and it isn't impacted by other
request data.
So let's support this common pattern as a "startup_config" callback,
making use of our recently added "call_{advertise,command}()"
functions. This allows us to simplify e.g. the "ensure_config_read()"
function added in 59e1205d167 (ls-refs: report unborn targets of
symrefs, 2021-02-05).
We could read all the config for all the protocol capabilities, but
let's do it one callback at a time in anticipation that some won't be
called at all, and that some might be more expensive than others in
the future.
I'm not migrating over the code in the upload_pack_v2 function in
upload-pack.c yet, that case is more complex since it deals with both
v1 and v2. It will be dealt with in a code a subsequent commit.
As we'll see in subsequent commits, by moving the
transfer.advertisesid config reading out of serve() we can simplify
the codepath around advertising-only requests. See 6b5b6e422ee (serve:
advertise session ID in v2 capabilities, 2020-11-11)) for the commit
that added transfer.advertisesid.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
ls-refs.c | 42 ++++++++++++++----------------------------
ls-refs.h | 1 +
serve.c | 43 +++++++++++++++++++++++++++++++++++++++++--
3 files changed, 56 insertions(+), 30 deletions(-)
@@ -7,37 +7,26 @@#include"pkt-line.h"#include"config.h"-staticintconfig_read;-staticintadvertise_unborn;-staticintallow_unborn;+/* "unborn" is on by default if there's no lsrefs.unborn config */+staticintadvertise_unborn=1;+staticintallow_unborn=1;-staticvoidensure_config_read(void)+intls_refs_startup_config(constchar*var,constchar*value,void*data){-constchar*str=NULL;--if(config_read)-return;--if(repo_config_get_string_tmp(the_repository,"lsrefs.unborn",&str)){-/*-*Ifthereisnosuchconfig,advertiseandallowitby-*default.-*/-advertise_unborn=1;-allow_unborn=1;-}else{-if(!strcmp(str,"advertise")){-advertise_unborn=1;+if(!strcmp(var,"lsrefs.unborn")){+if(!strcmp(value,"advertise")){+/* Allowed and advertised by default */+}elseif(!strcmp(value,"allow")){+advertise_unborn=0;allow_unborn=1;-}elseif(!strcmp(str,"allow")){-allow_unborn=1;-}elseif(!strcmp(str,"ignore")){-/* do nothing */+}elseif(!strcmp(value,"ignore")){+advertise_unborn=0;+allow_unborn=0;}else{-die(_("invalid value '%s' for lsrefs.unborn"),str);+die(_("invalid value '%s' for lsrefs.unborn"),value);}}-config_read=1;+return0;}/*
@@ -118,6 +156,9 @@ static int call_command(struct protocol_capability *command,structrepository*r,structstrvec*keys,structpacket_reader*request){++read_startup_config(command);+returncommand->command(r,keys,request);}
@@ -318,8 +359,6 @@ static int process_request(void)/* Main serve loop for protocol version 2 */voidserve(structserve_options*options){-git_config_get_bool("transfer.advertisesid",&advertise_sid);-if(options->advertise_capabilities||!options->stateless_rpc){/* serve by default supports v2 */packet_write_fmt(1,"version 2\n");
The advertise_capabilities() is only called from serve() and we always
emit this version line before it, it makes more sense to consider the
capabilities part of a "header" that has the version, so let's move
the writing of the version there.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
The "advertise capabilities" mode of serve.c added in
ed10cb952d3 (serve: introduce git-serve, 2018-03-15) is only used by
the http-backend.c to call {upload,receive}-pack with the
--advertise-refs parameter. See 42526b478e3 (Add stateless RPC options
to upload-pack, receive-pack, 2009-10-30).
Let's just make cmd_upload_pack() take the two (v2) or three (v2)
parameters the the v2/v1 servicing functions need directly, and pass
those in via the function signature. The logic of whether daemon mode
is implied by the timeout belongs in the v1 function (only used
there).
Once we split up the "advertise v2 refs" from "serve v2 request" it
becomes clear that v2 never cared about those in combination. The only
time it mattered was for v1 to emit its ref advertisement, in that
case we wanted to emit the smart-http-only "no-done" capability.
Since we only do that in the --advertise-refs codepath let's just have
it set "do_done" itself in v1's upload_pack() just before send_ref(),
at that point --advertise-refs and --stateless-rpc in combination are
redundant (the only user is get_info_refs() in http-backend.c), so we
can just pass in --advertise-refs only.
Since we need to touch all the serve() and advertise_capabilities()
codepaths let's rename them to less clever and obvious names, it's
been suggested numerous times, the latest of which is [1]'s suggestion
for protocol_v2_serve_loop(). Let's go with that.
1. https://lore.kernel.org/git/CAFQ2z_NyGb8rju5CKzmo6KhZXD0Dp21u-BbyCb2aNxLEoSPRJw@mail.gmail.com/
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
builtin/upload-pack.c | 25 ++++++++++++-------------
http-backend.c | 2 +-
serve.c | 18 +++++-------------
serve.h | 8 ++------
t/helper/test-serve-v2.c | 14 +++++++++-----
upload-pack.c | 18 +++++++++++-------
upload-pack.h | 10 ++--------
7 files changed, 42 insertions(+), 53 deletions(-)
@@ -16,16 +16,17 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix){constchar*dir;intstrict=0;-structupload_pack_optionsopts={0};-structserve_optionsserve_opts=SERVE_OPTIONS_INIT;+intadvertise_refs=0;+intstateless_rpc=0;+inttimeout=0;structoptionoptions[]={-OPT_BOOL(0,"stateless-rpc",&opts.stateless_rpc,+OPT_BOOL(0,"stateless-rpc",&stateless_rpc,N_("quit after a single request/response exchange")),-OPT_BOOL(0,"advertise-refs",&opts.advertise_refs,+OPT_BOOL(0,"advertise-refs",&advertise_refs,N_("exit immediately after initial ref advertisement")),OPT_BOOL(0,"strict",&strict,N_("do not try <directory>/.git/ if <directory> is no Git directory")),-OPT_INTEGER(0,"timeout",&opts.timeout,+OPT_INTEGER(0,"timeout",&timeout,N_("interrupt transfer after <n> seconds of inactivity")),OPT_END()};
@@ -162,7 +162,7 @@ static int call_command(struct protocol_capability *command,returncommand->command(r,keys,request);}-staticvoidadvertise_capabilities(void)+voidprotocol_v2_advertise_capabilities(void){structstrbufcapability=STRBUF_INIT;structstrbufvalue=STRBUF_INIT;
@@ -359,24 +359,16 @@ static int process_request(void)return0;}-/* Main serve loop for protocol version 2 */-voidserve(structserve_options*options)+voidprotocol_v2_serve_loop(intstateless_rpc){-if(options->advertise_capabilities||!options->stateless_rpc){-advertise_capabilities();-/*-*Ifonlythelistofcapabilitieswasrequestedexit-*immediatelyafteradvertisingcapabilities-*/-if(options->advertise_capabilities)-return;-}+if(!stateless_rpc)+protocol_v2_advertise_capabilities();/**Ifstateless-rpcwasrequestedthenexitafter*asinglerequest/responseexchange*/-if(options->stateless_rpc){+if(stateless_rpc){process_request();}else{for(;;)
The --advertise-refs documentation in git-upload-pack added in
9812f2136b3 (upload-pack.c: use parse-options API, 2016-05-31) hasn't
been entirely true ever since v2 support was implemented in
e52449b6722 (connect: request remote refs using v2, 2018-03-15). Under
v2 we don't advertise the refs at all, but rather dump the
capabilities header.
This option has always been an obscure internal implementation detail,
it wasn't even documented for git-receive-pack. Since it has exactly
one user let's rename it to --http-backend-info-refs, which is more
accurate and points the reader in the right direction. Let's also
cross-link this from the protocol v1 and v2 documentation.
I'm retaining a hidden --advertise-refs alias in case there's any
external users of this, and making both options hidden to the bash
completion (as with most other internal-only options).
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
Documentation/git-receive-pack.txt | 5 +++++
Documentation/git-upload-pack.txt | 12 ++++++++----
Documentation/technical/http-protocol.txt | 3 +++
Documentation/technical/protocol-v2.txt | 3 +++
builtin/receive-pack.c | 3 ++-
builtin/upload-pack.c | 5 +++--
http-backend.c | 2 +-
t/t5555-http-smart-common.sh | 14 ++++++++++++++
8 files changed, 39 insertions(+), 8 deletions(-)
@@ -41,6 +41,11 @@ OPTIONS <directory>:: The repository to sync into.+--http-backend-info-refs::+ Used by linkgit:git-http-backend[1] to serve up+ `$GIT_URL/info/refs?service=git-receive-pack` requests. See+ `--http-backend-info-refs` in linkgit:git-upload-pack[1].+ PRE-RECEIVE HOOK ---------------- Before any ref is updated, if $GIT_DIR/hooks/pre-receive file exists
@@ -36,10 +36,14 @@ OPTIONS This fits with the HTTP POST request processing model where a program may read the request, write a response, and must exit.---advertise-refs::- Only the initial ref advertisement is output, and the program exits- immediately. This fits with the HTTP GET request model, where- no request content is received but a response must be produced.+--http-backend-info-refs::+ Used by linkgit:git-http-backend[1] to serve up+ `$GIT_URL/info/refs?service=git-upload-pack` requests. See+ "Smart Clients" in link:technical/http-protocol.html[the HTTP+ transfer protocols] documentation and "HTTP Transport" in+ link:technical/protocol-v2.html[the Git Wire Protocol, Version+ 2] documentation. Also understood by+ linkgit:git-receive-pack[1]. <directory>:: The repository to sync from.
@@ -225,6 +225,9 @@ The client may send Extra Parameters (see Documentation/technical/pack-protocol.txt) as a colon-separated string in the Git-Protocol HTTP header.+Uses the `--http-backend-info-refs` option to+linkgit:git-upload-pack[1].+ Dumb Server Response ^^^^^^^^^^^^^^^^^^^^ Dumb servers MUST respond with the dumb server reply format.
@@ -81,6 +81,9 @@ A v2 server would reply: Subsequent requests are then made directly to the service `$GIT_URL/git-upload-pack`. (This works the same for git-receive-pack).+Uses the `--http-backend-info-refs` option to+linkgit:git-upload-pack[1].+ Capability Advertisement ------------------------
@@ -22,8 +22,9 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)structoptionoptions[]={OPT_BOOL(0,"stateless-rpc",&stateless_rpc,N_("quit after a single request/response exchange")),-OPT_BOOL(0,"advertise-refs",&advertise_refs,-N_("exit immediately after initial ref advertisement")),+OPT_HIDDEN_BOOL(0,"http-backend-info-refs",&advertise_refs,+N_("serve up the info/refs for git-http-backend")),+OPT_ALIAS(0,"advertise-refs","http-backend-info-refs"),OPT_BOOL(0,"strict",&strict,N_("do not try <directory>/.git/ if <directory> is no Git directory")),OPT_INTEGER(0,"timeout",&timeout,
The --advertise-refs option had no explicit tests of its own, only
other http tests that would fail at a distance if it it was
broken. Let's test its behavior explicitly.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
t/t5555-http-smart-common.sh | 145 +++++++++++++++++++++++++++++++++++
1 file changed, 145 insertions(+)
create mode 100755 t/t5555-http-smart-common.sh
@@ -0,0 +1,145 @@+test_description='test functionality common to smart fetch & push'++../test-lib.sh++test_expect_success'setup''+test_commit--no-taginitial+'++test_expect_success'git upload-pack --advertise-refs''+cat>expect<<-EOF&&+$(gitrev-parseHEAD)HEAD+$(gitrev-parseHEAD)$(gitsymbolic-refHEAD)+0000+EOF++# We only care about GIT_PROTOCOL, not GIT_TEST_PROTOCOL_VERSION+sane_unsetGIT_PROTOCOL&&+GIT_TEST_PROTOCOL_VERSION=2\+gitupload-pack--advertise-refs.>out2>err&&++test-toolpkt-lineunpack<out>actual&&+test_must_be_emptyerr&&+test_cmpactualexpect&&++# The --advertise-refs alias works+gitupload-pack--advertise-refs.>out2>err&&++test-toolpkt-lineunpack<out>actual&&+test_must_be_emptyerr&&+test_cmpactualexpect+'++test_expect_success'git upload-pack --advertise-refs: v0''+# With no specified protocol+cat>expect<<-EOF&&+$(gitrev-parseHEAD)HEAD+$(gitrev-parseHEAD)$(gitsymbolic-refHEAD)+0000+EOF++gitupload-pack--advertise-refs.>out2>err&&+test-toolpkt-lineunpack<out>actual&&+test_must_be_emptyerr&&+test_cmpactualexpect&&++# With explicit v0+GIT_PROTOCOL=version=0\+gitupload-pack--advertise-refs.>out2>err&&+test-toolpkt-lineunpack<out>actual2>err&&+test_must_be_emptyerr&&+test_cmpactualexpect++'++test_expect_success'git receive-pack --advertise-refs: v0''+# With no specified protocol+cat>expect<<-EOF&&+$(gitrev-parseHEAD)$(gitsymbolic-refHEAD)+0000+EOF++gitreceive-pack--advertise-refs.>out2>err&&+test-toolpkt-lineunpack<out>actual&&+test_must_be_emptyerr&&+test_cmpactualexpect&&++# With explicit v0+GIT_PROTOCOL=version=0\+gitreceive-pack--advertise-refs.>out2>err&&+test-toolpkt-lineunpack<out>actual2>err&&+test_must_be_emptyerr&&+test_cmpactualexpect++'++test_expect_success'git upload-pack --advertise-refs: v1''+# With no specified protocol+cat>expect<<-EOF&&+version1+$(gitrev-parseHEAD)HEAD+$(gitrev-parseHEAD)$(gitsymbolic-refHEAD)+0000+EOF++GIT_PROTOCOL=version=1\+gitupload-pack--advertise-refs.>out&&++test-toolpkt-lineunpack<out>actual2>err&&+test_must_be_emptyerr&&+test_cmpactualexpect+'++test_expect_success'git receive-pack --advertise-refs: v1''+# With no specified protocol+cat>expect<<-EOF&&+version1+$(gitrev-parseHEAD)$(gitsymbolic-refHEAD)+0000+EOF++GIT_PROTOCOL=version=1\+gitreceive-pack--advertise-refs.>out&&++test-toolpkt-lineunpack<out>actual2>err&&+test_must_be_emptyerr&&+test_cmpactualexpect+'++test_expect_success'git upload-pack --advertise-refs: v2''+cat>expect<<-EOF&&+version2+agent=FAKE+ls-refs=unborn+fetch=shallowwait-for-done+server-option+object-format=$(test_oidalgo)+object-info+0000+EOF++GIT_PROTOCOL=version=2\+GIT_USER_AGENT=FAKE\+gitupload-pack--advertise-refs.>out2>err&&++test-toolpkt-lineunpack<out>actual&&+test_must_be_emptyerr&&+test_cmpactualexpect+'++test_expect_success'git receive-pack --advertise-refs: v2''+# There is no v2 yet for receive-pack, implicit v0+cat>expect<<-EOF&&+$(gitrev-parseHEAD)$(gitsymbolic-refHEAD)+0000+EOF++GIT_PROTOCOL=version=2\+gitreceive-pack--advertise-refs.>out2>err&&++test-toolpkt-lineunpack<out>actual&&+test_must_be_emptyerr&&+test_cmpactualexpect+'++test_done
Convert the config reading code in upload-pack.c to use the new
"startup_config" callback when we're using the v2 protocol, and
lightly fake up the same when we're using v0 and v1.
Before the series that fixed 08450ef7918 (upload-pack: clear
filter_options for each v2 fetch command, 2020-05-08) landed, most of
what's now "struct upload_pack_data" used to be static variables at
the top of this file.
This moves some of them back. See f203a88cf14 (upload-pack: move
keepalive to upload_pack_data, 2020-06-04), f1514c6aad0 (upload-pack:
move allow_unadvertised_object_request to upload_pack_data,
2020-06-11) etc.
I think this makes it easier to understand the this code, as we're now
clearly separating data and config that changes on a
request-to-request basis (see 08450ef7918), and the sort of config
that serve.c's "startup_config" is aimed at.
Thus it's clear that the "allow_uor" passed to functions like
"is_our_ref()" is constant after startup (usually it'll never change
for a given server's configuration, or change once).
This requires a very light compatibility layer with the serve.c
callback mechanism in the form of "upload_pack" for the v0 and v1
protocols.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 1 +
upload-pack.c | 133 +++++++++++++++++++++++++++++---------------------
upload-pack.h | 2 +
3 files changed, 80 insertions(+), 56 deletions(-)
@@ -703,13 +702,13 @@ static int get_reachable_list(struct upload_pack_data *data,return0;}-staticinthas_unreachable(structobject_array*src,enumallow_uorallow_uor)+staticinthas_unreachable(structobject_array*src){structchild_processcmd=CHILD_PROCESS_INIT;charbuf[1];inti;-if(do_reachable_revlist(&cmd,src,NULL,allow_uor)<0)+if(do_reachable_revlist(&cmd,src,NULL)<0)return1;/*
@@ -748,9 +747,9 @@ static void check_non_tip(struct upload_pack_data *data)*uploadpack.allowReachableSHA1InWant,*non-tiprequestscanneverhappen.*/-if(!data->stateless_rpc&&!(data->allow_uor&ALLOW_REACHABLE_SHA1))+if(!data->stateless_rpc&&!(config_allow_uor&ALLOW_REACHABLE_SHA1))gotoerror;-if(!has_unreachable(&data->want_obj,data->allow_uor))+if(!has_unreachable(&data->want_obj))/* All the non-tip ones are ancestors of what we advertised */return;
@@ -758,7 +757,7 @@ static void check_non_tip(struct upload_pack_data *data)/* Pick one of them (we know there at least is one) */for(i=0;i<data->want_obj.nr;i++){structobject*o=data->want_obj.objects[i].item;-if(!is_our_ref(o,data->allow_uor)){+if(!is_our_ref(o)){packet_writer_error(&data->writer,"upload-pack: not our ref %s",oid_to_hex(&o->oid));
The serve.c API added in ed10cb952d3 (serve: introduce git-serve,
2018-03-15) was passing in the raw capabilities "keys", but nothing
downstream of it ever used them.
Let's remove that code because it's not needed, and because if and
when we need to pass data about the advertisement (I have some WIP
patches for that), it makes much more sense to have the serve.c parse
the capabilities, and then pass specific information we need down than
expecting its API users to re-do their own parsing of the raw data.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
ls-refs.c | 3 +--
ls-refs.h | 4 +---
protocol-caps.c | 3 +--
protocol-caps.h | 4 +---
serve.c | 7 +++----
upload-pack.c | 3 +--
upload-pack.h | 4 +---
7 files changed, 9 insertions(+), 19 deletions(-)
On 2021.07.22 01:40, Ævar Arnfjörð Bjarmason wrote:
For v2, see:
https://lore.kernel.org/git/cover-0.8-00000000000-20210628T191634Z-avarab@gmail.com/
Junio: Sorry about the late update, re:
http://lore.kernel.org/git/xmqqsg07cz4g.fsf@gitster.g
I think most people were on the fence about the need for this
"startup_config" callback in v2. I think we could still do without it,
but as the new 08/12 shows a big part of the API complexity was due to
serve() supporting the --advertise-refs mode directly. 08-10/12 is a
new late-series cleanup of that, which makes serve.[ch] a lot simpler.
Ævar Arnfjörð Bjarmason (12):
serve: mark has_capability() as static
transport: rename "fetch" in transport_vtable to "fetch_refs"
transport: use designated initializers
serve: use designated initializers
serve.c: add call_{advertise,command}() indirection
serve: add support for a "startup" git_config() callback
serve.c: move version line to advertise_capabilities()
serve.[ch]: remove "serve_options", split up --advertise-refs code
{upload,receive}-pack tests: add --advertise-refs tests
upload-pack: document and rename --advertise-refs
upload-pack.c: convert to new serve.c "startup" config cb
serve.[ch]: don't pass "struct strvec *keys" to commands
Sorry for the delayed response on this series; I've been away from work
for the past several weeks.
I'm in favor of the cleanups in patches 1-4. I'm afraid I am not
familiar enough with the server code to have useful feedback on the rest
of the patches, at least not at first glance.
This is a general API cleanup and simplifiction of of serve.[ch] and
its interaction with "upload-pack --advertise-refs".
Previous rounds of this series had a way to define "startup config"
for commands hanging off the v2 server. That's now entirely gone,
along with prep work required for it.
For v3, see :
https://lore.kernel.org/git/cover-00.12-00000000000-20210721T233307Z-avarab@gmail.com/
The fixup for the missing test shebang has also been squashed in,
thanks Carlo!:
https://lore.kernel.org/git/20210803060005.18151-1-carenas@gmail.com/
Despite the overall diffstat this is a net deletion of code in any
meaningful sense of reducing complexity, i.e. it goes into the plus on
the diffstat due to the addition of previously missing tests, and the
use of designated initializers.
Ævar Arnfjörð Bjarmason (10):
serve: mark has_capability() as static
transport: rename "fetch" in transport_vtable to "fetch_refs"
transport: use designated initializers
serve: use designated initializers
serve.[ch]: don't pass "struct strvec *keys" to commands
serve: move transfer.advertiseSID check into session_id_advertise()
serve.c: move version line to advertise_capabilities()
{upload,receive}-pack tests: add --advertise-refs tests
serve.[ch]: remove "serve_options", split up --advertise-refs code
upload-pack: document and rename --advertise-refs
Documentation/git-receive-pack.txt | 5 +
Documentation/git-upload-pack.txt | 12 +-
Documentation/technical/http-protocol.txt | 3 +
Documentation/technical/protocol-v2.txt | 3 +
builtin/receive-pack.c | 3 +-
builtin/upload-pack.c | 28 ++--
http-backend.c | 2 +-
ls-refs.c | 3 +-
ls-refs.h | 4 +-
protocol-caps.c | 3 +-
protocol-caps.h | 4 +-
serve.c | 82 ++++++-----
serve.h | 12 +-
t/helper/test-serve-v2.c | 14 +-
t/t5555-http-smart-common.sh | 161 ++++++++++++++++++++++
transport-helper.c | 18 +--
transport-internal.h | 2 +-
transport.c | 32 ++---
upload-pack.c | 21 +--
upload-pack.h | 14 +-
20 files changed, 298 insertions(+), 128 deletions(-)
create mode 100755 t/t5555-http-smart-common.sh
Range-diff against v3:
1: 192fb64ef82 = 1: 13bb1a06078 serve: mark has_capability() as static
2: d716bd3c537 = 2: 162f717436f transport: rename "fetch" in transport_vtable to "fetch_refs"
3: d31690614af = 3: d3d5818adda transport: use designated initializers
4: 13f1a8d8325 = 4: 8da15c373cc serve: use designated initializers
5: 99eeff6f890 < -: ----------- serve.c: add call_{advertise,command}() indirection
6: be719dc3dc1 < -: ----------- serve: add support for a "startup" git_config() callback
12: e4eb31b5b8e ! 5: 7714f81d62c serve.[ch]: don't pass "struct strvec *keys" to commands
@@ Commit message
2018-03-15) was passing in the raw capabilities "keys", but nothing
downstream of it ever used them.
- Let's remove that code because it's not needed, and because if and
- when we need to pass data about the advertisement (I have some WIP
- patches for that), it makes much more sense to have the serve.c parse
- the capabilities, and then pass specific information we need down than
- expecting its API users to re-do their own parsing of the raw data.
+ Let's remove that code because it's not needed. If we do end up
+ needing to pass information about the advertisement in the future
+ it'll make more sense to have serve.c parse the capabilities keys and
+ pass the result of its parsing, rather than expecting expecting its
+ API users to parse the same keys again.
Signed-off-by: Ævar Arnfjörð Bjarmason [off-list ref]
@@ ls-refs.h
-int ls_refs(struct repository *r, struct strvec *keys,
- struct packet_reader *request);
+int ls_refs(struct repository *r, struct packet_reader *request);
- int ls_refs_startup_config(const char *var, const char *value, void *data);
int ls_refs_advertise(struct repository *r, struct strbuf *value);
+ #endif /* LS_REFS_H */
## protocol-caps.c ##
@@ protocol-caps.c: static void send_info(struct repository *r, struct packet_writer *writer,
- strbuf_release(&send_buffer);
+ }
}
-int cap_object_info(struct repository *r, struct strvec *keys,
@@ protocol-caps.h
#endif /* PROTOCOL_CAPS_H */
## serve.c ##
-@@ serve.c: static int session_id_advertise(struct repository *r, struct strbuf *value)
- }
-
- typedef int (*advertise_fn_t)(struct repository *r, struct strbuf *value);
--typedef int (*command_fn_t)(struct repository *r, struct strvec *keys,
-+typedef int (*command_fn_t)(struct repository *r,
- struct packet_reader *request);
-
- struct protocol_capability {
@@ serve.c: struct protocol_capability {
/*
@@ serve.c: struct protocol_capability {
* use to read the command specific part of the request. Every command
* MUST read until a flush packet is seen before sending a response.
*
-@@ serve.c: static int call_command(struct protocol_capability *command,
+ * This field should be NULL for capabilities which are not commands.
+ */
+- int (*command)(struct repository *r,
+- struct strvec *keys,
+- struct packet_reader *request);
++ int (*command)(struct repository *r, struct packet_reader *request);
+ };
- read_startup_config(command);
+ static struct protocol_capability capabilities[] = {
+@@ serve.c: static int process_request(void)
+ if (has_capability(&keys, "session-id", &client_sid))
+ trace2_data_string("transfer", NULL, "client-sid", client_sid);
-- return command->command(r, keys, request);
-+ return command->command(r, request);
- }
+- command->command(the_repository, &keys, &reader);
++ command->command(the_repository, &reader);
- void protocol_v2_advertise_capabilities(void)
+ strvec_clear(&keys);
+ return 0;
## upload-pack.c ##
@@ upload-pack.c: enum fetch_state {
@@ upload-pack.c: enum fetch_state {
struct upload_pack_data data;
## upload-pack.h ##
-@@ upload-pack.h: void upload_pack(const int advertise_refs, const int stateless_rpc,
- const int timeout);
+@@ upload-pack.h: struct upload_pack_options {
+ void upload_pack(struct upload_pack_options *options);
struct repository;
-struct strvec;
-: ----------- > 6: 33db6b7cf53 serve: move transfer.advertiseSID check into session_id_advertise()
7: b7928ddbe9b ! 7: 9828e08cbad serve.c: move version line to advertise_capabilities()
@@ Commit message
serve.c: move version line to advertise_capabilities()
The advertise_capabilities() is only called from serve() and we always
- emit this version line before it, it makes more sense to consider the
- capabilities part of a "header" that has the version, so let's move
- the writing of the version there.
+ emit this version line before it. In a subsequent commit I'll make
+ builtin/upload-pack.c sometimes call advertise_capabilities()
+ directly, so it'll make sense to have this line emitted by
+ advertise_capabilities(), not serve() itself.
Signed-off-by: Ævar Arnfjörð Bjarmason [off-list ref]
9: beafe9811c1 ! 8: fd58abb7420 {upload,receive}-pack tests: add --advertise-refs tests
@@ Commit message
## t/t5555-http-smart-common.sh (new) ##
@@
++#!/bin/sh
++
+test_description='test functionality common to smart fetch & push'
+
+. ./test-lib.sh
8: fb80f152713 ! 9: c9a35868933 serve.[ch]: remove "serve_options", split up --advertise-refs code
@@ http-backend.c: static void get_info_refs(struct strbuf *hdr, char *arg)
## serve.c ##
-@@ serve.c: static int call_command(struct protocol_capability *command,
- return command->command(r, keys, request);
- }
+@@ serve.c: static struct protocol_capability capabilities[] = {
+ },
+ };
-static void advertise_capabilities(void)
+void protocol_v2_advertise_capabilities(void)
@@ upload-pack.h
+ const int timeout);
struct repository;
- struct strvec;
+ struct packet_reader;
10: c6870b5f18a = 10: 2006cb234b6 upload-pack: document and rename --advertise-refs
11: 2d4c3d0d463 < -: ----------- upload-pack.c: convert to new serve.c "startup" config cb
--
2.33.0.rc0.597.gc569a812f0a
The has_capability() function introduced in ed10cb952d3 (serve:
introduce git-serve, 2018-03-15) has never been used anywhere except
serve.c, so let's mark it as static.
It was later changed from "extern" in 554544276a6 (*.[ch]: remove
extern from function declarations using spatch, 2019-04-29), but we
could have simply marked it as "static" instead.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 4 ++--
serve.h | 4 ----
2 files changed, 2 insertions(+), 6 deletions(-)
Rename the "fetch" member of the transport_vtable to "fetch_refs" for
consistency with the existing "push_refs". Neither of them just push
"refs" but refs and objects, but having the two match makes the code
more readable than having it be inconsistent, especially since
"fetch_refs" is a lot easier to grep for than "fetch".
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
transport-helper.c | 8 ++++----
transport-internal.h | 2 +-
transport.c | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
@@ -671,8 +671,8 @@ static int connect_helper(struct transport *transport, const char *name,staticstructref*get_refs_list_using_list(structtransport*transport,intfor_push);-staticintfetch(structtransport*transport,-intnr_heads,structref**to_fetch)+staticintfetch_refs(structtransport*transport,+intnr_heads,structref**to_fetch){structhelper_data*data=transport->data;inti,count;
@@ -681,7 +681,7 @@ static int fetch(struct transport *transport,if(process_connect(transport,0)){do_take_over(transport);-returntransport->vtable->fetch(transport,nr_heads,to_fetch);+returntransport->vtable->fetch_refs(transport,nr_heads,to_fetch);}/*
@@ -1263,7 +1263,7 @@ static struct ref *get_refs_list_using_list(struct transport *transport,staticstructtransport_vtablevtable={set_helper_option,get_refs_list,-fetch,+fetch_refs,push_refs,connect_helper,release_helper
Change the assignments to the various transport_vtables to use
designated initializers, this makes the code easier to read and
maintain.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
transport-helper.c | 12 ++++++------
transport.c | 30 ++++++++++++------------------
2 files changed, 18 insertions(+), 24 deletions(-)
@@ -883,12 +883,10 @@ static int disconnect_git(struct transport *transport)}staticstructtransport_vtabletaken_over_vtable={-NULL,-get_refs_via_connect,-fetch_refs_via_pack,-git_transport_push,-NULL,-disconnect_git+.get_refs_list=get_refs_via_connect,+.fetch_refs=fetch_refs_via_pack,+.push_refs=git_transport_push,+.disconnect=disconnect_git};voidtransport_take_over(structtransport*transport,
Change the declaration of the protocol_capability struct to use
designated initializers, this makes this more verbose now, but a
follow-up commit will add a new field. At that point these lines would
be too dense to be on one line comfortably.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 38 +++++++++++++++++++++++++++++++-------
1 file changed, 31 insertions(+), 7 deletions(-)
The serve.c API added in ed10cb952d3 (serve: introduce git-serve,
2018-03-15) was passing in the raw capabilities "keys", but nothing
downstream of it ever used them.
Let's remove that code because it's not needed. If we do end up
needing to pass information about the advertisement in the future
it'll make more sense to have serve.c parse the capabilities keys and
pass the result of its parsing, rather than expecting expecting its
API users to parse the same keys again.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
ls-refs.c | 3 +--
ls-refs.h | 4 +---
protocol-caps.c | 3 +--
protocol-caps.h | 4 +---
serve.c | 9 +++------
upload-pack.c | 3 +--
upload-pack.h | 4 +---
7 files changed, 9 insertions(+), 21 deletions(-)
In 6b5b6e422ee (serve: advertise session ID in v2 capabilities,
2020-11-11) the check for transfer.advertiseSID was added to the
beginning of the main serve() loop. Thus on startup of the server we'd
populate it.
Let's instead use an explicit lazy initialization pattern in
session_id_advertise() itself, we'll still look the config up only
once per-process, but by moving it out of serve() itself the further
changing of that routine becomes easier.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
serve.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
@@ -35,6 +35,9 @@ static int object_format_advertise(struct repository *r,staticintsession_id_advertise(structrepository*r,structstrbuf*value){+if(advertise_sid==-1&&+git_config_get_bool("transfer.advertisesid",&advertise_sid))+advertise_sid=0;if(!advertise_sid)return0;if(value)
@@ -300,8 +303,6 @@ static int process_request(void)/* Main serve loop for protocol version 2 */voidserve(structserve_options*options){-git_config_get_bool("transfer.advertisesid",&advertise_sid);-if(options->advertise_capabilities||!options->stateless_rpc){/* serve by default supports v2 */packet_write_fmt(1,"version 2\n");