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