Hi all,

This patch add the url_rewrite_extras for redirector helpers.
The url_rewrite_extras is a "quoted string" with logformat %macro
support. It is appended to request line for redirector helpers.

Example usage:
   url_rewrite_extras "Note1=%{Note1}note Note2=%{Note2}note"

The url_rewrtite_extras it is similar to the "key_extras" authenticator
helpers options. Originally developed to allow notes exchange between
authenicator helpers and redirector helpers.

In this patch we add a new type for cf.data the TokenOrQuotedString to
allow new configurations use quoted strings for the new option without
explicitly turning configuration_includes_quoted_values on.

This is a Measurement Factory project.


Add url_rewrite_extras for redirector helpers

The url_rewrite_extras is a "quoted string" with logformat %macro support. It
is appended to request line for redirector helpers.

Example usage:
   url_rewrite_extras "Note1=%{Note1}note Note2=%{Note2}note"

This is a Measurement Factory project.
=== modified file 'src/SquidConfig.h'
--- src/SquidConfig.h	2014-01-12 17:51:12 +0000
+++ src/SquidConfig.h	2014-02-20 17:59:54 +0000
@@ -523,40 +523,42 @@
         char *flags;
         acl_access *cert_error;
         SSL_CTX *sslContext;
         sslproxy_cert_sign *cert_sign;
         sslproxy_cert_adapt *cert_adapt;
     } ssl_client;
 #endif
 
     char *accept_filter;
     int umask;
     int max_filedescriptors;
     int workers;
     CpuAffinityMap *cpuAffinityMap;
 
 #if USE_LOADABLE_MODULES
     wordlist *loadable_module_names;
 #endif
 
     int client_ip_max_connections;
 
+    char *redirector_extras;
+
     struct {
         int v4_first;       ///< Place IPv4 first in the order of DNS results.
         ssize_t packet_max; ///< maximum size EDNS advertised for DNS replies.
     } dns;
 
 };
 
 extern SquidConfig Config;
 
 class SquidConfig2
 {
 public:
     struct {
         int enable_purge;
         int mangle_request_headers;
     } onoff;
     uid_t effectiveUserID;
     gid_t effectiveGroupID;
 };
 

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2014-02-10 09:59:19 +0000
+++ src/cache_cf.cc	2014-02-23 20:44:06 +0000
@@ -3020,40 +3020,55 @@
     if (!token) {
         self_destruct();
         return;
     }
 
     while (*token && xisspace(*token))
         ++token;
 
     if (!*token) {
         self_destruct();
         return;
     }
 
     *var = xstrdup((char *) token);
 }
 
 #define dump_eol dump_string
 #define free_eol free_string
 
 static void
+parse_TokenOrQuotedString(char **var)
+{
+    char *token = ConfigParser::NextQuotedToken();
+    safe_free(*var);
+
+    if (token == NULL)
+        self_destruct();
+
+    *var = xstrdup(token);
+}
+
+#define dump_TokenOrQuotedString dump_string
+#define free_TokenOrQuotedString free_string
+
+static void
 dump_time_t(StoreEntry * entry, const char *name, time_t var)
 {
     storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
 }
 
 void
 parse_time_t(time_t * var)
 {
     time_msec_t tval;
     parseTimeLine(&tval, T_SECOND_STR, false);
     *var = static_cast<time_t>(tval/1000);
 }
 
 static void
 free_time_t(time_t * var)
 {
     *var = 0;
 }
 
 static void

=== modified file 'src/cf.data.depend'
--- src/cf.data.depend	2013-08-29 09:21:53 +0000
+++ src/cf.data.depend	2014-02-23 20:44:21 +0000
@@ -38,39 +38,40 @@
 adaptation_service_chain_type	icap_service ecap_service
 icap_access_type	icap_class acl
 icap_class_type		icap_service
 icap_service_type
 icap_service_failure_limit
 ecap_service_type
 int
 kb_int64_t
 kb_size_t
 logformat
 YesNoNone
 memcachemode
 note			acl
 obsolete
 onoff
 peer
 peer_access		cache_peer acl
 pipelinePrefetch
 PortCfg
 QosConfig
+TokenOrQuotedString
 refreshpattern
 removalpolicy
 size_t
 IpAddress_list
 string
 string
 time_msec
 time_t
 tristate
 uri_whitespace
 u_short
 wccp2_method
 wccp2_amethod
 wccp2_service
 wccp2_service_info
 wordlist
 sslproxy_ssl_bump	acl
 sslproxy_cert_sign	acl
 sslproxy_cert_adapt	acl

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2014-01-30 21:24:44 +0000
+++ src/cf.data.pre	2014-02-23 20:44:32 +0000
@@ -4738,40 +4738,52 @@
 	This clause supports both fast and slow acl types.
 	See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details.
 DOC_END
 
 NAME: url_rewrite_bypass redirector_bypass
 TYPE: onoff
 LOC: Config.onoff.redirector_bypass
 DEFAULT: off
 DOC_START
 	When this is 'on', a request will not go through the
 	redirector if all the helpers are busy.  If this is 'off'
 	and the redirector queue grows too large, Squid will exit
 	with a FATAL error and ask you to increase the number of
 	redirectors.  You should only enable this if the redirectors
 	are not critical to your caching system.  If you use
 	redirectors for access control, and you enable this option,
 	users may have access to pages they should not
 	be allowed to request.
 DOC_END
 
