apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From minf...@apache.org
Subject svn commit: r1489517 - in /apr/apr/trunk: CHANGES Makefile.in encoding/ encoding/apr_escape.c include/apr_escape.h test/Makefile.in test/abts_tests.h test/testescape.c test/testutil.h tools/ tools/gen_test_char.c
Date Tue, 04 Jun 2013 17:02:18 GMT
Author: minfrin
Date: Tue Jun  4 17:02:17 2013
New Revision: 1489517

URL: http://svn.apache.org/r1489517
Log:
Add the apr_escape interface.

Added:
    apr/apr/trunk/encoding/apr_escape.c
    apr/apr/trunk/include/apr_escape.h
    apr/apr/trunk/test/testescape.c
    apr/apr/trunk/tools/   (with props)
    apr/apr/trunk/tools/gen_test_char.c
Modified:
    apr/apr/trunk/CHANGES
    apr/apr/trunk/Makefile.in
    apr/apr/trunk/encoding/   (props changed)
    apr/apr/trunk/test/Makefile.in
    apr/apr/trunk/test/abts_tests.h
    apr/apr/trunk/test/testutil.h

Modified: apr/apr/trunk/CHANGES
URL: http://svn.apache.org/viewvc/apr/apr/trunk/CHANGES?rev=1489517&r1=1489516&r2=1489517&view=diff
==============================================================================
--- apr/apr/trunk/CHANGES [utf-8] (original)
+++ apr/apr/trunk/CHANGES [utf-8] Tue Jun  4 17:02:17 2013
@@ -1,6 +1,8 @@
                                                      -*- coding: utf-8 -*-
 Changes for APR 2.0.0
 
+  *) Add the apr_escape interface. [Graham Leggett]
+     
   *) Add support to apr_memcache for unix domain sockets. PR 54573 [Remi
      Gacogne <rgacogne+asf aquaray.com>]
 

Modified: apr/apr/trunk/Makefile.in
URL: http://svn.apache.org/viewvc/apr/apr/trunk/Makefile.in?rev=1489517&r1=1489516&r2=1489517&view=diff
==============================================================================
--- apr/apr/trunk/Makefile.in (original)
+++ apr/apr/trunk/Makefile.in Tue Jun  4 17:02:17 2013
@@ -43,7 +43,7 @@ APRUTIL_EXPORT_LIBS = @APRUTIL_EXPORT_LI
 # building the entire package.
 #
 TARGETS = $(TARGET_LIB) $(APR_DSO_MODULES) \
-	apr.exp apr-config.out build/apr_rules.out
+	include/private/apr_escape_test_char.h apr.exp apr-config.out build/apr_rules.out
 
 LT_VERSION = @LT_VERSION@
 
@@ -52,7 +52,7 @@ LT_VERSION = @LT_VERSION@
 @INCLUDE_OUTPUTS@
 
 CLEAN_TARGETS = apr-config.out apr.exp exports.c export_vars.c .make.dirs \
-	build/apr_rules.out
+	build/apr_rules.out tools/gen_test_char
 DISTCLEAN_TARGETS = config.cache config.log config.status \
 	include/apr.h include/arch/unix/apr_private.h \
 	libtool $(APR_CONFIG) build/apr_rules.mk apr.pc \
@@ -157,5 +157,15 @@ check: $(TARGET_LIB)
 etags:
 	etags `find . -name '*.[ch]'`
 
