]> sjero.net Git - wget/blobdiff - src/url.c
[svn] Added support for --restrict-file-names=lowercase and --restrict-file-names...
[wget] / src / url.c
index 0a23df32d38ba2806cb8ae0f20a0587f802d6016..1d199feaf040c0f96d52d0022d07ca59587ad9ab 100644 (file)
--- a/src/url.c
+++ b/src/url.c
@@ -43,6 +43,10 @@ so, delete this exception statement from your version.  */
 #include "url.h"
 #include "host.h"  /* for is_valid_ipv6_address */
 
+#ifdef TESTING
+#include "test.h"
+#endif
+
 enum {
   scm_disabled = 1,            /* for https when OpenSSL fails to init. */
   scm_has_params = 2,          /* whether scheme has ;params */
@@ -508,7 +512,8 @@ parse_credentials (const char *beg, const char *end, char **user, char **passwd)
 }
 
 /* Used by main.c: detect URLs written using the "shorthand" URL forms
-   popularized by Netscape and NcFTP.  HTTP shorthands look like this:
+   originally popularized by Netscape and NcFTP.  HTTP shorthands look
+   like this:
 
    www.foo.com[:port]/dir/file   -> http://www.foo.com[:port]/dir/file
    www.foo.com[:port]            -> http://www.foo.com[:port]
@@ -524,52 +529,42 @@ char *
 rewrite_shorthand_url (const char *url)
 {
   const char *p;
+  char *ret;
 
   if (url_scheme (url) != SCHEME_INVALID)
     return NULL;
 
   /* Look for a ':' or '/'.  The former signifies NcFTP syntax, the
      latter Netscape.  */
-  for (p = url; *p && *p != ':' && *p != '/'; p++)
-    ;
-
+  p = strpbrk (url, ":/");
   if (p == url)
     return NULL;
 
   /* If we're looking at "://", it means the URL uses a scheme we
      don't support, which may include "https" when compiled without
      SSL support.  Don't bogusly rewrite such URLs.  */
-  if (p[0] == ':' && p[1] == '/' && p[2] == '/')
+  if (p && p[0] == ':' && p[1] == '/' && p[2] == '/')
     return NULL;
 
-  if (*p == ':')
+  if (p && *p == ':')
     {
-      const char *pp;
-      char *res;
-      /* If the characters after the colon and before the next slash
-        or end of string are all digits, it's HTTP.  */
-      int digits = 0;
-      for (pp = p + 1; ISDIGIT (*pp); pp++)
-       ++digits;
-      if (digits > 0 && (*pp == '/' || *pp == '\0'))
+      /* Colon indicates ftp, as in foo.bar.com:path.  Check for
+        special case of http port number ("localhost:10000").  */
+      int digits = strspn (p + 1, "0123456789");
+      if (digits && (p[1 + digits] == '/' || p[1 + digits] == '\0'))
        goto http;
 
-      /* Prepend "ftp://" to the entire URL... */
-      res = xmalloc (6 + strlen (url) + 1);
-      sprintf (res, "ftp://%s", url);
-      /* ...and replace ':' with '/'. */
-      res[6 + (p - url)] = '/';
-      return res;
+      /* Turn "foo.bar.com:path" to "ftp://foo.bar.com/path". */
+      ret = aprintf ("ftp://%s", url);
+      ret[6 + (p - url)] = '/';
     }
   else
     {
-      char *res;
     http:
-      /* Just prepend "http://" to what we have. */
-      res = xmalloc (7 + strlen (url) + 1);
-      sprintf (res, "http://%s", url);
-      return res;
+      /* Just prepend "http://" to URL. */
+      ret = aprintf ("http://%s", url);
     }
+  return ret;
 }
 \f
 static void split_path (const char *, char **, char **);
@@ -1369,6 +1364,21 @@ append_uri_pathel (const char *b, const char *e, bool escaped,
        }
       assert (q - TAIL (dest) == outlen);
     }
+  
+  /* Perform inline case transformation if required.  */
+  if (opt.restrict_files_case == restrict_lowercase
+      || opt.restrict_files_case == restrict_uppercase)
+    {
+      char *q;
+      for (q = TAIL (dest); *q; ++q)
+        {
+          if (opt.restrict_files_case == restrict_lowercase)
+            *q = TOLOWER (*q);
+          else
+            *q = TOUPPER (*q);
+        }
+    }
+         
   TAIL_INCR (dest, outlen);
 }
 
