]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
RFC 1738 encoder upgraded action flags
authorAmos Jeffries <squid3@treenet.co.nz>
Sun, 3 Apr 2011 11:16:42 +0000 (05:16 -0600)
committerAmos Jeffries <squid3@treenet.co.nz>
Sun, 3 Apr 2011 11:16:42 +0000 (05:16 -0600)
This updates the encoder flags parameter to allow selection of individual
character sets of CTRLS, UNSAFE, and RESERVED.

Also, to permit selective omission of the % and space characters from the
UNSAFE set.

Also, an optimization is added to skip SAFE characters on a short-circuit.

include/rfc1738.h
lib/rfc1738.c
lib/tests/testRFC1738.cc

index b3538ecad0045d8063c49de500eca9806658629a..0ab10cd3a7a9b726e619f9452d1f3a51c26fc960 100644 (file)
@@ -4,35 +4,46 @@
 /* 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
-
+#define RFC1738_ESCAPE_CTRLS       1
+#define RFC1738_ESCAPE_UNSAFE      2
+#define RFC1738_ESCAPE_RESERVED    4
+#define RFC1738_ESCAPE_ALL         (RFC1738_ESCAPE_UNSAFE|RFC1738_ESCAPE_RESERVED|RFC1738_ESCAPE_CTRLS)
+// exclusions
+#define RFC1738_ESCAPE_NOSPACE     128
+#define RFC1738_ESCAPE_NOPERCENT   256
+// Backward compatibility
+#define RFC1738_ESCAPE_UNESCAPED   (RFC1738_ESCAPE_UNSAFE|RFC1738_ESCAPE_CTRLS|RFC1738_ESCAPE_NOPERCENT)
 
 /**
  * \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
+ * ASCII characters are split into four groups:
+ * \item CTRLS    Binary control codes. Dangerous to include in URLs.
+ * \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.
+ * \param flags  RFC1738_ESCAPE_CTRLS     Encode the blatantly dangerous binary codes.
+ * \param flags  RFC1738_ESCAPE_UNSAFE    Encode printable unsafe characters (excluding CTRLs).
+ * \param flags  RFC1738_ESCAPE_RESERVED  Encode reserved characters.
+ * \param flags  RFC1738_ESCAPE_ALL       Encode all binary CTRL, unsafe and reserved characters.
+ * \param flags  RFC1738_ESCAPE_NOSPACE   Ignore the space whitespace character.
+ * \param flags  RFC1738_ESCAPE_NOPERCENT Ignore the escaping delimiter '%'.
  */
 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)
+/* Default RFC 1738 escaping. Escape all UNSAFE characters and binary CTRL codes */
+#define rfc1738_escape(x)  rfc1738_do_escape(x, RFC1738_ESCAPE_UNSAFE|RFC1738_ESCAPE_CTRLS)
+
+/* Escape a partial URL. Encoding every binary code, unsafe or reserved character. */
+#define rfc1738_escape_part(x)  rfc1738_do_escape(x, RFC1738_ESCAPE_ALL)
+
+/* Escape a URL. Encoding every unsafe characters but skipping reserved and already-encoded bytes.
+ * Suitable for safely encoding an absolute URL which may be encoded but is not trusted. */
+#define rfc1738_escape_unescaped(x)  rfc1738_do_escape(x, RFC1738_ESCAPE_UNSAFE|RFC1738_ESCAPE_CTRLS|RFC1738_ESCAPE_NOPERCENT)
 
 
 /**
index 70289b4545a53bd6237a06916051d88079271f6a..834410889e45d5e0be306b81513124c1f648afe7 100644 (file)
@@ -53,6 +53,7 @@ static char rfc1738_unsafe_chars[] = {
     (char) 0x22,               /* " */
     (char) 0x23,               /* # */
 #if 0                          /* done in code */
+    (char) 0x20,               /* space */
     (char) 0x25,               /* % */
 #endif
     (char) 0x7B,               /* { */
