1
0
mirror of https://github.com/moparisthebest/wget synced 2024-07-03 16:38:41 -04:00

Add support for .. at beginning of paths back in, but only for FTP.

This commit is contained in:
Micah Cowan 2008-04-27 03:23:54 -07:00
parent db61675ec0
commit 886cc094e1
3 changed files with 71 additions and 36 deletions

View File

@ -1,5 +1,12 @@
2008-04-27 Micah Cowan <micah@cowan.name> 2008-04-27 Micah Cowan <micah@cowan.name>
* url.c (path_simplify): Go back to allowing leading ".." in
paths, but only for FTP URLs.
(test_path_simplify): Add scheme-specificness to tests, adapt for
mu_run_test.
* test.c (all_tests): Add test_path_simplify.
* main.c (main): Downgrade -r, -p with -O to a warning rather than * main.c (main): Downgrade -r, -p with -O to a warning rather than
an error; elaborate just a bit more for other -O combination an error; elaborate just a bit more for other -O combination
cases. cases.

View File

@ -40,6 +40,7 @@ const char *test_subdir_p();
const char *test_dir_matches_p(); const char *test_dir_matches_p();
const char *test_commands_sorted(); const char *test_commands_sorted();
const char *test_cmd_spec_restrict_file_names(); const char *test_cmd_spec_restrict_file_names();
const char *test_path_simplify ();
const char *test_append_uri_pathel(); const char *test_append_uri_pathel();
const char *test_are_urls_equal(); const char *test_are_urls_equal();
const char *test_is_robots_txt_url(); const char *test_is_robots_txt_url();
@ -54,6 +55,7 @@ all_tests()
mu_run_test (test_dir_matches_p); mu_run_test (test_dir_matches_p);
mu_run_test (test_commands_sorted); mu_run_test (test_commands_sorted);
mu_run_test (test_cmd_spec_restrict_file_names); mu_run_test (test_cmd_spec_restrict_file_names);
mu_run_test (test_path_simplify);
mu_run_test (test_append_uri_pathel); mu_run_test (test_append_uri_pathel);
mu_run_test (test_are_urls_equal); mu_run_test (test_are_urls_equal);
mu_run_test (test_is_robots_txt_url); mu_run_test (test_is_robots_txt_url);

View File

