]> git.ipfire.org Git - thirdparty/squid.git/blob - src/Notes.cc
f6ba7cc4c9f3cd31fe88b1c69014aba451b86cb2
[thirdparty/squid.git] / src / Notes.cc
1 /*
2 * Copyright (C) 1996-2016 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 "SquidConfig.h"
20 #include "Store.h"
21 #include "StrList.h"
22
23 #include <algorithm>
24 #include <string>
25
26 Note::Value::~Value()
27 {
28 aclDestroyAclList(&aclList);
29 }
30
31 Note::Value::Pointer
32 Note::addValue(const String &value)
33 {
34 Value::Pointer v = new Value(value);
35 values.push_back(v);
36 return v;
37 }
38
39 const char *
40 Note::match(HttpRequest *request, HttpReply *reply, const AccessLogEntry::Pointer &al)
41 {
42
43 typedef Values::iterator VLI;
44 ACLFilledChecklist ch(NULL, request, NULL);
45 ch.reply = reply;
46 if (reply)
47 HTTPMSGLOCK(ch.reply);
48
49 for (VLI i = values.begin(); i != values.end(); ++i ) {
50 const int ret= ch.fastCheck((*i)->aclList);
51 debugs(93, 5, HERE << "Check for header name: " << key << ": " << (*i)->value
52 <<", HttpRequest: " << request << " HttpReply: " << reply << " matched: " << ret);
53 if (ret == ACCESS_ALLOWED) {
54 if (al != NULL && (*i)->valueFormat != NULL) {
55 static MemBuf mb;
56 mb.reset();
57 (*i)->valueFormat->assemble(mb, al, 0);
58 return mb.content();
59 } else
60 return (*i)->value.termedBuf();
61 }
62 }
63 return NULL;
64 }
65
66 Note::Pointer
67 Notes::add(const String &noteKey)
68 {
69 typedef Notes::NotesList::iterator AMLI;
70 for (AMLI i = notes.begin(); i != notes.end(); ++i) {
71 if ((*i)->key == noteKey)
72 return (*i);
73 }
74
75 Note::Pointer note = new Note(noteKey);
76 notes.push_back(note);
77 return note;
78 }
79
80 Note::Pointer
81 Notes::parse(ConfigParser &parser)
82 {
83 String key = ConfigParser::NextToken();
84 ConfigParser::EnableMacros();
85 String value = ConfigParser::NextQuotedToken();
86 ConfigParser::DisableMacros();
87 bool valueWasQuoted = ConfigParser::LastTokenWasQuoted();
88 Note::Pointer note = add(key);
89 Note::Value::Pointer noteValue = note->addValue(value);
90
91 String label(key);
92 label.append('=');
93 label.append(value);
94 aclParseAclList(parser, &noteValue->aclList, label.termedBuf());
95 if (formattedValues && valueWasQuoted) {
96 noteValue->valueFormat = new Format::Format(descr ? descr : "Notes");
97 noteValue->valueFormat->parse(value.termedBuf());
98 }
99 if (blacklisted) {
100 for (int i = 0; blacklisted[i] != NULL; ++i) {
101 if (note->key.caseCmp(blacklisted[i]) == 0) {
102 fatalf("%s:%d: meta key \"%s\" is a reserved %s name",
103 cfg_filename, config_lineno, note->key.termedBuf(),
104 descr ? descr : "");
105 }
106 }
107 }
108
109 return note;
110 }
111
112 void
113 Notes::dump(StoreEntry *entry, const char *key)
114 {
115 typedef Notes::NotesList::iterator AMLI;
116 for (AMLI m = notes.begin(); m != notes.end(); ++m) {
117 typedef Note::Values::iterator VLI;
118 for (VLI v =(*m)->values.begin(); v != (*m)->values.end(); ++v ) {
119 storeAppendPrintf(entry, "%s " SQUIDSTRINGPH " %s",
120 key, SQUIDSTRINGPRINT((*m)->key), ConfigParser::QuoteString((*v)->value));
121 dump_acl_list(entry, (*v)->aclList);
122 storeAppendPrintf(entry, "\n");
123 }
124 }
125 }
126
127 void
128 Notes::clean()
129 {
130 notes.clear();
131 }
132
133 NotePairs::~NotePairs()
134 {
135 while (!entries.empty()) {
136 delete entries.back();
137 entries.pop_back();
138 }
139 }
140
141 const char *
142 NotePairs::find(const char *noteKey, const char *sep) const
143 {
144 static String value;
145 value.clean();
146 for (std::vector<NotePairs::Entry *>::const_iterator i = entries.begin(); i != entries.end(); ++i) {
147 if ((*i)->name.cmp(noteKey) == 0) {
148 if (value.size())
149 value.append(sep);
150 value.append((*i)->value);
151 }
152 }
153 return value.size() ? value.termedBuf() : NULL;
154 }
155
156 const char *
157 NotePairs::toString(const char *sep) const
158 {
159 static String value;
160 value.clean();
161 for (std::vector<NotePairs::Entry *>::const_iterator i = entries.begin(); i != entries.end(); ++i) {
162 value.append((*i)->name);
163 value.append(": ");
164 value.append((*i)->value);
165 value.append(sep);
166 }
167 return value.size() ? value.termedBuf() : NULL;
168 }
169
170 const char *
171 NotePairs::findFirst(const char *noteKey) const
172 {
173 for (std::vector<NotePairs::Entry *>::const_iterator i = entries.begin(); i != entries.end(); ++i) {
174 if ((*i)->name.cmp(noteKey) == 0)
175 return (*i)->value.termedBuf();
176 }
177 return NULL;
178 }
179
180 void
181 NotePairs::add(const char *key, const char *note)
182 {
183 entries.push_back(new NotePairs::Entry(key, note));
184 }
185
186 void
187 NotePairs::remove(const char *key)
188 {
189 std::vector<NotePairs::Entry *>::iterator i = entries.begin();
190 while (i != entries.end()) {
191 if ((*i)->name.cmp(key) == 0) {
192 delete *i;
193 i = entries.erase(i);
194 } else {
195 ++i;
196 }
197 }
198 }
199
200 void
201 NotePairs::addStrList(const char *key, const char *values)
202 {
203 String strValues(values);
204 const char *item;
205 const char *pos = NULL;
206 int ilen = 0;
207 while (strListGetItem(&strValues, ',', &item, &ilen, &pos)) {
208 String v;
209 v.append(item, ilen);
210 entries.push_back(new NotePairs::Entry(key, v.termedBuf()));
211 }
212 }
213
214 bool
215 NotePairs::hasPair(const char *key, const char *value) const
216 {
217 for (std::vector<NotePairs::Entry *>::const_iterator i = entries.begin(); i != entries.end(); ++i) {
218 if ((*i)->name.cmp(key) == 0 && (*i)->value.cmp(value) == 0)
219 return true;
220 }
221 return false;
222 }
223
224 void
225 NotePairs::append(const NotePairs *src)
226 {
227 for (std::vector<NotePairs::Entry *>::const_iterator i = src->entries.begin(); i != src->entries.end(); ++i) {
228 entries.push_back(new NotePairs::Entry((*i)->name.termedBuf(), (*i)->value.termedBuf()));
229 }
230 }
231
232 void
233 NotePairs::appendNewOnly(const NotePairs *src)
234 {
235 for (std::vector<NotePairs::Entry *>::const_iterator i = src->entries.begin(); i != src->entries.end(); ++i) {
236 if (!hasPair((*i)->name.termedBuf(), (*i)->value.termedBuf()))
237 entries.push_back(new NotePairs::Entry((*i)->name.termedBuf(), (*i)->value.termedBuf()));
238 }
239 }
240
241 void
242 NotePairs::replaceOrAdd(const NotePairs *src)
243 {
244 for (std::vector<NotePairs::Entry *>::const_iterator i = src->entries.begin(); i != src->entries.end(); ++i) {
245 remove((*i)->name.termedBuf());
246 }
247 append(src);
248 }
249
250 NotePairs &
251 SyncNotes(AccessLogEntry &ale, HttpRequest &request)
252 {
253 // XXX: auth code only has access to HttpRequest being authenticated
254 // so we must handle the case where HttpRequest is set without ALE being set.
255
256 if (!ale.notes) {
257 if (!request.notes)
258 request.notes = new NotePairs;
259 ale.notes = request.notes;
260 } else {
261 assert(ale.notes == request.notes);
262 }
263 return *ale.notes;
264 }
265
266 void
267 UpdateRequestNotes(ConnStateData *csd, HttpRequest &request, NotePairs const &helperNotes)
268 {
269 // Tag client connection if the helper responded with clt_conn_tag=tag.
270 if (const char *connTag = helperNotes.findFirst("clt_conn_tag")) {
271 if (csd)
272 csd->connectionTag(connTag);
273 }
274 if (!request.notes)
275 request.notes = new NotePairs;
276 request.notes->replaceOrAdd(&helperNotes);
277 }
278