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