From 13e80e5b4349c180994235349dfb7769f59aa6fa Mon Sep 17 00:00:00 2001 From: wessels <> Date: Mon, 3 Nov 1997 23:19:23 +0000 Subject: [PATCH] From: Henrik Nordstrom * Allow %escapes to be send in a FTP url. The path is now handled correctly: 1) Split the path on / 2) Decode each part (possibly introducing / or ..) * Removed up the "cleanup" of URL's.. it is basically not a good idea to try to clean up the URL. If we get a strange URL it is probably the intention. The "cleanup" code usually makes a mess of things.. And when this cleanup was removed, it was much easier to handle "BASE HREF" or not... * Added back .. in listings (code was not updated) * Changed .. to generate %2e%2e/ when appropriate ("root" directory, or after %2e%2e) * Added a link to %2f/ when on "Top level" URL. * Added a "Up" link to ../ on the above two ones. (I chosed the term Up, since it is to a shorter URL.. whether this it up/down in the file system is hard to tell...) * Changed text to "Home directory" when in directory /%2f/ --- src/ftp.cc | 126 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 31 deletions(-) diff --git a/src/ftp.cc b/src/ftp.cc index b8a81d47bf..712e829cca 100644 --- a/src/ftp.cc +++ b/src/ftp.cc @@ -1,6 +1,5 @@ - /* - * $Id: ftp.cc,v 1.162 1997/11/03 16:05:23 wessels Exp $ + * $Id: ftp.cc,v 1.163 1997/11/03 16:19:23 wessels Exp $ * * DEBUG: section 9 File Transfer Protocol (FTP) * AUTHOR: Harvest Derived @@ -42,6 +41,7 @@ enum { FTP_TRIED_NLST, FTP_USE_BASE, FTP_ROOT_DIR, + FTP_NO_DOTDOT, FTP_HTML_HEADER_SENT }; @@ -265,7 +265,7 @@ ftpListingStart(FtpStateData * ftpState) storeAppendPrintf(e, "\n"); if (EBIT_TEST(ftpState->flags, FTP_USE_BASE)) storeAppendPrintf(e, "\n", - rfc1738_escape(ftpState->title_url)); + ftpState->title_url); storeAppendPrintf(e, "\n"); if (ftpState->cwd_message) { storeAppendPrintf(e, "
\n");
@@ -467,22 +467,12 @@ dots_fill(size_t len)
 static char *
 ftpHtmlifyListEntry(char *line, int flags)
 {
-    LOCAL_ARRAY(char, link, 2048);
+    LOCAL_ARRAY(char, link, 2048 + 40);
     LOCAL_ARRAY(char, icon, 2048);
     LOCAL_ARRAY(char, html, 8192);
     char *ename = NULL;
     size_t width = Config.Ftp.list_width;
     ftpListParts *parts;
-    /* check .. as special case */
-    if (!strcmp(line, "..")) {
-	snprintf(icon, 2048, "\"%-6s\"",
-	    "http://internal.squid/icons/",
-	    ICON_DIRUP,
-	    "[DIR]");
-	snprintf(link, 2048, "%s", "../", "Parent Directory");
-	snprintf(html, 8192, "%s %s\n", icon, link);
-	return html;
-    }
     if (strlen(line) > 1024) {
 	snprintf(html, 8192, "%s\n", line);
 	return html;
@@ -491,6 +481,41 @@ ftpHtmlifyListEntry(char *line, int flags)
 	snprintf(html, 8192, "%s\n", line);
 	return html;
     }
+    /* check .. as special case */
+    if (!strcmp(parts->name, "..")) {
+	snprintf(icon, 2048, "\"%-6s\"",
+	    "http://internal.squid/icons/",
+	    ICON_DIRUP,
+	    "[DIR]");
+	if (!EBIT_TEST(flags, FTP_NO_DOTDOT) && !EBIT_TEST(flags, FTP_ROOT_DIR)) {
+	    /* Normal directory */
+	    snprintf(link, 2048, "%s",
+		"../",
+		"Parent Directory");
+	} else if (!EBIT_TEST(flags, FTP_NO_DOTDOT) && EBIT_TEST(flags, FTP_ROOT_DIR)) {
+	    /* "Top level" directory */
+	    snprintf(link, 2048, "%s (%s)",
+		"%2e%2e/",
+		"Parent Directory",
+		"%2f/",
+		"Root Directory");
+	} else if (EBIT_TEST(flags, FTP_NO_DOTDOT) && !EBIT_TEST(flags, FTP_ROOT_DIR)) {
+	    /* Normal directory where last component is / or ..  */
+	    snprintf(link, 2048, "%s (%s)",
+		"%2e%2e/",
+		"Parent Directory",
+		"../",
+		"Up");
+	} else {		/* NO_DOTDOT && ROOT_DIR */
+	    /* "UNIX Root" directory */
+	    snprintf(link, 2048, "%s",
+		"../",
+		"Home Directory");
+	}
+	snprintf(html, 8192, "%s %s\n", icon, link);
+	ftpListPartsFree(&parts);
+	return html;
+    }
     if (!strcmp(parts->name, ".") || !strcmp(parts->name, "..")) {
 	*html = '\0';
 	ftpListPartsFree(&parts);
@@ -737,6 +762,30 @@ ftpCheckAuth(FtpStateData * ftpState, char *req_hdr)
     return 0;			/* different username */
 }
 
+static void
+ftpCheckUrlpath(FtpStateData * ftpState)
+{
+    request_t *request = ftpState->request;
+    int l;
+    l = strlen(request->urlpath);
+    EBIT_SET(ftpState->flags, FTP_USE_BASE);
+    /* check for null path */
+    if (*request->urlpath == '\0') {
+	xstrncpy(request->urlpath, "/", MAX_URL);
+	EBIT_SET(ftpState->flags, FTP_ISDIR);
+	EBIT_SET(ftpState->flags, FTP_ROOT_DIR);
+    } else if (!strcmp(request->urlpath, "/%2f/")) {
+	EBIT_SET(ftpState->flags, FTP_ISDIR);
+	EBIT_SET(ftpState->flags, FTP_ROOT_DIR);
+    } else if ((l >= 1) && (*(request->urlpath + l - 1) == '/')) {
+	EBIT_SET(ftpState->flags, FTP_ISDIR);
+	EBIT_CLR(ftpState->flags, FTP_USE_BASE);
+	if (l == 1)
+	    EBIT_SET(ftpState->flags, FTP_ROOT_DIR);
+    }
+}
+
+#ifdef OLD_FTP_CLEANUP
 static void
 ftpCleanupUrlpath(FtpStateData * ftpState)
 {
@@ -793,6 +842,7 @@ ftpCleanupUrlpath(FtpStateData * ftpState)
 	}
     } while (again);
 }
