]> git.ipfire.org Git - thirdparty/squid.git/blame - src/adaptation/ServiceConfig.cc
Set Squid IDs for known header names to speedup comparisons.
[thirdparty/squid.git] / src / adaptation / ServiceConfig.cc
CommitLineData
d81a31f1 1/*
b510f3a1 2 * DEBUG: section 93 Adaptation
d81a31f1
AR
3 */
4
5#include "squid.h"
6#include "ConfigParser.h"
7#include "adaptation/ServiceConfig.h"
3496b53a 8#include "ip/tools.h"
d81a31f1 9
26ac0430 10Adaptation::ServiceConfig::ServiceConfig():
e1381638 11 port(-1), method(methodNone), point(pointNone),
e6713f4e 12 bypass(false), routing(false), ipv6(false)
d81a31f1
AR
13{}
14
15const char *
16Adaptation::ServiceConfig::methodStr() const
17{
18 return Adaptation::methodStr(method);
19}
20
21const char *
22Adaptation::ServiceConfig::vectPointStr() const
23{
24 return Adaptation::vectPointStr(point);
25}
26
27Adaptation::Method
28Adaptation::ServiceConfig::parseMethod(const char *str) const
29{
30 if (!strncasecmp(str, "REQMOD", 6))
31 return Adaptation::methodReqmod;
32
33 if (!strncasecmp(str, "RESPMOD", 7))
34 return Adaptation::methodRespmod;
35
36 return Adaptation::methodNone;
37}
38
39Adaptation::VectPoint
40Adaptation::ServiceConfig::parseVectPoint(const char *service_configConfig) const
41{
42 const char *t = service_configConfig;
43 const char *q = strchr(t, '_');
44
45 if (q)
46 t = q + 1;
47
48 if (!strcasecmp(t, "precache"))
49 return Adaptation::pointPreCache;
50
51 if (!strcasecmp(t, "postcache"))
52 return Adaptation::pointPostCache;
53
54 return Adaptation::pointNone;
55}
56
57bool
58Adaptation::ServiceConfig::parse()
59{
60 char *method_point = NULL;
61
62 ConfigParser::ParseString(&key);
63 ConfigParser::ParseString(&method_point);
d81a31f1
AR
64 method = parseMethod(method_point);
65 point = parseVectPoint(method_point);
66
a22e6cd3
AR
67 // reset optional parameters in case we are reconfiguring
68 bypass = routing = false;
69
70 // handle optional service name=value parameters
71 const char *lastOption = NULL;
8e2fb579 72 bool grokkedUri = false;
a22e6cd3
AR
73 while (char *option = strtok(NULL, w_space)) {
74 if (strcmp(option, "0") == 0) { // backward compatibility
75 bypass = false;
76 continue;
77 }
78 if (strcmp(option, "1") == 0) { // backward compatibility
79 bypass = true;
80 continue;
81 }
82
83 const char *name = option;
84 char *value = strstr(option, "=");
85 if (!value) {
86 lastOption = option;
87 break;
88 }
89 *value = '\0'; // terminate option name
90 ++value; // skip '='
91
92 // TODO: warn if option is set twice?
93 bool grokked = false;
94 if (strcmp(name, "bypass") == 0)
95 grokked = grokBool(bypass, name, value);
e1381638 96 else if (strcmp(name, "routing") == 0)
a22e6cd3 97 grokked = grokBool(routing, name, value);
8e2fb579
AR
98 else if (strcmp(name, "uri") == 0)
99 grokked = grokkedUri = grokUri(value);
3496b53a 100 else if (strcmp(name, "ipv6") == 0) {
e6713f4e 101 grokked = grokBool(ipv6, name, value);
3496b53a
AJ
102 if (grokked && ipv6 && !Ip::EnableIpv6)
103 debugs(3, DBG_IMPORTANT, "WARNING: IPv6 is disabled. ICAP service option ignored.");
e6713f4e 104 } else {
a22e6cd3 105 debugs(3, 0, cfg_filename << ':' << config_lineno << ": " <<
e1381638 106 "unknown adaptation service option: " << name << '=' << value);
a22e6cd3
AR
107 }
108 if (!grokked)
109 return false;
110 }
111
112 // what is left must be the service URI
8e2fb579 113 if (!grokkedUri && !grokUri(lastOption))
a22e6cd3
AR
114 return false;
115
116 // there should be nothing else left
117 if (const char *tail = strtok(NULL, w_space)) {
118 debugs(3, 0, cfg_filename << ':' << config_lineno << ": " <<
e1381638 119 "garbage after adaptation service URI: " << tail);
a22e6cd3
AR
120 return false;
121 }
d81a31f1 122
a22e6cd3 123 debugs(3,5, cfg_filename << ':' << config_lineno << ": " <<
e1381638
AJ
124 "adaptation_service " << key << ' ' <<
125 methodStr() << "_" << vectPointStr() << ' ' <<
126 bypass << routing << ' ' <<
127 uri);
a22e6cd3
AR
128
129 return true;
130}
131
132bool
133Adaptation::ServiceConfig::grokUri(const char *value)
134{
d81a31f1 135 // TODO: find core code that parses URLs and extracts various parts
5957a4c9 136 // AYJ: most of this is duplicate of urlParse() in src/url.cc
d81a31f1 137
a22e6cd3
AR
138 if (!value || !*value) {
139 debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
140 "empty adaptation service URI");
141 return false;
142 }
143
144 uri = value;
145
d81a31f1
AR
146 // extract scheme and use it as the service_configConfig protocol
147 const char *schemeSuffix = "://";
a22e6cd3
AR
148 const String::size_type schemeEnd = uri.find(schemeSuffix);
149 if (schemeEnd != String::npos)
b2f458b7 150 protocol=uri.substr(0,schemeEnd);
826a1fed 151
26ac0430
AJ
152 debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " <<
153 "service protocol is " << protocol);
826a1fed
FC
154
155 if (protocol.size() == 0)
26ac0430 156 return false;
d81a31f1
AR
157
158 // skip scheme
c1945e7d 159 const char *s = uri.termedBuf() + protocol.size() + strlen(schemeSuffix);
d81a31f1
AR
160
161 const char *e;
162
163 bool have_port = false;
164
5957a4c9
AJ
165 int len = 0;
166 if (*s == '[') {
167 const char *t;
168 if ((t = strchr(s, ']')) == NULL)
169 return false;
170
171 s++;
172 len = t - s;
173 if ((e = strchr(t, ':')) != NULL) {
174 have_port = true;
175 } else if ((e = strchr(t, '/')) != NULL) {
176 have_port = false;
177 } else {
178 return false;
179 }
792beadc 180 } else {
5957a4c9
AJ
181 if ((e = strchr(s, ':')) != NULL) {
182 have_port = true;
183 } else if ((e = strchr(s, '/')) != NULL) {
184 have_port = false;
185 } else {
186 return false;
187 }
188 len = e - s;
d81a31f1
AR
189 }
190
d81a31f1
AR
191 host.limitInit(s, len);
192 s = e;
193
26ac0430 194 port = -1;
d81a31f1
AR
195 if (have_port) {
196 s++;
197
198 if ((e = strchr(s, '/')) != NULL) {
199 char *t;
26ac0430 200 const unsigned long p = strtoul(s, &t, 0);
d81a31f1 201
26ac0430
AJ
202 if (p > 65535) // port value is too high
203 return false;
d81a31f1
AR
204
205 port = static_cast<int>(p);
206
207 if (t != e) // extras after the port
208 return false;
209
210 s = e;
211
212 if (s[0] != '/')
213 return false;
214 }
215 }
216
217 // if no port, the caller may use service_configConfigs or supply the default if neeeded
218
219 s++;
220 e = strchr(s, '\0');
221 len = e - s;
222
223 if (len > 1024) {
224 debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
26ac0430 225 "long resource name (>1024), probably wrong");
d81a31f1
AR
226 }
227
228 resource.limitInit(s, len + 1);
a22e6cd3
AR
229 return true;
230}
231
d81a31f1 232
a22e6cd3
AR
233bool
234Adaptation::ServiceConfig::grokBool(bool &var, const char *name, const char *value)
235{
236 if (!strcmp(value, "0") || !strcmp(value, "off"))
237 var = false;
e1381638 238 else if (!strcmp(value, "1") || !strcmp(value, "on"))
a22e6cd3
AR
239 var = true;
240 else {
d81a31f1 241 debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
a22e6cd3
AR
242 "wrong value for boolean " << name << "; " <<
243 "'0', '1', 'on', or 'off' expected but got: " << value);
d81a31f1
AR
244 return false;
245 }
246
247 return true;
248}