[squid-dev] [PATCH] shell un-escaping squidclient -H option

Amos Jeffries squid3 at treenet.co.nz
Thu May 19 13:51:59 UTC 2016


The squidclient -H parameter takes a string with some limited
shellescaped characters. Currently just \n was expanded to the CRLF
sequence. Other shell escaped characters were left untouched.

However, to properly test headers containing weird CR, LF and HTAB
positioning it needs to be able to receive these special characters
individually and thus unescape them.

Add a new function similar to perform shell unescape with special
characters \r, \n, and \t. All other characters are un-escaped to
themselves. Including '\\'.

Amos
-------------- next part --------------
=== modified file 'tools/squidclient/squidclient.cc'
--- tools/squidclient/squidclient.cc	2016-04-03 23:41:58 +0000
+++ tools/squidclient/squidclient.cc	2016-05-19 13:46:00 +0000
@@ -94,61 +94,108 @@
 static void
 usage(const char *progname)
 {
     std::cerr << "Version: " << VERSION << std::endl
               << "Usage: " << progname << " [Basic Options] [HTTP Options]" << std::endl
               << std::endl;
     std::cerr
             << "    -s | --quiet    Silent.  Do not print response message to stdout." << std::endl
             << "    -v | --verbose  Verbose debugging. Repeat (-vv) to increase output level." << std::endl
             << "                    Levels:" << std::endl
             << "                      1 - Print outgoing request message to stderr." << std::endl
             << "                      2 - Print action trace to stderr." << std::endl
             << "    --help          Display this help text." << std::endl
             << std::endl;
     Transport::Config.usage();
     Ping::Config.usage();
     std::cerr
             << "HTTP Options:" << std::endl
             << "    -a           Do NOT include Accept: header." << std::endl
             << "    -A           User-Agent: header. Use \"\" to omit." << std::endl
-            << "    -H 'string'  Extra headers to send. Use '\\n' for new lines." << std::endl
+            << "    -H 'string'  Extra headers to send. Use '\\\\' for \\, '\\n' for LF, '\\r' for CR and '\\t' for tab." << std::endl
             << "    -i IMS       If-Modified-Since time (in Epoch seconds)." << std::endl
             << "    -j hosthdr   Host header content" << std::endl
             << "    -k           Keep the connection active. Default is to do only one request then close." << std::endl
             << "    -m method    Request method, default is GET." << std::endl
 #if HAVE_GSSAPI
             << "    -n           Proxy Negotiate(Kerberos) authentication" << std::endl
             << "    -N           WWW Negotiate(Kerberos) authentication" << std::endl
 #endif
             << "    -P file      Send content from the named file as request payload" << std::endl
             << "    -r           Force cache to reload URL" << std::endl
             << "    -t count     Trace count cache-hops" << std::endl
             << "    -u user      Proxy authentication username" << std::endl
             << "    -U user      WWW authentication username" << std::endl
             << "    -V version   HTTP Version. Use '-' for HTTP/0.9 omitted case" << std::endl
             << "    -w password  Proxy authentication password" << std::endl
             << "    -W password  WWW authentication password" << std::endl
             ;
     exit(1);
 }
 
+static void
+shellUnescape(char *buf)
+{
+    if (!buf)
+        return;
+
+    unsigned char *p, *d;
+    unsigned char ch;
+
+    d = p = (unsigned char *)buf;
+
+    while ((ch = *p)) {
+
+        if (ch == '\\') {
+            ++p;
+
+            switch (*p) {
+            case 'n':
+                ch = '\n';
+                break;
+            case 'r':
+                ch = '\r';
+                break;
+            case 't':
+                ch = '\t';
+                break;
+            default:
+                ch = *p;
+                break;
+            }
+
+            *d = ch;
+
+            if (!ch)
+                continue;
+
+        } else {
+            *d = *p;
+        }
+
+        ++p;
+        ++d;
+    }
+
+    *d = '\0';
+}
+
 int
 main(int argc, char *argv[])
 {
     int len, bytesWritten;
     bool to_stdout, reload;
     int keep_alive = 0;
     int opt_noaccept = 0;
 #if HAVE_GSSAPI
     int www_neg = 0, proxy_neg = 0;
 #endif
     char url[BUFSIZ], msg[MESSAGELEN], buf[BUFSIZ];
     char extra_hdrs[HEADERLEN];
     const char *method = "GET";
     extern char *optarg;
     time_t ims = 0;
     int max_forwards = -1;
 
     const char *proxy_user = NULL;
     const char *proxy_password = NULL;
     const char *www_user = NULL;
@@ -245,44 +292,42 @@
 
             case 'P':
                 put_file = xstrdup(optarg);
                 break;
 
             case 'i':       /* IMS */
                 ims = (time_t) atoi(optarg);
                 break;
 
             case 'm':
                 method = xstrdup(optarg);
                 break;
 
             case 't':
                 method = xstrdup("TRACE");
                 max_forwards = atoi(optarg);
                 break;
 
             case 'H':
                 if (strlen(optarg)) {
-                    char *t;
                     strncpy(extra_hdrs, optarg, sizeof(extra_hdrs));
-                    while ((t = strstr(extra_hdrs, "\\n")))
-                        *t = '\r', *(t + 1) = '\n';
+                    shellUnescape(extra_hdrs);
                 }
                 break;
 
             case 'T':
                 Transport::Config.ioTimeout = atoi(optarg);
                 break;
 
             case 'u':
                 proxy_user = optarg;
                 break;
 
             case 'w':
                 proxy_password = optarg;
                 break;
 
             case 'U':
                 www_user = optarg;
                 break;
 
             case 'W':



More information about the squid-dev mailing list