This patch is generated from the xsitescript-20001104 branch of HEAD in squid
Thu Sep 11 11:58:08 2003 GMT
See http://devel.squid-cache.org/

Index: squid/include/util.h
diff -u squid/include/util.h:1.3 squid/include/util.h:1.3.6.1
--- squid/include/util.h:1.3	Mon Oct 23 08:04:18 2000
+++ squid/include/util.h	Sun Oct 29 14:59:56 2000
@@ -84,6 +84,9 @@
 extern char *rfc1738_escape_part(const char *);
 extern void rfc1738_unescape(char *);
 
+/* html.c */
+extern char *html_quote(const char *);
+
 #if XMALLOC_STATISTICS
 extern void malloc_statistics(void (*)(int, int, int, void *), void *);
 #endif
Index: squid/lib/Makefile.in
diff -u squid/lib/Makefile.in:1.3 squid/lib/Makefile.in:1.3.6.1
--- squid/lib/Makefile.in:1.3	Mon Oct 23 08:04:19 2000
+++ squid/lib/Makefile.in	Sun Oct 29 13:23:33 2000
@@ -39,6 +39,7 @@
 		  Stack.o \
 		  hash.o \
 		  heap.o \
+                  html.o \
 		  $(LIBOBJS)
 REGEXOBJS	= GNUregex.o
 DLMALLOCOBJS	= dlmalloc.o
Index: squid/lib/html.c
diff -u /dev/null squid/lib/html.c:1.1.2.4
--- /dev/null	Thu Sep 11 04:58:10 2003
+++ squid/lib/html.c	Sun Oct 29 14:59:32 2000
@@ -0,0 +1,122 @@
+/*
+ * $Id: squid-xsitescript-20001104-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $
+ * 
+ * DEBUG:
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by the
+ *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
+ *  the Regents of the University of California.  Please see the
+ *  COPYRIGHT file for full details.  Squid incorporates software
+ *  developed and/or copyrighted by other sources.  Please see the
+ *  CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "config.h"
+
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "util.h"
+#include "snprintf.h"
+
+/*  
+ *  HTML defines these characters as special entities that should be quoted.
+ */
+static struct {
+    unsigned char code;
+    char *quote;
+} htmlstandardentities[] =
+{
+    /* NOTE: The quoted form MUST not be larger than 6 character.
+     * see close to the MemPool commend below
+     */
+    { '<', "&lt;" },
+    { '>', "&gt;" },
+    { '"', "&quot;" },
+    { '&', "&amp;" },
+    { '\'', "&#39;" },
+    { 0, NULL }
+};
+
+/*
+ *  html_do_quote - Returns a static buffer containing the quoted 
+ *  string.
+ */
+char *
+html_quote(const char *string)
+{
+    static char *buf;
+    static size_t bufsize = 0;
+    const char *src;
+    char *dst;
+    int i;
+
+    /* XXX This really should be implemented using a MemPool, but
+     * MemPools are not yet available in lib...
+     */
+    if (buf == NULL || strlen(string) * 6 > bufsize) {
+	xfree(buf);
+	bufsize = strlen(string) * 6 + 1;
+	buf = xcalloc(bufsize, 1);
+    }
+    for (src = string, dst = buf; *src; src++) {
+	char *escape = NULL;
+	const unsigned char ch = *src;
+
+	/* Walk thru the list of HTML Entities that must be quoted to
+	 * display safely
+	 */
+	for (i = 0; htmlstandardentities[i].code; i++) {
+	    if (ch == htmlstandardentities[i].code) {
+		escape = htmlstandardentities[i].quote;
+		break;
+	    }
+	}
+	/* Encode control chars just to be on the safe side, and make
+	 * sure all 8-bit characters are encoded to protect from buggy
+	 * clients
+	 */
+	if ( !escape && (ch <= 0x1F || ch >= 0x7f) && ch != '\n' && ch != '\r' && ch != '\t' ) {
+	    static char dec_encoded[7];
+	    snprintf(dec_encoded, sizeof dec_encoded, "&#%3d;", (int) ch);
+	    escape = dec_encoded;
+	}
+
+	if (escape) {
+	    /* Ok, An escaped form was found above. Use it */
+	    strncpy(dst, escape, 6);
+	    dst += strlen(escape);
+	} else {
+	    /* Apparently there is no need to escape this character */
+	    *dst++ = ch;
+	}
+    }
+    /* Nullterminate and return the result */
+    *dst = '\0';
+    return (buf);
+}
Index: squid/src/errorpage.c
diff -u squid/src/errorpage.c:1.3 squid/src/errorpage.c:1.3.6.2
--- squid/src/errorpage.c:1.3	Mon Oct 23 08:04:21 2000
+++ squid/src/errorpage.c	Sun Oct 29 15:01:16 2000
@@ -423,6 +423,7 @@
     request_t *r = err->request;
     static MemBuf mb = MemBufNULL;
     const char *p = NULL;	/* takes priority over mb if set */
