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*
// 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;
#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;
#if USE_HTCP
protocolHtcp.assignHostId(PROTO_HTCP);
#endif
+
+ // allows adapter to safely ignore this in adapter::Service::configure()
+ metaBypassable.assignHostId(1);
}
std::string
#if USE_HTCP
extern const libecap::Name protocolHtcp;
#endif
+extern const libecap::Name metaBypassable; ///< an ecap_service parameter
} // namespace Ecap
} // namespace Adaptation
#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;
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());
#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"
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()
{
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();
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
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
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());
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
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
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