@@ -1520,8 +1530,7 @@ path_simplify (char *path)
 {
   char *h = path;              /* hare */
   char *t = path;              /* tortoise */
-  char *beg = path;            /* boundary for backing the tortoise */
-  char *end = path + strlen (path);
+  char *end = strchr (path, '\0');
 
   while (h < end)
     {
@@ -1536,26 +1545,17 @@ path_simplify (char *path)
        {
          /* Handle "../" by retreating the tortoise by one path
             element -- but not past beggining.  */
-         if (t > beg)
+         if (t > path)
            {
              /* Move backwards until T hits the beginning of the
                 previous path element or the beginning of path. */
-             for (--t; t > beg && t[-1] != '/'; t--)
+             for (--t; t > path && t[-1] != '/'; t--)
                ;
            }
-         else
-           {
-             /* If we're at the beginning, copy the "../" literally
-                move the beginning so a later ".." doesn't remove
-                it.  */
-             beg = t + 3;
-             goto regular;
-           }
          h += 3;
        }
       else
        {
-       regular:
          /* A regular path element.  If H hasn't advanced past T,
             simply skip to the next path element.  Otherwise, copy
             the path element until the next slash.  */
@@ -1601,17 +1601,8 @@ path_end (const char *url)
 }
 
 /* Find the last occurrence of character C in the range [b, e), or
-   NULL, if none are present.  We might want to use memrchr (a GNU
-   extension) under GNU libc.  */
-
-static const char *
-find_last_char (const char *b, const char *e, char c)
-{
-  for (; e > b; e--)
-    if (*e == c)
-      return e;
-  return NULL;
-}
+   NULL, if none are present.  */
+#define find_last_char(b, e, c) memrchr ((b), (c), (e) - (b))
 
 /* Merge BASE with LINK and return the resulting URI.
 
@@ -1981,8 +1972,8 @@ test_path_simplify (void)
     { "",                      "",             false },
     { ".",                     "",             true },
     { "./",                    "",             true },
-    { "..",                    "..",           false },
-    { "../",                   "../",          false },
+    { "..",                    "",             true },
+    { "../",                   "",             true },
     { "foo",                   "foo",          false },
     { "foo/bar",               "foo/bar",      false },
     { "foo///bar",             "foo///bar",    false },
@@ -1995,9 +1986,9 @@ test_path_simplify (void)
     { "foo/bar/../x",          "foo/x",        true },
     { "foo/bar/../x/",         "foo/x/",       true },
     { "foo/..",                        "",             true },
-    { "foo/../..",             "..",           true },
-    { "foo/../../..",          "../..",        true },
-    { "foo/../../bar/../../baz", "../../baz",  true },
+    { "foo/../..",             "",             true },
+    { "foo/../../..",          "",             true },
+    { "foo/../../bar/../../baz", "baz",                true },
     { "a/b/../../c",           "c",            true },
     { "./a/../b",              "b",            true }
   };
@@ -2012,3 +2003,38 @@ test_path_simplify (void)
     }
 }
 #endif
+\f
+#ifdef TESTING
+
+const char *
+test_append_uri_pathel()
+{
+  int i;
+  struct {
+    char *original_url;
+    char *input;
+    bool escaped;
+    char *expected_result;
+  } test_array[] = {
+    { "http://www.yoyodyne.com/path/", "somepage.html", false, "http://www.yoyodyne.com/path/somepage.html" },
+  };
+  
+  for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i) 
+    {
+      struct growable dest;
+      const char *p = test_array[i].input;
+      
+      memset (&dest, 0, sizeof (dest));
+      
+      append_string (test_array[i].original_url, &dest);
+      append_uri_pathel (p, p + strlen(p), test_array[i].escaped, &dest);
+
+      mu_assert ("test_append_uri_pathel: wrong result", 
+                 strcmp (dest.base, test_array[i].expected_result) == 0);
+    }
+
+  return NULL;
+}
+
+#endif /* TESTING */
+