Merge branch 'rs/daemon-interpolate'
authorJunio C Hamano <gitster@pobox.com>
Tue, 3 Mar 2015 22:37:04 +0000 (14:37 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 3 Mar 2015 22:37:04 +0000 (14:37 -0800)
"git daemon" looked up the hostname even when "%CH" and "%IP"
interpolations are not requested, which was unnecessary.

* rs/daemon-interpolate:
daemon: use callback to build interpolated path
daemon: look up client-supplied hostname lazily

1  2 
daemon.c
diff --combined daemon.c
index 54a03bd527a81485b498e33225ed54c54c0dbff7,df9768fecc490b681449bdaff17bacb78d257f8c..09fa652fd172cf7bb5b1cf8a4f0ccbc072ca2111
+++ b/daemon.c
@@@ -61,6 -61,22 +61,22 @@@ static char *canon_hostname
  static char *ip_address;
  static char *tcp_port;
  
+ static int hostname_lookup_done;
+ static void lookup_hostname(void);
+ static const char *get_canon_hostname(void)
+ {
+       lookup_hostname();
+       return canon_hostname;
+ }
+ static const char *get_ip_address(void)
+ {
+       lookup_hostname();
+       return ip_address;
+ }
  static void logreport(int priority, const char *err, va_list params)
  {
        if (log_syslog) {
@@@ -106,6 -122,46 +122,46 @@@ static void NORETURN daemon_die(const c
        exit(1);
  }
  
+ static void strbuf_addstr_or_null(struct strbuf *sb, const char *s)
+ {
+       if (s)
+               strbuf_addstr(sb, s);
+ }
+ struct expand_path_context {
+       const char *directory;
+ };
+ static size_t expand_path(struct strbuf *sb, const char *placeholder, void *ctx)
+ {
+       struct expand_path_context *context = ctx;
+       switch (placeholder[0]) {
+       case 'H':
+               strbuf_addstr_or_null(sb, hostname);
+               return 1;
+       case 'C':
+               if (placeholder[1] == 'H') {
+                       strbuf_addstr_or_null(sb, get_canon_hostname());
+                       return 2;
+               }
+               break;
+       case 'I':
+               if (placeholder[1] == 'P') {
+                       strbuf_addstr_or_null(sb, get_ip_address());
+                       return 2;
+               }
+               break;
+       case 'P':
+               strbuf_addstr_or_null(sb, tcp_port);
+               return 1;
+       case 'D':
+               strbuf_addstr(sb, context->directory);
+               return 1;
+       }
+       return 0;
+ }
  static const char *path_ok(const char *directory)
  {
        static char rpath[PATH_MAX];
        }
        else if (interpolated_path && saw_extended_args) {
                struct strbuf expanded_path = STRBUF_INIT;
-               struct strbuf_expand_dict_entry dict[6];
-               dict[0].placeholder = "H"; dict[0].value = hostname;
-               dict[1].placeholder = "CH"; dict[1].value = canon_hostname;
-               dict[2].placeholder = "IP"; dict[2].value = ip_address;
-               dict[3].placeholder = "P"; dict[3].value = tcp_port;
-               dict[4].placeholder = "D"; dict[4].value = directory;
-               dict[5].placeholder = NULL; dict[5].value = NULL;
+               struct expand_path_context context;
+               context.directory = directory;
                if (*dir != '/') {
                        /* Allow only absolute */
                        logerror("'%s': Non-absolute path denied (interpolated-path active)", dir);
                }
  
                strbuf_expand(&expanded_path, interpolated_path,
-                               strbuf_expand_dict_cb, &dict);
+                             expand_path, &context);
                strlcpy(interp_path, expanded_path.buf, PATH_MAX);
                strbuf_release(&expanded_path);
                loginfo("Interpolated dir '%s'", interp_path);
@@@ -230,6 -282,23 +282,6 @@@ struct daemon_service 
        int overridable;
  };
  
 -static struct daemon_service *service_looking_at;
 -static int service_enabled;
 -
 -static int git_daemon_config(const char *var, const char *value, void *cb)
 -{
 -      const char *service;
 -
 -      if (skip_prefix(var, "daemon.", &service) &&
 -          !strcmp(service, service_looking_at->config_name)) {
 -              service_enabled = git_config_bool(var, value);
 -              return 0;
 -      }
 -
 -      /* we are not interested in parsing any other configuration here */
 -      return 0;
 -}
 -
  static int daemon_error(const char *dir, const char *msg)
  {
        if (!informative_errors)
@@@ -242,7 -311,7 +294,7 @@@ static const char *access_hook
  
  static int run_access_hook(struct daemon_service *service, const char *dir, const char *path)
  {
 -      struct child_process child;
 +      struct child_process child = CHILD_PROCESS_INIT;
        struct strbuf buf = STRBUF_INIT;
        const char *argv[8];
        const char **arg = argv;
        *arg++ = service->name;
        *arg++ = path;
        *arg++ = STRARG(hostname);
-       *arg++ = STRARG(canon_hostname);
-       *arg++ = STRARG(ip_address);
+       *arg++ = STRARG(get_canon_hostname());
+       *arg++ = STRARG(get_ip_address());
        *arg++ = STRARG(tcp_port);
        *arg = NULL;
  #undef STRARG
  
 -      memset(&child, 0, sizeof(child));
        child.use_shell = 1;
        child.argv = argv;
        child.no_stdin = 1;
@@@ -306,7 -376,6 +358,7 @@@ static int run_service(const char *dir
  {
        const char *path;
        int enabled = service->enabled;
 +      struct strbuf var = STRBUF_INIT;
  
        loginfo("Request %s for '%s'", service->name, dir);
  
        }
  
        if (service->overridable) {
 -              service_looking_at = service;
 -              service_enabled = -1;
 -              git_config(git_daemon_config, NULL);
 -              if (0 <= service_enabled)
 -                      enabled = service_enabled;
 +              strbuf_addf(&var, "daemon.%s", service->config_name);
 +              git_config_get_bool(var.buf, &enabled);
 +              strbuf_release(&var);
        }
        if (!enabled) {
                logerror("'%s': service not enabled for '%s'",
@@@ -387,8 -458,9 +439,8 @@@ static void copy_to_log(int fd
  
  static int run_service_command(const char **argv)
  {
 -      struct child_process cld;
 +      struct child_process cld = CHILD_PROCESS_INIT;
  
 -      memset(&cld, 0, sizeof(cld));
        cld.argv = argv;
        cld.git_cmd = 1;
        cld.err = -1;
@@@ -509,6 -581,7 +561,7 @@@ static void parse_host_arg(char *extra_
                                }
                                free(hostname);
                                hostname = xstrdup_tolower(host);
+                               hostname_lookup_done = 0;
                        }
  
                        /* On to the next one */
                if (extra_args < end && *extra_args)
                        die("Invalid request");
        }
+ }
  
-       /*
-        * Locate canonical hostname and its IP address.
-        */
-       if (hostname) {
+ /*
+  * Locate canonical hostname and its IP address.
+  */
+ static void lookup_hostname(void)
+ {
+       if (!hostname_lookup_done && hostname) {
  #ifndef NO_IPV6
                struct addrinfo hints;
                struct addrinfo *ai;
                        ip_address = xstrdup(addrbuf);
                }
  #endif
+               hostname_lookup_done = 1;
        }
  }
  
@@@ -714,7 -791,7 +771,7 @@@ static void check_dead_children(void
  static char **cld_argv;
  static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
  {
 -      struct child_process cld = { NULL };
 +      struct child_process cld = CHILD_PROCESS_INIT;
        char addrbuf[300] = "REMOTE_ADDR=", portbuf[300];
        char *env[] = { addrbuf, portbuf, NULL };