]> sjero.net Git - wget/blobdiff - src/url.c
[svn] Fix memory leak in a rare case in url.c.
[wget] / src / url.c
index 4a4f465b50675af577e7bbf139b6099f5beb7d9e..cf95c126066c33afaf5f80dcd289a2fd21d77c6a 100644 (file)
--- a/src/url.c
+++ b/src/url.c
@@ -198,8 +198,8 @@ url_escape_1 (const char *s, unsigned char mask, int allow_passthrough)
        {
          unsigned char c = *p1++;
          *p2++ = '%';
-         *p2++ = XNUM_TO_digit (c >> 4);
-         *p2++ = XNUM_TO_digit (c & 0xf);
+         *p2++ = XNUM_TO_DIGIT (c >> 4);
+         *p2++ = XNUM_TO_DIGIT (c & 0xf);
        }
       else
        *p2++ = *p1++;
@@ -618,28 +618,23 @@ lowercase_str (char *str)
 
 static char *parse_errors[] = {
 #define PE_NO_ERROR                    0
-  "No error",
+  N_("No error"),
 #define PE_UNSUPPORTED_SCHEME          1
-  "Unsupported scheme",
+  N_("Unsupported scheme"),
 #define PE_EMPTY_HOST                  2
-  "Empty host",
+  N_("Empty host"),
 #define PE_BAD_PORT_NUMBER             3
-  "Bad port number",
+  N_("Bad port number"),
 #define PE_INVALID_USER_NAME           4
-  "Invalid user name",
+  N_("Invalid user name"),
 #define PE_UNTERMINATED_IPV6_ADDRESS   5
-  "Unterminated IPv6 numeric address",
+  N_("Unterminated IPv6 numeric address"),
 #define PE_IPV6_NOT_SUPPORTED          6
-  "IPv6 addresses not supported",
+  N_("IPv6 addresses not supported"),
 #define PE_INVALID_IPV6_ADDRESS                7
-  "Invalid IPv6 numeric address"
+  N_("Invalid IPv6 numeric address")
 };
 
-#define SETERR(p, v) do {                      \
-  if (p)                                       \
-    *(p) = (v);                                        \
-} while (0)
-
 #ifdef ENABLE_IPV6
 /* The following two functions were adapted from glibc. */
 
@@ -800,13 +795,15 @@ url_parse (const char *url, int *error)
   int port;
   char *user = NULL, *passwd = NULL;
 
-  char *url_encoded;
+  char *url_encoded = NULL;
+
+  int error_code;
 
   scheme = url_scheme (url);
   if (scheme == SCHEME_INVALID)
     {
-      SETERR (error, PE_UNSUPPORTED_SCHEME);
-      return NULL;
+      error_code = PE_UNSUPPORTED_SCHEME;
+      goto error;
     }
 
   url_encoded = reencode_escapes (url);
@@ -843,23 +840,23 @@ url_parse (const char *url, int *error)
 
       if (!host_e)
        {
-         SETERR (error, PE_UNTERMINATED_IPV6_ADDRESS);
-         return NULL;
+         error_code = PE_UNTERMINATED_IPV6_ADDRESS;
+         goto error;
        }
 
 #ifdef ENABLE_IPV6
       /* Check if the IPv6 address is valid. */
       if (!is_valid_ipv6_address(host_b, host_e))
        {
-         SETERR (error, PE_INVALID_IPV6_ADDRESS);
-         return NULL;
+         error_code = PE_INVALID_IPV6_ADDRESS;
+         goto error;
        }
 
       /* Continue parsing after the closing ']'. */
       p = host_e + 1;
 #else
-      SETERR (error, PE_IPV6_NOT_SUPPORTED);
-      return NULL;
+      error_code = PE_IPV6_NOT_SUPPORTED;
+      goto error;
 #endif
     }
   else
@@ -870,8 +867,8 @@ url_parse (const char *url, int *error)
 
   if (host_b == host_e)
     {
-      SETERR (error, PE_EMPTY_HOST);
-      return NULL;
+      error_code = PE_EMPTY_HOST;
+      goto error;
     }
 
   port = scheme_default_port (scheme);
@@ -890,8 +887,8 @@ url_parse (const char *url, int *error)
        {
          /* http://host:/whatever */
          /*             ^         */
-         SETERR (error, PE_BAD_PORT_NUMBER);
-         return NULL;
+          error_code = PE_BAD_PORT_NUMBER;
+         goto error;
        }
 
       for (port = 0, pp = port_b; pp < port_e; pp++)
@@ -900,8 +897,8 @@ url_parse (const char *url, int *error)
            {
              /* http://host:12randomgarbage/blah */
              /*               ^                  */
-             SETERR (error, PE_BAD_PORT_NUMBER);
-             return NULL;
+              error_code = PE_BAD_PORT_NUMBER;
+              goto error;
            }
          
          port = 10 * port + (*pp - '0');
@@ -960,8 +957,8 @@ url_parse (const char *url, int *error)
       /*     uname_b   uname_e */
       if (!parse_credentials (uname_b, uname_e - 1, &user, &passwd))
        {
-         SETERR (error, PE_INVALID_USER_NAME);
-         return NULL;
+         error_code = PE_INVALID_USER_NAME;
+         goto error;
        }
     }
 
@@ -1007,13 +1004,27 @@ url_parse (const char *url, int *error)
   url_encoded = NULL;
 
   return u;
+
+ error:
+  /* Cleanup in case of error: */
+  if (url_encoded && url_encoded != url)
+    xfree (url_encoded);
+
+  /* Transmit the error code to the caller, if the caller wants to
+     know.  */
+  if (error)
+    *error = error_code;
+  return NULL;
 }
 
+/* Return the error message string from ERROR_CODE, which should have
+   been retrieved from url_parse.  The error message is translated.  */
+
 const char *
 url_error (int error_code)
 {
   assert (error_code >= 0 && error_code < countof (parse_errors));
-  return parse_errors[error_code];
+  return _(parse_errors[error_code]);
 }
 
 /* Split PATH into DIR and FILE.  PATH comes from the URL and is
@@ -1130,6 +1141,7 @@ url_escape_dir (const char *dir)
 
   for (; *h; h++, t++)
     {
+      /* url_escape_1 having converted '/' to "%2F" exactly. */
       if (*h == '%' && h[1] == '2' && h[2] == 'F')
        {
          *t = '/';
@@ -1619,6 +1631,11 @@ find_last_char (const char *b, const char *e, char c)
    "back up one element".  Single leading and trailing slashes are
    preserved.
 
+   This function does not handle URL escapes explicitly.  If you're
+   passing paths from URLs, make sure to unquote "%2e" and "%2E" to
+   ".", so that this function can find the dots.  (Wget's URL parser
+   calls reencode_escapes, which see.)
+
    For example, "a/b/c/./../d/.." will yield "a/b/".  More exhaustive
    test examples are provided below.  If you change anything in this
    function, run test_path_simplify to make sure you haven't broken a