]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2025 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_SRC_NOTES_H | |
10 | #define SQUID_SRC_NOTES_H | |
11 | ||
12 | #include "acl/forward.h" | |
13 | #include "base/RefCount.h" | |
14 | #include "format/Format.h" | |
15 | #include "mem/forward.h" | |
16 | #include "sbuf/forward.h" | |
17 | #include "SquidString.h" | |
18 | ||
19 | #include <iosfwd> | |
20 | #include <string> | |
21 | #include <vector> | |
22 | ||
23 | class HttpRequest; | |
24 | class HttpReply; | |
25 | class AccessLogEntry; | |
26 | class NotePairs; | |
27 | ||
28 | typedef RefCount<AccessLogEntry> AccessLogEntryPointer; | |
29 | typedef RefCount<NotePairs> NotePairsPointer; | |
30 | ||
31 | /** | |
32 | * Used to store a note configuration. The notes are custom key:value | |
33 | * pairs ICAP request headers or ECAP options used to pass | |
34 | * custom transaction-state related meta information to squid | |
35 | * internal subsystems or to adaptation services. | |
36 | */ | |
37 | class Note: public RefCountable | |
38 | { | |
39 | public: | |
40 | typedef RefCount<Note> Pointer; | |
41 | ||
42 | /// Stores a value for the note. | |
43 | class Value: public RefCountable | |
44 | { | |
45 | public: | |
46 | typedef RefCount<Value> Pointer; | |
47 | friend class Note; | |
48 | ||
49 | enum Method { mhReplace, mhAppend }; | |
50 | ||
51 | Value(const char *aVal, const bool quoted, const char *descr, const Method method = mhReplace); | |
52 | ~Value() override; | |
53 | Value(const Value&) = delete; | |
54 | Value &operator=(const Value&) = delete; | |
55 | ||
56 | Method method() const { return theMethod; } | |
57 | const SBuf &value() const { return theValue; } | |
58 | ||
59 | ACLList *aclList; ///< The access list used to determine if this value is valid for a request | |
60 | ||
61 | private: | |
62 | /// \return the formatted value with expanded logformat %macros (quoted values). | |
63 | /// \return the original value (non-quoted values). | |
64 | const SBuf &format(const AccessLogEntryPointer &al); | |
65 | ||
66 | Format::Format *valueFormat; ///< Compiled annotation value format. | |
67 | SBuf theValue; ///< Configured annotation value, possibly with %macros. | |
68 | /// The expanded value produced by format(), empty for non-quoted values. | |
69 | SBuf theFormattedValue; | |
70 | /// Specifies how theValue will be applied to the existing annotation | |
71 | /// with the same key: it either replaces the existing value or is appended | |
72 | /// to the list of existing values. | |
73 | Method theMethod; | |
74 | }; | |
75 | typedef std::vector<Value::Pointer> Values; | |
76 | ||
77 | Note(const char *aKey, const size_t keyLen): theKey(aKey, keyLen) {} | |
78 | explicit Note(const SBuf aKey): theKey(aKey) {} | |
79 | Note(const Note&) = delete; | |
80 | Note &operator=(const Note&) = delete; | |
81 | ||
82 | /// Adds a value to the note and returns a pointer to the | |
83 | /// related Value object. | |
84 | Value::Pointer addValue(const char *value, const bool quoted, const char *descr, | |
85 | const Value::Method m = Value::mhAppend); | |
86 | ||
87 | /// Walks through the possible values list of the note, selects | |
88 | /// the first value, matching the given HttpRequest and HttpReply | |
89 | /// and assigns the given 'matched' to it. | |
90 | /// \return true if matched, false otherwise | |
91 | bool match(HttpRequest *request, HttpReply *reply, const AccessLogEntryPointer &al, SBuf &matched); | |
92 | const SBuf &key() const { return theKey; } | |
93 | void updateNotePairs(NotePairsPointer pairs, const CharacterSet *delimiters, const AccessLogEntryPointer &al); | |
94 | ||
95 | /// Prints key and value(s) using a "note" directive format (including directive name). | |
96 | void printAsNoteDirective(StoreEntry *, const char *directiveName) const; | |
97 | ||
98 | /// Prints using "annotate_transaction acl parameter" format, one key=value | |
99 | /// or key+=value parameter per stored value. | |
100 | void printAsAnnotationAclParameters(std::ostream &) const; | |
101 | ||
102 | private: | |
103 | SBuf theKey; ///< The note key | |
104 | Values values; ///< The possible values list for the note | |
105 | }; | |
106 | ||
107 | class ConfigParser; | |
108 | ||
109 | /** | |
110 | * Used to store a notes configuration list. | |
111 | */ | |
112 | class Notes : public RefCountable | |
113 | { | |
114 | public: | |
115 | typedef RefCount<Notes> Pointer; | |
116 | typedef std::vector<SBuf> Keys; ///< unordered annotation names | |
117 | typedef std::vector<Note::Pointer> NotesList; | |
118 | typedef NotesList::iterator iterator; ///< iterates over the notes list | |
119 | typedef NotesList::const_iterator const_iterator; ///< iterates over the notes list | |
120 | ||
121 | explicit Notes(const char *aDescr, const Keys *extraReservedKeys = nullptr, bool allowFormatted = true); | |
122 | Notes() = default; | |
123 | ~Notes() override { notes.clear(); } | |
124 | Notes(const Notes&) = delete; | |
125 | Notes &operator=(const Notes&) = delete; | |
126 | ||
127 | /// Parses a notes line and returns a pointer to the parsed Note object. | |
128 | Note::Pointer parse(ConfigParser &parser); | |
129 | ||
130 | /// Parses an annotate line with "key=value" or "key+=value" formats. | |
131 | void parseKvPair(); | |
132 | ||
133 | /// Prints notes using "note" squid.conf directive format, one directive per stored note. | |
134 | void printAsNoteDirectives(StoreEntry *, const char *directiveName) const; | |
135 | ||
136 | /// clean the notes list | |
137 | void clean() { notes.clear(); } | |
138 | ||
139 | /// points to the first argument | |
140 | iterator begin() { return notes.begin(); } | |
141 | /// points to the end of list | |
142 | iterator end() { return notes.end(); } | |
143 | /// \returns true if the notes list is empty | |
144 | bool empty() const { return notes.empty(); } | |
145 | ||
146 | /// print notes using "annotate_transaction acl parameters" format, one | |
147 | /// key=value parameter per note | |
148 | void printAsAnnotationAclParameters(std::ostream &) const; | |
149 | ||
150 | void updateNotePairs(NotePairsPointer pairs, const CharacterSet *delimiters, | |
151 | const AccessLogEntryPointer &al); | |
152 | private: | |
153 | /// Makes sure the given key is not on the given list of banned names. | |
154 | void banReservedKey(const SBuf &key, const Keys &banned) const; | |
155 | ||
156 | /// Verifies that the key is not reserved (fatal error) and | |
157 | /// does not contain special characters (non-fatal error). | |
158 | void validateKey(const SBuf &key) const; | |
159 | ||
160 | /// Adds a note to the notes list and returns a pointer to the | |
161 | /// related Note object. If the note key already exists in list, | |
162 | /// returns a pointer to the existing object. | |
163 | /// If keyLen is not provided, the noteKey is assumed null-terminated. | |
164 | Note::Pointer add(const SBuf ¬eKey); | |
165 | Note::Pointer find(const SBuf ¬eKey); | |
166 | ||
167 | NotesList notes; ///< The Note::Pointer objects array list | |
168 | const char *descr = nullptr; ///< identifies note source in error messages | |
169 | ||
170 | Keys reservedKeys; ///< a list of additional prohibited key names | |
171 | bool formattedValues = false; ///< whether to expand quoted logformat %codes | |
172 | ||
173 | static const Notes::Keys &ReservedKeys(); ///< always prohibited key names | |
174 | }; | |
175 | ||
176 | /** | |
177 | * Used to store list of notes | |
178 | */ | |
179 | class NotePairs: public RefCountable | |
180 | { | |
181 | public: | |
182 | typedef RefCount<NotePairs> Pointer; | |
183 | ||
184 | /// Used to store a note key/value pair. | |
185 | class Entry : public RefCountable | |
186 | { | |
187 | MEMPROXY_CLASS(Entry); | |
188 | public: | |
189 | typedef RefCount<Entry> Pointer; | |
190 | ||
191 | Entry(const SBuf &aKey, const SBuf &aValue) | |
192 | : theName(aKey), theValue(aValue) {} | |
193 | Entry(const char *aKey, const char *aValue) | |
194 | : theName(aKey), theValue(aValue) {} | |
195 | Entry(const Entry &) = delete; | |
196 | Entry &operator=(const Entry &) = delete; | |
197 | ||
198 | const SBuf &name() const { return theName; } | |
199 | const SBuf &value() const { return theValue; } | |
200 | ||
201 | private: | |
202 | SBuf theName; | |
203 | SBuf theValue; | |
204 | }; | |
205 | typedef std::vector<Entry::Pointer> Entries; ///< The key/value pair entries | |
206 | typedef std::vector<SBuf> Names; | |
207 | ||
208 | NotePairs() {} | |
209 | NotePairs &operator=(NotePairs const &) = delete; | |
210 | NotePairs(NotePairs const &) = delete; | |
211 | ||
212 | /// Append the entries of the src NotePairs list to our list. | |
213 | void append(const NotePairs *src); | |
214 | ||
215 | /// Replace existing list entries with the src NotePairs entries. | |
216 | /// Do not replace but append entries named in the appendables | |
217 | /// Entries which do not exist in the destination set are added. | |
218 | void replaceOrAddOrAppend(const NotePairs *src, const Names &appendables); | |
219 | ||
220 | /// Replace existing list entries with the src NotePairs entries. | |
221 | /// Entries which do not exist in the destination set are added. | |
222 | void replaceOrAdd(const NotePairs *src); | |
223 | ||
224 | /// Append any new entries of the src NotePairs list to our list. | |
225 | /// Entries which already exist in the destination set are ignored. | |
226 | void appendNewOnly(const NotePairs *src); | |
227 | ||
228 | /// \param resultNote a comma separated list of notes with key 'noteKey'. | |
229 | /// \returns true if there are entries with the given 'noteKey'. | |
230 | /// Use findFirst() instead when a unique kv-pair is needed. | |
231 | bool find(SBuf &resultNote, const char *noteKey, const char *sep = ",") const; | |
232 | ||
233 | /// \returns the first note value for this key or an empty string. | |
234 | const char *findFirst(const char *noteKey) const; | |
235 | ||
236 | /// Adds a note key and value to the notes list. | |
237 | /// If the key name already exists in the list, add the given value to its set | |
238 | /// of values. | |
239 | void add(const SBuf &key, const SBuf &value); | |
240 | void add(const char *key, const char *value); | |
241 | ||
242 | /// Remove all notes with a given key. If keyLen is not | |
243 | /// provided, the key is assumed null-terminated. | |
244 | void remove(const char *key); | |
245 | void remove(const SBuf &key); | |
246 | ||
247 | /// Adds a note key and values strList to the notes list. | |
248 | /// If the key name already exists in the list, add the new values to its set | |
249 | /// of values. | |
250 | void addStrList(const SBuf &key, const SBuf &values, const CharacterSet &delimiters); | |
251 | ||
252 | /// \returns true if the key/value pair is already stored | |
253 | bool hasPair(const SBuf &key, const SBuf &value) const; | |
254 | ||
255 | /// Reports all entries (if any), printing exactly four items for each: | |
256 | /// entry name, nameValueSeparator, entry value, and entry terminator. | |
257 | void print(std::ostream &os, const char *nameValueSeparator, const char *entryTerminator) const; | |
258 | ||
259 | /// \returns true if there are not entries in the list | |
260 | bool empty() const {return entries.empty();} | |
261 | ||
262 | void clear() { entries.clear(); } | |
263 | ||
264 | /// If delimiters are provided, returns another Entries, converting each single multi-token | |
265 | /// pair to multiple single-token pairs; returns existing entries otherwise. | |
266 | const Entries &expandListEntries(const CharacterSet *delimiters) const; | |
267 | ||
268 | private: | |
269 | Entries entries; ///< The key/value pair entries | |
270 | }; | |
271 | ||
272 | #endif /* SQUID_SRC_NOTES_H */ | |
273 |