]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
libecap v0.2.0 options support: supply client IP and user name to eCAP.
authorAlex Rousskov <rousskov@measurement-factory.com>
Thu, 17 Feb 2011 19:27:54 +0000 (12:27 -0700)
committerAlex Rousskov <rousskov@measurement-factory.com>
Thu, 17 Feb 2011 19:27:54 +0000 (12:27 -0700)
Squid now uses libecap::Options API to send client IP and user name
meta-information to the eCAP adapter transaction, just like ICAP code
does when talking to an ICAP service transaction.

Renamed related icap_* options to their more general adaptation_*
equivalents because they now control both eCAP and ICAP behavior.
Old icap_* names are deprecated but still available.

Converted eCAP service configuration code to support the new Options
API, polished.

src/adaptation/Config.cc
src/adaptation/Config.h
src/adaptation/ecap/Host.cc
src/adaptation/ecap/Host.h
src/adaptation/ecap/ServiceRep.cc
src/adaptation/ecap/XactionRep.cc
src/adaptation/ecap/XactionRep.h
src/adaptation/icap/ModXact.cc
src/cf.data.pre

index 612a1f3367f35e005e1736b070620bd71366bdc3..f789686ff7d031db237b2c6dd9aea6168e00248c 100644 (file)
@@ -47,6 +47,9 @@
 bool Adaptation::Config::Enabled = false;
 char *Adaptation::Config::masterx_shared_name = NULL;
 int Adaptation::Config::service_iteration_limit = 16;
+int Adaptation::Config::send_client_ip = false;
+int Adaptation::Config::send_username = false;
+int Adaptation::Config::use_indirect_client = true;
 
 
 Adaptation::ServiceConfig*
index 6ae34a481736a8a8de791dfea0ac01376be4fe8e..f9f8dfd8d1a0e53f9a34d84f53230034013244dd 100644 (file)
@@ -32,15 +32,16 @@ public:
     // these are global squid.conf options, documented elsewhere
     static char *masterx_shared_name; // global TODO: do we need TheConfig?
     static int service_iteration_limit;
+    static int send_client_ip;
+    static int send_username;
+    static int use_indirect_client;
+
     // Options below are accessed via Icap::TheConfig or Ecap::TheConfig
     // TODO: move ICAP-specific options to Icap::Config and add TheConfig
     int onoff;
-    int send_client_ip;
-    int send_client_username;
     int service_failure_limit;
     time_t oldest_service_failure;
     int service_revival_delay;
-    int icap_uses_indirect_client;
 
     typedef Vector<ServiceConfigPointer> ServiceConfigs;
     ServiceConfigs serviceConfigs;
index 7903cb887b3f5036abb4fd4172d577755aa67952..370645d74ed6067b591b87cd638ba5d5911339e2 100644 (file)
@@ -18,6 +18,7 @@ const libecap::Name Adaptation::Ecap::protocolIcp("ICP", libecap::Name::NextId()
 #if USE_HTCP
 const libecap::Name Adaptation::Ecap::protocolHtcp("Htcp", libecap::Name::NextId());
 #endif
+const libecap::Name Adaptation::Ecap::metaBypassable("bypassable", libecap::Name::NextId());
 
 /// the host application (i.e., Squid) wrapper registered with libecap
 static libecap::shared_ptr<Adaptation::Ecap::Host> TheHost;
@@ -47,6 +48,9 @@ Adaptation::Ecap::Host::Host()
 #if USE_HTCP
     protocolHtcp.assignHostId(PROTO_HTCP);
 #endif
+
+    // allows adapter to safely ignore this in adapter::Service::configure()
+    metaBypassable.assignHostId(1);
 }
 
 std::string
index 6ec696b9075005143a010fd6880c00b3c8672103..846a707aaecfa11cb93c8c86b936247898c3d854 100644 (file)
@@ -47,6 +47,7 @@ extern const libecap::Name protocolIcp;
 #if USE_HTCP
 extern const libecap::Name protocolHtcp;
 #endif
