--- /dev/null
+Index: lib/html_quote.c
+===================================================================
+RCS file: /server/cvs-server/squid/squid/lib/html_quote.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -c -r1.1 -r1.2
+*** lib/html_quote.c 2000/11/21 21:13:38 1.1
+--- lib/html_quote.c 2000/11/21 21:14:44 1.2
+***************
+*** 0 ****
+--- 1,134 ----
++ /*
++ * $Id$
++ *
++ * 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
++ */
++ {
++ '<', "<"
++ },
++ {
++ '>', ">"
++ },
++ {
++ '"', """
++ },
++ {
++ '&', "&"
++ },
++ {
++ '\'', "'"
++ },
++ {
++ 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: lib/Makefile.in
+===================================================================
+RCS file: /server/cvs-server/squid/squid/lib/Makefile.in,v
+retrieving revision 1.44.2.1
+retrieving revision 1.44.2.3
+diff -c -r1.44.2.1 -r1.44.2.3
+*** lib/Makefile.in 1999/07/07 19:14:26 1.44.2.1
+--- lib/Makefile.in 2000/11/21 21:19:40 1.44.2.3
+***************
+*** 39,44 ****
+--- 39,45 ----
+ Stack.o \
+ hash.o \
+ heap.o \
++ html_quote.o \
+ $(LIBOBJS)
+ REGEXOBJS = GNUregex.o
+ DLMALLOCOBJS = dlmalloc.o
+Index: include/util.h
+===================================================================
+RCS file: /server/cvs-server/squid/squid/include/util.h,v
+retrieving revision 1.53.4.2
+retrieving revision 1.53.4.3
+diff -c -r1.53.4.2 -r1.53.4.3
+*** include/util.h 1999/08/30 22:41:43 1.53.4.2
+--- include/util.h 2000/11/04 23:04:50 1.53.4.3
+***************
+*** 84,89 ****
+--- 84,92 ----
+ 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, void *), void *);
+ #endif
+Index: src/errorpage.c
+===================================================================
+RCS file: /server/cvs-server/squid/squid/src/errorpage.c,v
+retrieving revision 1.151.2.4
+retrieving revision 1.151.2.5
+diff -c -r1.151.2.4 -r1.151.2.5
+*** src/errorpage.c 2000/07/13 05:32:26 1.151.2.4
+--- src/errorpage.c 2000/11/04 23:04:51 1.151.2.5
+***************
+*** 423,428 ****
+--- 423,429 ----
+ 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,529 ****
+--- 525,531 ----
+ 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,566 ****
+--- 563,570 ----
+ 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: src/ftp.c
+===================================================================
+RCS file: /server/cvs-server/squid/squid/src/ftp.c,v
+retrieving revision 1.286.2.19
+retrieving revision 1.286.2.20
+diff -c -r1.286.2.19 -r1.286.2.20
+*** src/ftp.c 2000/03/16 06:24:36 1.286.2.19
+--- src/ftp.c 2000/11/04 23:04:51 1.286.2.20
+***************
+*** 354,375 ****
+ wordlist *w;
+ char *dirup;
+ int i, j, k;
+ 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);
+ storeAppendPrintf(e, "</TITLE>\n");
+ if (ftpState->flags.use_base)
+ storeAppendPrintf(e, "<BASE HREF=\"%s\">\n",
+! 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, "</PRE>\n");
+ storeAppendPrintf(e, "<HR>\n");
+ wordlistDestroy(&ftpState->cwd_message);
+--- 354,376 ----
+ 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",
+! html_quote(ftpState->title_url));
+ storeAppendPrintf(e, "</TITLE>\n");
+ if (ftpState->flags.use_base)
+ storeAppendPrintf(e, "<BASE HREF=\"%s\">\n",
+! 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", html_quote(w->key));
+ storeAppendPrintf(e, "</PRE>\n");
+ storeAppendPrintf(e, "<HR>\n");
+ wordlistDestroy(&ftpState->cwd_message);
+***************
+*** 378,402 ****
+ storeAppendPrintf(e, "FTP Directory: ");
+ /* "ftp://" == 6 characters */
+ assert(strlen(ftpState->title_url) >= 6);
+! for (i = 6, j = 0; ftpState->title_url[i]; j = i) {
+ storeAppendPrintf(e, "<A HREF=\"");
+! i += strcspn(&ftpState->title_url[i], "/");
+! if (ftpState->title_url[i] == '/')
+ i++;
+ for (k = 0; k < i; k++)
+! storeAppendPrintf(e, "%c", ftpState->title_url[k]);
+ storeAppendPrintf(e, "\">");
+ for (k = j; k < i - 1; k++)
+! storeAppendPrintf(e, "%c", ftpState->title_url[k]);
+ if (ftpState->title_url[k] != '/')
+! storeAppendPrintf(e, "%c", ftpState->title_url[k++]);
+ storeAppendPrintf(e, "</A>");
+ if (k < i)
+! storeAppendPrintf(e, "%c", ftpState->title_url[k++]);
+ if (i == j) {
+ /* Error guard, or "assert" */
+ storeAppendPrintf(e, "ERROR: Failed to parse URL: %s\n",
+! ftpState->title_url);
+ debug(9, 0) ("Failed to parse URL: %s\n", ftpState->title_url);
+ break;
+ }
+--- 379,404 ----
+ storeAppendPrintf(e, "FTP Directory: ");
+ /* "ftp://" == 6 characters */
+ assert(strlen(ftpState->title_url) >= 6);
+! title = html_quote(ftpState->title_url);
+! for (i = 6, j = 0; title[i]; j = i) {
+ storeAppendPrintf(e, "<A HREF=\"");
+! i += strcspn(&title[i], "/");
+! if (title[i] == '/')
+ i++;
+ for (k = 0; k < i; k++)
+! storeAppendPrintf(e, "%c", title[k]);
+ storeAppendPrintf(e, "\">");
+ for (k = j; k < i - 1; k++)
+! storeAppendPrintf(e, "%c", title[k]);
+ if (ftpState->title_url[k] != '/')
+! storeAppendPrintf(e, "%c", title[k++]);
+ storeAppendPrintf(e, "</A>");
+ if (k < i)
+! storeAppendPrintf(e, "%c", title[k++]);
+ if (i == j) {
+ /* Error guard, or "assert" */
+ storeAppendPrintf(e, "ERROR: Failed to parse URL: %s\n",
+! html_quote(ftpState->title_url));
+ debug(9, 0) ("Failed to parse URL: %s\n", ftpState->title_url);
+ break;
+ }
+***************
+*** 648,654 ****
+ return html;
+ }
+ /* Handle builtin <dirup> */
+! if (!strcmp(line, "<internal-dirup>")) {
+ /* <A HREF="{href}">{icon}</A> <A HREF="{href}">{text}</A> {link} */
+ snprintf(icon, 2048, "<IMG BORDER=0 SRC=\"%s\" ALT=\"%-6s\">",
+ mimeGetIconURL("internal-dirup"),
+--- 650,656 ----
+ return html;
+ }
+ /* Handle builtin <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,726 ****
+ mimeGetIconURL("internal-link"),
+ "[LINK]");
+ /* sometimes there is an 'l' flag, but no "->" link */
+! if (parts->link)
+ snprintf(link, 2048, " -> <A HREF=\"%s\">%s</A>",
+! rfc1738_escape(parts->link),
+! parts->link);
+ break;
+ case '\0':
+ snprintf(icon, 2048, "<IMG BORDER=0 SRC=\"%s\" ALT=\"%-6s\">",
+--- 719,731 ----
+ mimeGetIconURL("internal-link"),
+ "[LINK]");
+ /* sometimes there is an 'l' flag, but no "->" link */
+! if (parts->link) {
+! char *link2 = xstrdup(html_quote(rfc1738_escape(parts->link)));
+ snprintf(link, 2048, " -> <A HREF=\"%s\">%s</A>",
+! link2,
+! html_quote(parts->link));
+! safe_free(link2);
+! }
+ break;
+ case '\0':
+ snprintf(icon, 2048, "<IMG BORDER=0 SRC=\"%s\" ALT=\"%-6s\">",
+***************
+*** 728,734 ****
+ "[UNKNOWN]");
+ snprintf(chdir, 2048, " <A HREF=\"%s/;type=d\"><IMG BORDER=0 SRC=\"%s\" "
+ "ALT=\"[DIR]\"></A>",
+! rfc1738_escape(parts->name),
+ mimeGetIconURL("internal-dir"));
+ break;
+ case '-':
+--- 733,739 ----
+ "[UNKNOWN]");
+ snprintf(chdir, 2048, " <A HREF=\"%s/;type=d\"><IMG BORDER=0 SRC=\"%s\" "
+ "ALT=\"[DIR]\"></A>",
+! rfc1738_escape_part(parts->name),
+ mimeGetIconURL("internal-dir"));
+ break;
+ case '-':
+***************
+*** 755,767 ****
+ 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)),
+ 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)),
+ chdir, view, download, link);
+ }
+ ftpListPartsFree(&parts);
+--- 760,772 ----
+ 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, 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, html_quote(text), dots_fill(strlen(text)),
+ chdir, view, download, link);
+ }
+ ftpListPartsFree(&parts);
+Index: src/gopher.c
+===================================================================
+RCS file: /server/cvs-server/squid/squid/src/gopher.c,v
+retrieving revision 1.150.4.3
+retrieving revision 1.150.4.5
+diff -c -r1.150.4.3 -r1.150.4.5
+*** src/gopher.c 2000/04/07 20:32:29 1.150.4.3
+--- src/gopher.c 2000/11/10 21:20:49 1.150.4.5
+***************
+*** 470,488 ****
+ 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);
+ else
+! snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"telnet://%s/\">%s</A>\n",
+! icon_url, host, 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);
+ }
+ safe_free(escaped_selector);
+ strcat(outbuf, tmpbuf);
+--- 470,489 ----
+ 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%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%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, html_quote(name));
+ }
+ safe_free(escaped_selector);
+ strcat(outbuf, tmpbuf);
+***************
+*** 516,525 ****
+ 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);
+ gopherState->cso_recno = recno;
+ } else {
+! snprintf(tmpbuf, TEMP_BUF_SIZE, "%s\n", result);
+ }
+ strcat(outbuf, tmpbuf);
+ gopherState->data_in = 1;
+--- 517,526 ----
+ break;
+
+ if (gopherState->cso_recno != recno) {
+! 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", html_quote(result));
+ }
+ strcat(outbuf, tmpbuf);
+ gopherState->data_in = 1;
+***************
+*** 544,550 ****
+ case 502: /* Too Many Matches */
+ {
+ /* Print the message the server returns */
+! snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR><H2>%s</H2>\n<PRE>", result);
+ strcat(outbuf, tmpbuf);
+ gopherState->data_in = 1;
+ break;
+--- 545,551 ----
+ case 502: /* Too Many Matches */
+ {
+ /* Print the message the server returns */
+! snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR><H2>%s</H2>\n<PRE>", html_quote(result));
+ strcat(outbuf, tmpbuf);
+ gopherState->data_in = 1;
+ break;