#include "mgr/Command.h"
#include "mgr/Forwarder.h"
#include "mgr/FunAction.h"
+#include "mgr/QueryParams.h"
#include "protos.h" /* rotate_logs() */
#include "SquidTime.h"
#include "Store.h"
LOCAL_ARRAY(char, host, MAX_URL);
LOCAL_ARRAY(char, request, MAX_URL);
LOCAL_ARRAY(char, password, MAX_URL);
- t = sscanf(url, "cache_object://%[^/]/%[^@]@%s", host, request, password);
+ LOCAL_ARRAY(char, params, MAX_URL);
+ host[0] = 0;
+ request[0] = 0;
+ password[0] = 0;
+ params[0] = 0;
+ int pos = -1;
+ int len = strlen(url);
+ Must(len > 0);
+ t = sscanf(url, "cache_object://%[^/]/%[^@?]%n@%[^?]?%s", host, request, &pos, password, params);
+
+ Must(pos > 0);
+ if (url[pos] == '?') {
+ ++pos;
+ if (pos < len)
+ xstrncpy(params, url + pos, sizeof(params));
+ }
if (t < 2)
xstrncpy(request, "menu", MAX_URL);
}
Mgr::Command::Pointer cmd = new Mgr::Command;
+ if (!Mgr::QueryParams::Parse(params, cmd->params.queryParams))
+ return NULL;
cmd->profile = profile;
cmd->params.httpUri = url;
cmd->params.userName = String();
- cmd->params.password = t == 3 ? String(password) : String();
+ cmd->params.password = password;
cmd->params.actionName = request;
return cmd;
}
msg.getString(actionName);
msg.getString(userName);
msg.getString(password);
+ queryParams.unpack(msg);
}
void
msg.putString(actionName);
msg.putString(userName);
msg.putString(password);
+ queryParams.pack(msg);
}
#include "HttpRequestMethod.h"
#include "ipc/forward.h"
+#include "mgr/QueryParams.h"
namespace Mgr
{
String actionName; ///< action name (and credentials realm)
String userName; ///< user login name; currently only used for logging
String password; ///< user password; used for acceptance check and cleared
-
+ QueryParams queryParams;
};
} // namespace Mgr
#include "ipc/Coordinator.h"
#include "mgr/ActionWriter.h"
#include "mgr/Command.h"
+#include "mgr/IntParam.h"
#include "mgr/Inquirer.h"
#include "mgr/Request.h"
#include "mgr/Response.h"
aggrAction(anAction),
cause(aCause),
fd(aFd),
- strands(coords), pos(strands.begin()),
+ strands(applyQueryParams(coords, aCause.params.queryParams)), pos(strands.begin()),
requestId(0), closer(NULL), timeout(aggrAction->atomic() ? 10 : 100)
{
debugs(16, 5, HERE << "FD " << aFd << " action: " << aggrAction);
- // order by ascending kid IDs; useful for non-aggregatable stats
- std::sort(strands.begin(), strands.end(), LesserStrandByKidId);
-
closer = asyncCall(16, 5, "Mgr::Inquirer::noteCommClosed",
CommCbMemFunT<Inquirer, CommCloseCbParams>(this, &Inquirer::noteCommClosed));
comm_add_close_handler(fd, closer);
Must(aggrAction != NULL);
std::auto_ptr<HttpReply> reply(new HttpReply);
- reply->setHeaders(HTTP_OK, NULL, "text/plain", -1, squid_curtime, squid_curtime);
+ reply->setHeaders(strands.empty() ? HTTP_BAD_REQUEST : HTTP_OK, NULL, "text/plain", -1, squid_curtime, squid_curtime);
reply->header.putStr(HDR_CONNECTION, "close"); // until we chunk response
std::auto_ptr<MemBuf> replyBuf(reply->pack());
writer = asyncCall(16, 5, "Mgr::Inquirer::noteWroteHeader",
DequeueRequest(requestId);
requestId = 0;
}
- if (aggrAction->aggregatable()) {
+ if (!strands.empty() && aggrAction->aggregatable()) {
removeCloseHandler();
AsyncJob::Start(new ActionWriter(aggrAction, fd));
fd = -1; // should not close fd because we passed it to ActionWriter
buf.terminate();
return buf.content();
}
+
+Ipc::StrandCoords
+Mgr::Inquirer::applyQueryParams(const Ipc::StrandCoords& aStrands, const QueryParams& aParams)
+{
+ Ipc::StrandCoords strands;
+
+ QueryParam::Pointer processesParam = cause.params.queryParams.get("processes");
+ QueryParam::Pointer workersParam = cause.params.queryParams.get("workers");
+
+ if (processesParam == NULL || workersParam == NULL) {
+ if (processesParam != NULL) {
+ IntParam* param = dynamic_cast<IntParam*>(processesParam.getRaw());
+ if (param != NULL && param->type == QueryParam::ptInt) {
+ const std::vector<int>& processes = param->value();
+ for (Ipc::StrandCoords::const_iterator iter = aStrands.begin();
+ iter != aStrands.end(); ++iter)
+ {
+ if (std::find(processes.begin(), processes.end(), iter->kidId) != processes.end())
+ strands.push_back(*iter);
+ }
+ }
+ } else if (workersParam != NULL) {
+ IntParam* param = dynamic_cast<IntParam*>(workersParam.getRaw());
+ if (param != NULL && param->type == QueryParam::ptInt) {
+ const std::vector<int>& workers = param->value();
+ for (size_t i = 0; i < aStrands.size(); ++i)
+ {
+ if (std::find(workers.begin(), workers.end(), i + 1) != workers.end())
+ strands.push_back(aStrands[i]);
+ }
+ }
+ } else {
+ strands = aStrands;
+ }
+
+ // order by ascending kid IDs; useful for non-aggregatable stats
+ std::sort(strands.begin(), strands.end(), LesserStrandByKidId);
+ }
+
+ debugs(0, 0, HERE << "strands kid IDs = ");
+ for (Ipc::StrandCoords::const_iterator iter = strands.begin(); iter != strands.end(); ++iter) {
+ debugs(0, 0, HERE << iter->kidId);
+ }
+
+ return strands;
+}
void close();
void removeCloseHandler();
+ Ipc::StrandCoords applyQueryParams(const Ipc::StrandCoords& aStrands,
+ const QueryParams& aParams);
private:
Action::Pointer aggrAction; //< action to aggregate
--- /dev/null
+/*
+ * $Id$
+ *
+ * DEBUG: section 16 Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/IntParam.h"
+
+
+Mgr::IntParam::IntParam():
+ QueryParam(QueryParam::ptInt), array()
+{
+}
+
+Mgr::IntParam::IntParam(const std::vector<int>& anArray):
+ QueryParam(QueryParam::ptInt), array(anArray)
+{
+}
+
+void
+Mgr::IntParam::pack(Ipc::TypedMsgHdr& msg) const
+{
+ msg.putPod(type);
+ msg.putInt(array.size());
+ typedef std::vector<int>::const_iterator Iterator;
+ for (Iterator iter = array.begin(); iter != array.end(); ++iter)
+ msg.putInt(*iter);
+}
+
+void
+Mgr::IntParam::unpackValue(const Ipc::TypedMsgHdr& msg)
+{
+ array.clear();
+ int count = msg.getInt();
+ Must(count >= 0);
+ for ( ; count > 0; --count)
+ array.push_back(msg.getInt());
+}
+
+const std::vector<int>&
+Mgr::IntParam::value() const
+{
+ return array;
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * DEBUG: section 16 Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_INT_PARAM_H
+#define SQUID_MGR_INT_PARAM_H
+
+#include "ipc/forward.h"
+#include "mgr/forward.h"
+#include "mgr/QueryParam.h"
+#include <vector>
+
+
+namespace Mgr
+{
+
+class IntParam: public QueryParam
+{
+public:
+ IntParam();
+ IntParam(const std::vector<int>& anArray);
+ virtual void pack(Ipc::TypedMsgHdr& msg) const;
+ virtual void unpackValue(const Ipc::TypedMsgHdr& msg);
+ const std::vector<int>& value() const;
+
+private:
+ std::vector<int> array;
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_INT_PARAM_H */
StoreIoAction.cc \
StoreIoAction.h \
StoreToCommWriter.cc \
- StoreToCommWriter.h
+ StoreToCommWriter.h \
+ QueryParam.h \
+ QueryParams.cc \
+ QueryParams.h \
+ IntParam.cc \
+ IntParam.h \
+ StringParam.cc \
+ StringParam.h
--- /dev/null
+/*
+ * $Id$
+ *
+ * DEBUG: section 16 Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_QUERY_PARAM_H
+#define SQUID_MGR_QUERY_PARAM_H
+
+#include "ipc/forward.h"
+#include "RefCount.h"
+
+
+namespace Mgr
+{
+
+class QueryParam: public RefCountable
+{
+public:
+ typedef enum {ptInt = 1, ptString} Type;
+ typedef RefCount<QueryParam> Pointer;
+
+public:
+ QueryParam(Type aType): type(aType) {}
+ virtual ~QueryParam() {}
+ virtual void pack(Ipc::TypedMsgHdr& msg) const = 0; ///< store parameter into msg
+ virtual void unpackValue(const Ipc::TypedMsgHdr& msg) = 0; ///< load parameter value from msg
+
+private:
+ QueryParam(const QueryParam&); // not implemented
+ QueryParam& operator= (const QueryParam&); // not implemented
+
+public:
+ Type type;
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_QUERY_PARAM_H */
--- /dev/null
+/*
+ * $Id$
+ *
+ * DEBUG: section 16 Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/IntParam.h"
+#include "mgr/StringParam.h"
+#include "mgr/QueryParams.h"
+#include <regex.h>
+
+
+Mgr::QueryParam::Pointer
+Mgr::QueryParams::get(const String& name)
+{
+ Must(name.size() != 0);
+ Params::iterator pos = find(name);
+ return (pos == params.end() ? NULL : pos->second);
+}
+
+void
+Mgr::QueryParams::pack(Ipc::TypedMsgHdr& msg) const
+{
+ msg.putInt(params.size());
+ for (Params::const_iterator iter = params.begin(); iter != params.end(); ++iter) {
+ Must(iter->first.size() != 0);
+ msg.putString(iter->first);
+ Must(iter->second != NULL);
+ iter->second->pack(msg);
+ }
+}
+
+void
+Mgr::QueryParams::unpack(const Ipc::TypedMsgHdr& msg)
+{
+ int count = msg.getInt();
+ Must(count >= 0);
+ params.clear();
+ for ( ; count > 0; --count) {
+ String name;
+ msg.getString(name);
+ Must(name.size() != 0);
+ QueryParam::Type type;
+ msg.getPod(type);
+ QueryParam::Pointer value = CreateParam(type);
+ value->unpackValue(msg);
+ params.push_back(Param(name, value));
+ }
+}
+
+Mgr::QueryParams::Params::iterator
+Mgr::QueryParams::find(const String& name)
+{
+ Must(name.size() != 0);
+ Params::iterator iter = params.begin();
+ for ( ; iter != params.end(); ++iter) {
+ if (name.caseCmp(iter->first) == 0)
+ break;
+ }
+ return iter;
+}
+
+bool
+Mgr::QueryParams::ParseParam(const String& paramStr, Param& param)
+{
+ bool parsed = false;
+ regmatch_t pmatch[3];
+ regex_t intExpr;
+ regcomp(&intExpr, "^([a-z][a-z0-9_]*)=([0-9]+((,[0-9]+))*)$", REG_EXTENDED | REG_ICASE);
+ regex_t stringExpr;
+ regcomp(&stringExpr, "^([a-z][a-z0-9_]*)=([^&= ]+)$", REG_EXTENDED | REG_ICASE);
+ if (regexec(&intExpr, paramStr.termedBuf(), 3, pmatch, 0) == 0) {
+ param.first = paramStr.substr(pmatch[1].rm_so, pmatch[1].rm_eo);
+ std::vector<int> array;
+ int n = pmatch[2].rm_so;
+ for (int i = n; i < pmatch[2].rm_eo; ++i) {
+ if (paramStr[i] == ',') {
+ array.push_back(atoi(paramStr.substr(n, i).termedBuf()));
+ n = i + 1;
+ }
+ }
+ if (n < pmatch[2].rm_eo)
+ array.push_back(atoi(paramStr.substr(n, pmatch[2].rm_eo).termedBuf()));
+ param.second = new IntParam(array);
+ parsed = true;
+ } else if (regexec(&stringExpr, paramStr.termedBuf(), 3, pmatch, 0) == 0) {
+ param.first = paramStr.substr(pmatch[1].rm_so, pmatch[1].rm_eo);
+ param.second = new StringParam(paramStr.substr(pmatch[2].rm_so, pmatch[2].rm_eo));
+ parsed = true;
+ }
+ regfree(&stringExpr);
+ regfree(&intExpr);
+ return parsed;
+}
+
+bool
+Mgr::QueryParams::Parse(const String& aParamsStr, QueryParams& aParams)
+{
+ if (aParamsStr.size() != 0) {
+ Param param;
+ size_t n = 0;
+ size_t len = aParamsStr.size();
+ for (size_t i = n; i < len; ++i) {
+ if (aParamsStr[i] == '&') {
+ if (!ParseParam(aParamsStr.substr(n, i), param))
+ return false;
+ aParams.params.push_back(param);
+ n = i + 1;
+ }
+ }
+ if (n < len) {
+ if (!ParseParam(aParamsStr.substr(n, len), param))
+ return false;
+ aParams.params.push_back(param);
+ }
+ }
+ return true;
+}
+
+Mgr::QueryParam::Pointer
+Mgr::QueryParams::CreateParam(QueryParam::Type aType)
+{
+ switch(aType) {
+ case QueryParam::ptInt:
+ return new IntParam();
+
+ case QueryParam::ptString:
+ return new StringParam();
+
+ default:
+ throw TexcHere("unknown parameter type");
+ break;
+ }
+ return NULL;
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * DEBUG: section 16 Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_QUERY_PARAMS_H
+#define SQUID_MGR_QUERY_PARAMS_H
+
+#include "ipc/forward.h"
+#include "mgr/QueryParam.h"
+#include "SquidString.h"
+#include <vector>
+#include <utility>
+
+
+namespace Mgr
+{
+
+class QueryParams
+{
+public:
+ typedef std::pair<String, QueryParam::Pointer> Param;
+ typedef std::vector<Param> Params;
+
+public:
+ /// returns query parameter by name
+ QueryParam::Pointer get(const String& name);
+ void pack(Ipc::TypedMsgHdr& msg) const; ///< store params into msg
+ void unpack(const Ipc::TypedMsgHdr& msg); ///< load params from msg
+ /// parses the query string parameters
+ static bool Parse(const String& aParamsStr, QueryParams& aParams);
+
+private:
+ /// find query parameter by name
+ Params::iterator find(const String& name);
+ /// creates a parameter of the specified type
+ static QueryParam::Pointer CreateParam(QueryParam::Type aType);
+ /// parses string like "param=value"; returns true if success
+ static bool ParseParam(const String& paramStr, Param& param);
+
+private:
+ Params params;
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_QUERY_PARAMS_H */
--- /dev/null
+/*
+ * $Id$
+ *
+ * DEBUG: section 16 Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/StringParam.h"
+
+
+Mgr::StringParam::StringParam():
+ QueryParam(QueryParam::ptString), str()
+{
+}
+
+Mgr::StringParam::StringParam(const String& aString):
+ QueryParam(QueryParam::ptString), str(aString)
+{
+}
+
+void
+Mgr::StringParam::pack(Ipc::TypedMsgHdr& msg) const
+{
+ msg.putPod(type);
+ msg.putString(str);
+}
+
+void
+Mgr::StringParam::unpackValue(const Ipc::TypedMsgHdr& msg)
+{
+ msg.getString(str);
+}
+
+const String&
+Mgr::StringParam::value() const
+{
+ return str;
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * DEBUG: section 16 Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_STRING_PARAM_H
+#define SQUID_MGR_STRING_PARAM_H
+
+#include "ipc/forward.h"
+#include "mgr/forward.h"
+#include "mgr/QueryParam.h"
+#include "SquidString.h"
+
+
+namespace Mgr
+{
+
+class StringParam: public QueryParam
+{
+public:
+ StringParam();
+ StringParam(const String& aString);
+ virtual void pack(Ipc::TypedMsgHdr& msg) const;
+ virtual void unpackValue(const Ipc::TypedMsgHdr& msg);
+ const String& value() const;
+
+private:
+ String str;
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_STRING_PARAM_H */
class Command;
class Request;
class Response;
+class QueryParam;
+class QueryParams;
typedef RefCount<Action> ActionPointer;
typedef RefCount<ActionProfile> ActionProfilePointer;