+extern const libecap::Name metaBypassable; ///< an ecap_service parameter
 
 } // namespace Ecap
 } // namespace Adaptation
index e95296c81d2509d0bceee2aacbc3c313f85d04e2..c22d060bb41cc6d6dbbc5b22993e1de2a521d826 100644 (file)
@@ -4,10 +4,11 @@
 #include "squid.h"
 #include <list>
 #include <libecap/adapter/service.h>
-#include <libecap/common/config.h>
+#include <libecap/common/options.h>
 #include <libecap/common/name.h>
 #include <libecap/common/named_values.h>
 #include "adaptation/ecap/Config.h"
+#include "adaptation/ecap/Host.h"
 #include "adaptation/ecap/ServiceRep.h"
 #include "adaptation/ecap/XactionRep.h"
 #include "base/TextException.h"
 // configured eCAP service wrappers
 static std::list<Adaptation::Ecap::ServiceRep::AdapterService> TheServices;
 
+namespace Adaptation
+{
+namespace Ecap
+{
+
 /// wraps Adaptation::Ecap::ServiceConfig to allow eCAP visitors
-class ConfigRep: public libecap::Config
+class ConfigRep: public libecap::Options
 {
 public:
     typedef Adaptation::Ecap::ServiceConfig Master;
     typedef libecap::Name Name;
     typedef libecap::Area Area;
 
-    ConfigRep(const Master &aMaster): master(aMaster) {}
+    ConfigRep(const Master &aMaster);
 
-    // libecap::Config API
-    virtual void visitEach(libecap::NamedValueVisitor &visitor) const;
+    // libecap::Options API
+    virtual const libecap::Area option(const libecap::Name &name) const;
+    virtual void visitEachOption(libecap::NamedValueVisitor &visitor) const;
 
     const Master &master; ///< the configuration being wrapped
 };
 
+} // namespace Ecap
+} // namespace Adaptation
+
+
+Adaptation::Ecap::ConfigRep::ConfigRep(const Master &aMaster): master(aMaster)
+{
+}
+
+const libecap::Area
+Adaptation::Ecap::ConfigRep::option(const libecap::Name &name) const
+{
+    // we may supply the params we know about, but only when names have host ID
+    if (name == metaBypassable)
+        return Area(master.bypass ? "1" : "0", 1);
+
+    // TODO: We could build a by-name index, but is it worth it? Good adapters
+    // should use visitEachOption() instead, to check for name typos/errors.
+    typedef Master::Extensions::const_iterator MECI;
+    for (MECI i = master.extensions.begin(); i != master.extensions.end(); ++i) {
+        if (name == i->first)
+            return Area(i->second.data(), i->second.size());
+    }
+
+    return Area();
+}
+
 void
