]> git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/ServiceConfig.cc
Support adaptation sets and chains, including dynamic ICAP chains:
[thirdparty/squid.git] / src / adaptation / ServiceConfig.cc
1 /*
2 * DEBUG: section XXX
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
95 if (strcmp(name, "routing") == 0)
96 grokked = grokBool(routing, name, value);
97 else {
98 debugs(3, 0, cfg_filename << ':' << config_lineno << ": " <<
99 "unknown adaptation service option: " << name << '=' << value);
100 }
101 if (!grokked)
102 return false;
103 }
104
105 // what is left must be the service URI
106 if (!grokUri(lastOption))
107 return false;
108
109 // there should be nothing else left
110 if (const char *tail = strtok(NULL, w_space)) {
111 debugs(3, 0, cfg_filename << ':' << config_lineno << ": " <<
112 "garbage after adaptation service URI: " << tail);
113 return false;
114 }
115
116 debugs(3,5, cfg_filename << ':' << config_lineno << ": " <<
117 "adaptation_service " << key << ' ' <<
118 methodStr() << "_" << vectPointStr() << ' ' <<
119 bypass << routing << ' ' <<
120 uri);
121
122 return true;
123 }
124
125 bool
126 Adaptation::ServiceConfig::grokUri(const char *value)
127 {
128 // TODO: find core code that parses URLs and extracts various parts
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 if ((e = strchr(s, ':')) != NULL) {
158 have_port = true;
159 } else if ((e = strchr(s, '/')) != NULL) {
160 have_port = false;
161 } else {
162 return false;
163 }
164
165 int len = e - s;
166 host.limitInit(s, len);
167 s = e;
168
169 port = -1;
170 if (have_port) {
171 s++;
172
173 if ((e = strchr(s, '/')) != NULL) {
174 char *t;
175 const unsigned long p = strtoul(s, &t, 0);
176
177 if (p > 65535) // port value is too high
178 return false;
179
180 port = static_cast<int>(p);
181
182 if (t != e) // extras after the port
183 return false;
184
185 s = e;
186
187 if (s[0] != '/')
188 return false;
189 }
190 }
191
192 // if no port, the caller may use service_configConfigs or supply the default if neeeded
193
194 s++;
195 e = strchr(s, '\0');
196 len = e - s;
197
198 if (len > 1024) {
199 debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
200 "long resource name (>1024), probably wrong");
201 }
202
203 resource.limitInit(s, len + 1);
204 return true;
205 }
206
207
208 bool
209 Adaptation::ServiceConfig::grokBool(bool &var, const char *name, const char *value)
210 {
211 if (!strcmp(value, "0") || !strcmp(value, "off"))
212 var = false;
213 else
214 if (!strcmp(value, "1") || !strcmp(value, "on"))
215 var = true;
216 else {
217 debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
218 "wrong value for boolean " << name << "; " <<
219 "'0', '1', 'on', or 'off' expected but got: " << value);
220 return false;
221 }
222
223 return true;
224 }