Notes.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2020 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 
35 Note::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");
40  if (!valueFormat->parse(theValue.c_str())) {
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 
49 const 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 
63 Note::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 
69 bool
71 {
72  ACLFilledChecklist ch(nullptr, request, nullptr);
73  ch.al = al;
74  ch.reply = reply;
75  ch.syncAle(request, nullptr);
76  if (reply)
77  HTTPMSGLOCK(ch.reply);
78 
79  for (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 
93 void
95 {
96  for (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 
107 void
108 Note::dump(StoreEntry *entry, const char *k)
109 {
110  for (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 
118 SBuf
119 Note::toString(const char *sep) const
120 {
121  SBuf result;
122  for (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 
128 const 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 
150 Notes::Notes(const char *aDescr, const Keys *extraBlacklist, bool allowFormatted):
151  descr(aDescr),
152  formattedValues(allowFormatted)
153 {
154  if (extraBlacklist)
155  blacklist = *extraBlacklist;
156 }
157 
159 Notes::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 
168 Notes::find(const SBuf &noteKey)
169 {
170  for (auto n: notes)
171  if (n->key() == noteKey)
172  return n;
173  return nullptr;
174 }
175 
176 void
177 Notes::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 
183 void
184 Notes::validateKey(const SBuf &key) const
185 {
186  banReservedKey(key, BlackList());
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 
222 void
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;
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 
247 void
249 {
250  for (auto n: notes)
251  n->updateNotePairs(pairs, delimiters, al);
252 }
253 
254 void
255 Notes::dump(StoreEntry *entry, const char *key)
256 {
257  for (auto n: notes)
258  n->dump(entry, key);
259 }
260 
261 const char *
262 Notes::toString(const char *sep) const
263 {
264  static SBuf result;
265  result.clear();
266  for (auto note: notes)
267  result.append(note->toString(sep));
268  return result.isEmpty() ? nullptr : result.c_str();
269 }
270 
271 bool
272 NotePairs::find(SBuf &resultNote, const char *noteKey, const char *sep) const
273 {
274  resultNote.clear();
275  for (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 
285 const char *
286 NotePairs::toString(const char *sep) const
287 {
288  static SBuf result;
289  result.clear();
290  for (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 
296 const char *
297 NotePairs::findFirst(const char *noteKey) const
298 {
299  for (auto e: entries)
300  if (!e->name().cmp(noteKey))
301  return const_cast<SBuf &>(e->value()).c_str();
302  return nullptr;
303 }
304 
305 void
306 NotePairs::add(const char *key, const char *note)
307 {
308  entries.push_back(new NotePairs::Entry(key, note));
309 }
310 
311 void
312 NotePairs::add(const SBuf &key, const SBuf &note)
313 {
314  entries.push_back(new NotePairs::Entry(key, note));
315 }
316 
317 void
318 NotePairs::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 
325 void
327 {
328  Entries::iterator i = entries.begin();
329  while (i != entries.end())
330  i = (*i)->name() == key ? entries.erase(i) : i+1;
331 }
332 
333 static void
334 AppendTokens(NotePairs::Entries &entries, const SBuf &key, const SBuf &val, const CharacterSet &delimiters)
335 {
336  Parser::Tokenizer tok(val);
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 
345 const NotePairs::Entries &
347 {
348  if (delimiters) {
349  static NotePairs::Entries expandedEntries;
350  expandedEntries.clear();
351  for(auto entry: entries)
352  AppendTokens(expandedEntries, entry->name(), entry->value(), *delimiters);
353  return expandedEntries;
354  }
355  return entries;
356 }
357 
358 void
359 NotePairs::addStrList(const SBuf &key, const SBuf &values, const CharacterSet &delimiters)
360 {
361  AppendTokens(entries, key, values, delimiters);
362 }
363 
364 bool
365 NotePairs::hasPair(const SBuf &key, const SBuf &value) const
366 {
367  for (auto e: entries)
368  if (e->name() == key && e->value() == value)
369  return true;
370  return false;
371 }
372 
373 void
375 {
376  for (auto e: src->entries)
377  entries.push_back(new NotePairs::Entry(e->name(), e->value()));
378 }
379 
380 void
382 {
383  for (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 
389 void
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 
399 void
401 {
402  for (auto e: src->entries)
403  remove(e->name());
404  append(src);
405 }
406 
void appendNewOnly(const NotePairs *src)
Definition: Notes.cc:381
void replaceOrAdd(const NotePairs *src)
Definition: Notes.cc:400
ACLList * aclList
The access list used to determine if this value is valid for a request.
Definition: Notes.h:57
#define Here()
source code location of the caller
Definition: Here.h:15
void parseKvPair()
Parses an annotate line with "key=value" or "key+=value" formats.
Definition: Notes.cc:223
void validateKey(const SBuf &key) const
Definition: Notes.cc:184
static char * NextQuotedToken()
const char * findFirst(const char *noteKey) const
Definition: Notes.cc:297
const char * descr
identifies note source in error messages
Definition: Notes.h:161
bool isEmpty() const
Definition: SBuf.h:420
void dump(StoreEntry *entry, const char *name)
Dump the notes list to the given StoreEntry object.
Definition: Notes.cc:255
static void EnableMacros()
Allow macros inside quoted strings.
Definition: ConfigParser.h:125
SBuf toString(const char *sep) const
Definition: Notes.cc:119
static const Notes::Keys & BlackList()
always prohibited key names
Definition: Notes.cc:129
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:901
Value(const char *aVal, const bool quoted, const char *descr, const Method method=mhReplace)
Definition: Notes.cc:35
Note::Pointer parse(ConfigParser &parser)
Parses a notes line and returns a pointer to the parsed Note object.
Definition: Notes.cc:202
Values values
The possible values list for the note.
Definition: Notes.h:100
static bool LastTokenWasQuoted()
Definition: ConfigParser.h:92
static char * keys[]
Definition: WinSvc.cc:84
NotesList notes
The Note::Pointer objects array list.
Definition: Notes.h:160
Definition: SBuf.h:86
const char * toString(const char *sep="\r\n") const
Definition: Notes.cc:262
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
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
const char * toString(const char *sep="\r\n") const
Definition: Notes.cc:286
SBuf & Printf(const char *fmt,...)
Definition: SBuf.cc:224
#define DBG_CRITICAL
Definition: Debug.h:45
bool empty() const
Definition: Notes.h:253
bool parse(const char *def)
Definition: Format.cc:67
std::vector< SBuf > Names
Definition: Notes.h:199
void clear()
Definition: SBuf.cc:178
static const CharacterSet ALPHA
Definition: CharacterSet.h:76
#define TexcHere(msg)
legacy convenience macro; it is not difficult to type Here() now
Definition: TextException.h:55
Used to store a note key/value pair.
Definition: Notes.h:178
static void DisableMacros()
Do not allow macros inside quoted strings.
Definition: ConfigParser.h:128
~Value()
Definition: Notes.cc:29
@ mhAppend
Definition: Notes.h:47
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:128
@ mhReplace
Definition: Notes.h:47
void updateNotePairs(NotePairsPointer pairs, const CharacterSet *delimiters, const AccessLogEntryPointer &al)
Definition: Notes.cc:248
const Acl::Answer & fastCheck()
Definition: Checklist.cc:336
Note::Pointer find(const SBuf &noteKey)
Definition: Notes.cc:168
Definition: MemBuf.h:23
std::vector< SBuf > Keys
unordered annotation names
Definition: Notes.h:112
static void AppendTokens(NotePairs::Entries &entries, const SBuf &key, const SBuf &val, const CharacterSet &delimiters)
Definition: Notes.cc:334
const SBuf & key() const
Definition: Notes.h:90
bool find(SBuf &resultNote, const char *noteKey, const char *sep=",") const
Definition: Notes.cc:272
Entries entries
The key/value pair entries.
Definition: Notes.h:262
#define assert(EX)
Definition: assert.h:19
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:160
virtual void syncAle(HttpRequest *adaptedRequest, const char *logUri) const
assigns uninitialized adapted_request and url ALE components
static bool NextKvPair(char *&key, char *&value)
static const CharacterSet DIGIT
Definition: CharacterSet.h:84
Format::Format * valueFormat
Compiled annotation value format.
Definition: Notes.h:64
const Entries & expandListEntries(const CharacterSet *delimiters) const
Definition: Notes.cc:346
const char * c_str()
Definition: SBuf.cc:526
Keys blacklist
a list of additional prohibited key names
Definition: Notes.h:163
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:404
void addStrList(const SBuf &key, const SBuf &values, const CharacterSet &delimiters)
Definition: Notes.cc:359
SBuf & append(const SBuf &S)
Definition: SBuf.cc:195
void updateNotePairs(NotePairsPointer pairs, const CharacterSet *delimiters, const AccessLogEntryPointer &al)
Definition: Notes.cc:94
Notes()=default
static char * NextToken()
static const size_type npos
Definition: SBuf.h:92
static const char * QuoteString(const String &var)
size_type findFirstNotOf(const CharacterSet &set, size_type startPos=0) const
Definition: SBuf.cc:756
SBuf theValue
Definition: Notes.h:65
Stores a value for the note.
Definition: Notes.h:41
Note::Pointer add(const SBuf &noteKey)
Definition: Notes.cc:159
void dump_acl_list(StoreEntry *entry, ACLList *head)
Definition: cache_cf.cc:1450
Value::Pointer addValue(const char *value, const bool quoted, const char *descr, const Value::Method m=Value::mhAppend)
Definition: Notes.cc:63
void append(const NotePairs *src)
Append the entries of the src NotePairs list to our list.
Definition: Notes.cc:374
Definition: parse.c:160
bool hasPair(const SBuf &key, const SBuf &value) const
Definition: Notes.cc:365
bool match(HttpRequest *request, HttpReply *reply, const AccessLogEntryPointer &al, SBuf &matched)
Definition: Notes.cc:70
an std::runtime_error with thrower location info
Definition: TextException.h:19
char * content()
start of the added data
Definition: MemBuf.h:41
size_t HttpReply *STUB StoreEntry const KeyScope scope const HttpRequestMethod & method
Definition: stub_store.cc:108
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:124
void remove(const char *key)
Definition: Notes.cc:318
void reset()
Definition: MemBuf.cc:132
void add(const SBuf &key, const SBuf &value)
Definition: Notes.cc:312
SBuf & appendf(const char *fmt,...)
Definition: SBuf.cc:239
void aclParseAclList(ConfigParser &, Acl::Tree **treep, const char *label)
Definition: Gadgets.cc:190
int token
Definition: parse.c:163
optimized set of C chars, with quick membership test and merge support
Definition: CharacterSet.h:17
std::vector< Entry::Pointer > Entries
The key/value pair entries.
Definition: Notes.h:198
String SBufToString(const SBuf &s)
Definition: StringConvert.h:26
void aclDestroyAclList(ACLList **list)
Definition: Gadgets.cc:267
Definition: Notes.h:35
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
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
const SBuf & format(const AccessLogEntryPointer &al)
Definition: Notes.cc:50
bool formattedValues
whether to expand quoted logformat codes
Definition: Notes.h:164
void replaceOrAddOrAppend(const NotePairs *src, const Names &appendables)
Definition: Notes.cc:390

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors