* Adds API header file for this library.
* Reveals the do_escape API and creates meaningful flags for its API.
* Adds documentation.
* Convert original unit tests by Robert Collins to cppunit code
* Add new tests based on work for Samba by Andrew Bartlett
#define LDAP_DEPRECATED 1
+#include "rfc1738.h"
#include "util.h"
#include <stdio.h>
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "rfc1738.h"
#include "util.h"
#include <stdio.h>
*/
#include "config.h"
+#include "rfc1738.h"
#if HAVE_STDIO_H
#include <stdio.h>
* Compile this program with: gcc -o pam_auth pam_auth.c -lpam -ldl
*/
+#include "rfc1738.h"
#include "util.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include "rfc1738.h"
#include "util.h"
#ifdef HAVE_SASL_SASL_H
*/
#include "config.h"
+#include "rfc1738.h"
+
#if HAVE_STDIO_H
#include <stdio.h>
#endif
*/
#include "config.h"
+#include "rfc1738.h"
#if HAVE_STDIO_H
#include <stdio.h>
*
*/
+#include "rfc1738.h"
#include "util.h"
#include <stdio.h>
#define LDAP_DEPRECATED 1
+#include "rfc1738.h"
#include "util.h"
#include <stdio.h>
*
*/
+#include "rfc1738.h"
#include "util.h"
#include <stdio.h>
--- /dev/null
+#ifndef _SQUID_INCLUDE_RFC1738_H
+#define _SQUID_INCLUDE_RFC1738_H
+
+/* for SQUIDCEXTERN */
+#include "config.h"
+
+
+/* Encoder rfc1738_do_escape flag values. */
+#define RFC1738_ESCAPE_UNSAFE 0
+#define RFC1738_ESCAPE_RESERVED 1
+#define RFC1738_ESCAPE_UNESCAPED -1
+
+
+/**
+ * \group rfc1738 RFC 1738 URL-escaping library
+ *
+ * Public API is formed of a triplet of encode functions mapping to the rfc1738_do_encode() engine.
+ *
+ * ASCII characters are split into three groups:
+ * \item SAFE Characters which are safe to occur in any URL. For example A,B,C
+ * \item UNSAFE Characters which are completely usafe to occur in any URL. For example; backspace, tab, space, newline
+ * \item RESERVED Characters which are reserved for special meaning and may only occur in certain parts of a URL.
+ *
+ * Returns a static buffer containing the RFC 1738 compliant, escaped version of the given url.
+ *
+ * \param flags RFC1738_ESCAPE_UNSAFE Only encode unsafe characters. Ignore reserved.
+ * \param flags RFC1738_ESCAPE_RESERVED Encode all unsafe and reserved characters.
+ * \param flags RFC1738_ESCAPE_UNESCAPED Encode all unsafe characters which have not already been encoded.
+ */
+SQUIDCEXTERN char *rfc1738_do_escape(const char *url, int flags);
+
+/* Old API functions */
+#define rfc1738_escape(x) rfc1738_do_escape(x, RFC1738_ESCAPE_UNSAFE)
+#define rfc1738_escape_part(x) rfc1738_do_escape(x, RFC1738_ESCAPE_RESERVED)
+#define rfc1738_escape_unescaped(x) rfc1738_do_escape(x, RFC1738_ESCAPE_UNESCAPED)
+
+
+/**
+ * Unescape a URL string according to RFC 1738 specification.
+ * String is unescaped in-place
+ */
+SQUIDCEXTERN void rfc1738_unescape(char *url);
+
+
+#endif /* _SQUID_INCLUDE_RFC1738_H */
#include "SquidNew.h"
#endif
-/* rfc1738.c */
-SQUIDCEXTERN char *rfc1738_escape(const char *);
-SQUIDCEXTERN char *rfc1738_escape_unescaped(const char *);
-SQUIDCEXTERN char *rfc1738_escape_part(const char *);
-SQUIDCEXTERN void rfc1738_unescape(char *);
-
/* charset.c */
SQUIDCEXTERN char *latin1_to_utf8(char *out, size_t size, const char *in);
tests/testArray.cc \
tests/testRFC1035.h \
tests/testRFC1035.cc \
+ tests/testRFC1738.h \
+ tests/testRFC1738.cc \
tests/testMain.cc \
$(XPROF_STATS_SOURCE) \
$(WIN32SRC) \
*/
#include "config.h"
+#include "rfc1738.h"
+#include "util.h"
#if HAVE_STDIO_H
#include <stdio.h>
#include <string.h>
#endif
-#include "util.h"
-
/*
* RFC 1738 defines that these characters should be escaped, as well
* any non-US-ASCII character or anything between 0x00 - 0x1F.
* rfc1738_escape - Returns a static buffer contains the RFC 1738
* compliant, escaped version of the given url.
*/
-static char *
-rfc1738_do_escape(const char *url, int encode_reserved)
+char *
+rfc1738_do_escape(const char *url, int flags)
{
static char *buf;
static size_t bufsize = 0;
if (buf == NULL || strlen(url) * 3 > bufsize) {
xfree(buf);
bufsize = strlen(url) * 3 + 1;
- buf = xcalloc(bufsize, 1);
+ buf = (char*)xcalloc(bufsize, 1);
}
for (p = url, q = buf; *p != '\0' && q < (buf + bufsize - 1); p++, q++) {
do_escape = 0;
}
}
/* Handle % separately */
- if (encode_reserved >= 0 && *p == '%')
+ if (flags != RFC1738_ESCAPE_UNESCAPED && *p == '%')
do_escape = 1;
/* RFC 1738 defines these chars as reserved */
- for (i = 0; i < sizeof(rfc1738_reserved_chars) && encode_reserved > 0; i++) {
+ for (i = 0; i < sizeof(rfc1738_reserved_chars) && flags == RFC1738_ESCAPE_RESERVED; i++) {
if (*p == rfc1738_reserved_chars[i]) {
do_escape = 1;
break;
return (buf);
}
+#if 0 /* legacy API */
/*
* rfc1738_escape - Returns a static buffer that contains the RFC
* 1738 compliant, escaped version of the given url.
{
return rfc1738_do_escape(url, 1);
}
+#endif /* 0 */
/*
* rfc1738_unescape() - Converts escaped characters (%xy numbers) in
--- /dev/null
+#include "config.h"
+
+#if HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#include "testRFC1738.h"
+
+/* Being a C library code it is best bodily included and tested with C++ type-safe techniques. */
+#include "lib/rfc1738.c"
+
+CPPUNIT_TEST_SUITE_REGISTRATION( testRFC1738 );
+
+/* Regular Format de-coding tests */
+void testRFC1738::testUrlDecode()
+{
+ char *unescaped_str;
+
+ /* regular URL-path */
+ unescaped_str = xstrdup("%2Fdata%2Fsource%2Fpath");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "/data/source/path",18)==0);
+ xfree(unescaped_str);
+
+ /* path in full URL */
+ unescaped_str = xstrdup("http://foo.invalid%2Fdata%2Fsource%2Fpath");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "http://foo.invalid/data/source/path",36)==0);
+ xfree(unescaped_str);
+
+// TODO query string...
+
+ /* Newline %0A encoded */
+ unescaped_str = xstrdup("w%0Ard");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "w\nrd",5)==0);
+ xfree(unescaped_str);
+
+ /* Handle Un-encoded % */
+ unescaped_str = xstrdup("w%rd");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "w%rd",5)==0);
+ xfree(unescaped_str);
+
+ /* Handle encoded % */
+ unescaped_str = xstrdup("w%%rd");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "w%%rd",6)==0);
+ xfree(unescaped_str);
+
+ /* Handle mixed-encoded % */
+ unescaped_str = xstrdup("w%%%rd");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "w%%rd",6)==0);
+ xfree(unescaped_str);
+
+ /* A corrupt string */
+ unescaped_str = xstrdup("Bad String %1");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "Bad String %1",14)==0);
+ xfree(unescaped_str);
+
+
+ /* A partly corrupt string */
+ unescaped_str = xstrdup("Bad String %1A%3");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "Bad String \032%3",15)==0);
+ xfree(unescaped_str);
+
+ /* A non corrupt string */
+ unescaped_str = xstrdup("Good String %1A");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "Good String \032",14)==0);
+ xfree(unescaped_str);
+}
+
+/**
+ * Public API is formed of a triplet of encode functions mapping to the rfc1738_do_encode() engine.
+ *
+ * Flags:
+ * rfc1738_escape == 0
+ * rfc1738_escape_unescaped == -1
+ * rfc1738_escape_part == 1
+ */
+void testRFC1738::testUrlEncode()
+{
+ char *result;
+
+#define RFC1738_ESCAPE_UNSAFE 0
+#define RFC1738_ESCAPE_RESERVED 1
+#define RFC1738_ESCAPE_UNESCAPED -1
+
+ /* TEST: Escaping only unsafe characters */
+
+ /* regular URL (no encoding needed) */
+ result = rfc1738_do_escape("http://foo.invalid/data/source/path", RFC1738_ESCAPE_UNSAFE);
+ CPPUNIT_ASSERT(memcmp(result, "http://foo.invalid/data/source/path",36)==0);
+
+ /* long string of unsafe # characters */
+ result = rfc1738_do_escape("################ ################ ################ ################ ################ ################ ################ ################", RFC1738_ESCAPE_UNSAFE);
+ CPPUNIT_ASSERT(memcmp(result, "%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23",406)==0);
+
+
+ /* TEST: escaping only reserved characters */
+
+ /* regular URL (full encoding requested) */
+ result = rfc1738_do_escape("http://foo.invalid/data/source/path", RFC1738_ESCAPE_RESERVED);
+ CPPUNIT_ASSERT(memcmp(result, "http%3A%2F%2Ffoo.invalid%2Fdata%2Fsource%2Fpath",48)==0);
+
+ /* regular path (encoding wanted for ALL special chars) */
+ result = rfc1738_do_escape("/data/source/path", RFC1738_ESCAPE_RESERVED);
+ CPPUNIT_ASSERT(memcmp(result, "%2Fdata%2Fsource%2Fpath",24)==0);
+
+
+ /* TEST: safety-escaping a string already partially escaped */
+
+ /* escaping of dangerous characters in a partially escaped string */
+ result = rfc1738_do_escape("http://foo.invalid/data%2Fsource[]", RFC1738_ESCAPE_UNESCAPED);
+ CPPUNIT_ASSERT(memcmp(result, "http://foo.invalid/data%2Fsource%5B%5D",39)==0);
+
+ /* escaping of hexadecimal 0xFF characters in a partially escaped string */
+ result = rfc1738_do_escape("http://foo.invalid/data%2Fsource\xFF\xFF", RFC1738_ESCAPE_UNESCAPED);
+ CPPUNIT_ASSERT(memcmp(result, "http://foo.invalid/data%2Fsource%FF%FF",39)==0);
+
+}
+
+/** SECURITY BUG TESTS: avoid null truncation attacks by skipping %00 bytes */
+void testRFC1738::PercentZeroNullDecoding()
+{
+ char *unescaped_str;
+
+ /* Attack with %00 encoded NULL */
+ unescaped_str = xstrdup("w%00rd");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "w%00rd",7)==0);
+ xfree(unescaped_str);
+
+ /* Attack with %0 encoded NULL */
+ unescaped_str = xstrdup("w%0rd");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "w%0rd",6)==0);
+ xfree(unescaped_str);
+
+ /* Handle '0' bytes embeded in encoded % */
+ unescaped_str = xstrdup("w%%00%rd");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "w%00%rd",8)==0);
+ xfree(unescaped_str);
+
+ /* Handle NULL bytes with encoded % */
+ unescaped_str = xstrdup("w%%%00%rd");
+ rfc1738_unescape(unescaped_str);
+ CPPUNIT_ASSERT(memcmp(unescaped_str, "w%%00%rd",9)==0);
+ xfree(unescaped_str);
+}
--- /dev/null
+#ifndef SQUID_LIB_TEST_RFC1738_H
+#define SQUID_LIB_TEST_RFC1738_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+/**
+ * Test the URL coder RFC 1738 Engine
+ */
+class testRFC1738 : public CPPUNIT_NS::TestFixture
+{
+ CPPUNIT_TEST_SUITE( testRFC1738 );
+// CPPUNIT_TEST( testUrlDecode );
+// CPPUNIT_TEST( testUrlEncode );
+
+ CPPUNIT_TEST( PercentZeroNullDecoding );
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+
+protected:
+ void testUrlDecode();
+ void testUrlEncode();
+
+ // bugs.
+ void PercentZeroNullDecoding();
+};
+
+#endif /* SQUID_LIB_TEST_RFC1738_H */
#include "HttpReply.h"
#include "HttpRequest.h"
#include "MemBuf.h"
+#include "rfc1738.h"
#include "SquidTime.h"
static void accessLogSquid(AccessLogEntry * al, Logfile * logfile);
#include "acl/Url.h"
#include "acl/Checklist.h"
#include "acl/RegexData.h"
-
+#include "rfc1738.h"
int
ACLUrlStrategy::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist)
#include "acl/Checklist.h"
#include "acl/RegexData.h"
#include "HttpRequest.h"
-
+#include "rfc1738.h"
int
ACLUrlPathStrategy::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist)
#include "Store.h"
#include "HttpReply.h"
#include "basicScheme.h"
+#include "rfc1738.h"
#include "wordlist.h"
#include "SquidTime.h"
#include "acl/Gadgets.h"
#include "StoreFileSystem.h"
#include "Parsing.h"
+#include "rfc1738.h"
#include "MemBuf.h"
#include "wordlist.h"
#include "ident/Config.h"
#include "SquidTime.h"
#include "ChunkedCodingParser.h"
#include "eui/Config.h"
+#include "rfc1738.h"
#if LINGERING_CLOSE
#define comm_close comm_lingering_close
#include "MemObject.h"
#include "fde.h"
#include "MemBuf.h"
+#include "rfc1738.h"
#include "URLScheme.h"
#include "wordlist.h"
#include "auth/Gadgets.h"
#include "helper.h"
#include "MemBuf.h"
+#include "rfc1738.h"
#include "URLScheme.h"
#include "wordlist.h"
#include "SquidTime.h"
#include "URLScheme.h"
#include "SquidString.h"
+#include "rfc1738.h"
/**
\defgroup ServerProtocolFTPInternal Server-Side FTP Internals
#endif
#include "MemBuf.h"
#include "forward.h"
+#include "rfc1738.h"
#include "SquidTime.h"
/**
#include "MemBuf.h"
#include "MemObject.h"
#include "protos.h"
+#include "rfc1738.h"
#include "SquidTime.h"
#include "Store.h"
#include "TextException.h"
#include "SwapDir.h"
#include "icmp/net_db.h"
#include "ip/IpAddress.h"
+#include "rfc1738.h"
/// \ingroup ServerProtocolICPInternal2
static void icpLogIcp(const IpAddress &, log_type, int, const char *, int);
#include "comm.h"
#include "fde.h"
#include "ip/IpAddress.h"
+#include "rfc1738.h"
static const char *hello_string = "hi there\n";
#define HELLO_BUF_SZ 32
#include "HttpRequest.h"
#include "client_side.h"
#include "helper.h"
+#include "rfc1738.h"
typedef struct {
void *data;
#include "URL.h"
#include "HttpRequest.h"
#include "URLScheme.h"
+#include "rfc1738.h"
static HttpRequest *urnParse(const HttpRequestMethod& method, char *urn);
static const char valid_hostname_chars_u[] =
$(top_builddir)/src/globals.o \
$(top_builddir)/src/time.o
-EXTRA_PROGRAMS = mem_node_test membanger splay tcp-banger2 rfc1738
+EXTRA_PROGRAMS = mem_node_test membanger splay tcp-banger2
EXTRA_DIST = testheaders.sh
syntheticoperators \
VirtualDeleteOperator \
StackTest \
- rfc1738 \
refcount\
splay\
MemPoolTest\
mem_node_test\
mem_hdr_test \
refcount\
- rfc1738\
splay \
StackTest \
syntheticoperators \
syntheticoperators_SOURCES = syntheticoperators.cc $(DEBUG_SOURCE)
VirtualDeleteOperator_SOURCES = VirtualDeleteOperator.cc $(DEBUG_SOURCE)
-rfc1738_SOURCES = rfc1738.cc
-
## membanger won't link today. Bitrot..
##CC = gcc
##CFLAGS = -g -Wall -I../include -I../src
+++ /dev/null
-
-/*
- * $Id$
- *
- * DEBUG: section xx RFC 1738 string [un]escaping
- * AUTHOR: Robert Collins
- *
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; 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.
- *
- * Copyright (c) 2003 Robert Collins <robertc@squid-cache.org>
- */
-
-#include "squid.h"
-#include "util.h"
-/* testing:
-SQUIDCEXTERN char *rfc1738_escape(const char *);
-SQUIDCEXTERN char *rfc1738_escape_unescaped(const char *);
-SQUIDCEXTERN char *rfc1738_escape_part(const char *);
-SQUIDCEXTERN void rfc1738_unescape(char *);
-*/
-
-/* A corrupt string */
-#define BADSTRING "An Escaped %1"
-/* A partly corrupt string */
-#define CASE1 "An escaped %1A%3"
-#define RESULT1 "An escaped \032%3"
-/* A non corrupt string */
-#define GOODSTRING "An Escaped %1A"
-#define GOODUSTRING "An Escaped \032"
-
-void
-testAString(char const *aString, char const *aResult)
-{
- char *escapedString;
- escapedString = xstrdup (aString);
- rfc1738_unescape(escapedString);
- if (strcmp(escapedString, aResult))
- exit (1);
- safe_free (escapedString);
-}
-
-void
-testUnescaping()
-{
- testAString(BADSTRING,BADSTRING);
- testAString(GOODSTRING, GOODUSTRING);
- testAString(CASE1, RESULT1);
-}
-
-int
-main (int argc, char **argv)
-{
- testUnescaping();
- return 0;
-}
*/
#include "config.h"
+#include "rfc1738.h"
#if HAVE_UNISTD_H
#include <unistd.h>