]>
Commit | Line | Data |
---|---|---|
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 | 10 | Adaptation::ServiceConfig::ServiceConfig(): |
e1381638 | 11 | port(-1), method(methodNone), point(pointNone), |
e6713f4e | 12 | bypass(false), routing(false), ipv6(false) |
d81a31f1 AR |
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 | 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 | ||
132 | bool | |
133 | Adaptation::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 |
233 | bool |
234 | Adaptation::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 | } |