+    int do_quote = 1;
 
     memBufReset(&mb);
     switch (token) {
@@ -524,6 +525,7 @@
 	    memBufPrintf(&mb, "%s", sign_mb.buf);
 	    memBufClean(&sign_mb);
 	    err->page_id = saved_id;
+	    do_quote = 0;
 	} else {
 	    /* wow, somebody put %S into ERR_SIGNATURE, stop recursion */
 	    p = "[%S]";
@@ -561,6 +563,8 @@
 	p = mb.buf;		/* do not use mb after this assignment! */
     assert(p);
     debug(4, 3) ("errorConvert: %%%c --> '%s'\n", token, p);
+    if (do_quote)
+	p = html_quote(p);
     return p;
 }
 
Index: squid/src/ftp.c
diff -u squid/src/ftp.c:1.3 squid/src/ftp.c:1.3.6.1
--- squid/src/ftp.c:1.3	Mon Oct 23 08:04:21 2000
+++ squid/src/ftp.c	Sun Oct 29 15:43:21 2000
@@ -354,22 +354,23 @@
     wordlist *w;
     char *dirup;
     int i, j, k;
+    char *title;
     storeBuffer(e);
     storeAppendPrintf(e, "<!-- HTML listing generated by Squid %s -->\n",
 	version_string);
     storeAppendPrintf(e, "<!-- %s -->\n", mkrfc1123(squid_curtime));
     storeAppendPrintf(e, "<HTML><HEAD><TITLE>\n");
     storeAppendPrintf(e, "FTP Directory: %s\n",
-	ftpState->title_url);
+	html_quote(ftpState->title_url));
     storeAppendPrintf(e, "</TITLE>\n");
     if (ftpState->flags.use_base)
 	storeAppendPrintf(e, "<BASE HREF=\"%s\">\n",
-	    ftpState->base_href);
+	    html_quote(ftpState->base_href));
     storeAppendPrintf(e, "</HEAD><BODY>\n");
     if (ftpState->cwd_message) {
 	storeAppendPrintf(e, "<PRE>\n");
 	for (w = ftpState->cwd_message; w; w = w->next)
-	    storeAppendPrintf(e, "%s\n", w->key);
+	    storeAppendPrintf(e, "%s\n", html_quote(w->key));
 	storeAppendPrintf(e, "</PRE>\n");
 	storeAppendPrintf(e, "<HR>\n");
 	wordlistDestroy(&ftpState->cwd_message);
@@ -378,25 +379,26 @@
     storeAppendPrintf(e, "FTP Directory: ");
     /* "ftp://" == 6 characters */
     assert(strlen(ftpState->title_url) >= 6);
-    for (i = 6, j = 0; ftpState->title_url[i]; j = i) {
+    title = html_quote(ftpState->title_url);
+    for (i = 6, j = 0; title[i]; j = i) {
 	storeAppendPrintf(e, "<A HREF=\"");
-	i += strcspn(&ftpState->title_url[i], "/");
-	if (ftpState->title_url[i] == '/')
+	i += strcspn(&title[i], "/");
+	if (title[i] == '/')
 	    i++;
 	for (k = 0; k < i; k++)
-	    storeAppendPrintf(e, "%c", ftpState->title_url[k]);
+	    storeAppendPrintf(e, "%c", title[k]);
 	storeAppendPrintf(e, "\">");
 	for (k = j; k < i - 1; k++)
-	    storeAppendPrintf(e, "%c", ftpState->title_url[k]);
+	    storeAppendPrintf(e, "%c", title[k]);
 	if (ftpState->title_url[k] != '/')
-	    storeAppendPrintf(e, "%c", ftpState->title_url[k++]);
+	    storeAppendPrintf(e, "%c", title[k++]);
 	storeAppendPrintf(e, "</A>");
 	if (k < i)
-	    storeAppendPrintf(e, "%c", ftpState->title_url[k++]);
+	    storeAppendPrintf(e, "%c", title[k++]);
 	if (i == j) {
 	    /* Error guard, or "assert" */
 	    storeAppendPrintf(e, "ERROR: Failed to parse URL: %s\n",
-		ftpState->title_url);
+		html_quote(ftpState->title_url));
 	    debug(9, 0) ("Failed to parse URL: %s\n", ftpState->title_url);
 	    break;
 	}
@@ -648,7 +650,7 @@
 	return html;
     }
     /* Handle builtin <dirup> */
-    if (!strcmp(line, "<internal-dirup>")) {
+    if (strcmp(line, "<internal-dirup>") == 0) {
 	/* <A HREF="{href}">{icon}</A> <A HREF="{href}">{text}</A> {link} */
 	snprintf(icon, 2048, "<IMG BORDER=0 SRC=\"%s\" ALT=\"%-6s\">",
 	    mimeGetIconURL("internal-dirup"),
@@ -717,10 +719,13 @@
 	    mimeGetIconURL("internal-link"),
 	    "[LINK]");
 	/* sometimes there is an 'l' flag, but no "->" link */
-	if (parts->link)
+	if (parts->link) {
+	    char *link2 = xstrdup(html_quote(rfc1738_escape(parts->link)));
 	    snprintf(link, 2048, " -> <A HREF=\"%s\">%s</A>",
-		rfc1738_escape(parts->link),
-		parts->link);
+		link2,
+		html_quote(parts->link));
+	    safe_free(link2);
+	}
 	break;
     case '\0':
 	snprintf(icon, 2048, "<IMG BORDER=0 SRC=\"%s\" ALT=\"%-6s\">",
@@ -728,7 +733,7 @@
 	    "[UNKNOWN]");
 	snprintf(chdir, 2048, " <A HREF=\"%s/;type=d\"><IMG BORDER=0 SRC=\"%s\" "
 	    "ALT=\"[DIR]\"></A>",
-	    rfc1738_escape(parts->name),
+	    rfc1738_escape_part(parts->name),
 	    mimeGetIconURL("internal-dir"));
 	break;
     case '-':
@@ -755,13 +760,13 @@
     if (parts->type != '\0') {
 	snprintf(html, 8192, "<A HREF=\"%s\">%s</A> <A HREF=\"%s\">%s</A>%s "
 	    "%s%8s%s%s%s%s\n",
-	    href, icon, href, text, dots_fill(strlen(text)),
+	    href, icon, href, html_quote(text), dots_fill(strlen(text)),
 	    parts->date, size, chdir, view, download, link);
     } else {
 	/* Plain listing. {icon} {text} ... {chdir}{view}{download} */
 	snprintf(html, 8192, "<A HREF=\"%s\">%s</A> <A HREF=\"%s\">%s</A>%s "
 	    "%s%s%s%s\n",
-	    href, icon, href, text, dots_fill(strlen(text)),
+	    href, icon, href, html_quote(text), dots_fill(strlen(text)),
 	    chdir, view, download, link);
     }
     ftpListPartsFree(&parts);
Index: squid/src/gopher.c
diff -u squid/src/gopher.c:1.3 squid/src/gopher.c:1.3.6.1
--- squid/src/gopher.c:1.3	Mon Oct 23 08:04:21 2000
+++ squid/src/gopher.c	Sun Oct 29 16:01:49 2000
@@ -469,19 +469,20 @@
 			    break;
 			}
 
-
 			memset(tmpbuf, '\0', TEMP_BUF_SIZE);
 			if ((gtype == GOPHER_TELNET) || (gtype == GOPHER_3270)) {
 			    if (strlen(escaped_selector) != 0)
-				snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"telnet://%s@%s/\">%s</A>\n",
-				    icon_url, escaped_selector, host, name);
+				snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"telnet://%s@%s%s%s/\">%s</A>\n",
+				    icon_url, escaped_selector, rfc1738_escape_part(host), 
+				    *port ? ":" : "", port, html_quote(name));
 			    else
