]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ICAP/ICAPOptions.cc
Fix several issues in translation uncovered by further testing.
[thirdparty/squid.git] / src / ICAP / ICAPOptions.cc
1 #include "squid.h"
2 #include "wordlist.h"
3 #include "HttpReply.h"
4 #include "ICAPOptions.h"
5 #include "TextException.h"
6 #include "ICAPConfig.h"
7 #include "SquidTime.h"
8
9 extern ICAPConfig TheICAPConfig;
10
11 ICAPOptions::ICAPOptions(): error("unconfigured"),
12 max_connections(-1), allow204(false),
13 preview(-1), theTTL(-1)
14 {
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 }
26
27 ICAPOptions::~ICAPOptions()
28 {
29 }
30
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.
34 ICAPOptions::TransferKind ICAPOptions::transferKind(const String &urlPath) const
35 {
36 if (theTransfers.preview.matches(urlPath))
37 return xferPreview;
38
39 if (theTransfers.complete.matches(urlPath))
40 return xferComplete;
41
42 if (theTransfers.ignore.matches(urlPath))
43 return xferIgnore;
44
45 debugs(93,7, "ICAPOptions url " << urlPath << " matches no extensions; " <<
46 "using default: " << theTransfers.byDefault->name);
47 return theTransfers.byDefault->kind;
48 }
49
50 bool ICAPOptions::valid() const
51 {
52 return !error;
53 }
54
55 bool ICAPOptions::fresh() const
56 {
57 return squid_curtime <= expire();
58 }
59
60 int ICAPOptions::ttl() const
61 {
62 Must(valid());
63 return theTTL >= 0 ? theTTL : TheICAPConfig.default_options_ttl;
64 }
65
66 time_t ICAPOptions::expire() const
67 {
68 Must(valid());
69 return theTimestamp + ttl();
70 }
71
72 void ICAPOptions::configure(const HttpReply *reply)
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
82 if (h->hasByNameListMember("Methods", "REQMOD", ','))
83 cfgMethod(ICAP::methodReqmod);
84
85 if (h->hasByNameListMember("Methods", "RESPMOD", ','))
86 cfgMethod(ICAP::methodRespmod);
87
88 service = h->getByName("Service");
89
90 serviceId = h->getByName("ServiceId");
91
92 istag = h->getByName("ISTag");
93
94 if (h->getByName("Opt-body-type").size())
95 error = "ICAP service returns unsupported OPTIONS body";
96
97 cfgIntHeader(h, "Max-Connections", max_connections);
98
99 cfgIntHeader(h, "Options-TTL", theTTL);
100
101 theTimestamp = h->getTime(HDR_DATE);
102
103 if (theTimestamp < 0)
104 theTimestamp = squid_curtime;
105
106 if (h->hasListMember(HDR_ALLOW, "204", ','))
107 allow204 = true;
108
109 cfgIntHeader(h, "Preview", preview);
110
111 cfgTransferList(h, theTransfers.preview);
112 cfgTransferList(h, theTransfers.ignore);
113 cfgTransferList(h, theTransfers.complete);
114 }
115
116 void ICAPOptions::cfgMethod(ICAP::Method m)
117 {
118 Must(m != ICAP::methodNone);
119 methods += m;
120 }
121
122 // TODO: HttpHeader should provide a general method for this type of conversion
123 void ICAPOptions::cfgIntHeader(const HttpHeader *h, const char *fname, int &value)
124 {
125 const String s = h->getByName(fname);
126
127 if (s.size() && xisdigit(*s.termedBuf()))
128 value = atoi(s.termedBuf());
129 else
130 value = -1;
131
132 debugs(93,5, "ICAPOptions::cfgIntHeader " << fname << ": " << value);
133 }
134
135 void ICAPOptions::cfgTransferList(const HttpHeader *h, TransferList &list)
136 {
137 const String buf = h->getByName(list.name);
138 bool foundStar = false;
139 list.parse(buf, foundStar);
140
141 if (foundStar) {
142 theTransfers.byDefault = &list;
143 debugs(93,5, "ICAPOptions::cfgTransferList: " <<
144 "set default transfer to " << list.name);
145 }
146
147 list.report(5, "ICAPOptions::cfgTransferList: ");
148 }
149
150
151 /* ICAPOptions::TransferList */
152
153 ICAPOptions::TransferList::TransferList(): extensions(NULL), name(NULL),
154 kind(xferNone)
155 {
156 };
157
158 ICAPOptions::TransferList::~TransferList()
159 {
160 wordlistDestroy(&extensions);
161 };
162
163 void ICAPOptions::TransferList::add(const char *extension)
164 {
165 wordlistAdd(&extensions, extension);
166 };
167
168 bool ICAPOptions::TransferList::matches(const String &urlPath) const
169 {
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 '.'
179 if (urlPath[eOff-1] == '.' &&
180 strcmp(urlPath.termedBuf() + eOff, e->key) == 0) {
181 debugs(93,7, "ICAPOptions url " << urlPath << " matches " <<
182 name << " extension " << e->key);
183 return true;
184 }
185 }
186 }
187 debugs(93,8, "ICAPOptions url " << urlPath << " matches no " << name << " extensions");
188 return false;
189 }
190
191 void ICAPOptions::TransferList::parse(const String &buf, bool &foundStar)
192 {
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
206 void ICAPOptions::TransferList::report(int level, const char *prefix) const
207 {
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 }
214 }