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