+NAME: url_rewrite_extras format
+TYPE: TokenOrQuotedString
+LOC: Config.redirector_extras
+DEFAULT: none
+DOC_START
+	Specifies a string to be append to request line format for the
+	rewriter helper. "Quoted" format values may contain spaces and
+	logformat %macros. In theory, any logformat %macro can be used.
+	In practice, a %macro expands as a dash (-) if the helper request is
+	sent before the required macro information is available to Squid.
+DOC_END
+
 COMMENT_START
  OPTIONS FOR STORE ID
  -----------------------------------------------------------------------------
 COMMENT_END
 
 NAME: store_id_program storeurl_rewrite_program
 TYPE: wordlist
 LOC: Config.Program.store_id
 DEFAULT: none
 DOC_START
 	Specify the location of the executable StoreID helper to use.
 	Since they can perform almost any function there isn't one included.
 
 	For each requested URL, the helper will receive one line with the format
 
 	  [channel-ID <SP>] URL <SP> client_ip "/" fqdn <SP> user <SP> method [<SP> kv-pairs]<NL>
 
 
 	After processing the request the helper must reply using the following format:
 

=== modified file 'src/client_side_request.cc'
--- src/client_side_request.cc	2013-12-06 23:52:26 +0000
+++ src/client_side_request.cc	2014-02-21 17:07:39 +0000
@@ -879,41 +879,41 @@
 static void
 clientRedirectAccessCheckDone(allow_t answer, void *data)
 {
     ClientRequestContext *context = (ClientRequestContext *)data;
     ClientHttpRequest *http = context->http;
     context->acl_checklist = NULL;
 
     if (answer == ACCESS_ALLOWED)
         redirectStart(http, clientRedirectDoneWrapper, context);
     else {
         HelperReply nilReply;
         nilReply.result = HelperReply::Error;
         context->clientRedirectDone(nilReply);
     }
 }
 
 void
 ClientRequestContext::clientRedirectStart()
 {
     debugs(33, 5, HERE << "'" << http->uri << "'");
-
+    (void)SyncNotes(*http->al, *http->request);
     if (Config.accessList.redirector) {
         acl_checklist = clientAclChecklistCreate(Config.accessList.redirector, http);
         acl_checklist->nonBlockingCheck(clientRedirectAccessCheckDone, this);
     } else
         redirectStart(http, clientRedirectDoneWrapper, this);
 }
 
 /**
  * This methods handles Access checks result of StoreId access list.
  * Will handle as "ERR" (no change) in a case Access is not allowed.
  */
 static void
 clientStoreIdAccessCheckDone(allow_t answer, void *data)
 {
     ClientRequestContext *context = static_cast<ClientRequestContext *>(data);
     ClientHttpRequest *http = context->http;
     context->acl_checklist = NULL;
 
     if (answer == ACCESS_ALLOWED)
         storeIdStart(http, clientStoreIdDoneWrapper, context);

=== modified file 'src/redirect.cc'
--- src/redirect.cc	2013-11-23 00:58:42 +0000
+++ src/redirect.cc	2014-02-21 15:49:59 +0000
@@ -21,40 +21,41 @@
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #include "squid.h"
 #include "acl/Checklist.h"
 #include "client_side.h"
 #include "client_side_reply.h"
 #include "client_side_request.h"
 #include "comm/Connection.h"
 #include "fde.h"
 #include "fqdncache.h"
+#include "format/Format.h"
 #include "globals.h"
 #include "HttpRequest.h"
 #include "mgr/Registration.h"
 #include "redirect.h"
 #include "rfc1738.h"
 #include "SBuf.h"
 #include "SquidConfig.h"
 #include "Store.h"
 #if USE_AUTH
 #include "auth/UserRequest.h"
 #endif
 #if USE_SSL
 #include "ssl/support.h"
 #endif
 
 /// url maximum lengh + extra informations passed to redirector
 #define MAX_REDIRECTOR_REQUEST_STRLEN (MAX_URL + 1024)
 
 class RedirectStateData
 {
@@ -65,40 +66,41 @@
     void *data;
     SBuf orig_url;
 
     Ip::Address client_addr;
     const char *client_ident;
     const char *method_s;
     HLPCB *handler;
 
 private:
     CBDATA_CLASS2(RedirectStateData);
 };
 
 static HLPCB redirectHandleReply;
 static HLPCB storeIdHandleReply;
 static helper *redirectors = NULL;
 static helper *storeIds = NULL;
 static OBJH redirectStats;
 static OBJH storeIdStats;
 static int redirectorBypassed = 0;
 static int storeIdBypassed = 0;
+static Format::Format *redirectorExtrasFmt = NULL;
 
 CBDATA_CLASS_INIT(RedirectStateData);
 
 RedirectStateData::RedirectStateData(const char *url) :
         data(NULL),
         orig_url(url),
         client_addr(),
         client_ident(NULL),
         method_s(NULL),
         handler(NULL)
 {
 }
 
 RedirectStateData::~RedirectStateData()
 {
 }
 
 static void
 redirectHandleReply(void *data, const HelperReply &reply)
 {
@@ -272,48 +274,54 @@
 #if USE_SSL
 
     if (!r->client_ident && conn != NULL && Comm::IsConnOpen(conn->clientConnection)) {
         r->client_ident = sslGetUserEmail(fd_table[conn->clientConnection->fd].ssl);
         debugs(61, 5, HERE << "ssl-user=" << (r->client_ident?r->client_ident:"NULL"));
     }
 #endif
 
     if (!r->client_ident)
         r->client_ident = dash_str;
 
     r->method_s = RequestMethodStr(http->request->method);
 
     r->handler = handler;
 
     r->data = cbdataReference(data);
 
     if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL)
         fqdn = dash_str;
 
-    sz = snprintf(buf, MAX_REDIRECTOR_REQUEST_STRLEN, "%s %s/%s %s %s myip=%s myport=%d\n",
+    static MemBuf requestExtras;
+    requestExtras.reset();
+    redirectorExtrasFmt->assemble(requestExtras, http->al, 0);
+
+    sz = snprintf(buf, MAX_REDIRECTOR_REQUEST_STRLEN, "%s %s/%s %s %s myip=%s myport=%d%s%s\n",
                   r->orig_url.c_str(),
                   r->client_addr.toStr(claddr,MAX_IPSTRLEN),
                   fqdn,
                   r->client_ident[0] ? rfc1738_escape(r->client_ident) : dash_str,
                   r->method_s,
                   http->request->my_addr.toStr(myaddr,MAX_IPSTRLEN),
-                  http->request->my_addr.port());
+                  http->request->my_addr.port(),
+                  requestExtras.hasContent() ? " " : "",
+                  requestExtras.hasContent() ? requestExtras.content() : "");
 
     if ((sz<=0) || (sz>=MAX_REDIRECTOR_REQUEST_STRLEN)) {
         if (sz<=0) {
             status = Http::scInternalServerError;
             debugs(61, DBG_CRITICAL, "ERROR: Gateway Failure. Can not build request to be passed to " << name << ". Request ABORTED.");
         } else {
             status = Http::scRequestUriTooLarge;
             debugs(61, DBG_CRITICAL, "ERROR: Gateway Failure. Request passed to " << name << " exceeds MAX_REDIRECTOR_REQUEST_STRLEN (" << MAX_REDIRECTOR_REQUEST_STRLEN << "). Request ABORTED.");
         }
 
         clientStreamNode *node = (clientStreamNode *)http->client_stream.tail->prev->data;
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
         Ip::Address tmpnoaddr;
         tmpnoaddr.setNoAddr();
         repContext->setReplyToError(ERR_GATEWAY_FAILURE, status,
                                     http->request->method, NULL,
                                     http->getConn() != NULL && http->getConn()->clientConnection != NULL ?
                                     http->getConn()->clientConnection->remote : tmpnoaddr,
                                     http->request,
@@ -403,49 +411,56 @@
 
         redirectors->ipc_type = IPC_STREAM;
 
         helperOpenServers(redirectors);
     }
 
     if (Config.Program.store_id) {
 
         if (storeIds == NULL)
             storeIds = new helper("store_id");
 
         storeIds->cmdline = Config.Program.store_id;
 
         storeIds->childs.updateLimits(Config.storeIdChildren);
 
         storeIds->ipc_type = IPC_STREAM;
 
         helperOpenServers(storeIds);
     }
 
+    if (Config.redirector_extras) {
+        redirectorExtrasFmt = new ::Format::Format("redirecor_extras");
+        (void)redirectorExtrasFmt->parse(Config.redirector_extras);
+    }
+
     init = true;
 }
 
 void
 redirectShutdown(void)
 {
     /** FIXME: Temporary unified helpers Shutdown
      * When and if needed for more helpers a separated shutdown
      * method will be added for each of them.
      */
     if (!storeIds && !redirectors)
         return;
 
     if (redirectors)
         helperShutdown(redirectors);
 
     if (storeIds)
         helperShutdown(storeIds);
 
     if (!shutting_down)
         return;
 
     delete redirectors;
     redirectors = NULL;
 
     delete storeIds;
     storeIds = NULL;
 
+    delete redirectorExtrasFmt;
+    redirectorExtrasFmt = NULL;
 }

Reply via email to