+#endif
 
 static void
 ftpBuildTitleUrl(FtpStateData * ftpState)
@@ -814,9 +864,13 @@ ftpBuildTitleUrl(FtpStateData * ftpState)
     strcat(t, request->host);
     if (request->port != urlDefaultPort(PROTO_FTP))
 	snprintf(&t[strlen(t)], len - strlen(t), ":%d", request->port);
+#ifdef OLD_FTP_CLEANUP
     strcat(t, "/");
     if (!EBIT_TEST(ftpState->flags, FTP_ROOT_DIR))
 	strcat(t, request->urlpath);
+#else
+    strcat(t, request->urlpath);
+#endif
 }
 
 void
@@ -852,7 +906,11 @@ ftpStart(request_t * request, StoreEntry * entry)
 	ftpStateFree(-1, ftpState);
 	return;
     }
+#ifdef OLD_FTP_CLEANUP
     ftpCleanupUrlpath(ftpState);
+#else
+    ftpCheckUrlpath(ftpState);
+#endif
     ftpBuildTitleUrl(ftpState);
     debug(9, 5) ("FtpStart: host=%s, path=%s, user=%s, passwd=%s\n",
 	ftpState->request->host, ftpState->request->urlpath,
@@ -1152,21 +1210,20 @@ ftpReadType(FtpStateData * ftpState)
     char *d;
     debug(9, 3) ("This is ftpReadType\n");
     if (code == 200) {
-	if (EBIT_TEST(ftpState->flags, FTP_ROOT_DIR)) {
-	    ftpSendPasv(ftpState);
-	} else {
-	    path = xstrdup(ftpState->request->urlpath);
-	    T = &ftpState->pathcomps;
-	    for (d = strtok(path, "/"); d; d = strtok(NULL, "/")) {
-		rfc1738_unescape(d);
-		w = xcalloc(1, sizeof(wordlist));
-		w->key = xstrdup(d);
-		*T = w;
-		T = &w->next;
-	    }
-	    xfree(path);
-	    ftpSendCwd(ftpState);
+	path = xstrdup(ftpState->request->urlpath);
+	T = &ftpState->pathcomps;
+	for (d = strtok(path, "/"); d; d = strtok(NULL, "/")) {
+	    rfc1738_unescape(d);
+	    w = xcalloc(1, sizeof(wordlist));
+	    w->key = xstrdup(d);
+	    *T = w;
+	    T = &w->next;
 	}
+	xfree(path);
+	if (ftpState->pathcomps)
+	    ftpSendCwd(ftpState);
+	else
+	    ftpSendPasv(ftpState);
     } else {
 	ftpFail(ftpState);
     }
@@ -1179,16 +1236,23 @@ ftpSendCwd(FtpStateData * ftpState)
     debug(9, 3) ("ftpSendCwd\n");
     if ((w = ftpState->pathcomps) == NULL) {
 	debug(9, 3) ("the final component was a directory\n");
-	EBIT_SET(ftpState->flags, FTP_ISDIR);
-	EBIT_SET(ftpState->flags, FTP_USE_BASE);
-	if (!EBIT_TEST(ftpState->flags, FTP_ROOT_DIR))
+	if (!EBIT_TEST(ftpState->flags, FTP_ISDIR)) {
+	    debug(9, 3) ("and path did not end in /\n");
 	    strcat(ftpState->title_url, "/");
+	    EBIT_SET(ftpState->flags, FTP_ISDIR);
+	    EBIT_SET(ftpState->flags, FTP_USE_BASE);
+	}
 	ftpSendPasv(ftpState);
 	return;
     }
     snprintf(cbuf, 1024, "CWD %s\r\n", w->key);
     ftpWriteCommand(cbuf, ftpState);
     ftpState->state = SENT_CWD;
+    if (!strcmp(w->key, "..") || !strcmp(w->key, "/")) {
+	EBIT_SET(ftpState->flags, FTP_NO_DOTDOT);
+    } else {
+	EBIT_CLR(ftpState->flags, FTP_NO_DOTDOT);
+    }
 }
 
 static void
-- 
2.47.3