Signed-off-by: Mike Hommey <m...@glandium.org>
---
 connect.c | 54 ++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 36 insertions(+), 18 deletions(-)

diff --git a/connect.c b/connect.c
index 4be06f4..0819c25 100644
--- a/connect.c
+++ b/connect.c
@@ -588,11 +588,13 @@ static char *get_port(char *host)
  * Extract protocol and relevant parts from the specified connection URL.
  * The caller must free() the returned strings.
  */
-static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
-                                      char **ret_port, char **ret_path)
+static enum protocol parse_connect_url(const char *url_orig, char **ret_user,
+                                      char **ret_host, char **ret_port,
+                                      char **ret_path)
 {
        char *url;
        char *host, *path;
+       const char *user = NULL;
        const char *port = NULL;
        char *end;
        int separator = '/';
@@ -650,23 +652,31 @@ static enum protocol parse_connect_url(const char 
*url_orig, char **ret_host,
 
        get_host_and_port(&host, &port);
 
-       if (*host && !port) {
+       if (*host) {
                /*
-                * get_host_and_port does not return a port in the
-                * [host:port]:path case. In that case, it is called with
-                * "[host:port]" and returns "host:port" and NULL.
-                * To support this undocumented legacy we still need to split
-                * the port.
-                * "host:port" may also look like "user@host:port". As the
-                * `user` portion tends to be less strict than `host:port`,
-                * we first put it out of the equation: since a hostname
-                * cannot contain a '@', we start from the last '@' in the
-                * string.
+                * At this point, the host part may look like user@host:port.
+                * As the `user` portion tends to be less strict than
+                * `host:port`, we first put it out of the equation: since a
+                * hostname cannot contain a '@', we start from the last '@'
+                * in the string.
                 */
                char *end_user = strrchr(host, '@');
-               port = get_port(end_user ? end_user : host);
+               if (end_user) {
+                       *end_user = '\0';
+                       user = host;
+                       host = end_user + 1;
+               }
        }
+       /*
+        * get_host_and_port does not return a port in the [host:port]:path
+        * case. In that case, it is called with "[host:port]" and returns
+        * "host:port" and NULL.
+        * To support this undocumented legacy we still need to split the port.
+        */
+       if (!port)
+               port = get_port(host);
 
+       *ret_user = user ? xstrdup(user) : NULL;
        *ret_host = xstrdup(host);
        *ret_port = port ? xstrdup(port) : NULL;
        *ret_path = path;
@@ -690,7 +700,7 @@ static struct child_process no_fork = CHILD_PROCESS_INIT;
 struct child_process *git_connect(int fd[2], const char *url,
                                  const char *prog, int flags)
 {
-       char *host, *port, *path;
+       char *user, *host, *port, *path;
        struct child_process *conn = &no_fork;
        enum protocol protocol;
        struct strbuf cmd = STRBUF_INIT;
@@ -700,11 +710,14 @@ struct child_process *git_connect(int fd[2], const char 
*url,
         */
        signal(SIGCHLD, SIG_DFL);
 
-       protocol = parse_connect_url(url, &host, &port, &path);
+       protocol = parse_connect_url(url, &user, &host, &port, &path);
        if (flags & CONNECT_DIAG_URL) {
                printf("Diag: url=%s\n", url ? url : "NULL");
                printf("Diag: protocol=%s\n", prot_name(protocol));
-               printf("Diag: userandhost=%s\n", host ? host : "NULL");
+               if (user)
+                       printf("Diag: userandhost=%s@%s\n", user, host);
+               else
+                       printf("Diag: userandhost=%s\n", host ? host : "NULL");
                printf("Diag: port=%s\n", port ? port : "NONE");
                printf("Diag: path=%s\n", path ? path : "NULL");
                conn = NULL;
@@ -813,7 +826,11 @@ struct child_process *git_connect(int fd[2], const char 
*url,
                                argv_array_push(&conn->args, putty ? "-P" : 
"-p");
                                argv_array_push(&conn->args, port);
                        }
-                       argv_array_push(&conn->args, host);
+                       if (user)
+                               argv_array_pushf(&conn->args, "%s@%s",
+                                                user, host);
+                       else
+                               argv_array_push(&conn->args, host);
                } else {
                        transport_check_allowed("file");
                }
@@ -826,6 +843,7 @@ struct child_process *git_connect(int fd[2], const char 
*url,
                fd[1] = conn->in;  /* write to child's stdin */
                strbuf_release(&cmd);
        }
+       free(user);
        free(host);
        free(port);
        free(path);
-- 
2.8.3

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to