@ -81,7 +81,7 @@ static struct scheme_data supported_schemes[] =
/* Forward declarations: */ /* Forward declarations: */
static bool path_simplify (char *); static bool path_simplify (enum url_scheme, char *);
/* Support for escaping and unescaping of URL strings. */ /* Support for escaping and unescaping of URL strings. */
@ -829,7 +829,7 @@ url_parse (const char *url, int *error)
u->passwd = passwd; u->passwd = passwd;
u->path = strdupdelim (path_b, path_e); u->path = strdupdelim (path_b, path_e);
path_modified = path_simplify (u->path); path_modified = path_simplify (scheme, u->path);
split_path (u->path, &u->dir, &u->file); split_path (u->path, &u->dir, &u->file);
host_modified = lowercase_str (u->host); host_modified = lowercase_str (u->host);
@ -1526,10 +1526,11 @@ url_file_name (const struct url *u)
test case. */ test case. */
static bool static bool
path_simplify (char *path) path_simplify (enum url_scheme scheme, char *path)
{ {
char *h = path; /* hare */ char *h = path; /* hare */
char *t = path; /* tortoise */ char *t = path; /* tortoise */
char *beg = path;
char *end = strchr (path, '\0'); char *end = strchr (path, '\0');
while (h < end) while (h < end)
@ -1545,17 +1546,29 @@ path_simplify (char *path)
{ {
/* Handle "../" by retreating the tortoise by one path /* Handle "../" by retreating the tortoise by one path
element -- but not past beggining. */ element -- but not past beggining. */
if (t > path) if (t > beg)
{ {
/* Move backwards until T hits the beginning of the /* Move backwards until T hits the beginning of the
previous path element or the beginning of path. */ previous path element or the beginning of path. */
for (--t; t > path && t[-1] != '/'; t--) for (--t; t > beg && t[-1] != '/'; t--)
; ;
} }
else if (scheme == SCHEME_FTP)
{
/* If we're at the beginning, copy the "../" literally
and move the beginning so a later ".." doesn't remove
it. This violates RFC 3986; but we do it for FTP
anyway because there is otherwise no way to get at a
parent directory, when the FTP server drops us in a
non-root directory (which is not uncommon). */
beg = t + 3;
goto regular;
}
h += 3; h += 3;
} }
else else
{ {
regular:
/* A regular path element. If H hasn't advanced past T, /* A regular path element. If H hasn't advanced past T,
simply skip to the next path element. Otherwise, copy simply skip to the next path element. Otherwise, copy
the path element until the next slash. */ the path element until the next slash. */
@ -1991,9 +2004,10 @@ are_urls_equal (const char *u1, const char *u2)
return (*p == 0 && *q == 0 ? true : false); return (*p == 0 && *q == 0 ? true : false);
} }
#if 0 #ifdef TESTING
/* Debugging and testing support for path_simplify. */ /* Debugging and testing support for path_simplify. */
#if 0
/* Debug: run path_simplify on PATH and return the result in a new /* Debug: run path_simplify on PATH and return the result in a new
string. Useful for calling from the debugger. */ string. Useful for calling from the debugger. */
static char * static char *
@ -2003,17 +2017,20 @@ ps (char *path)
path_simplify (copy); path_simplify (copy);
return copy; return copy;
} }
#endif
static void static const char *
run_test (char *test, char *expected_result, bool expected_change) run_test (char *test, char *expected_result, enum url_scheme scheme,
bool expected_change)
{ {
char *test_copy = xstrdup (test); char *test_copy = xstrdup (test);
bool modified = path_simplify (test_copy); bool modified = path_simplify (scheme, test_copy);
if (0 != strcmp (test_copy, expected_result)) if (0 != strcmp (test_copy, expected_result))
{ {
printf ("Failed path_simplify(\"%s\"): expected \"%s\", got \"%s\".\n", printf ("Failed path_simplify(\"%s\"): expected \"%s\", got \"%s\".\n",
test, expected_result, test_copy); test, expected_result, test_copy);
mu_assert ("", 0);
} }
if (modified != expected_change) if (modified != expected_change)
{ {
@ -2025,51 +2042,60 @@ run_test (char *test, char *expected_result, bool expected_change)
test); test);
} }
xfree (test_copy); xfree (test_copy);
mu_assert ("", modified == expected_change);
return NULL;
} }
static void const char *
test_path_simplify (void) test_path_simplify (void)
{ {
static struct { static struct {
char *test, *result; char *test, *result;
enum url_scheme scheme;
bool should_modify; bool should_modify;
} tests[] = { } tests[] = {
{ "", "", false }, { "", "", SCHEME_HTTP, false },
{ ".", "", true }, { ".", "", SCHEME_HTTP, true },
{ "./", "", true }, { "./", "", SCHEME_HTTP, true },
{ "..", "", true }, { "..", "", SCHEME_HTTP, true },
{ "../", "", true }, { "../", "", SCHEME_HTTP, true },
{ "foo", "foo", false }, { "..", "..", SCHEME_FTP, false },
{ "foo/bar", "foo/bar", false }, { "../", "../", SCHEME_FTP, false },
{ "foo///bar", "foo///bar", false }, { "foo", "foo", SCHEME_HTTP, false },
{ "foo/.", "foo/", true }, { "foo/bar", "foo/bar", SCHEME_HTTP, false },
{ "foo/./", "foo/", true }, { "foo///bar", "foo///bar", SCHEME_HTTP, false },
{ "foo./", "foo./", false }, { "foo/.", "foo/", SCHEME_HTTP, true },
{ "foo/../bar", "bar", true }, { "foo/./", "foo/", SCHEME_HTTP, true },
{ "foo/../bar/", "bar/", true }, { "foo./", "foo./", SCHEME_HTTP, false },
{ "foo/bar/..", "foo/", true }, { "foo/../bar", "bar", SCHEME_HTTP, true },
{ "foo/bar/../x", "foo/x", true }, { "foo/../bar/", "bar/", SCHEME_HTTP, true },
{ "foo/bar/../x/", "foo/x/", true }, { "foo/bar/..", "foo/", SCHEME_HTTP, true },
{ "foo/..", "", true }, { "foo/bar/../x", "foo/x", SCHEME_HTTP, true },
{ "foo/../..", "", true }, { "foo/bar/../x/", "foo/x/", SCHEME_HTTP, true },
{ "foo/../../..", "", true }, { "foo/..", "", SCHEME_HTTP, true },
{ "foo/../../bar/../../baz", "baz", true }, { "foo/../..", "", SCHEME_HTTP, true },
{ "a/b/../../c", "c", true }, { "foo/../../..", "", SCHEME_HTTP, true },
{ "./a/../b", "b", true } { "foo/../../bar/../../baz", "baz", SCHEME_HTTP, true },
{ "foo/../..", "..", SCHEME_FTP, true },
{ "foo/../../..", "../..", SCHEME_FTP, true },
{ "foo/../../bar/../../baz", "../../baz", SCHEME_FTP, true },
{ "a/b/../../c", "c", SCHEME_HTTP, true },
{ "./a/../b", "b", SCHEME_HTTP, true }
}; };
int i; int i;
for (i = 0; i < countof (tests); i++) for (i = 0; i < countof (tests); i++)
{ {
const char *message;
char *test = tests[i].test; char *test = tests[i].test;
char *expected_result = tests[i].result; char *expected_result = tests[i].result;
enum url_scheme scheme = tests[i].scheme;
bool expected_change = tests[i].should_modify; bool expected_change = tests[i].should_modify;
run_test (test, expected_result, expected_change); message = run_test (test, expected_result, scheme, expected_change);
if (message) return message;
} }
return NULL;
} }
#endif
#ifdef TESTING
const char * const char *
test_append_uri_pathel() test_append_uri_pathel()