-ConfigRep::visitEach(libecap::NamedValueVisitor &visitor) const
+Adaptation::Ecap::ConfigRep::visitEachOption(libecap::NamedValueVisitor &visitor) const
 {
     // we may supply the params we know about too, but only if we set host ID
-    static const Name optBypass("bypassable");
-    if (!optBypass.assignedHostId())
-         optBypass.assignHostId(1); // allows adapter to safely ignore this
-    visitor.visit(optBypass, Area(master.bypass ? "1" : "0", 1));
+    visitor.visit(metaBypassable, Area(master.bypass ? "1" : "0", 1));
 
     // visit adapter-specific options (i.e., those not recognized by Squid)
     typedef Master::Extensions::const_iterator MECI;
@@ -70,7 +100,7 @@ Adaptation::Ecap::ServiceRep::finalize()
     theService = FindAdapterService(cfg().uri);
     if (theService) {
         debugs(93,3, HERE << "configuring eCAP service: " << theService->uri());
-        ConfigRep cfgRep(dynamic_cast<const ServiceConfig&>(cfg()));
+        const ConfigRep cfgRep(dynamic_cast<const ServiceConfig&>(cfg()));
         theService->configure(cfgRep);
 
         debugs(93,3, HERE << "starting eCAP service: " << theService->uri());
index 7a0876a49e71daadcddd80c8b07da521f39f733b..17e686136955945c9130eabdafe265e6d74df764 100644 (file)
@@ -4,11 +4,14 @@
 #include "squid.h"
 #include <libecap/common/area.h>
 #include <libecap/common/delay.h>
+#include <libecap/common/named_values.h>
+#include <libecap/common/names.h>
 #include <libecap/adapter/xaction.h>
 #include "HttpRequest.h"
 #include "HttpReply.h"
 #include "SquidTime.h"
 #include "adaptation/ecap/XactionRep.h"
+#include "adaptation/ecap/Config.h"
 #include "adaptation/Initiator.h"
 #include "base/TextException.h"
 
@@ -53,6 +56,67 @@ Adaptation::Ecap::XactionRep::service()
     return *theService;
 }
 
+const libecap::Area
+Adaptation::Ecap::XactionRep::option(const libecap::Name &name) const
+{
+    if (name == libecap::metaClientIp)
+        return clientIpValue();
+    if (name == libecap::metaUserName)
+        return usernameValue();
+    // TODO: metaServerIp, metaAuthenticatedUser, metaAuthenticatedGroups, and 
+    // Adaptation::Config::masterx_shared_name
+    return libecap::Area();
+}
+
+void
+Adaptation::Ecap::XactionRep::visitEachOption(libecap::NamedValueVisitor &visitor) const
+{
+    if (const libecap::Area value = clientIpValue())
+       visitor.visit(libecap::metaClientIp, value);
+    if (const libecap::Area value = usernameValue())
+       visitor.visit(libecap::metaUserName, value);
+    // TODO: metaServerIp, metaAuthenticatedUser, metaAuthenticatedGroups, and 
+    // Adaptation::Config::masterx_shared_name
+}
+
+const libecap::Area
+Adaptation::Ecap::XactionRep::clientIpValue() const
+{
+    const HttpRequest *request = dynamic_cast<const HttpRequest*>(theCauseRep ?
+                                 theCauseRep->raw().header : theVirginRep.raw().header);
+    Must(request);
+    // TODO: move this logic into HttpRequest::clientIp(bool) and
+    // HttpRequest::clientIpString(bool) and reuse everywhere
+    if (TheConfig.send_client_ip && request) {
+        Ip::Address client_addr;
+#if FOLLOW_X_FORWARDED_FOR
+        if (TheConfig.use_indirect_client) {
+            client_addr = request->indirect_client_addr;
+               } else
+#endif
+            client_addr = request->client_addr;
+        if (!client_addr.IsAnyAddr() && !client_addr.IsNoAddr()) {
+            char ntoabuf[MAX_IPSTRLEN] = "";
+            client_addr.NtoA(ntoabuf,MAX_IPSTRLEN);
+            return libecap::Area::FromTempBuffer(ntoabuf, strlen(ntoabuf));
+        }
+       }
+    return libecap::Area();
+}
+
+const libecap::Area
+Adaptation::Ecap::XactionRep::usernameValue() const
+{
+    const HttpRequest *request = dynamic_cast<const HttpRequest*>(theCauseRep ?
+                                 theCauseRep->raw().header : theVirginRep.raw().header);
+    Must(request);
+    if (request->auth_user_request != NULL) {
+        if (char const *name = request->auth_user_request->username())
+            return libecap::Area::FromTempBuffer(name, strlen(name));
+       }
+    return libecap::Area();
+}
+
 void
 Adaptation::Ecap::XactionRep::start()
 {
index 1a073502c1ac73f0247a7b9ab42c1d2765fb38f3..61163ee772b6c0124a284aac071136fda22984b3 100644 (file)
@@ -35,6 +35,8 @@ public:
     void master(const AdapterXaction &aMaster); // establish a link
 
     // libecap::host::Xaction API
+    virtual const libecap::Area option(const libecap::Name &name) const;
+    virtual void visitEachOption(libecap::NamedValueVisitor &visitor) const;
     virtual libecap::Message &virgin();
     virtual const libecap::Message &cause();
     virtual libecap::Message &adapted();
@@ -87,6 +89,9 @@ protected:
     void terminateMaster();
     void scheduleStop(const char *reason);
 
+    const libecap::Area clientIpValue() const;
+    const libecap::Area usernameValue() const;
+
 private:
     AdapterXaction theMaster; // the actual adaptation xaction we represent
     Adaptation::ServicePointer theService; ///< xaction's adaptation service
index d093c09221bd54e8418967a84f48017de85af2aa..ae54334c4a791db8df1f7bbe01e4b36a1d7b7a76 100644 (file)
@@ -1357,7 +1357,7 @@ void Adaptation::Icap::ModXact::makeRequestHeaders(MemBuf &buf)
     if (TheConfig.send_client_ip && request) {
         Ip::Address client_addr;
 #if FOLLOW_X_FORWARDED_FOR
-        if (TheConfig.icap_uses_indirect_client) {
+        if (TheConfig.use_indirect_client) {
             client_addr = request->indirect_client_addr;
         } else
 #endif
@@ -1366,7 +1366,7 @@ void Adaptation::Icap::ModXact::makeRequestHeaders(MemBuf &buf)
             buf.Printf("X-Client-IP: %s\r\n", client_addr.NtoA(ntoabuf,MAX_IPSTRLEN));
     }
 
-    if (TheConfig.send_client_username && request)
+    if (TheConfig.send_username && request)
         makeUsernameHeader(request, buf);
 
     // fprintf(stderr, "%s\n", buf.content());
index e485a9adfdc3e6e64d3b98ff31dcbb75569b1876..321b8c17071f356c1e586da93fac1ffbaddca60a 100644 (file)
@@ -4103,12 +4103,12 @@ Example:
  broken_posts allow buggy_server
 DOC_END
 
-NAME: icap_uses_indirect_client
+NAME: adaptation_uses_indirect_client icap_uses_indirect_client
 COMMENT: on|off
 TYPE: onoff
-IFDEF: FOLLOW_X_FORWARDED_FOR&&ICAP_CLIENT
+IFDEF: FOLLOW_X_FORWARDED_FOR&&USE_ADAPTATION
 DEFAULT: on
-LOC: Adaptation::Icap::TheConfig.icap_uses_indirect_client
+LOC: Adaptation::Config::use_indirect_client
 DOC_START
    Controls whether the indirect client address
    (see follow_x_forwarded_for) instead of the
@@ -6351,25 +6351,27 @@ DOC_START
        an ICAP server.
 DOC_END
 
-NAME: icap_send_client_ip
+NAME: adaptation_send_client_ip icap_send_client_ip
 TYPE: onoff
-IFDEF: ICAP_CLIENT
+IFDEF: USE_ADAPTATION
 COMMENT: on|off
-LOC: Adaptation::Icap::TheConfig.send_client_ip
+LOC: Adaptation::Config::send_client_ip
 DEFAULT: off
 DOC_START
        This adds the header "X-Client-IP" to ICAP requests.
 DOC_END
 
-NAME: icap_send_client_username
+NAME: adaptation_send_username icap_send_client_username
 TYPE: onoff
-IFDEF: ICAP_CLIENT
+IFDEF: USE_ADAPTATION
 COMMENT: on|off
-LOC: Adaptation::Icap::TheConfig.send_client_username
+LOC: Adaptation::Config::send_username
 DEFAULT: off
 DOC_START
        This sends authenticated HTTP client username (if available) to
-       the ICAP service. The username value is encoded based on the
+       the adaptation service.
+
+       For ICAP, the username value is encoded based on the
        icap_client_username_encode option and is sent using the header
        specified by the icap_client_username_header option.
 DOC_END
@@ -6380,7 +6382,7 @@ IFDEF: ICAP_CLIENT
 LOC: Adaptation::Icap::TheConfig.client_username_header
 DEFAULT: X-Client-Username
 DOC_START
-       ICAP request header name to use for send_client_username.
+       ICAP request header name to use for send_username.
 DOC_END
 
 NAME: icap_client_username_encode