]> git.ipfire.org Git - thirdparty/squid.git/blame - src/adaptation/icap/Options.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / adaptation / icap / Options.cc
CommitLineData
bbc27441 1/*
f70aedc4 2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
bbc27441
AJ
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
582c2af2 9#include "squid.h"
26cc52cb 10#include "adaptation/icap/Config.h"
3d93a84d
AJ
11#include "adaptation/icap/Options.h"
12#include "base/TextException.h"
13#include "HttpReply.h"
985c86bc 14#include "SquidTime.h"
28204b3b 15#include "StrList.h"
3d93a84d 16#include "wordlist.h"
78e8cfc4 17
23541b3e 18Adaptation::Icap::Options::Options() :
f53969cc
SM
19 error("unconfigured"),
20 max_connections(-1),
21 allow204(false),
22 allow206(false),
23 preview(-1),
24 theTTL(-1),
25 theTimestamp(0)
774c051c 26{
c99de607 27 theTransfers.preview.name = "Transfer-Preview";
28 theTransfers.preview.kind = xferPreview;
29 theTransfers.ignore.name = "Transfer-Ignore";
30 theTransfers.ignore.kind = xferIgnore;
31 theTransfers.complete.name = "Transfer-Complete";
32 theTransfers.complete.kind = xferComplete;
33
34 // Section 4.10.2 of RFC 3507 says that default is no Preview
35 // TODO: provide a squid.conf option to overwrite the default
36 theTransfers.byDefault = &theTransfers.complete;
37}
774c051c 38
26cc52cb 39Adaptation::Icap::Options::~Options()
774c051c 40{
774c051c 41}
42
c99de607 43// future optimization note: this method is called by ICAP ACL code at least
44// twice for each HTTP message to see if the message should be ignored. For any
45// non-ignored HTTP message, ICAP calls to check whether a preview is needed.
51b5dcf5
AJ
46Adaptation::Icap::Options::TransferKind
47Adaptation::Icap::Options::transferKind(const SBuf &urlPath) const
774c051c 48{
c99de607 49 if (theTransfers.preview.matches(urlPath))
50 return xferPreview;
774c051c 51
c99de607 52 if (theTransfers.complete.matches(urlPath))
53 return xferComplete;
774c051c 54
c99de607 55 if (theTransfers.ignore.matches(urlPath))
56 return xferIgnore;
774c051c 57
51b5dcf5 58 debugs(93,7, "url " << urlPath << " matches no extensions; " <<
9e008dda 59 "using default: " << theTransfers.byDefault->name);
c99de607 60 return theTransfers.byDefault->kind;
774c051c 61}
62
26cc52cb 63bool Adaptation::Icap::Options::valid() const
774c051c 64{
65 return !error;
66}
67
26cc52cb 68bool Adaptation::Icap::Options::fresh() const
774c051c 69{
70 return squid_curtime <= expire();
71}
72
26cc52cb 73int Adaptation::Icap::Options::ttl() const
5f8252d2 74{
75 Must(valid());
26cc52cb 76 return theTTL >= 0 ? theTTL : TheConfig.default_options_ttl;
5f8252d2 77}
78
26cc52cb 79time_t Adaptation::Icap::Options::expire() const
774c051c 80{
81 Must(valid());
5f8252d2 82 return theTimestamp + ttl();
774c051c 83}
84
26cc52cb 85void Adaptation::Icap::Options::configure(const HttpReply *reply)
774c051c 86{
87 error = NULL; // reset initial "unconfigured" value (or an old error?)
88
89 const HttpHeader *h = &reply->header;
90
9b769c67 91 if (reply->sline.status() != Http::scOkay)
774c051c 92 error = "unsupported status code of OPTIONS response";
93
94 // Methods
a9925b40 95 if (h->hasByNameListMember("Methods", "REQMOD", ','))
774c051c 96 cfgMethod(ICAP::methodReqmod);
97
a9925b40 98 if (h->hasByNameListMember("Methods", "RESPMOD", ','))
774c051c 99 cfgMethod(ICAP::methodRespmod);
100
a9925b40 101 service = h->getByName("Service");
774c051c 102
a9925b40 103 serviceId = h->getByName("ServiceId");
774c051c 104
a9925b40 105 istag = h->getByName("ISTag");
774c051c 106
40bb9887
AR
107 if (h->getByName("Opt-body-type").size()) {
108 // TODO: add a class to rate-limit such warnings using FadingCounter
109 debugs(93,DBG_IMPORTANT, "WARNING: Ignoring unsupported ICAP " <<
ab745b44 110 "OPTIONS body; type: " << h->getByName("Opt-body-type"));
40bb9887
AR
111 // Do not set error, assuming the response headers are valid.
112 }
774c051c 113
114 cfgIntHeader(h, "Max-Connections", max_connections);
2dba5b8e
CT
115 if (max_connections == 0)
116 debugs(93, DBG_IMPORTANT, "WARNING: Max-Connections is set to zero! ");
774c051c 117
8eeb99bf 118 cfgIntHeader(h, "Options-TTL", theTTL);
774c051c 119
789217a2 120 theTimestamp = h->getTime(Http::HdrType::DATE);
774c051c 121
8eeb99bf 122 if (theTimestamp < 0)
123 theTimestamp = squid_curtime;
774c051c 124
789217a2 125 if (h->hasListMember(Http::HdrType::ALLOW, "204", ','))
774c051c 126 allow204 = true;
127
789217a2 128 if (h->hasListMember(Http::HdrType::ALLOW, "206", ','))
83c51da9
CT
129 allow206 = true;
130
774c051c 131 cfgIntHeader(h, "Preview", preview);
132
c99de607 133 cfgTransferList(h, theTransfers.preview);
134 cfgTransferList(h, theTransfers.ignore);
135 cfgTransferList(h, theTransfers.complete);
774c051c 136}
137
26cc52cb 138void Adaptation::Icap::Options::cfgMethod(ICAP::Method m)
774c051c 139{
140 Must(m != ICAP::methodNone);
4c9eadc2 141 methods.push_back(m);
774c051c 142}
143
144// TODO: HttpHeader should provide a general method for this type of conversion
26cc52cb 145void Adaptation::Icap::Options::cfgIntHeader(const HttpHeader *h, const char *fname, int &value)
774c051c 146{
30abd221 147 const String s = h->getByName(fname);
774c051c 148
5b4117d8
FC
149 if (s.size() && xisdigit(*s.termedBuf()))
150 value = atoi(s.termedBuf());
774c051c 151 else
152 value = -1;
c99de607 153
192378eb 154 debugs(93,5, HERE << "int header: " << fname << ": " << value);
c99de607 155}
156
26cc52cb 157void Adaptation::Icap::Options::cfgTransferList(const HttpHeader *h, TransferList &list)
c99de607 158{
30abd221 159 const String buf = h->getByName(list.name);
c99de607 160 bool foundStar = false;
161 list.parse(buf, foundStar);
162
163 if (foundStar) {
164 theTransfers.byDefault = &list;
192378eb 165 debugs(93,5, HERE << "set default transfer to " << list.name);
c99de607 166 }
167
26cc52cb 168 list.report(5, "Adaptation::Icap::Options::cfgTransferList: ");
c99de607 169}
170
26cc52cb 171/* Adaptation::Icap::Options::TransferList */
c99de607 172
26cc52cb 173Adaptation::Icap::Options::TransferList::TransferList(): extensions(NULL), name(NULL),
f53969cc 174 kind(xferNone)
9e008dda 175{
c99de607 176};
177
26cc52cb 178Adaptation::Icap::Options::TransferList::~TransferList()
9e008dda 179{
c99de607 180 wordlistDestroy(&extensions);
181};
182
26cc52cb 183void Adaptation::Icap::Options::TransferList::add(const char *extension)
9e008dda 184{
c99de607 185 wordlistAdd(&extensions, extension);
186};
187
51b5dcf5 188bool Adaptation::Icap::Options::TransferList::matches(const SBuf &urlPath) const
9e008dda 189{
51b5dcf5 190 const SBuf::size_type urlLen = urlPath.length();
c99de607 191 for (wordlist *e = extensions; e; e = e->next) {
192 // optimize: store extension lengths
51b5dcf5 193 const size_t eLen = strlen(e->key);
c99de607 194
195 // assume URL contains at least '/' before the extension
196 if (eLen < urlLen) {
51b5dcf5 197 const size_t eOff = urlLen - eLen;
c99de607 198 // RFC 3507 examples imply that extensions come without leading '.'
51b5dcf5
AJ
199 if (urlPath[eOff-1] == '.' && urlPath.substr(eOff).cmp(e->key, eLen) == 0) {
200 debugs(93,7, "url " << urlPath << " matches " << name << " extension " << e->key);
c99de607 201 return true;
202 }
203 }
204 }
51b5dcf5 205 debugs(93,8, "url " << urlPath << " matches no " << name << " extensions");
c99de607 206 return false;
207}
208
26cc52cb 209void Adaptation::Icap::Options::TransferList::parse(const String &buf, bool &foundStar)
9e008dda 210{
c99de607 211 foundStar = false;
212
213 const char *item;
214 const char *pos = NULL;
215 int ilen;
216 while (strListGetItem(&buf, ',', &item, &ilen, &pos)) {
217 if (ilen == 1 && *item == '*')
218 foundStar = true;
5c6dae44
AJ
219 else {
220 const char *tmp = xstrndup(item, ilen+1);
221 add(tmp);
222 xfree(tmp);
223 }
c99de607 224 }
225}
226
26cc52cb 227void Adaptation::Icap::Options::TransferList::report(int level, const char *prefix) const
9e008dda 228{
c99de607 229 if (extensions) {
230 for (wordlist *e = extensions; e; e = e->next)
231 debugs(93,level, prefix << name << ": " << e->key);
232 } else {
233 debugs(93,level, prefix << "no " << name << " extensions");
234 }
774c051c 235}
f53969cc 236