+OBJECTS_gen_test_char = tools/gen_test_char.lo $(LOCAL_LIBS)
+tools/gen_test_char@EXEEXT@: $(OBJECTS_gen_test_char)
+	$(LINK_PROG) $(OBJECTS_gen_test_char) $(ALL_LIBS)
+
+include/private/apr_escape_test_char.h: tools/gen_test_char
+	tools/gen_test_char > include/private/apr_escape_test_char.h
+
+LINK_PROG = $(LIBTOOL) $(LTFLAGS) --mode=link $(COMPILE) $(LT_LDFLAGS) \
+	    @LT_NO_INSTALL@ $(ALL_LDFLAGS) -o $@
+
 # DO NOT REMOVE
 docs: $(INCDIR)/*.h

Propchange: apr/apr/trunk/encoding/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Tue Jun  4 17:02:17 2013
@@ -2,3 +2,6 @@ Makefile
 *.lo
 *.la
 .libs
+gen_test_char
+gen_test_char.exe
+test_char.h

Added: apr/apr/trunk/encoding/apr_escape.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/encoding/apr_escape.c?rev=1489517&view=auto
==============================================================================
--- apr/apr/trunk/encoding/apr_escape.c (added)
+++ apr/apr/trunk/encoding/apr_escape.c Tue Jun  4 17:02:17 2013
@@ -0,0 +1,1156 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* escape/unescape functions.
+ *
+ * These functions perform various escaping operations, and are provided in
+ * pairs, a function to query the length of and escape existing buffers, as
+ * well as companion functions to perform the same process to memory
+ * allocated from a pool.
+ *
+ * The API is designed to have the smallest possible RAM footprint, and so
+ * will only allocate the exact amount of RAM needed for each conversion.
+ */
+
+#include "apr_escape.h"
+#include "apr_escape_test_char.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+
+/* helper for Latin1 <-> entity encoding */
+#if APR_CHARSET_EBCDIC
+#include "apr_xlate.h"
+#define RAW_ASCII_CHAR(ch)  apr_xlate_conv_byte(ap_hdrs_from_ascii, \
+                                                (unsigned char)ch)
+#else /* APR_CHARSET_EBCDIC */
+#define RAW_ASCII_CHAR(ch)  (ch)
+#endif /* !APR_CHARSET_EBCDIC */
+
+/* we assume the folks using this ensure 0 <= c < 256... which means
+ * you need a cast to (unsigned char) first, you can't just plug a
+ * char in here and get it to work, because if char is signed then it
+ * will first be sign extended.
+ */
+#define TEST_CHAR(c, f)        (test_char_table[(unsigned)(c)] & (f))
+
+APR_DECLARE(apr_status_t) apr_escape_shell(char *escaped, const char *str,
+        apr_ssize_t slen, apr_size_t *len)
+{
+    unsigned char *d;
+    const unsigned char *s;
+    apr_size_t size = 1;
+    int found = 0;
+
+    d = (unsigned char *) escaped;
+    s = (const unsigned char *) str;
+
+    if (s) {
+        if (d) {
+            for (; *s && slen; ++s, slen--) {
+#if defined(OS2) || defined(WIN32)
+                /*
+                 * Newlines to Win32/OS2 CreateProcess() are ill advised.
+                 * Convert them to spaces since they are effectively white
+                 * space to most applications
+                 */
+                if (*s == '\r' || *s == '\n') {
+                    if (d) {
+                        *d++ = ' ';
+                        found = 1;
+                    }
+                    continue;
+                }
+#endif
+                if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
+                    *d++ = '\\';
+                    size++;
+                    found = 1;
+                }
+                *d++ = *s;
+                size++;
+            }
+            *d = '\0';
+        }
+        else {
+            for (; *s && slen; ++s, slen--) {
+                if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
+                    size++;
+                    found = 1;
+                }
+                size++;
+            }
+        }
+    }
+
+    if (len) {
+        *len = size;
+    }
+    if (!found) {
+        return APR_NOTFOUND;
+    }
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(const char *) apr_pescape_shell(apr_pool_t *p, const char *str)
+{
+    apr_size_t len;
+
+    switch (apr_escape_shell(NULL, str, APR_ESCAPE_STRING, &len)) {
+    case APR_SUCCESS: {
+        char *cmd = apr_palloc(p, len);
+        apr_escape_shell(cmd, str, APR_ESCAPE_STRING, NULL);
+        return cmd;
+    }
+    case APR_NOTFOUND: {
+        break;
+    }
+    }
+
+    return str;
+}
+
+static char x2c(const char *what)
+{
+    register char digit;
+
+#if !APR_CHARSET_EBCDIC
+    digit =
+            ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
+    digit *= 16;
+    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
+#else /*APR_CHARSET_EBCDIC*/
+    char xstr[5];
+    xstr[0]='0';
+    xstr[1]='x';
+    xstr[2]=what[0];
+    xstr[3]=what[1];
+    xstr[4]='\0';
+    digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
+            0xFF & strtol(xstr, NULL, 16));
+#endif /*APR_CHARSET_EBCDIC*/
+    return (digit);
+}
+
+APR_DECLARE(apr_status_t) apr_unescape_url(char *escaped, const char *url,
+        apr_ssize_t slen, const char *forbid, const char *reserved, int plus,
+        apr_size_t *len)
+{
+    apr_size_t size = 1;
+    int found = 0;
+    const char *s = (const char *) url;
+    char *d = (char *) escaped;
+    register int badesc, badpath;
+
+    if (!url) {
+        return APR_NOTFOUND;
+    }
+
+    badesc = 0;
+    badpath = 0;
+    if (s) {
+        if (d) {
+            for (; *s && slen; ++s, d++, slen--) {
+                if (plus && *s == '+') {
+                    *d = ' ';
+                    found = 1;
+                }
+                else if (*s != '%') {
+                    *d = *s;
+                }
+                else {
+                    if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) {
+                        badesc = 1;
+                        *d = '%';
+                    }
+                    else {
+                        char decoded;
+                        decoded = x2c(s + 1);
+                        if ((decoded == '\0')
+                                || (forbid && strchr(forbid, decoded))) {
+                            badpath = 1;
+                            *d = decoded;
+                            s += 2;
+                            slen -= 2;
+                        }
+                        else if (reserved && strchr(reserved, decoded)) {
+                            *d++ = *s++;
+                            *d++ = *s++;
+                            *d = *s;
+                            size += 2;
+                        }
+                        else {
+                            *d = decoded;
+                            s += 2;
+                            slen -= 2;
+                            found = 1;
+                        }
+                    }
+                }
+                size++;
+            }
+            *d = '\0';
+        }
+        else {
+            for (; *s && slen; ++s, slen--) {
+                if (plus && *s == '+') {
+                    found = 1;
+                }
+                else if (*s != '%') {
+                    /* character unchanged */
+                }
+                else {
+                    if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) {
+                        badesc = 1;
+                    }
+                    else {
+                        char decoded;
+                        decoded = x2c(s + 1);
+                        if ((decoded == '\0')
+                                || (forbid && strchr(forbid, decoded))) {
+                            badpath = 1;
+                            s += 2;
+                            slen -= 2;
+                        }
+                        else if (reserved && strchr(reserved, decoded)) {
+                            s += 2;
+                            slen -= 2;
+                            size += 2;
+                        }
+                        else {
+                            s += 2;
+                            slen -= 2;
+                            found = 1;
+                        }
+                    }
+                }
+                size++;
+            }
+        }
+    }
+
+    if (len) {
+        *len = size;
+    }
+    if (badesc) {
+        return APR_EINVAL;
+    }
+    else if (badpath) {
+        return APR_BADCH;
+    }
+    else if (!found) {
+        return APR_NOTFOUND;
+    }
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(const char *) apr_punescape_url(apr_pool_t *p, const char *url,
+        const char *forbid, const char *reserved, int plus)
+{
+    apr_size_t len;
+
+    switch (apr_unescape_url(NULL, url, APR_ESCAPE_STRING, forbid, reserved,
+            plus, &len)) {
+    case APR_SUCCESS: {
+        char *buf = apr_palloc(p, len);
+        apr_unescape_url(buf, url, APR_ESCAPE_STRING, forbid, reserved, plus,
+                NULL);
+        return buf;
+    }
+    case APR_EINVAL:
+    case APR_BADCH: {
+        return NULL;
+    }
+    case APR_NOTFOUND: {
+        break;
+    }
+    }
+
+    return url;
+}
+
+/* c2x takes an unsigned, and expects the caller has guaranteed that
+ * 0 <= what < 256... which usually means that you have to cast to
+ * unsigned char first, because (unsigned)(char)(x) first goes through
+ * signed extension to an int before the unsigned cast.
+ *
+ * The reason for this assumption is to assist gcc code generation --
+ * the unsigned char -> unsigned extension is already done earlier in
+ * both uses of this code, so there's no need to waste time doing it
+ * again.
+ */
+static const char c2x_table[] = "0123456789abcdef";
+
+static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
+        unsigned char *where)
+{
+#if APR_CHARSET_EBCDIC
+    what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
+#endif /*APR_CHARSET_EBCDIC*/
+    *where++ = prefix;
+    *where++ = c2x_table[what >> 4];
+    *where++ = c2x_table[what & 0xf];
+    return where;
+}
+
+APR_DECLARE(apr_status_t) apr_escape_path_segment(char *escaped,
+        const char *str, apr_ssize_t slen, apr_size_t *len)
+{
+    apr_size_t size = 1;
+    int found = 0;
+    const unsigned char *s = (const unsigned char *) str;
+    unsigned char *d = (unsigned char *) escaped;
+    unsigned c;
+
+    if (s) {
+        if (d) {
+            while ((c = *s) && slen) {
+                if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
+                    d = c2x(c, '%', d);
+                    size += 2;
+                    found = 1;
+                }
+                else {
+                    *d++ = c;
+                }
+                ++s;
+                size++;
+                slen--;
+            }
+            *d = '\0';
+        }
+        else {
+            while ((c = *s) && slen) {
+                if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
+                    size += 2;
+                    found = 1;
+                }
+                ++s;
+                size++;
+                slen--;
+            }
+        }
+    }
+
+    if (len) {
+        *len = size;
+    }
+    if (!found) {
+        return APR_NOTFOUND;
+    }
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(const char *) apr_pescape_path_segment(apr_pool_t *p,
+        const char *str)
+{
+    apr_size_t len;
+
+    switch (apr_escape_path_segment(NULL, str, APR_ESCAPE_STRING, &len)) {
+    case APR_SUCCESS: {
+        char *cmd = apr_palloc(p, len);
+        apr_escape_path_segment(cmd, str, APR_ESCAPE_STRING, NULL);
+        return cmd;
+    }
+    case APR_NOTFOUND: {
+        break;
+    }
+    }
+
+    return str;
+}
+
+APR_DECLARE(apr_status_t) apr_escape_path(char *escaped, const char *path,
+        apr_ssize_t slen, int partial, apr_size_t *len)
+{
+    apr_size_t size = 1;
+    int found = 0;
+    const unsigned char *s = (const unsigned char *) path;
+    unsigned char *d = (unsigned char *) escaped;
+    unsigned c;
+
+    if (!path) {
+        return APR_NOTFOUND;
+    }
+
+    if (!partial) {
+        const char *colon = strchr(path, ':');
+        const char *slash = strchr(path, '/');
+
+        if (colon && (!slash || colon < slash)) {
+            if (d) {
+                *d++ = '.';
+                *d++ = '/';
+            }
+            size += 2;
+            found = 1;
+        }
+    }
+    if (d) {
+        while ((c = *s) && slen) {
+            if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
+                d = c2x(c, '%', d);
+            }
+            else {
+                *d++ = c;
+            }
+            ++s;
+            size++;
+            slen--;
+        }
+        *d = '\0';
+    }
+    else {
+        while ((c = *s) && slen) {
+            if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
+                size += 2;
+                found = 1;
+            }
+            ++s;
+            size++;
+            slen--;
+        }
+    }
+
+    if (len) {
+        *len = size;
+    }
+    if (!found) {
+        return APR_NOTFOUND;
+    }
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(const char *) apr_pescape_path(apr_pool_t *p, const char *str,
+        int partial)
+{
+    apr_size_t len;
+
+    switch (apr_escape_path(NULL, str, APR_ESCAPE_STRING, partial, &len)) {
+    case APR_SUCCESS: {
+        char *path = apr_palloc(p, len);
+        apr_escape_path(path, str, APR_ESCAPE_STRING, partial, NULL);
+        return path;
+    }
+    case APR_NOTFOUND: {
+        break;
+    }
+    }
+
+    return str;
+}
+
+APR_DECLARE(apr_status_t) apr_escape_urlencoded(char *escaped, const char *str,
+        apr_ssize_t slen, apr_size_t *len)
+{
+    apr_size_t size = 1;
+    int found = 0;
+    const unsigned char *s = (const unsigned char *) str;
+    unsigned char *d = (unsigned char *) escaped;
+    unsigned c;
+
+    if (s) {
+        if (d) {
+            while ((c = *s) && slen) {
+                if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
+                    d = c2x(c, '%', d);
+                    size += 2;
+                    found = 1;
+                }
+                else if (c == ' ') {
+                    *d++ = '+';
+                    found = 1;
+                }
+                else {
+                    *d++ = c;
+                }
+                ++s;
+                size++;
+                slen--;
+            }
+            *d = '\0';
+        }
+        else {
+            while ((c = *s) && slen) {
+                if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
+                    size += 2;
+                    found = 1;
+                }
+                else if (c == ' ') {
+                    found = 1;
+                }
+                ++s;
+                size++;
+                slen--;
+            }
+        }
+    }
+
+    if (len) {
+        *len = size;
+    }
+    if (!found) {
+        return APR_NOTFOUND;
+    }
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(const char *) apr_pescape_urlencoded(apr_pool_t *p, const char *str)
+{
+    apr_size_t len;
+
+    switch (apr_escape_urlencoded(NULL, str, APR_ESCAPE_STRING, &len)) {
+    case APR_SUCCESS: {
+        char *encoded = apr_palloc(p, len);
+        apr_escape_urlencoded(encoded, str, APR_ESCAPE_STRING, NULL);
+        return encoded;
+    }
+    case APR_NOTFOUND: {
+        break;
+    }
+    }
+
+    return str;
+}
+
+APR_DECLARE(apr_status_t) apr_escape_entity(char *escaped, const char *str,
+        apr_ssize_t slen, int toasc, apr_size_t *len)
+{
+    apr_size_t size = 1;
+    int found = 0;
+    const unsigned char *s = (const unsigned char *) str;
+    unsigned char *d = (unsigned char *) escaped;
+    unsigned c;
+
+    if (s) {
+        if (d) {
+            while ((c = *s) && slen) {
+                if (TEST_CHAR(c, T_ESCAPE_XML)) {
+                    switch (c) {
+                    case '>': {
+                        memcpy(d, "&gt;", 4);
+                        size += 4;
+                        d += 4;
+                        break;
+                    }
+                    case '<': {
+                        memcpy(d, "&lt;", 4);
+                        size += 4;
+                        d += 4;
+                        break;
+                    }
+                    case '&': {
+                        memcpy(d, "&amp;", 5);
+                        size += 5;
+                        d += 5;
+                        break;
+                    }
+                    case '\"': {
+                        memcpy(d, "&quot;", 6);
+                        size += 6;
+                        d += 6;
+                        break;
+                    }
+                    case '\'': {
+                        memcpy(d, "&apos;", 6);
+                        size += 6;
+                        d += 6;
+                        break;
+                    }
+                    }
+                    found = 1;
+                }
+                else if (toasc && !apr_isascii(c)) {
+                    int offset = apr_snprintf((char *) d, 6, "&#%3.3d;", c);
+                    size += offset;
+                    d += offset;
+                    found = 1;
+                }
+                else {
+                    *d++ = c;
+                    size++;
+                }
+                ++s;
+                slen--;
+            }
+            *d = '\0';
+        }
+        else {
+            while ((c = *s) && slen) {
+                if (TEST_CHAR(c, T_ESCAPE_XML)) {
+                    switch (c) {
+                    case '>': {
+                        size += 4;
+                        break;
+                    }
+                    case '<': {
+                        size += 4;
+                        break;
+                    }
+                    case '&': {
+                        size += 5;
+                        break;
+                    }
+                    case '\"': {
+                        size += 6;
+                        break;
+                    }
+                    case '\'': {
+                        size += 6;
+                        break;
+                    }
+                    }
+                    found = 1;
+                }
+                else if (toasc && !apr_isascii(c)) {
+                    char buf[8];
+                    size += apr_snprintf(buf, 6, "&#%3.3d;", c);
+                    found = 1;
+                }
+                else {
+                    size++;
+                }
+                ++s;
+                slen--;
+            }
+        }
+    }
+
+    if (len) {
+        *len = size;
+    }
+    if (!found) {
+        return APR_NOTFOUND;
+    }
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(const char *) apr_pescape_entity(apr_pool_t *p, const char *str,
+        int toasc)
+{
+    apr_size_t len;
+
+    switch (apr_escape_entity(NULL, str, APR_ESCAPE_STRING, toasc, &len)) {
+    case APR_SUCCESS: {
+        char *cmd = apr_palloc(p, len);
+        apr_escape_entity(cmd, str, APR_ESCAPE_STRING, toasc, NULL);
+        return cmd;
+    }
+    case APR_NOTFOUND: {
+        break;
+    }
+    }
+
+    return str;
+}
+
+/* maximum length of any ISO-LATIN-1 HTML entity name. */
+#define MAXENTLEN (6)
+
+APR_DECLARE(apr_status_t) apr_unescape_entity(char *unescaped, const char *str,
+        apr_ssize_t slen, apr_size_t *len)
+{
+    int found = 0;
+    apr_size_t size = 1;
+    int val, i, j;
+    char *d = unescaped;
+    const char *s = str;
+    const char *ents;
+    static const char * const entlist[MAXENTLEN + 1] =
+    {
+            NULL, /* 0 */
+            NULL, /* 1 */
+            "lt\074gt\076", /* 2 */
+            "amp\046ETH\320eth\360", /* 3 */
+            "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml"
+            "\353iuml\357ouml\366uuml\374yuml\377", /* 4 */
+            "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc"
+            "\333THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352"
+            "icirc\356ocirc\364ucirc\373thorn\376", /* 5 */
+            "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311"
+            "Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde"
+            "\325Oslash\330Ugrave\331Uacute\332Yacute\335agrave\340"
+            "aacute\341atilde\343ccedil\347egrave\350eacute\351igrave"
+            "\354iacute\355ntilde\361ograve\362oacute\363otilde\365"
+            "oslash\370ugrave\371uacute\372yacute\375" /* 6 */
+    };
+
+    if (s) {
+        if (d) {
+            for (; *s != '\0' && slen; s++, d++, size++, slen--) {
+                if (*s != '&') {
+                    *d = *s;
+                    continue;
+                }
+                /* find end of entity */
+                for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0;
+                        i++) {
+                    continue;
+                }
+
+                if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */
+                    *d = *s;
+                    continue;
+                }
+
+                /* is it numeric ? */
+                if (s[1] == '#') {
+                    for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) {
+                        val = val * 10 + s[j] - '0';
+                    }
+                    s += i;
+                    if (j < i || val <= 8 || (val >= 11 && val <= 31)
+                            || (val >= 127 && val <= 160) || val >= 256) {
+                        d--; /* no data to output */
+                        size--;
+                    }
+                    else {
+                        *d = RAW_ASCII_CHAR(val);
+                        found = 1;
+                    }
+                }
+                else {
+                    j = i - 1;
+                    if (j > MAXENTLEN || entlist[j] == NULL) {
+                        /* wrong length */
+                        *d = '&';
+                        continue; /* skip it */
+                    }
+                    for (ents = entlist[j]; *ents != '\0'; ents += i) {
+                        if (strncmp(s + 1, ents, j) == 0) {
+                            break;
+                        }
+                    }
+
+                    if (*ents == '\0') {
+                        *d = '&'; /* unknown */
+                    }
+                    else {
+                        *d = RAW_ASCII_CHAR(((const unsigned char *) ents)[j]);
+                        s += i;
+                        slen -= i;
+                        found = 1;
+                    }
+                }
+            }
+            *d = '\0';
+        }
+        else {
+            for (; *s != '\0' && slen; s++, size++, slen--) {
+                if (*s != '&') {
+                    continue;
+                }
+                /* find end of entity */
+                for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0;
+                        i++) {
+                    continue;
+                }
+
+                if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */
+                    continue;
+                }
+
+                /* is it numeric ? */
+                if (s[1] == '#') {
+                    for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) {
+                        val = val * 10 + s[j] - '0';
+                    }
+                    s += i;
+                    if (j < i || val <= 8 || (val >= 11 && val <= 31)
+                            || (val >= 127 && val <= 160) || val >= 256) {
+                        /* no data to output */
+                        size--;
+                    }
+                    else {
+                        found = 1;
+                    }
+                }
+                else {
+                    j = i - 1;
+                    if (j > MAXENTLEN || entlist[j] == NULL) {
+                        /* wrong length */
+                        continue; /* skip it */
+                    }
+                    for (ents = entlist[j]; *ents != '\0'; ents += i) {
+                        if (strncmp(s + 1, ents, j) == 0) {
+                            break;
+                        }
+                    }
+
+                    if (*ents == '\0') {
+                        /* unknown */
+                    }
+                    else {
+                        s += i;
+                        slen -= i;
+                        found = 1;
+                    }
+                }
+            }
+        }
+    }
+
+    if (len) {
+        *len = size;
+    }
+    if (!found) {
+        return APR_NOTFOUND;
+    }
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(const char *) apr_punescape_entity(apr_pool_t *p, const char *str)
+{
+    apr_size_t len;
+
+    switch (apr_unescape_entity(NULL, str, APR_ESCAPE_STRING, &len)) {
+    case APR_SUCCESS: {
+        char *cmd = apr_palloc(p, len);
+        apr_unescape_entity(cmd, str, APR_ESCAPE_STRING, NULL);
+        return cmd;
+    }
+    case APR_NOTFOUND: {
+        break;
+    }
+    }
+
+    return str;
+}
+
+APR_DECLARE(apr_status_t) apr_escape_echo(char *escaped, const char *str,
+        apr_ssize_t slen, int quote, apr_size_t *len)
+{
+    apr_size_t size = 1;
+    int found = 0;
+    const unsigned char *s = (const unsigned char *) str;
+    unsigned char *d = (unsigned char *) escaped;
+    unsigned c;
+
+    if (s) {
+        if (d) {
+            while ((c = *s) && slen) {
+                if (TEST_CHAR(c, T_ESCAPE_ECHO)) {
+                    *d++ = '\\';
+                    size++;
+                    switch (c) {
+                    case '\a':
+                        *d++ = 'a';
+                        size++;
+                        found = 1;
+                        break;
+                    case '\b':
+                        *d++ = 'b';
+                        size++;
+                        found = 1;
+                        break;
+                    case '\e':
+                        *d++ = 'e';
+                        size++;
+                        found = 1;
+                        break;
+                    case '\f':
+                        *d++ = 'f';
+                        size++;
+                        found = 1;
+                        break;
+                    case '\n':
+                        *d++ = 'n';
+                        size++;
+                        found = 1;
+                        break;
+                    case '\r':
+                        *d++ = 'r';
+                        size++;
+                        found = 1;
+                        break;
+                    case '\t':
+                        *d++ = 't';
+                        size++;
+                        found = 1;
+                        break;
+                    case '\v':
+                        *d++ = 'v';
+                        size++;
+                        found = 1;
+                        break;
+                    case '\\':
+                        *d++ = '\\';
+                        size++;
+                        found = 1;
+                        break;
+                    case '"':
+                        if (quote) {
+                            *d++ = c;
+                            size++;
+                            found = 1;
+                        }
+                        else {
+                            d[-1] = c;
+                        }
+                        break;
+                    default:
+                        c2x(c, 'x', d);
+                        d += 3;
+                        size += 3;
+                        found = 1;
+                        break;
+                    }
+                }
+                else {
+                    *d++ = c;
+                    size++;
+                }
+                ++s;
+                slen--;
+            }
+            *d = '\0';
+        }
+        else {
+            while ((c = *s) && slen) {
+                if (TEST_CHAR(c, T_ESCAPE_ECHO)) {
+                    size++;
+                    switch (c) {
+                    case '\a':
+                    case '\b':
+                    case '\e':
+                    case '\f':
+                    case '\n':
+                    case '\r':
+                    case '\t':
+                    case '\v':
+                    case '\\':
+                        size++;
+                        found = 1;
+                        break;
+                    case '"':
+                        if (quote) {
+                            size++;
+                            found = 1;
+                        }
+                        break;
+                    default:
+                        size += 3;
+                        found = 1;
+                        break;
+                    }
+                }
+                else {
+                    size++;
+                }
+                ++s;
+                slen--;
+            }
+        }
+    }
+
+    if (len) {
+        *len = size;
+    }
+    if (!found) {
+        return APR_NOTFOUND;
+    }
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(const char *) apr_pescape_echo(apr_pool_t *p, const char *str,
+        int quote)
+{
+    apr_size_t len;
+
+    switch (apr_escape_echo(NULL, str, APR_ESCAPE_STRING, quote, &len)) {
+    case APR_SUCCESS: {
+        char *cmd = apr_palloc(p, len);
+        apr_escape_echo(cmd, str, APR_ESCAPE_STRING, quote, NULL);
+        return cmd;
+    }
+    case APR_NOTFOUND: {
+        break;
+    }
+    }
+
+    return str;
+}
+
+APR_DECLARE(apr_status_t) apr_escape_hex(char *dest, const void *src,
+        apr_size_t srclen, int colon, apr_size_t *len)
+{
+    const unsigned char *in = src;
+    apr_size_t size;
+
+    if (!src) {
+        return APR_NOTFOUND;
+    }
+
+    if (dest) {
+        for (size = 0; size < srclen; size++) {
+            if (colon && size) {
+                *dest++ = ':';
+            }
+            *dest++ = c2x_table[in[size] >> 4];
+            *dest++ = c2x_table[in[size] & 0xf];
+        }
+        *dest = '\0';
+    }
+
+    if (len) {
+        if (colon && srclen) {
+            *len = srclen * 3;
+        }
+        else {
+            *len = srclen * 2 + 1;
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(const char *) apr_pescape_hex(apr_pool_t *p, const void *src,
+        apr_size_t srclen, int colon)
+{
+    apr_size_t len;
+
+    switch (apr_escape_hex(NULL, src, srclen, colon, &len)) {
+    case APR_SUCCESS: {
+        char *cmd = apr_palloc(p, len);
+        apr_escape_hex(cmd, src, srclen, colon, NULL);
+        return cmd;
+    }
+    case APR_NOTFOUND: {
+        break;
+    }
+    }
+
+    return src;
+}
+
+APR_DECLARE(apr_status_t) apr_unescape_hex(void *dest, const char *str,
+        apr_ssize_t slen, int colon, apr_size_t *len)
+{
+    apr_size_t size = 0;
+    int flip = 0;
+    const unsigned char *s = (const unsigned char *) str;
+    unsigned char *d = (unsigned char *) dest;
+    unsigned c;
+    unsigned char u = 0;
+
+    if (s) {
+        if (d) {
+            while ((c = *s) && slen) {
+
+                if (!flip) {
+                    u = 0;
+                }
+
+                if (colon && c == ':' && !flip) {
+                    ++s;
+                    slen--;
+                    continue;
+                }
+                else if (apr_isdigit(c)) {
+                    u |= c - '0';
+                }
+                else if (apr_isupper(c) && c <= 'F') {
+                    u |= c - ('A' - 10);
+                }
+                else if (apr_islower(c) && c <= 'f') {
+                    u |= c - ('a' - 10);
+                }
+                else {
+                    return APR_BADCH;
+                }
+
+                if (flip) {
+                    *d++ = u;
+                    size++;
+                }
+                else {
+                    u <<= 4;
+                    *d = u;
+                }
+                flip = !flip;
+
+                ++s;
+                slen--;
+            }
+        }
+        else {
+            while ((c = *s) && slen) {
+
+                if (colon && c == ':' && !flip) {
+                    ++s;
+                    slen--;
+                    continue;
+                }
+                else if (apr_isdigit(c)) {
+                    /* valid */
+                }
+                else if (apr_isupper(c) && c <= 'F') {
+                    /* valid */
+                }
+                else if (apr_islower(c) && c <= 'f') {
+                    /* valid */
+                }
+                else {
+                    return APR_BADCH;
+                }
+
+                if (flip) {
+                    size++;
+                }
+                flip = !flip;
+
+                ++s;
+                slen--;
+            }
+        }
+    }
+
+    if (len) {
+        *len = size;
+    }
+    if (!s) {
+        return APR_NOTFOUND;
+    }
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(const void *) apr_punescape_hex(apr_pool_t *p, const char *str,
+        int colon, apr_size_t *len)
+{
+    apr_size_t size;
+
+    switch (apr_unescape_hex(NULL, str, APR_ESCAPE_STRING, colon, &size)) {
+    case APR_SUCCESS: {
+        void *cmd = apr_palloc(p, size);
+        apr_unescape_hex(cmd, str, APR_ESCAPE_STRING, colon, len);
+        return cmd;
+    }
+    case APR_BADCH:
+    case APR_NOTFOUND: {
+        break;
+    }
+    }
+
+    return NULL;
+}

Added: apr/apr/trunk/include/apr_escape.h
URL: http://svn.apache.org/viewvc/apr/apr/trunk/include/apr_escape.h?rev=1489517&view=auto
==============================================================================
--- apr/apr/trunk/include/apr_escape.h (added)
+++ apr/apr/trunk/include/apr_escape.h Tue Jun  4 17:02:17 2013
@@ -0,0 +1,375 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file apr_escape.h
+ * @brief APR-UTIL Escaping
+ */
+#ifndef APR_ESCAPE_H
+#define APR_ESCAPE_H
+#include "apu.h"
+#include "apr_general.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup APR_Util_Escaping Escape functions
+ * @ingroup APR
+ * @{
+ */
+
+/* Simple escape/unescape functions.
+ *
+ */
+
+/**
+ * When passing a string to one of the escape functions, this value can be
+ * passed to indicate a string-valued key, and have the length computed
+ * automatically.
+ */
+#define APR_ESCAPE_STRING     (-1)
+
+/**
+ * Perform shell escaping on the provided string.
+ * 
+ * Shell escaping causes characters to be prefixed with a '\' character.
+ * @param escaped Optional buffer to write the encoded string, can be
+ * NULL
+ * @param str The original string
+ * @param slen The length of the original string, or APR_ESCAPE_STRING
+ * @param len If present, returns the length of the string
+ * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were
+ * detected or the string was NULL
+ */
+APR_DECLARE(apr_status_t) apr_escape_shell(char *escaped, const char *str,
+        apr_ssize_t slen, apr_size_t *len);
+
+/**
+ * Perform shell escaping on the provided string, returning the result
+ * from the pool.
+ *
+ * Shell escaping causes characters to be prefixed with a '\' character.
+ *
+ * If no characters were escaped, the original string is returned.
+ * @param p Pool to allocate from
+ * @param str The original string
+ * @return the encoded string, allocated from the pool, or the original
+ * string if no escaping took place or the string was NULL.
+ */
+APR_DECLARE(const char *) apr_pescape_shell(apr_pool_t *p, const char *str)
+        __attribute__((nonnull(1)));
+
+/*
+ * Unescapes a URL, leaving reserved characters intact.
+ * @param escaped Optional buffer to write the encoded string, can be
+ * NULL
+ * @param url String to be unescaped
+ * @param slen The length of the original url, or APR_ESCAPE_STRING
+ * @param forbid Optional list of forbidden characters, in addition to
+ * 0x00
+ * @param reserved Optional list of reserved characters that will be
+ * left unescaped
+ * @param plus If non zero, '+' is converted to ' ' as per
+ * application/x-www-form-urlencoded encoding
+ * @param len If set, the length of the escaped string will be returned
+ * @return APR_SUCCESS on success, APR_NOTFOUND if no characters are
+ * decoded or the string is NULL, APR_EINVAL if a bad escape sequence is
+ * found, APR_BADCH if a character on the forbid list is found.
+ */
+APR_DECLARE(apr_status_t) apr_unescape_url(char *escaped, const char *url,
+        apr_ssize_t slen, const char *forbid, const char *reserved, int plus,
+        apr_size_t *len);
+
+/*
+ * Unescapes a URL, leaving reserved characters intact, returning the
+ * result from a pool.
+ * @param p Pool to allocate from
+ * @param url String to be unescaped in place
+ * @param forbid Optional list of forbidden characters, in addition to
+ * 0x00
+ * @param reserved Optional list of reserved characters that will be
+ * left unescaped
+ * @param plus If non zero, '+' is converted to ' ' as per
+ * application/x-www-form-urlencoded encoding
+ * @return A string allocated from the pool on success, the original string
+ * if no characters are decoded, or NULL if a bad escape sequence is found
+ * or if a character on the forbid list is found, or if the original string
+ * was NULL.
+ */
+APR_DECLARE(const char *) apr_punescape_url(apr_pool_t *p, const char *url,
+        const char *forbid, const char *reserved, int plus)
+        __attribute__((nonnull(1)));
+
+/**
+ * Escape a path segment, as defined in RFC1808.
+ * @param escaped Optional buffer to write the encoded string, can be
+ * NULL
+ * @param str The original string
+ * @param slen The length of the original string, or APR_ESCAPE_STRING
+ * @param len If present, returns the length of the string
+ * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were
+ * detected or the string was NULL
+ */
+APR_DECLARE(apr_status_t) apr_escape_path_segment(char *escaped,
+        const char *str, apr_ssize_t slen, apr_size_t *len);
+
+/**
+ * Escape a path segment, as defined in RFC1808, returning the result from a
+ * pool.
+ * @param p Pool to allocate from
+ * @param url String to be escaped
+ * @return A string allocated from the pool on success, the original string
+ * if no characters are encoded or the string is NULL.
+ */
+APR_DECLARE(const char *) apr_pescape_path_segment(apr_pool_t *p,
+        const char *str) __attribute__((nonnull(1)));
+
+/**
+ * Converts an OS path to a URL, in an OS dependent way, as defined in RFC1808.
+ * In all cases if a ':' occurs before the first '/' in the URL, the URL should
+ * be prefixed with "./" (or the ':' escaped). In the case of Unix, this means
+ * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
+ * efficiency reasons, we don't use escape_path_segment(), which is provided for
+ * reference. Again, RFC 1808 is where this stuff is defined.
+ *
+ * If partial is set, os_escape_path() assumes that the path will be appended to
+ * something with a '/' in it (and thus does not prefix "./").
+ * @param escaped Optional buffer to write the encoded string, can be
+ * NULL
+ * @param str The original string
+ * @param slen The length of the original string, or APR_ESCAPE_STRING
+ * @param partial If non zero, suppresses the prepending of "./"
+ * @param len If present, returns the length of the string
+ * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were
+ * detected or if the string was NULL
+ */
+APR_DECLARE(apr_status_t) apr_escape_path(char *escaped, const char *path,
+        apr_ssize_t slen, int partial, apr_size_t *len);
+
+/**
+ * Converts an OS path to a URL, in an OS dependent way, as defined in RFC1808,
+ * returning the result from a pool.
+ *
+ * In all cases if a ':' occurs before the first '/' in the URL, the URL should
+ * be prefixed with "./" (or the ':' escaped). In the case of Unix, this means
+ * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
+ * efficiency reasons, we don't use escape_path_segment(), which is provided for
+ * reference. Again, RFC 1808 is where this stuff is defined.
+ *
+ * If partial is set, os_escape_path() assumes that the path will be appended to
+ * something with a '/' in it (and thus does not prefix "./").
+ * @param p Pool to allocate from
+ * @param str The original string
+ * @param partial If non zero, suppresses the prepending of "./"
+ * @return A string allocated from the pool on success, the original string
+ * if no characters are encoded or if the string was NULL.
+ */
+APR_DECLARE(const char *) apr_pescape_path(apr_pool_t *p, const char *str,
+        int partial) __attribute__((nonnull(1)));
+
+/**
+ * Urlencode a string, as defined in
+ * http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1.
+ * @param escaped Optional buffer to write the encoded string, can be
+ * NULL
+ * @param str The original string
+ * @param slen The length of the original string, or APR_ESCAPE_STRING
+ * @param len If present, returns the length of the string
+ * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were
+ * detected or if the stirng was NULL
+ */
+APR_DECLARE(apr_status_t) apr_escape_urlencoded(char *escaped, const char *str,
+        apr_ssize_t slen, apr_size_t *len);
+
+/**
+ * Urlencode a string, as defined in
+ * http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1, returning
+ * the result from a pool.
+ * @param p Pool to allocate from
+ * @param url String to be escaped
+ * @return A string allocated from the pool on success, the original string
+ * if no characters are encoded or if the string was NULL.
+ */
+APR_DECLARE(const char *) apr_pescape_urlencoded(apr_pool_t *p,
+        const char *str) __attribute__((nonnull(1)));
+
+/**
+ * Apply entity encoding to a string. Characters are replaced as follows:
+ * '<' becomes '&lt;', '>' becomes '&gt;', '&' becomes '&amp;', the
+ * double quote becomes '&quot;" and the single quote becomes '&apos;'.
+ *
+ * If toasc is not zero, any non ascii character will be encoded as
+ * '%#ddd;', where ddd is the decimal code of the character.
+ * @param escaped Optional buffer to write the encoded string, can be
+ * NULL
+ * @param str The original string
+ * @param slen The length of the original string, or APR_ESCAPE_STRING
+ * @param toasc If non zero, encode non ascii characters
+ * @param len If present, returns the length of the string
+ * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were
+ * detected or the string was NULL
+ */
+APR_DECLARE(apr_status_t) apr_escape_entity(char *escaped, const char *str,
+        apr_ssize_t slen, int toasc, apr_size_t *len);
+
+/**
+ * Apply entity encoding to a string, returning the result from a pool.
+ * Characters are replaced as follows: '<' becomes '&lt;', '>' becomes
+ * '&gt;', '&' becomes '&amp;', the double quote becomes '&quot;" and the
+ * single quote becomes '&apos;'.
+ * @param p Pool to allocate from
+ * @param str The original string
+ * @param toasc If non zero, encode non ascii characters
+ * @return A string allocated from the pool on success, the original string
+ * if no characters are encoded or the string is NULL.
+ */
+APR_DECLARE(const char *) apr_pescape_entity(apr_pool_t *p, const char *str,
+        int toasc) __attribute__((nonnull(1)));
+
+/*
+ * Decodes html entities or numeric character references in a string. If
+ * the string to be unescaped is syntactically incorrect, then the
+ * following fixups will be made:
+ * unknown entities will be left undecoded;
+ * references to unused numeric characters will be deleted.
+ * In particular, &#00; will not be decoded, but will be deleted.
+ * @param escaped Optional buffer to write the encoded string, can be
+ * NULL
+ * @param str The original string
+ * @param slen The length of the original string, or APR_ESCAPE_STRING
+ * @param len If present, returns the length of the string
+ * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were
+ * detected or the string was NULL
+ */
+APR_DECLARE(apr_status_t) apr_unescape_entity(char *unescaped, const char *str,
+        apr_ssize_t slen, apr_size_t *len);
+
+/*
+ * Decodes html entities or numeric character references in a string. If
+ * the string to be unescaped is syntactically incorrect, then the
+ * following fixups will be made:
+ * unknown entities will be left undecoded;
+ * references to unused numeric characters will be deleted.
+ * In particular, &#00; will not be decoded, but will be deleted.
+ * @param p Pool to allocate from
+ * @param str The original string
+ * @return A string allocated from the pool on success, the original string
+ * if no characters are encoded or the string is NULL.
+ */
+APR_DECLARE(const char *) apr_punescape_entity(apr_pool_t *p, const char *str)
+        __attribute__((nonnull(1)));
+
+/**
+ * Escape control characters in a string, as performed by the shell's
+ * 'echo' command. Characters are replaced as follows:
+ * \a alert (bell), \b backspace, \e an escape character, \f form feed,
+ * \n new line, \r carriage return, \t horizontal tab, \v vertical tab,
+ * \\ backslash.
+ *
+ * Any non ascii character will be encoded as '\xHH', where HH is the hex
+ * code of the character.
+ *
+ * If quote is not zero, the double quote character will also be escaped.
+ * @param escaped Optional buffer to write the encoded string, can be
+ * NULL
+ * @param str The original string
+ * @param slen The length of the original string, or APR_ESCAPE_STRING
+ * @param quote If non zero, encode double quotes
+ * @param len If present, returns the length of the string
+ * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were
+ * detected or the string was NULL
+ */
+APR_DECLARE(apr_status_t) apr_escape_echo(char *escaped, const char *str,
+        apr_ssize_t slen, int quote, apr_size_t *len);
+
+/**
+ * Escape control characters in a string, as performed by the shell's
+ * 'echo' command, and return the results from a pool. Characters are
+ * replaced as follows: \a alert (bell), \b backspace, \e an escape
+ * character, \f form feed, \n new line, \r carriage return, \t
+ * horizontal tab, \v vertical tab, \\ backslash.
+ *
+ * Any non ascii character will be encoded as '\xHH', where HH is the hex
+ * code of the character.
+ *
+ * If quote is not zero, the double quote character will also be escaped.
+ * @param p Pool to allocate from
+ * @param str The original string
+ * @param quote If non zero, encode double quotes
+ * @return A string allocated from the pool on success, the original string
+ * if no characters are encoded or the string is NULL.
+ */
+APR_DECLARE(const char *) apr_pescape_echo(apr_pool_t *p, const char *str,
+        int quote);
+
+/**
+ * Convert binary data to a hex encoding.
+ * @param dest The destination buffer, can be NULL
+ * @param src The original buffer
+ * @param slen The length of the original buffer
+ * @param colon If not zero, insert colon characters between hex digits.
+ * @param len If present, returns the length of the string
+ * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL
+ */
+APR_DECLARE(apr_status_t) apr_escape_hex(char *dest, const void *src,
+        apr_size_t srclen, int colon, apr_size_t *len);
+
+/**
+ * Convert binary data to a hex encoding, and return the results from a
+ * pool.
+ * @param p Pool to allocate from
+ * @param src The original buffer
+ * @param srclen The length of the original buffer
+ * @param colon If not zero, insert colon characters between hex digits.
+ * @return A zero padded buffer allocated from the pool on success, or
+ * NULL if src was NULL.
+ */
+APR_DECLARE(const char *) apr_pescape_hex(apr_pool_t *p, const void *src,
+        apr_size_t slen, int colon) __attribute__((nonnull(1)));
+
+/**
+ * Convert hex encoded string to binary data.
+ * @param dest The destination buffer, can be NULL
+ * @param src The original buffer
+ * @param slen The length of the original buffer
+ * @param colon If not zero, ignore colon characters between hex digits.
+ * @param len If present, returns the length of the string
+ * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL, or APR_BADCH
+ * if a non hex character is present.
+ */
+APR_DECLARE(apr_status_t) apr_unescape_hex(void *dest, const char *str,
+        apr_ssize_t slen, int colon, apr_size_t *len);
+
+/**
+ * Convert hex encoding to binary data, and return the results from a pool.
+ * If the colon character appears between pairs of hex digits, it will be
+ * ignored.
+ * @param p Pool to allocate from
+ * @param str The original string
+ * @param colon If not zero, ignore colon characters between hex digits.
+ * @param len If present, returns the length of the final buffer
+ * @return A buffer allocated from the pool on success, or NULL if src was
+ * NULL, or a bad character was present.
+ */
+APR_DECLARE(const void *) apr_punescape_hex(apr_pool_t *p, const char *str,
+        int colon, apr_size_t *len);
+
+/** @} */
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* !APR_ESCAPE_H */

Modified: apr/apr/trunk/test/Makefile.in
URL: http://svn.apache.org/viewvc/apr/apr/trunk/test/Makefile.in?rev=1489517&r1=1489516&r2=1489517&view=diff
==============================================================================
--- apr/apr/trunk/test/Makefile.in (original)
+++ apr/apr/trunk/test/Makefile.in Tue Jun  4 17:02:17 2013
@@ -35,7 +35,7 @@ TESTS = testtime.lo teststr.lo testvsn.l
 	teststrmatch.lo testpass.lo testcrypto.lo testqueue.lo		\
 	testbuckets.lo testxml.lo testdbm.lo testuuid.lo testmd5.lo	\
 	testreslist.lo testbase64.lo testhooks.lo testlfsabi.lo         \
-	testlfsabi32.lo testlfsabi64.lo
+	testlfsabi32.lo testlfsabi64.lo testescape.lo
 
 OTHER_PROGRAMS = \
 	sendfile@EXEEXT@ \

Modified: apr/apr/trunk/test/abts_tests.h
URL: http://svn.apache.org/viewvc/apr/apr/trunk/test/abts_tests.h?rev=1489517&r1=1489516&r2=1489517&view=diff
==============================================================================
--- apr/apr/trunk/test/abts_tests.h (original)
+++ apr/apr/trunk/test/abts_tests.h Tue Jun  4 17:02:17 2013
@@ -28,6 +28,7 @@ const struct testlist {
     {testdso},
     {testdup},
     {testenv},
+    {testescape},
     {testfile},
     {testfilecopy},
     {testfileinfo},

Added: apr/apr/trunk/test/testescape.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/test/testescape.c?rev=1489517&view=auto
==============================================================================
--- apr/apr/trunk/test/testescape.c (added)
+++ apr/apr/trunk/test/testescape.c Tue Jun  4 17:02:17 2013
@@ -0,0 +1,255 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "apr_escape.h"
+#include "apr_strings.h"
+
+#include "abts.h"
+#include "testutil.h"
+
+static void test_escape(abts_case *tc, void *data)
+{
+    apr_pool_t *pool;
+    const char *src, *target;
+    const char *dest;
+    const void *vdest;
+    apr_size_t len, vlen;
+
+    apr_pool_create(&pool, NULL);
+
+    src = "Hello World &;`'\"|*?~<>^()[]{}$\\\n";
+    target = "Hello World \\&\\;\\`\\'\\\"\\|\\*\\?\\~\\<\\>\\^\\(\\)\\[\\]\\{\\}\\$\\\\\\\n";
+    dest = apr_pescape_shell(pool, src);
+    ABTS_ASSERT(tc, "shell escaped matches expected output",
+                (strcmp(dest, target) == 0));
+    apr_escape_shell(NULL, src, APR_ESCAPE_STRING, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "Hello";
+    dest = apr_punescape_url(pool, src, NULL, NULL, 0);
+    ABTS_PTR_EQUAL(tc, src, dest);
+
+    src = "Hello";
+    dest = apr_punescape_url(pool, src, NULL, NULL, 1);
+    ABTS_PTR_EQUAL(tc, src, dest);
+
+    src = "Hello%20";
+    dest = apr_punescape_url(pool, src, " ", NULL, 0);
+    ABTS_PTR_EQUAL(tc, NULL, dest);
+
+    src = "Hello%20World";
+    target = "Hello World";
+    dest = apr_punescape_url(pool, src, NULL, NULL, 0);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_unescape_url(NULL, src, APR_ESCAPE_STRING, NULL, NULL, 0, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "Hello+World";
+    target = "Hello World";
+    dest = apr_punescape_url(pool, src, NULL, NULL, 1);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_unescape_url(NULL, src, APR_ESCAPE_STRING, NULL, NULL, 1, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "Hello%20World";
+    target = "Hello%20World";
+    dest = apr_punescape_url(pool, src, NULL, " ", 0);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_unescape_url(NULL, src, APR_ESCAPE_STRING, NULL, " ", 0, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "Hello";
+    dest = apr_pescape_path_segment(pool, src);
+    ABTS_PTR_EQUAL(tc, src, dest);
+
+    src = "$-_.+!*'(),:@&=/~Hello World";
+    target = "$-_.+!*'(),:@&=%2f~Hello%20World";
+    dest = apr_pescape_path_segment(pool, src);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_escape_path_segment(NULL, src, APR_ESCAPE_STRING, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "Hello";
+    dest = apr_pescape_path(pool, src, 0);
+    ABTS_PTR_EQUAL(tc, src, dest);
+
+    src = "$-_.+!*'(),:@&=/~Hello World";
+    target = "./$-_.+!*'(),:@&=/~Hello%20World";
+    dest = apr_pescape_path(pool, src, 0);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_escape_path(NULL, src, APR_ESCAPE_STRING, 0, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "Hello";
+    dest = apr_pescape_path(pool, src, 1);
+    ABTS_PTR_EQUAL(tc, src, dest);
+
+    src = "$-_.+!*'(),:@&=/~Hello World";
+    target = "$-_.+!*'(),:@&=/~Hello%20World";
+    dest = apr_pescape_path(pool, src, 1);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_escape_path(NULL, src, APR_ESCAPE_STRING, 1, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "Hello";
+    dest = apr_pescape_urlencoded(pool, src);
+    ABTS_PTR_EQUAL(tc, src, dest);
+
+    src = "$-_.+!*'(),:@&=/~Hello World";
+    target = "%24-_.%2b%21*%27%28%29%2c%3a%40%26%3d%2f%7eHello+World";
+    dest = apr_pescape_urlencoded(pool, src);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_escape_urlencoded(NULL, src, APR_ESCAPE_STRING, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "Hello";
+    dest = apr_pescape_entity(pool, src, 0);
+    ABTS_PTR_EQUAL(tc, src, dest);
+
+    src = "\xFF<>&\'\"Hello World";
+    target = "\xFF&lt;&gt;&amp;'&quot;Hello World";
+    dest = apr_pescape_entity(pool, src, 0);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_escape_entity(NULL, src, APR_ESCAPE_STRING, 0, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "Hello";
+    dest = apr_pescape_entity(pool, src, 1);
+    ABTS_PTR_EQUAL(tc, src, dest);
+
+    src = "\xFF<>&\'\"Hello World";
+    target = "&#255&lt;&gt;&amp;'&quot;Hello World";
+    dest = apr_pescape_entity(pool, src, 1);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_escape_entity(NULL, src, APR_ESCAPE_STRING, 1, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "Hello";
+    dest = apr_punescape_entity(pool, src);
+    ABTS_PTR_EQUAL(tc, src, dest);
+
+    src = "\xFF&lt;&gt;&amp;'&quot;Hello World";
+    target = "\xFF<>&\'\"Hello World";
+    dest = apr_punescape_entity(pool, src);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_unescape_entity(NULL, src, APR_ESCAPE_STRING, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "&#255;&lt;&gt;&amp;'&quot;Hello World";
+    target = "\xFF<>&\'\"Hello World";
+    dest = apr_punescape_entity(pool, src);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_unescape_entity(NULL, src, APR_ESCAPE_STRING, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "&#32;&lt;&gt;&amp;'&quot;Hello World";
+    target = " <>&\'\"Hello World";
+    dest = apr_punescape_entity(pool, src);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_unescape_entity(NULL, src, APR_ESCAPE_STRING, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "Hello";
+    dest = apr_pescape_echo(pool, src, 0);
+    ABTS_PTR_EQUAL(tc, src, dest);
+
+    src = "\a\b\e\f\\n\r\t\v\"Hello World\"";
+    target = "\\a\\b\\e\\f\\\\n\\r\\t\\v\"Hello World\"";
+    dest = apr_pescape_echo(pool, src, 0);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_escape_echo(NULL, src, APR_ESCAPE_STRING, 0, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "\a\b\e\f\\n\r\t\v\"Hello World\"";
+    target = "\\a\\b\\e\\f\\\\n\\r\\t\\v\\\"Hello World\\\"";
+    dest = apr_pescape_echo(pool, src, 1);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_escape_echo(NULL, src, APR_ESCAPE_STRING, 1, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "\xFF\x00\xFF\x00";
+    target = "ff00ff00";
+    dest = apr_pescape_hex(pool, src, 4, 0);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_escape_hex(NULL, src, 4, 0, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "\xFF\x00\xFF\x00";
+    target = "ff:00:ff:00";
+    dest = apr_pescape_hex(pool, src, 4, 1);
+    ABTS_STR_EQUAL(tc, target, dest);
+    apr_escape_hex(NULL, src, 4, 1, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+            (len == strlen(dest) + 1));
+
+    src = "ff:00:ff:00";
+    target = "\xFF\x00\xFF\x00";
+    vdest = apr_punescape_hex(pool, src, 1, &vlen);
+    ABTS_ASSERT(tc, "apr_punescape_hex target!=dest", memcmp(target, vdest, 4) == 0);
+    ABTS_INT_EQUAL(tc, (int)vlen, 4);
+    apr_unescape_hex(NULL, src, APR_ESCAPE_STRING, 1, &len);
+    ABTS_ASSERT(tc,
+            apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, (apr_size_t)4),
+            (len == 4));
+
+    apr_pool_destroy(pool);
+}
+
+abts_suite *testescape(abts_suite *suite)
+{
+    suite = ADD_SUITE(suite);
+
+    abts_run_test(suite, test_escape, NULL);
+
+    return suite;
+}

Modified: apr/apr/trunk/test/testutil.h
URL: http://svn.apache.org/viewvc/apr/apr/trunk/test/testutil.h?rev=1489517&r1=1489516&r2=1489517&view=diff
==============================================================================
--- apr/apr/trunk/test/testutil.h (original)
+++ apr/apr/trunk/test/testutil.h Tue Jun  4 17:02:17 2013
@@ -110,6 +110,7 @@ abts_suite *testud(abts_suite *suite);
 abts_suite *testuser(abts_suite *suite);
 abts_suite *testvsn(abts_suite *suite);
 
+abts_suite *testescape(abts_suite *suite);
 abts_suite *teststrmatch(abts_suite *suite);
 abts_suite *testuri(abts_suite *suite);
 abts_suite *testuuid(abts_suite *suite);

Propchange: apr/apr/trunk/tools/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Jun  4 17:02:17 2013
@@ -0,0 +1,6 @@
+Makefile
+*.lo
+*.la
+.libs
+gen_test_char
+gen_test_char.exe

Added: apr/apr/trunk/tools/gen_test_char.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/tools/gen_test_char.c?rev=1489517&view=auto
==============================================================================
--- apr/apr/trunk/tools/gen_test_char.c (added)
+++ apr/apr/trunk/tools/gen_test_char.c Tue Jun  4 17:02:17 2013
@@ -0,0 +1,134 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef CROSS_COMPILE
+
+#define apr_isalnum(c) (isalnum(((unsigned char)(c))))
+#define apr_isalpha(c) (isalpha(((unsigned char)(c))))
+#define apr_iscntrl(c) (iscntrl(((unsigned char)(c))))
+#define apr_isprint(c) (isprint(((unsigned char)(c))))
+#include <ctype.h>
+#define APR_HAVE_STDIO_H 1
+#define APR_HAVE_STRING_H 1
+
+#else
+
+#include "apr.h"
+#include "apr_lib.h"
+
+#endif
+
+#if defined(WIN32) || defined(OS2)
+#define NEED_ENHANCED_ESCAPES
+#endif
+
+#if APR_HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if APR_HAVE_STRING_H
+#include <string.h>
+#endif
+
+/* A bunch of functions in util.c scan strings looking for certain characters.
+ * To make that more efficient we encode a lookup table.
+ */
+#define T_ESCAPE_SHELL_CMD    (0x01)
+#define T_ESCAPE_PATH_SEGMENT (0x02)
+#define T_OS_ESCAPE_PATH      (0x04)
+#define T_ESCAPE_ECHO         (0x08)
+#define T_ESCAPE_URLENCODED   (0x10)
+#define T_ESCAPE_XML          (0x20)
+
+int main(int argc, char *argv[])
+{
+    unsigned c;
+    unsigned char flags;
+
+    printf("/* this file is automatically generated by gen_test_char, "
+           "do not edit. \"make include/private/apr_escape_test_char.h\" to regenerate. */\n"
+           "#define T_ESCAPE_SHELL_CMD     (%u)\n"
+           "#define T_ESCAPE_PATH_SEGMENT  (%u)\n"
+           "#define T_OS_ESCAPE_PATH       (%u)\n"
+           "#define T_ESCAPE_ECHO          (%u)\n"
+           "#define T_ESCAPE_URLENCODED    (%u)\n"
+           "#define T_ESCAPE_XML           (%u)\n"
+           "\n"
+           "static const unsigned char test_char_table[256] = {",
+           T_ESCAPE_SHELL_CMD,
+           T_ESCAPE_PATH_SEGMENT,
+           T_OS_ESCAPE_PATH,
+           T_ESCAPE_ECHO,
+           T_ESCAPE_URLENCODED,
+           T_ESCAPE_XML);
+
+    for (c = 0; c < 256; ++c) {
+        flags = 0;
+        if (c % 20 == 0)
+            printf("\n    ");
+
+        /* escape_shell_cmd */
+#ifdef NEED_ENHANCED_ESCAPES
+        /* Win32/OS2 have many of the same vulnerable characters
+         * as Unix sh, plus the carriage return and percent char.
+         * The proper escaping of these characters varies from unix
+         * since Win32/OS2 use carets or doubled-double quotes,
+         * and neither lf nor cr can be escaped.  We escape unix
+         * specific as well, to assure that cross-compiled unix
+         * applications behave similiarly when invoked on win32/os2.
+         *
+         * Rem please keep in-sync with apr's list in win32/filesys.c
+         */
+        if (c && strchr("&;`'\"|*?~<>^()[]{}$\\\n\r%", c)) {
+            flags |= T_ESCAPE_SHELL_CMD;
+        }
+#else
+        if (c && strchr("&;`'\"|*?~<>^()[]{}$\\\n", c)) {
+            flags |= T_ESCAPE_SHELL_CMD;
+        }
+#endif
+
+        if (!apr_isalnum(c) && !strchr("$-_.+!*'(),:@&=~", c)) {
+            flags |= T_ESCAPE_PATH_SEGMENT;
+        }
+
+        if (!apr_isalnum(c) && !strchr("$-_.+!*'(),:@&=/~", c)) {
+            flags |= T_OS_ESCAPE_PATH;
+        }
+
+        if (!apr_isalnum(c) && !strchr(".-*_ ", c)) {
+            flags |= T_ESCAPE_URLENCODED;
+        }
+
+        /* For logging, escape all control characters,
+         * double quotes (because they delimit the request in the log file)
+         * backslashes (because we use backslash for escaping)
+         * and 8-bit chars with the high bit set
+         */
+        if (c && (!apr_isprint(c) || c == '"' || c == '\\' || apr_iscntrl(c))) {
+            flags |= T_ESCAPE_ECHO;
+        }
+
+        if (strchr("<>&\"", c)) {
+            flags |= T_ESCAPE_XML;
+        }
+
+        printf("%u%c", flags, (c < 255) ? ',' : ' ');
+    }
+
+    printf("\n};\n");
+
+    return 0;
+}



Mime
View raw message