]>
Commit | Line | Data |
---|---|---|
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 | 9 | Adaptation::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 | 26 | Adaptation::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 | 33 | Adaptation::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 | 49 | bool Adaptation::Icap::Options::valid() const |
774c051c | 50 | { |
51 | return !error; | |
52 | } | |
53 | ||
26cc52cb | 54 | bool Adaptation::Icap::Options::fresh() const |
774c051c | 55 | { |
56 | return squid_curtime <= expire(); | |
57 | } | |
58 | ||
26cc52cb | 59 | int Adaptation::Icap::Options::ttl() const |
5f8252d2 | 60 | { |
61 | Must(valid()); | |
26cc52cb | 62 | return theTTL >= 0 ? theTTL : TheConfig.default_options_ttl; |
5f8252d2 | 63 | } |
64 | ||
26cc52cb | 65 | time_t Adaptation::Icap::Options::expire() const |
774c051c | 66 | { |
67 | Must(valid()); | |
5f8252d2 | 68 | return theTimestamp + ttl(); |
774c051c | 69 | } |
70 | ||
26cc52cb | 71 | void 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 | 118 | void 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 | 125 | void 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 | 137 | void 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 | 154 | Adaptation::Icap::Options::TransferList::TransferList(): extensions(NULL), name(NULL), |
9e008dda AJ |
155 | kind(xferNone) |
156 | { | |
c99de607 | 157 | }; |
158 | ||
26cc52cb | 159 | Adaptation::Icap::Options::TransferList::~TransferList() |
9e008dda | 160 | { |
c99de607 | 161 | wordlistDestroy(&extensions); |
162 | }; | |
163 | ||
26cc52cb | 164 | void Adaptation::Icap::Options::TransferList::add(const char *extension) |
9e008dda | 165 | { |
c99de607 | 166 | wordlistAdd(&extensions, extension); |
167 | }; | |
168 | ||
26cc52cb | 169 | bool 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 | 192 | void 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 | 207 | void 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 | } |