Notes.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 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#include "squid.h"
10#include "AccessLogEntry.h"
11#include "acl/FilledChecklist.h"
12#include "acl/Gadgets.h"
13#include "client_side.h"
14#include "ConfigParser.h"
15#include "globals.h"
16#include "http/Stream.h"
17#include "HttpReply.h"
18#include "HttpRequest.h"
19#include "parser/Tokenizer.h"
20#include "sbuf/Stream.h"
21#include "sbuf/StringConvert.h"
22#include "SquidConfig.h"
23#include "Store.h"
24#include "StrList.h"
25
26#include <algorithm>
27#include <string>
28
30{
32 delete valueFormat;
33}
34
35Note::Value::Value(const char *aVal, const bool quoted, const char *descr, const Method m)
36 : aclList(nullptr), valueFormat(nullptr), theValue(aVal), theMethod(m)
37{
38 if (quoted) {
39 valueFormat = new Format::Format(descr ? descr : "Notes");
41 delete valueFormat;
42 SBuf exceptionMsg;
43 exceptionMsg.Printf("failed to parse annotation value %s", theValue.c_str());
44 throw TexcHere(exceptionMsg.c_str());
45 }
46 }
47}
48
49const SBuf &
51{
52 if (al && valueFormat) {
53 static MemBuf mb;
54 mb.reset();
55 valueFormat->assemble(mb, al, 0);
56 theFormattedValue.assign(mb.content());
57 return theFormattedValue;
58 }
59 return theValue;
60}
61
63Note::addValue(const char *value, const bool quoted, const char *descr, const Value::Method m)
64{
65 values.push_back(new Value(value, quoted, descr, m));
66 return values.back();
67}
68
69bool
70Note::match(HttpRequest *request, HttpReply *reply, const AccessLogEntry::Pointer &al, SBuf &matched)
71{
72 ACLFilledChecklist ch(nullptr, request, nullptr);
73 ch.al = al;
74 ch.reply = reply;
75 ch.syncAle(request, nullptr);
76 if (reply)
78
79 for (const auto &v: values) {
80 assert(v->aclList);
81 const auto ret = ch.fastCheck(v->aclList);
82 debugs(93, 5, "Check for header name: " << theKey << ": " << v->value() <<
83 ", HttpRequest: " << request << " HttpReply: " << reply << " matched: " << ret);
84 if (ret.allowed()) {
85 matched = v->format(al);
86 return true;
87 }
88 }
89 matched.clear();
90 return false;
91}
92
93void
95{
96 for (const auto &v: values) {
97 const SBuf &formatted = v->format(al);
98 if (!pairs->empty() && v->method() == Value::mhReplace)
99 pairs->remove(theKey);
100 if (delimiters)
101 pairs->addStrList(key(), formatted, *delimiters);
102 else
103 pairs->add(key(), formatted);
104 }
105}
106
107void
108Note::dump(StoreEntry *entry, const char *k)
109{
110 for (const auto &v: values) {
111 storeAppendPrintf(entry, "%s %.*s %s",
112 k, key().length(), key().rawContent(), ConfigParser::QuoteString(SBufToString(v->value())));
113 dump_acl_list(entry, v->aclList);
114 storeAppendPrintf(entry, "\n");
115 }
116}
117
118SBuf
119Note::toString(const char *sep) const
120{
121 SBuf result;
122 for (const auto &val: values)
123 result.appendf("%.*s: %.*s%s", key().length(), key().rawContent(),
124 val->value().length(), val->value().rawContent(), sep);
125 return result;
126}
127
128const Notes::Keys &
130{
131 // these keys are used for internal Squid-helper communication
132 static const char *names[] = {
133 "group",
134 "ha1",
135 "log",
136 "message",
137 "password",
138 "rewrite-url",
139 "status",
140 "tag",
141 "ttl",
142 "url",
143 "user"
144 };
145
146 static Keys keys(std::begin(names), std::end(names));
147 return keys;
148}
149
150Notes::Notes(const char *aDescr, const Keys *extraReservedKeys, bool allowFormatted):
151 descr(aDescr),
152 formattedValues(allowFormatted)
153{
154 if (extraReservedKeys)
155 reservedKeys = *extraReservedKeys;
156}
157
159Notes::add(const SBuf &noteKey)
160{
161 if (Note::Pointer p = find(noteKey))
162 return p;
163 notes.push_back(new Note(noteKey));
164 return notes.back();
165}
166
168Notes::find(const SBuf &noteKey)
169{
170 for (const auto &n: notes)
171 if (n->key() == noteKey)
172 return n;
173 return nullptr;
174}
175
176void
177Notes::banReservedKey(const SBuf &key, const Keys &banned) const
178{
179 if (std::find(banned.begin(), banned.end(), key) != banned.end())
180 throw TextException(ToSBuf("cannot use a reserved ", descr, " name: ", key), Here());
181}
182
183void
184Notes::validateKey(const SBuf &key) const
185{
188
189 // TODO: fix code duplication: the same set of specials is produced
190 // by isKeyNameChar().
191 static const CharacterSet allowedSpecials = CharacterSet::ALPHA +
192 CharacterSet::DIGIT + CharacterSet("specials", "-_");
193 const auto specialIndex = key.findFirstNotOf(allowedSpecials);
194 if (specialIndex != SBuf::npos) {
195 debugs(28, DBG_CRITICAL, "WARNING: used special character '" <<
196 key[specialIndex] << "' within annotation name. " <<
197 "Future Squid versions will not support this.");
198 }
199}
200
203{
204 const char *tok = ConfigParser::NextToken();
205 if (!tok)
206 fatalf("FATAL: Missing note key");
207 SBuf key(tok);
208 validateKey(key);
210 const char *val = ConfigParser::NextQuotedToken();
211 if (!val)
212 fatalf("FATAL: Missing note value");
214 Note::Pointer note = add(key);
215 Note::Value::Pointer noteValue = note->addValue(val, formattedValues && ConfigParser::LastTokenWasQuoted(), descr);
216 key.append('=');
217 key.append(val);
218 aclParseAclList(parser, &noteValue->aclList, key.c_str());
219 return note;
220}
221
222void
224 char *k, *v;
225 int parsedPairs = 0;
226 while (ConfigParser::NextKvPair(k, v)) {
227 int keyLen = strlen(k);
228 const Note::Value::Method method = (k[keyLen - 1] == '+') ? Note::Value::mhAppend : Note::Value::mhReplace;
229 if (method == Note::Value::mhAppend)
230 keyLen--;
231 else {
233 if (Note::Pointer oldNote = find(SBuf(k, keyLen)))
234 debugs(28, DBG_CRITICAL, "WARNING: annotation configuration with key " << k <<
235 " already exists and will be overwritten");
236 }
237 SBuf key(k, keyLen);
238 validateKey(key);
239 Note::Pointer note = add(key);
240 (void)note->addValue(v, formattedValues && ConfigParser::LastTokenWasQuoted(), descr, method);
241 parsedPairs++;
242 }
243 if (!parsedPairs)
244 fatalf("FATAL: Missing annotation kv pair");
245}
246
247void
249{
250 for (const auto &n: notes)
251 n->updateNotePairs(pairs, delimiters, al);
252}
253
254void
255Notes::dump(StoreEntry *entry, const char *key)
256{
257 for (const auto &n: notes)
258 n->dump(entry, key);
259}
260
261const char *
262Notes::toString(const char *sep) const
263{
264 static SBuf result;
265 result.clear();
266 for (const auto &note: notes)
267 result.append(note->toString(sep));
268 return result.isEmpty() ? nullptr : result.c_str();
269}
270
271bool
272NotePairs::find(SBuf &resultNote, const char *noteKey, const char *sep) const
273{
274 resultNote.clear();
275 for (const auto &e: entries) {
276 if (!e->name().cmp(noteKey)) {
277 if (!resultNote.isEmpty())
278 resultNote.append(sep);
279 resultNote.append(e->value());
280 }
281 }
282 return resultNote.length();
283}
284
285const char *
286NotePairs::toString(const char *sep) const
287{
288 static SBuf result;
289 result.clear();
290 for (const auto &e: entries)
291 result.appendf("%.*s: %.*s%s", e->name().length(), e->name().rawContent(),
292 e->value().length(), e->value().rawContent(), sep);
293 return result.isEmpty() ? nullptr : result.c_str();
294}
295
296const char *
297NotePairs::findFirst(const char *noteKey) const
298{
299 for (const auto &e: entries)
300 if (!e->name().cmp(noteKey))
301 return const_cast<SBuf &>(e->value()).c_str();
302 return nullptr;
303}
304
305void
306NotePairs::add(const char *key, const char *note)
307{
308 entries.push_back(new NotePairs::Entry(key, note));
309}
310
311void
312NotePairs::add(const SBuf &key, const SBuf &note)
313{
314 entries.push_back(new NotePairs::Entry(key, note));
315}
316
317void
318NotePairs::remove(const char *key)
319{
320 Entries::iterator i = entries.begin();
321 while (i != entries.end())
322 i = (*i)->name().cmp(key) ? i+1 : entries.erase(i);
323}
324
325void
327{
328 Entries::iterator i = entries.begin();
329 while (i != entries.end())
330 i = (*i)->name() == key ? entries.erase(i) : i+1;
331}
332
333static void
334AppendTokens(NotePairs::Entries &entries, const SBuf &key, const SBuf &val, const CharacterSet &delimiters)
335{
337 SBuf v;
338 while (tok.token(v, delimiters))
339 entries.push_back(new NotePairs::Entry(key, v));
340 v = tok.remaining();
341 if (!v.isEmpty())
342 entries.push_back(new NotePairs::Entry(key, v));
343}
344
345const NotePairs::Entries &
347{
348 if (delimiters) {
349 static NotePairs::Entries expandedEntries;
350 expandedEntries.clear();
351 for (const auto &entry: entries)
352 AppendTokens(expandedEntries, entry->name(), entry->value(), *delimiters);
353 return expandedEntries;
354 }
355 return entries;
356}
357
358void
359NotePairs::addStrList(const SBuf &key, const SBuf &values, const CharacterSet &delimiters)
360{
361 AppendTokens(entries, key, values, delimiters);
362}
363
364bool
365NotePairs::hasPair(const SBuf &key, const SBuf &value) const
366{
367 for (const auto &e: entries)
368 if (e->name() == key && e->value() == value)
369 return true;
370 return false;
371}
372
373void
375{
376 for (const auto &e: src->entries)
377 entries.push_back(new NotePairs::Entry(e->name(), e->value()));
378}
379
380void
382{
383 for (const auto &e: src->entries) {
384 if (!hasPair(e->name(), e->value()))
385 entries.push_back(new NotePairs::Entry(e->name(), e->value()));
386 }
387}
388
389void
391{
392 for (const auto &e: src->entries) {
393 if (std::find(appendables.begin(), appendables.end(), e->name()) == appendables.end())
394 remove(e->name());
395 }
396 append(src);
397}
398
399void
401{
402 for (const auto &e: src->entries)
403 remove(e->name());
404 append(src);
405}
406
#define Here()
source code location of the caller
Definition: Here.h:15
static void AppendTokens(NotePairs::Entries &entries, const SBuf &key, const SBuf &val, const CharacterSet &delimiters)
Definition: Notes.cc:334
String SBufToString(const SBuf &s)
Definition: StringConvert.h:26
#define TexcHere(msg)
legacy convenience macro; it is not difficult to type Here() now
Definition: TextException.h:63
static char * keys[]
Definition: WinSvc.cc:84
size_t aclParseAclList(ConfigParser &, Acl::Tree **treep, const char *label)
Definition: Gadgets.cc:188
#define assert(EX)
Definition: assert.h:17
Acl::Answer const & fastCheck()
Definition: Checklist.cc:332
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
void syncAle(HttpRequest *adaptedRequest, const char *logUri) const override
assigns uninitialized adapted_request and url ALE components
optimized set of C chars, with quick membership test and merge support
Definition: CharacterSet.h:18
static const CharacterSet DIGIT
Definition: CharacterSet.h:84
static const CharacterSet ALPHA
Definition: CharacterSet.h:76
static void DisableMacros()
Do not allow macros inside quoted strings.
Definition: ConfigParser.h:147
static char * NextQuotedToken()
static bool NextKvPair(char *&key, char *&value)
static bool LastTokenWasQuoted()
Definition: ConfigParser.h:117
static char * NextToken()
static void EnableMacros()
Allow macros inside quoted strings.
Definition: ConfigParser.h:144
static const char * QuoteString(const String &var)
bool parse(const char *def)
Definition: Format.cc:66
Definition: MemBuf.h:24
char * content()
start of the added data
Definition: MemBuf.h:41
void reset()
Definition: MemBuf.cc:129
Used to store a note key/value pair.
Definition: Notes.h:179
void appendNewOnly(const NotePairs *src)
Definition: Notes.cc:381
void append(const NotePairs *src)
Append the entries of the src NotePairs list to our list.
Definition: Notes.cc:374
bool empty() const
Definition: Notes.h:253
std::vector< SBuf > Names
Definition: Notes.h:199
std::vector< Entry::Pointer > Entries
The key/value pair entries.
Definition: Notes.h:198
bool find(SBuf &resultNote, const char *noteKey, const char *sep=",") const
Definition: Notes.cc:272
void add(const SBuf &key, const SBuf &value)
Definition: Notes.cc:312
void remove(const char *key)
Definition: Notes.cc:318
void replaceOrAdd(const NotePairs *src)
Definition: Notes.cc:400
bool hasPair(const SBuf &key, const SBuf &value) const
Definition: Notes.cc:365
const Entries & expandListEntries(const CharacterSet *delimiters) const
Definition: Notes.cc:346
const char * findFirst(const char *noteKey) const
Definition: Notes.cc:297
void addStrList(const SBuf &key, const SBuf &values, const CharacterSet &delimiters)
Definition: Notes.cc:359
Entries entries
The key/value pair entries.
Definition: Notes.h:262
const char * toString(const char *sep="\r\n") const
Definition: Notes.cc:286
void replaceOrAddOrAppend(const NotePairs *src, const Names &appendables)
Definition: Notes.cc:390
Stores a value for the note.
Definition: Notes.h:42
@ mhReplace
Definition: Notes.h:47
@ mhAppend
Definition: Notes.h:47
~Value() override
Definition: Notes.cc:29
SBuf theValue
Definition: Notes.h:65
Format::Format * valueFormat
Compiled annotation value format.
Definition: Notes.h:64
ACLList * aclList
The access list used to determine if this value is valid for a request.
Definition: Notes.h:57
Value(const char *aVal, const bool quoted, const char *descr, const Method method=mhReplace)
Definition: Notes.cc:35
const SBuf & format(const AccessLogEntryPointer &al)
Definition: Notes.cc:50
Definition: Notes.h:36
Value::Pointer addValue(const char *value, const bool quoted, const char *descr, const Value::Method m=Value::mhAppend)
Definition: Notes.cc:63
bool match(HttpRequest *request, HttpReply *reply, const AccessLogEntryPointer &al, SBuf &matched)
Definition: Notes.cc:70
Values values
The possible values list for the note.
Definition: Notes.h:100
void dump(StoreEntry *entry, const char *key)
Dump the single Note to the given StoreEntry object.
Definition: Notes.cc:108
SBuf theKey
The note key.
Definition: Notes.h:99
const SBuf & key() const
Definition: Notes.h:90
void updateNotePairs(NotePairsPointer pairs, const CharacterSet *delimiters, const AccessLogEntryPointer &al)
Definition: Notes.cc:94
SBuf toString(const char *sep) const
Definition: Notes.cc:119
Note::Pointer find(const SBuf &noteKey)
Definition: Notes.cc:168
Note::Pointer parse(ConfigParser &parser)
Parses a notes line and returns a pointer to the parsed Note object.
Definition: Notes.cc:202
Notes()=default
const char * toString(const char *sep="\r\n") const
Definition: Notes.cc:262
std::vector< SBuf > Keys
unordered annotation names
Definition: Notes.h:112
Note::Pointer add(const SBuf &noteKey)
Definition: Notes.cc:159
void updateNotePairs(NotePairsPointer pairs, const CharacterSet *delimiters, const AccessLogEntryPointer &al)
Definition: Notes.cc:248
const char * descr
identifies note source in error messages
Definition: Notes.h:161
void dump(StoreEntry *entry, const char *name)
Dump the notes list to the given StoreEntry object.
Definition: Notes.cc:255
void banReservedKey(const SBuf &key, const Keys &banned) const
Makes sure the given key is not on the given list of banned names.
Definition: Notes.cc:177
NotesList notes
The Note::Pointer objects array list.
Definition: Notes.h:160
bool formattedValues
whether to expand quoted logformat codes
Definition: Notes.h:164
static const Notes::Keys & ReservedKeys()
always prohibited key names
Definition: Notes.cc:129
void validateKey(const SBuf &key) const
Definition: Notes.cc:184
void parseKvPair()
Parses an annotate line with "key=value" or "key+=value" formats.
Definition: Notes.cc:223
Keys reservedKeys
a list of additional prohibited key names
Definition: Notes.h:163
Definition: SBuf.h:94
static const size_type npos
Definition: SBuf.h:99
const char * c_str()
Definition: SBuf.cc:516
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:415
SBuf & appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Definition: SBuf.cc:229
SBuf & Printf(const char *fmt,...) PRINTF_FORMAT_ARG2
Definition: SBuf.cc:214
size_type findFirstNotOf(const CharacterSet &set, size_type startPos=0) const
Definition: SBuf.cc:746
bool isEmpty() const
Definition: SBuf.h:431
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
void clear()
Definition: SBuf.cc:175
an std::runtime_error with thrower location info
Definition: TextException.h:21
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define DBG_CRITICAL
Definition: Stream.h:37
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
void dump_acl_list(StoreEntry *entry, ACLList *head)
Definition: cache_cf.cc:1508
void aclDestroyAclList(ACLList **list)
Definition: Gadgets.cc:267
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:161
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:63
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:841
Definition: parse.c:160
int token
Definition: parse.c:163

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors