]> git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/ServiceConfig.cc
Merged from parent (trunk r11379, v3.2.0.6+).
[thirdparty/squid.git] / src / adaptation / ServiceConfig.cc
1 /*
2 * DEBUG: section 93 Adaptation
3 */
4
5 #include "squid.h"
6 #include "ConfigParser.h"
7 #include "adaptation/ServiceConfig.h"
8 #include "ip/tools.h"
9
10 Adaptation::ServiceConfig::ServiceConfig():
11 port(-1), method(methodNone), point(pointNone),
12 bypass(false), routing(false), ipv6(false)
13 {}
14
15 const char *
16 Adaptation::ServiceConfig::methodStr() const
17 {
18 return Adaptation::methodStr(method);
19 }
20
21 const char *
22 Adaptation::ServiceConfig::vectPointStr() const
23 {
24 return Adaptation::vectPointStr(point);
25 }
26
27 Adaptation::Method
28 Adaptation::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
39 Adaptation::VectPoint
40 Adaptation::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
57 bool
58 Adaptation::ServiceConfig::parse()
59 {
60 String method_point;
61
62 ConfigParser::ParseString(&key);
63 ConfigParser::ParseString(&method_point);
64 method = parseMethod(method_point.termedBuf());
65 point = parseVectPoint(method_point.termedBuf());
66
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;
72 bool grokkedUri = false;
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);
96 else if (strcmp(name, "routing") == 0)
97 grokked = grokBool(routing, name, value);
98 else if (strcmp(name, "uri") == 0)
99 grokked = grokkedUri = grokUri(value);
100 else if (strcmp(name, "ipv6") == 0) {
101 grokked = grokBool(ipv6, name, value);
102 if (grokked && ipv6 && !Ip::EnableIpv6)
103 debugs(3, DBG_IMPORTANT, "WARNING: IPv6 is disabled. ICAP service option ignored.");
104 } else
105 grokked = grokExtension(name, value);
106
107 if (!grokked)
108 return false;
109 }
110
111 // what is left must be the service URI
112 if (!grokkedUri && !grokUri(lastOption))
113 return false;
114
115 // there should be nothing else left
116 if (const char *tail = strtok(NULL, w_space)) {
117 debugs(3, 0, cfg_filename << ':' << config_lineno << ": " <<
118 "garbage after adaptation service URI: " << tail);
119 return false;
120 }
121
122 debugs(3,5, cfg_filename << ':' << config_lineno << ": " <<
123 "adaptation_service " << key << ' ' <<
124 methodStr() << "_" << vectPointStr() << ' ' <<
125 bypass << routing << ' ' <<
126 uri);
127
128 return true;
129 }
130
131 bool
132 Adaptation::ServiceConfig::grokUri(const char *value)
133 {
134 // TODO: find core code that parses URLs and extracts various parts
135 // AYJ: most of this is duplicate of urlParse() in src/url.cc
136
137 if (!value || !*value) {
138 debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
139 "empty adaptation service URI");
140 return false;
141 }
142
143 uri = value;
144
145 // extract scheme and use it as the service_configConfig protocol
146 const char *schemeSuffix = "://";
147 const String::size_type schemeEnd = uri.find(schemeSuffix);
148 if (schemeEnd != String::npos)
149 protocol=uri.substr(0,schemeEnd);
150
151 debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " <<
152 "service protocol is " << protocol);
153
154 if (protocol.size() == 0)
155 return false;
156
157 // skip scheme
158 const char *s = uri.termedBuf() + protocol.size() + strlen(schemeSuffix);
159
160 const char *e;
161
162 bool have_port = false;
163
164 int len = 0;
165 if (*s == '[') {
166 const char *t;
167 if ((t = strchr(s, ']')) == NULL)
168 return false;
169
170 s++;
171 len = t - s;
172 if ((e = strchr(t, ':')) != NULL) {
173 have_port = true;
174 } else if ((e = strchr(t, '/')) != NULL) {
175 have_port = false;
176 } else {
177 return false;
178 }
179 } else {
180 if ((e = strchr(s, ':')) != NULL) {
181 have_port = true;
182 } else if ((e = strchr(s, '/')) != NULL) {
183 have_port = false;
184 } else {
185 return false;
186 }
187 len = e - s;
188 }
189
190 host.limitInit(s, len);
191 s = e;
192
193 port = -1;
194 if (have_port) {
195 s++;
196
197 if ((e = strchr(s, '/')) != NULL) {
198 char *t;
199 const unsigned long p = strtoul(s, &t, 0);
200
201 if (p > 65535) // port value is too high
202 return false;
203
204 port = static_cast<int>(p);
205
206 if (t != e) // extras after the port
207 return false;
208
209 s = e;
210
211 if (s[0] != '/')
212 return false;
213 }
214 }
215
216 // if no port, the caller may use service_configConfigs or supply the default if neeeded
217
218 s++;
219 e = strchr(s, '\0');
220 len = e - s;
221
222 if (len > 1024) {
223 debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
224 "long resource name (>1024), probably wrong");
225 }
226
227 resource.limitInit(s, len + 1);
228 return true;
229 }
230
231
232 bool
233 Adaptation::ServiceConfig::grokBool(bool &var, const char *name, const char *value)
234 {
235 if (!strcmp(value, "0") || !strcmp(value, "off"))
236 var = false;
237 else if (!strcmp(value, "1") || !strcmp(value, "on"))
238 var = true;
239 else {
240 debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
241 "wrong value for boolean " << name << "; " <<
242 "'0', '1', 'on', or 'off' expected but got: " << value);
243 return false;
244 }
245
246 return true;
247 }
248
249 bool
250 Adaptation::ServiceConfig::grokExtension(const char *name, const char *value)
251 {
252 // we do not accept extensions by default
253 debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " <<
254 "ERROR: unknown adaptation service option: " <<
255 name << '=' << value);
256 return false;
257 }