/// initial URL path characters that identify cache manager requests
static const SBuf &WellKnownUrlPathPrefix();
- void registerProfile(char const * action, char const * desc,
- OBJH * handler,
- int pw_req_flag, int atomic);
- void registerProfile(char const * action, char const * desc,
- Mgr::ClassActionCreationHandler *handler,
- int pw_req_flag, int atomic);
+ /// remembers the given profile while ignoring attempts to register a same-name duplicate
+ void registerProfile(const Mgr::ActionProfilePointer &);
+
Mgr::ActionProfilePointer findAction(char const * action) const;
Mgr::Action::Pointer createNamedAction(const char *actionName);
Mgr::Action::Pointer createRequestedAction(const Mgr::ActionParams &);
int CheckPassword(const Mgr::Command &cmd);
char *PasswdGet(Mgr::ActionPasswordList *, const char *);
- void registerProfile(const Mgr::ActionProfilePointer &profile);
-
Menu menu_;
};
tests/stub_libdiskio.cc \
tests/stub_liberror.cc \
tests/stub_libsecurity.cc \
- tests/stub_libstore.cc \
tests/stub_main_cc.cc \
mem_node.cc \
mime.cc \
/// \ingroup CacheManagerInternal
#define MGR_PASSWD_SZ 128
-/// creates Action using supplied Action::Create method and command
-class ClassActionCreator: public Mgr::ActionCreator
-{
-public:
- typedef Mgr::Action::Pointer Handler(const Mgr::Command::Pointer &cmd);
-
-public:
- ClassActionCreator(Handler *aHandler): handler(aHandler) {}
-
- Mgr::Action::Pointer create(const Mgr::Command::Pointer &cmd) const override {
- return handler(cmd);
- }
-
-private:
- Handler *handler;
-};
-
-/// Registers new profiles, ignoring attempts to register a duplicate
void
CacheManager::registerProfile(const Mgr::ActionProfile::Pointer &profile)
{
}
}
-/**
- \ingroup CacheManagerAPI
- * Registers a C-style action, which is implemented as a pointer to a function
- * taking as argument a pointer to a StoreEntry and returning void.
- * Implemented via CacheManagerActionLegacy.
- */
-void
-CacheManager::registerProfile(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic)
-{
- debugs(16, 3, "registering legacy " << action);
- const Mgr::ActionProfile::Pointer profile = new Mgr::ActionProfile(action,
- desc, pw_req_flag, atomic, new Mgr::FunActionCreator(handler));
- registerProfile(profile);
-}
-
-/**
- * \ingroup CacheManagerAPI
- * Registers a C++-style action, via a pointer to a subclass of
- * a CacheManagerAction object, whose run() method will be invoked when
- * CacheManager identifies that the user has requested the action.
- */
-void
-CacheManager::registerProfile(char const * action, char const * desc,
- ClassActionCreator::Handler *handler,
- int pw_req_flag, int atomic)
-{
- const Mgr::ActionProfile::Pointer profile = new Mgr::ActionProfile(action,
- desc, pw_req_flag, atomic, new ClassActionCreator(handler));
- registerProfile(profile);
-}
-
/**
\ingroup CacheManagerInternal
* Locates an action in the actions registry ActionsList.
return command().profile->isAtomic;
}
+Mgr::Format
+Mgr::Action::format() const
+{
+ return command().profile->format;
+}
+
const char*
Mgr::Action::name() const
{
return command().profile->name;
}
+const char *
+Mgr::Action::contentType() const
+{
+ switch (format()) {
+ case Format::yaml:
+ return "application/yaml;charset=utf-8";
+ case Format::informal:
+ return "text/plain;charset=utf-8";
+ }
+ assert(!"unreachable code");
+ return "";
+}
+
StoreEntry*
Mgr::Action::createStoreEntry() const
{
entry->complete();
}
+void
+Mgr::OpenKidSection(StoreEntry * const entry, const Format format)
+{
+ switch (format) {
+ case Format::yaml:
+ return storeAppendPrintf(entry, "---\nkid: %d\n", KidIdentifier);
+ case Format::informal:
+ return storeAppendPrintf(entry, "by kid%d {\n", KidIdentifier);
+ }
+ // unreachable code
+}
+
+void
+Mgr::CloseKidSection(StoreEntry * const entry, const Format format)
+{
+ switch (format) {
+ case Format::yaml:
+ return storeAppendPrintf(entry, "...\n");
+ case Format::informal:
+ return storeAppendPrintf(entry, "} by kid%d\n\n", KidIdentifier);
+ }
+ // unreachable code
+}
#define SQUID_SRC_MGR_ACTION_H
#include "ipc/forward.h"
+#include "mgr/ActionFeatures.h"
#include "mgr/forward.h"
class StoreEntry;
/// combined data should be written at the end of the coordinated response
virtual bool aggregatable() const { return true; } // most kid classes are
+ /// action report syntax
+ virtual Format format() const;
+
bool atomic() const; ///< dump() call writes everything before returning
const char *name() const; ///< label as seen in the cache manager menu
const Command &command() const; ///< the cause of this action
StoreEntry *createStoreEntry() const; ///< creates store entry from params
- ///< Content-Type: header value for this report
- virtual const char *contentType() const {return "text/plain;charset=utf-8";}
+ /// HTTP Content-Type header value for this Action report
+ const char *contentType() const;
protected:
/// calculate and keep local action-specific information
Action &operator= (const Action &); // not implemented
};
+/// starts writing a portion of the report specific to the current process
+/// \sa CloseKidSection()
+void OpenKidSection(StoreEntry *, Format);
+
+/// finishes writing a portion of the report specific to the current process
+/// \sa OpenKidSection()
+void CloseKidSection(StoreEntry *, Format);
+
} // namespace Mgr
#endif /* SQUID_SRC_MGR_ACTION_H */
--- /dev/null
+/*
+ * Copyright (C) 1996-2024 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SRC_MGR_ACTIONFEATURES_H
+#define SQUID_SRC_MGR_ACTIONFEATURES_H
+
+namespace Mgr
+{
+
+// Scoped enumeration declarations below solve two problems with ActionProfile
+// constructor, RegisterAction(), and related function calls, making argument
+// lists readable and safe:
+// 1. They eliminate dangerous guessing of f(..., 0, 1, false) meaning by
+// converting each anonymous constant into a named one (e.g., Atomic::no).
+// 2. They prevent accidental argument reordering by prohibiting implicit value
+// casts (e.g., both f(1, false) and f(false, 1) would otherwise compile).
+
+/// whether default cachemgr_passwd configuration denies the Action
+enum class Protected { no, yes };
+
+/// whether Action::dump() writes the entire report before returning
+enum class Atomic { no, yes };
+
+/// whether Action report uses valid YAML or unspecified/legacy formatting
+enum class Format { informal, yaml };
+
+} // namespace Mgr
+
+#endif /* SQUID_SRC_MGR_ACTIONFEATURES_H */
+
#define SQUID_SRC_MGR_ACTIONPROFILE_H
#include "mgr/ActionCreator.h"
+#include "mgr/ActionFeatures.h"
#include "mgr/forward.h"
namespace Mgr
typedef RefCount<ActionProfile> Pointer;
public:
- ActionProfile(const char* aName, const char* aDesc, bool aPwReq,
- bool anAtomic, const ActionCreatorPointer &aCreator):
- name(aName), desc(aDesc), isPwReq(aPwReq), isAtomic(anAtomic),
+ ActionProfile(const char* aName, const char* aDesc,
+ ActionCreatorPointer aCreator,
+ const Protected aProtected,
+ const Atomic anAtomic,
+ const Format aFormat):
+ name(aName), desc(aDesc),
+ isPwReq(aProtected == Protected::yes),
+ isAtomic(anAtomic == Atomic::yes),
+ format(aFormat),
creator(aCreator) {
}
const char *desc; ///< action description to build an action menu list
bool isPwReq; ///< whether password is required to perform the action
bool isAtomic; ///< whether action dumps everything in one dump() call
+ Format format; ///< action report syntax
ActionCreatorPointer creator; ///< creates Action objects with this profile
};
{
debugs(16, 5, MYNAME);
Must(entry != nullptr);
- if (UsingSmp())
- storeAppendPrintf(entry, "by kid%d {\n", KidIdentifier);
+
+ OpenKidSection(entry, format());
+
handler(entry);
- if (atomic() && UsingSmp())
- storeAppendPrintf(entry, "} by kid%d\n\n", KidIdentifier);
-}
+ if (atomic())
+ CloseKidSection(entry, format());
+ // non-atomic() actions must call CloseKidSection() when they are done
+}
OBJH *handler; ///< legacy function that collects and dumps info
};
-/// creates FunAction using ActionCreator API
-class FunActionCreator: public ActionCreator
-{
-public:
- explicit FunActionCreator(OBJH *aHandler): handler(aHandler) {}
-
- /* ActionCreator API */
- Action::Pointer create(const CommandPointer &cmd) const override {
- return FunAction::Create(cmd, handler);
- }
-
-private:
- OBJH *handler; ///< legacy function to pass to the FunAction wrapper
-};
-
} // namespace Mgr
#endif /* SQUID_SRC_MGR_FUNACTION_H */
Must(entry != nullptr);
#if XMALLOC_STATISTICS
- if (UsingSmp())
- storeAppendPrintf(entry, "by kid%d {\n", KidIdentifier);
+ // TODO: Move these stats into a new dedicated report.
+ Mgr::OpenKidSection(entry, Mgr::Format::informal);
DumpMallocStatistics(entry);
- if (UsingSmp())
- storeAppendPrintf(entry, "} by kid%d\n\n", KidIdentifier);
+ Mgr::CloseKidSection(entry, Mgr::Format::informal);
#endif
if (IamPrimaryProcess())
DumpInfo(data, entry);
replyBuf.reset(reply->pack());
} else {
std::unique_ptr<HttpReply> reply(new HttpReply);
- reply->setHeaders(Http::scOkay, nullptr, "text/plain", -1, squid_curtime, squid_curtime);
+ reply->setHeaders(Http::scOkay, nullptr, aggrAction->contentType(), -1, squid_curtime, squid_curtime);
CacheManager::PutCommonResponseHeaders(*reply, originOrNil);
reply->header.putStr(Http::HdrType::CONNECTION, "close"); // until we chunk response
replyBuf.reset(reply->pack());
Action.cc \
Action.h \
ActionCreator.h \
+ ActionFeatures.h \
ActionParams.cc \
ActionParams.h \
ActionPasswordList.cc \
#include "squid.h"
#include "CacheManager.h"
+#include "mgr/FunAction.h"
#include "mgr/Registration.h"
+namespace Mgr {
+
+/// creates FunAction using ActionCreator API
+class FunActionCreator: public ActionCreator
+{
+public:
+ explicit FunActionCreator(OBJH * const aHandler): handler(aHandler) {}
+
+ /* ActionCreator API */
+ Action::Pointer create(const CommandPointer &cmd) const override {
+ return FunAction::Create(cmd, handler);
+ }
+
+private:
+ OBJH *handler; ///< legacy function to pass to the FunAction wrapper
+};
+
+/// creates Action using supplied Action::Create method and command
+class ClassActionCreator: public ActionCreator
+{
+public:
+ using Handler = ClassActionCreationHandler;
+
+public:
+ ClassActionCreator(Handler * const aHandler): handler(aHandler) {}
+
+ /* ActionCreator API */
+ Action::Pointer create(const Command::Pointer &cmd) const override {
+ return handler(cmd);
+ }
+
+private:
+ Handler *handler; ///< configured Action object creator
+};
+
+} // namespace Mgr
+
void
Mgr::RegisterAction(char const * action, char const * desc,
OBJH * handler,
- int pw_req_flag, int atomic)
+ const Protected protection,
+ const Atomic atomicity,
+ const Format format)
{
- CacheManager::GetInstance()->registerProfile(action, desc, handler,
- pw_req_flag, atomic);
+ debugs(16, 3, "function-based " << action);
+ const auto profile = ActionProfile::Pointer::Make(action,
+ desc, new FunActionCreator(handler),
+ protection, atomicity, format);
+ CacheManager::GetInstance()->registerProfile(profile);
}
void
Mgr::RegisterAction(char const * action, char const * desc,
ClassActionCreationHandler *handler,
- int pw_req_flag, int atomic)
+ const Protected protection,
+ const Atomic atomicity,
+ const Format format)
{
- CacheManager::GetInstance()->registerProfile(action, desc, handler,
- pw_req_flag, atomic);
+ debugs(16, 3, "class-based " << action);
+ const auto profile = ActionProfile::Pointer::Make(action,
+ desc, new ClassActionCreator(handler),
+ protection, atomicity, format);
+ CacheManager::GetInstance()->registerProfile(profile);
}
#ifndef SQUID_SRC_MGR_REGISTRATION_H
#define SQUID_SRC_MGR_REGISTRATION_H
+#include "mgr/ActionFeatures.h"
#include "mgr/forward.h"
namespace Mgr
{
+/// Creates a function-based action profile and adds it to the cache manager
+/// collection (once across all calls with the same action name).
void RegisterAction(char const * action, char const * desc,
OBJH * handler,
- int pw_req_flag, int atomic);
+ Protected, Atomic, Format);
+/// wrapper for legacy Format-unaware function-based action registration code
+inline void
+RegisterAction(const char * const action, const char * const desc,
+ OBJH * handler,
+ int pw_req_flag, int atomic)
+{
+ return RegisterAction(action, desc, handler,
+ (pw_req_flag ? Protected::yes : Protected::no),
+ (atomic ? Atomic::yes : Atomic::no),
+ Format::informal);
+}
+
+/// Creates a class-based action profile and adds it to the cache manager
+/// collection (once across all calls with the same action name).
void RegisterAction(char const * action, char const * desc,
ClassActionCreationHandler *handler,
- int pw_req_flag, int atomic);
+ Protected, Atomic, Format);
+
+/// wrapper for legacy Format-unaware class-based action registration code
+inline void
+RegisterAction(const char * const action, const char * const desc,
+ ClassActionCreationHandler *handler,
+ int pw_req_flag, int atomic)
+{
+ return RegisterAction(action, desc, handler,
+ (pw_req_flag ? Protected::yes : Protected::no),
+ (atomic ? Atomic::yes : Atomic::no),
+ Format::informal);
+}
} // namespace Mgr
{
Mgr::RegisterAction("pconn",
"Persistent Connection Utilization Histograms",
- DumpWrapper, 0, 1);
+ DumpWrapper, Mgr::Protected::no, Mgr::Atomic::yes,
+ Mgr::Format::yaml);
}
void
StoreEntry *e;
if (state->theSearch->isDone()) {
- if (UsingSmp())
- storeAppendPrintf(state->sentry, "} by kid%d\n\n", KidIdentifier);
+ Mgr::CloseKidSection(state->sentry, Mgr::Format::informal);
state->sentry->complete();
state->sentry->unlock("statObjects+isDone");
delete state;
}
static CacheManager* instance = nullptr;
CacheManager* CacheManager::GetInstance() STUB_RETVAL(instance)
-void Mgr::RegisterAction(char const*, char const*, OBJH, int, int) {}
-void Mgr::RegisterAction(char const *, char const *, Mgr::ClassActionCreationHandler *, int, int) {}
+void Mgr::RegisterAction(char const *, char const *, OBJH *, Protected, Atomic, Format) {}
+void Mgr::RegisterAction(char const *, char const *, ClassActionCreationHandler *, Protected, Atomic, Format) {}
Mgr::Action::Pointer CacheManager::createRequestedAction(const Mgr::ActionParams &) STUB_RETVAL(nullptr)
void CacheManager::PutCommonResponseHeaders(HttpReply &, const char *) STUB
void Mgr::Action::add(const Action &) STUB
void Mgr::Action::respond(const Request &) STUB
void Mgr::Action::sendResponse(const Ipc::RequestId) STUB
+Mgr::Format Mgr::Action::format() const STUB_RETVAL(Mgr::Format::informal)
bool Mgr::Action::atomic() const STUB_RETVAL(false)
const char * Mgr::Action::name() const STUB_RETVAL(nullptr)
static Mgr::Command static_Command;
Mgr::QueryParam::Pointer Mgr::QueryParams::CreateParam(QueryParam::Type) STUB_RETVAL(Mgr::QueryParam::Pointer(nullptr))
#include "mgr/Registration.h"
-//void Mgr::RegisterAction(char const *, char const *, OBJH *, int, int);
-//void Mgr::RegisterAction(char const *, char const *, ClassActionCreationHandler *, int, int);
+//void Mgr::RegisterAction(char const *, char const *, OBJH *, Protected, Atomic, Format);
+//void Mgr::RegisterAction(char const *, char const *, ClassActionCreationHandler *, Protected, Atomic, Format);
#include "mgr/Request.h"
//Mgr::Request::Request(int, unsigned int, int, const Mgr::ActionParams &) STUB
#include "CacheManager.h"
#include "compat/cppunit.h"
#include "mgr/Action.h"
+#include "mgr/Registration.h"
#include "Store.h"
#include "unitTestMain.h"
CacheManager *manager=CacheManager::GetInstance();
CPPUNIT_ASSERT(manager != nullptr);
- manager->registerProfile("sample", "my sample", &dummy_action, false, false);
+ Mgr::RegisterAction("sample", "my sample", &dummy_action, Mgr::Protected::no, Mgr::Atomic::no, Mgr::Format::informal);
Mgr::Action::Pointer action = manager->createNamedAction("sample");
CPPUNIT_ASSERT(action != nullptr);
CPPUNIT_ASSERT(profile->creator != nullptr);
CPPUNIT_ASSERT_EQUAL(false, profile->isPwReq);
CPPUNIT_ASSERT_EQUAL(false, profile->isAtomic);
+ CPPUNIT_ASSERT_EQUAL(Mgr::Format::informal, profile->format);
+ CPPUNIT_ASSERT_EQUAL(Mgr::Format::informal, action->format());
CPPUNIT_ASSERT_EQUAL(String("sample"), String(action->name()));
StoreEntry *sentry=new StoreEntry();
+ sentry->createMemObject();
sentry->flags=0x25; //arbitrary test value
action->run(sentry, false);
CPPUNIT_ASSERT_EQUAL(1,(int)sentry->flags);