]> git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/Options.h
9746a0b42e9508782652c7fdea4ae73ffabc1987
[thirdparty/squid.git] / src / acl / Options.h
1 /*
2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 #ifndef SQUID_ACL_OPTIONS_H
10 #define SQUID_ACL_OPTIONS_H
11
12 #include "acl/forward.h"
13 #include "sbuf/forward.h"
14
15 #include <iosfwd>
16 #include <vector>
17
18 // After line continuation is handled by the preprocessor, an ACL object
19 // configuration can be visualized as a sequence of same-name "acl ..." lines:
20 //
21 // L1: acl exampleA typeT parameter1 -i parameter2 parameter3
22 // L2: acl exampleA typeT parameter4
23 // L3: acl exampleA typeT -i -n parameter5 +i parameter6
24 // L4: acl exampleA typeT -n parameter7
25 //
26 // There are two kinds of ACL options (a.k.a. flags):
27 //
28 // * Global (e.g., "-n"): Applies to all parameters regardless of where the
29 // option was discovered/parsed (e.g., "-n" on L3 affects parameter2 on L1).
30 // Declared by ACL class kids (or equivalent) via ACL::options().
31 //
32 // * Line (e.g., "-i"): Applies to the yet unparsed ACL parameters of the
33 // current "acl ..." line (e.g., "-i" on L1 has no effect on parameter4 on L2)
34 // Declared by ACLData class kids (or equivalent) via lineOptions().
35 //
36 // Here is the option:explicitly-affected-parameters map for the above exampleA:
37 // "-n": parameter1-7 (i.e. all parameters)
38 // "-i": parameter2, parameter3; parameter5
39 // "+i": parameter6
40 //
41 // The option name spelling determines the option kind and effect.
42 // Both option kinds use the same general option configuration syntax:
43 // option = name [ '=' value ]
44 // where "name" is option-specific spelling that looks like -x, +x, or --long
45 //
46 // On each "acl ..." line, global options can only appear before the first
47 // parameter, while line options can go before any parameter.
48 //
49 // XXX: The fact that global options affect previous (and subsequent) same-name
50 // "acl name ..." lines surprises and confuses those who comprehend ACLs in
51 // terms of configuration lines (which Squid effectively merges together).
52
53 namespace Acl {
54
55 /// A single option supported by an ACL: -x[=value] or --name[=value]
56 class Option
57 {
58 public:
59 typedef enum { valueNone, valueOptional, valueRequired } ValueExpectation;
60 explicit Option(const char *nameThatEnables, const char *nameThatDisables = nullptr, ValueExpectation vex = valueNone);
61 virtual ~Option() {}
62
63 /// whether the admin explicitly specified this option (i.e., whether
64 /// enable(), configureWith(), or disable() has been called)
65 virtual bool configured() const = 0;
66
67 /// called after parsing onName without a value (e.g., -x or --enable-x)
68 virtual void enable() const = 0;
69
70 /// called after parsing onName and a value (e.g., -x=v or --enable-x=v)
71 virtual void configureWith(const SBuf &rawValue) const = 0;
72
73 /// called after parsing offName (e.g., +i or --disable-x)
74 virtual void disable() const = 0;
75
76 /// clear enable(), configureWith(), or disable() effects
77 virtual void unconfigure() const = 0;
78
79 /// whether disable() has been called
80 virtual bool disabled() const = 0;
81
82 virtual bool valued() const = 0;
83
84 /// prints a configuration snippet (as an admin could have typed)
85 virtual void print(std::ostream &os) const = 0;
86
87 /// A name that must be used to explicitly enable this Option (required).
88 const char * const onName = nullptr;
89
90 /// A name that must be used to explicitly disable this Option (optional).
91 /// Nil for (and only for) options that cannot be disabled().
92 const char * const offName = nullptr;
93
94 ValueExpectation valueExpectation = valueNone; ///< expect "=value" part?
95 };
96
97 /// Stores configuration of a typical boolean flag or a single-value Option.
98 template <class Value>
99 class OptionValue
100 {
101 public:
102 typedef Value value_type;
103
104 // TODO: Some callers use .value without checking whether the option is
105 // enabled(), accessing the (default-initialized or customized) default
106 // value that way. This trick will stop working if we add valued options
107 // that can be disabled (e.g., --with-foo=x --without-foo). To support such
108 // options, store the default value separately and provide value accessor.
109
110 OptionValue(): value {} {}
111 explicit OptionValue(const Value &aValue): value(aValue) {}
112
113 /// whether the option is explicitly turned "on" (with or without a value)
114 bool enabled() const { return configured && !disabled; }
115 explicit operator bool() const { return enabled(); }
116
117 /// go back to the default-initialized state
118 void reset() { *this = OptionValue<Value>(); }
119
120 Value value; ///< final value storage, possibly after conversions
121 bool configured = false; ///< whether the option was present in squid.conf
122 /* flags for configured options */
123 bool disabled = false; ///< whether the option was turned off
124 bool valued = false; ///< whether a configured option had a value
125 };
126
127 /// a type-specific Option (e.g., a boolean --toggle or -m=SBuf)
128 template <class Recipient>
129 class TypedOption: public Option
130 {
131 public:
132 //typedef typename Recipient::value_type value_type;
133 explicit TypedOption(const char *nameThatEnables, const char *nameThatDisables = nullptr, ValueExpectation vex = valueNone):
134 Option(nameThatEnables, nameThatDisables, vex) {}
135
136 /// who to tell when this option is enabled
137 void linkWith(Recipient *recipient) const
138 {
139 assert(recipient);
140 recipient_ = recipient;
141 }
142
143 /* Option API */
144
145 bool configured() const override { return recipient_ && recipient_->configured; }
146 bool disabled() const override { return recipient_ && recipient_->disabled && /* paranoid: */ offName; }
147 bool valued() const override { return recipient_ && recipient_->valued; }
148
149 void unconfigure() const override {
150 assert(recipient_);
151 recipient_->reset();
152 }
153
154 void enable() const override
155 {
156 assert(recipient_);
157 recipient_->configured = true;
158 recipient_->disabled = false;
159 recipient_->valued = false;
160 // leave recipient_->value unchanged
161 }
162
163 void configureWith(const SBuf &rawValue) const override
164 {
165 assert(recipient_);
166 recipient_->configured = true;
167 recipient_->disabled = false;
168 recipient_->valued = true;
169 import(rawValue);
170 }
171
172 void disable() const override
173 {
174 assert(recipient_);
175 recipient_->configured = true;
176 recipient_->disabled = true;
177 recipient_->valued = false;
178 // leave recipient_->value unchanged
179 }
180
181 void print(std::ostream &os) const override
182 {
183 if (configured()) {
184 os << ' ' << (disabled() ? offName : onName);
185 if (valued())
186 os << '=' << recipient_->value;
187 }
188 // else do not report the implicit default
189 }
190
191 private:
192 void import(const SBuf &rawValue) const { recipient_->value = rawValue; }
193
194 // The "mutable" specifier demarcates set-once Option kind/behavior from the
195 // ever-changing recipient of the actual admin-configured option value.
196 mutable Recipient *recipient_ = nullptr; ///< parsing results storage
197 };
198
199 /* two typical option kinds: --foo and --bar=text */
200 typedef OptionValue<bool> BooleanOptionValue;
201 typedef OptionValue<SBuf> TextOptionValue;
202 typedef TypedOption<BooleanOptionValue> BooleanOption;
203 typedef TypedOption<TextOptionValue> TextOption;
204
205 // this specialization should never be called until we start supporting
206 // boolean option values like --name=enable or --name=false
207 template <>
208 inline void
209 BooleanOption::import(const SBuf &) const
210 {
211 assert(!"boolean options do not have ...=values (for now)");
212 }
213
214 using Options = std::vector<const Option *>;
215
216 /// parses the flags part of the being-parsed ACL, filling Option values
217 /// \param options options supported by the ACL as a whole (e.g., -n)
218 void ParseFlags(const Options &options);
219
220 /* handy for Class::options() and lineOptions() defaults */
221 const Options &NoOptions(); ///< \returns an empty Options container
222
223 /// A boolean option that controls case-sensitivity (-i/+i).
224 /// An enabled (-i) state is "case insensitive".
225 /// A disabled (+i) and default states are "case sensitive".
226 const BooleanOption &CaseSensitivityOption();
227
228 std::ostream &operator <<(std::ostream &, const Option &);
229 std::ostream &operator <<(std::ostream &, const Options &);
230
231 } // namespace Acl
232
233 #endif /* SQUID_ACL_OPTIONS_H */
234