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