-				snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"telnet://%s/\">%s</A>\n",
-				    icon_url, host, name);
+				snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"telnet://%s%s%s/\">%s</A>\n",
+				    icon_url, rfc1738_escape_part(host), *port ? ":" : "",
+				    port, html_quote(name));
 
 			} else {
 			    snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"gopher://%s/%c%s\">%s</A>\n",
-				icon_url, host, gtype, escaped_selector, name);
+				icon_url, host, gtype, escaped_selector, html_quote(name));
 			}
 			safe_free(escaped_selector);
 			strcat(outbuf, tmpbuf);
@@ -515,10 +516,10 @@
 			break;
 
 		    if (gopherState->cso_recno != recno) {
-			snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR><H2>Record# %d<br><i>%s</i></H2>\n<PRE>", recno, result);
+			snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR><H2>Record# %d<br><i>%s</i></H2>\n<PRE>", recno, html_quote(result));
 			gopherState->cso_recno = recno;
 		    } else {
-			snprintf(tmpbuf, TEMP_BUF_SIZE, "%s\n", result);
+			snprintf(tmpbuf, TEMP_BUF_SIZE, "%s\n", html_quote(result));
 		    }
 		    strcat(outbuf, tmpbuf);
 		    gopherState->data_in = 1;
@@ -543,7 +544,7 @@
 		    case 502:	/* Too Many Matches */
 			{
 			    /* Print the message the server returns */
-			    snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR><H2>%s</H2>\n<PRE>", result);
+			    snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR><H2>%s</H2>\n<PRE>", html_quote(result));
 			    strcat(outbuf, tmpbuf);
 			    gopherState->data_in = 1;
 			    break;
squid-xsitescript-20001104-HEAD.new squid-xsitescript-20001104-HEAD differ: char 80, line 2