@@ -64,8 +65,7 @@ static char rfc1738_unsafe_chars[] = {
     (char) 0x5B,               /* [ */
     (char) 0x5D,               /* ] */
     (char) 0x60,               /* ` */
-    (char) 0x27,               /* ' */
-    (char) 0x20                        /* space */
+    (char) 0x27                /* ' */
 };
 
 static char rfc1738_reserved_chars[] = {
@@ -97,36 +97,49 @@ rfc1738_do_escape(const char *url, int flags)
         buf = (char*)xcalloc(bufsize, 1);
     }
     for (p = url, q = buf; *p != '\0' && q < (buf + bufsize - 1); p++, q++) {
+
+        /* a-z, A-Z and 0-9 are SAFE. */
+        if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9')) {
+            *q = *p;
+            continue;
+        }
+
         do_escape = 0;
 
         /* RFC 1738 defines these chars as unsafe */
-        for (i = 0; i < sizeof(rfc1738_unsafe_chars); i++) {
-            if (*p == rfc1738_unsafe_chars[i]) {
-                do_escape = 1;
-                break;
+        if ((flags & RFC1738_ESCAPE_UNSAFE)) {
+            for (i = 0; i < sizeof(rfc1738_unsafe_chars); i++) {
+                if (*p == rfc1738_unsafe_chars[i]) {
+                    do_escape = 1;
+                    break;
+                }
             }
+            /* Handle % separately */
+            if (!(flags & RFC1738_ESCAPE_NOPERCENT) && *p == '%')
+                do_escape = 1;
+            /* Handle space separately */
+            else if (!(flags & RFC1738_ESCAPE_NOSPACE) && *p <= ' ')
+                do_escape = 1;
         }
-        /* Handle % separately */
-        if (flags != RFC1738_ESCAPE_UNESCAPED && *p == '%')
-            do_escape = 1;
         /* RFC 1738 defines these chars as reserved */
-        for (i = 0; i < sizeof(rfc1738_reserved_chars) && flags == RFC1738_ESCAPE_RESERVED; i++) {
-            if (*p == rfc1738_reserved_chars[i]) {
-                do_escape = 1;
-                break;
+        if ((flags & RFC1738_ESCAPE_RESERVED) && do_escape == 0) {
+            for (i = 0; i < sizeof(rfc1738_reserved_chars); i++) {
+                if (*p == rfc1738_reserved_chars[i]) {
+                    do_escape = 1;
+                    break;
+                }
             }
         }
-        /* RFC 1738 says any control chars (0x00-0x1F) are encoded */
-        if ((unsigned char) *p <= (unsigned char) 0x1F) {
-            do_escape = 1;
-        }
-        /* RFC 1738 says 0x7f is encoded */
-        if (*p == (char) 0x7F) {
-            do_escape = 1;
-        }
-        /* RFC 1738 says any non-US-ASCII are encoded */
-        if (((unsigned char) *p >= (unsigned char) 0x80)) {
-            do_escape = 1;
+        if ((flags & RFC1738_ESCAPE_CTRLS) && do_escape == 0) {
+            /* RFC 1738 says any control chars (0x00-0x1F) are encoded */
+            if ((unsigned char) *p <= (unsigned char) 0x1F)
+                do_escape = 1;
+            /* RFC 1738 says 0x7f is encoded */
+            else if (*p == (char) 0x7F)
+                do_escape = 1;
+            /* RFC 1738 says any non-US-ASCII are encoded */
+            else if (((unsigned char) *p >= (unsigned char) 0x80))
+                do_escape = 1;
         }
         /* Do the triplet encoding, or just copy the char */
         /* note: we do not need snprintf here as q is appropriately
index e58fc1897aaf88dd64477f8eecddb6df5812728f..1ea61ed1c39657f5dae89e99e138e8049e69615b 100644 (file)
@@ -86,10 +86,6 @@ 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) */