]>
Commit | Line | Data |
---|---|---|
fdc96a39 | 1 | /* |
b510f3a1 | 2 | * DEBUG: section 93 eCAP Interface |
fdc96a39 | 3 | */ |
582c2af2 | 4 | #include "squid.h" |
cf331c99 | 5 | #include "BodyPipe.h" |
602d9612 A |
6 | #include "HttpReply.h" |
7 | #include "HttpRequest.h" | |
cf331c99 AR |
8 | #include <libecap/common/names.h> |
9 | #include <libecap/common/area.h> | |
10 | #include <libecap/common/version.h> | |
12a410c3 | 11 | #include <libecap/common/named_values.h> |
602d9612 | 12 | #include "adaptation/ecap/Host.h" /* for protocol constants */ |
1f3c65fc AR |
13 | #include "adaptation/ecap/MessageRep.h" |
14 | #include "adaptation/ecap/XactionRep.h" | |
3d93a84d | 15 | #include "base/TextException.h" |
b1bd952a | 16 | #include "URL.h" |
fdc96a39 | 17 | |
cf331c99 AR |
18 | /* HeaderRep */ |
19 | ||
574b508c | 20 | Adaptation::Ecap::HeaderRep::HeaderRep(HttpMsg &aMessage): theHeader(aMessage.header), |
26ac0430 | 21 | theMessage(aMessage) |
cf331c99 AR |
22 | { |
23 | } | |
24 | ||
cf331c99 | 25 | bool |
574b508c | 26 | Adaptation::Ecap::HeaderRep::hasAny(const Name &name) const |
cf331c99 AR |
27 | { |
28 | const http_hdr_type squidId = TranslateHeaderId(name); | |
29 | // XXX: optimize to remove getByName: we do not need the value here | |
30 | return squidId == HDR_OTHER ? | |
26ac0430 AJ |
31 | theHeader.getByName(name.image().c_str()).size() > 0: |
32 | (bool)theHeader.has(squidId); | |
cf331c99 AR |
33 | } |
34 | ||
574b508c AR |
35 | Adaptation::Ecap::HeaderRep::Value |
36 | Adaptation::Ecap::HeaderRep::value(const Name &name) const | |
cf331c99 AR |
37 | { |
38 | const http_hdr_type squidId = TranslateHeaderId(name); | |
39 | const String value = squidId == HDR_OTHER ? | |
26ac0430 AJ |
40 | theHeader.getByName(name.image().c_str()) : |
41 | theHeader.getStrOrList(squidId); | |
b38b26cb | 42 | return value.size() > 0 ? |
001eaf80 | 43 | Value::FromTempString(value.termedBuf()) : Value(); |
cf331c99 AR |
44 | } |
45 | ||
46 | void | |
574b508c | 47 | Adaptation::Ecap::HeaderRep::add(const Name &name, const Value &value) |
cf331c99 AR |
48 | { |
49 | const http_hdr_type squidId = TranslateHeaderId(name); // HDR_OTHER OK | |
50 | HttpHeaderEntry *e = new HttpHeaderEntry(squidId, name.image().c_str(), | |
26ac0430 | 51 | value.toString().c_str()); |
cf331c99 | 52 | theHeader.addEntry(e); |
809fd5d3 AJ |
53 | |
54 | if (squidId == HDR_CONTENT_LENGTH) | |
74174c03 | 55 | theMessage.content_length = theHeader.getInt64(HDR_CONTENT_LENGTH); |
cf331c99 AR |
56 | } |
57 | ||
58 | void | |
574b508c | 59 | Adaptation::Ecap::HeaderRep::removeAny(const Name &name) |
cf331c99 AR |
60 | { |
61 | const http_hdr_type squidId = TranslateHeaderId(name); | |
62 | if (squidId == HDR_OTHER) | |
63 | theHeader.delByName(name.image().c_str()); | |
64 | else | |
65 | theHeader.delById(squidId); | |
809fd5d3 AJ |
66 | |
67 | if (squidId == HDR_CONTENT_LENGTH) | |
74174c03 | 68 | theMessage.content_length = theHeader.getInt64(HDR_CONTENT_LENGTH); |
cf331c99 AR |
69 | } |
70 | ||
12a410c3 AR |
71 | void |
72 | Adaptation::Ecap::HeaderRep::visitEach(libecap::NamedValueVisitor &visitor) const | |
73 | { | |
74 | HttpHeaderPos pos = HttpHeaderInitPos; | |
75 | while (HttpHeaderEntry *e = theHeader.getEntry(&pos)) { | |
76 | const Name name(e->name.termedBuf()); // optimize: find std Names | |
77 | name.assignHostId(e->id); | |
78 | visitor.visit(name, Value(e->value.rawBuf(), e->value.size())); | |
79 | } | |
80 | } | |
81 | ||
cf331c99 | 82 | libecap::Area |
574b508c | 83 | Adaptation::Ecap::HeaderRep::image() const |
cf331c99 AR |
84 | { |
85 | MemBuf mb; | |
86 | mb.init(); | |
87 | ||
88 | Packer p; | |
89 | packerToMemInit(&p, &mb); | |
90 | theMessage.packInto(&p, true); | |
91 | packerClean(&p); | |
92 | return Area::FromTempBuffer(mb.content(), mb.contentSize()); | |
93 | } | |
94 | ||
95 | // throws on failures | |
96 | void | |
574b508c | 97 | Adaptation::Ecap::HeaderRep::parse(const Area &buf) |
cf331c99 AR |
98 | { |
99 | MemBuf mb; | |
100 | mb.init(); | |
101 | mb.append(buf.start, buf.size); | |
955394ce | 102 | Http::StatusCode error; |
cf331c99 AR |
103 | Must(theMessage.parse(&mb, true, &error)); |
104 | } | |
105 | ||
77773405 | 106 | http_hdr_type |
574b508c | 107 | Adaptation::Ecap::HeaderRep::TranslateHeaderId(const Name &name) |
77773405 AR |
108 | { |
109 | if (name.assignedHostId()) | |
110 | return static_cast<http_hdr_type>(name.hostId()); | |
111 | return HDR_OTHER; | |
112 | } | |
113 | ||
77773405 AR |
114 | /* FirstLineRep */ |
115 | ||
574b508c | 116 | Adaptation::Ecap::FirstLineRep::FirstLineRep(HttpMsg &aMessage): theMessage(aMessage) |
77773405 AR |
117 | { |
118 | } | |
119 | ||
cf331c99 | 120 | libecap::Version |
574b508c | 121 | Adaptation::Ecap::FirstLineRep::version() const |
cf331c99 AR |
122 | { |
123 | return libecap::Version(theMessage.http_ver.major, | |
26ac0430 | 124 | theMessage.http_ver.minor); |
cf331c99 AR |
125 | } |
126 | ||
127 | void | |
574b508c | 128 | Adaptation::Ecap::FirstLineRep::version(const libecap::Version &aVersion) |
cf331c99 AR |
129 | { |
130 | theMessage.http_ver.major = aVersion.majr; | |
131 | theMessage.http_ver.minor = aVersion.minr; | |
132 | } | |
133 | ||
134 | libecap::Name | |
574b508c | 135 | Adaptation::Ecap::FirstLineRep::protocol() const |
cf331c99 AR |
136 | { |
137 | // TODO: optimize? | |
138 | switch (theMessage.protocol) { | |
39a19cb7 | 139 | case AnyP::PROTO_HTTP: |
26ac0430 | 140 | return libecap::protocolHttp; |
39a19cb7 | 141 | case AnyP::PROTO_HTTPS: |
26ac0430 | 142 | return libecap::protocolHttps; |
39a19cb7 | 143 | case AnyP::PROTO_FTP: |
26ac0430 | 144 | return libecap::protocolFtp; |
39a19cb7 | 145 | case AnyP::PROTO_GOPHER: |
26ac0430 | 146 | return libecap::protocolGopher; |
39a19cb7 | 147 | case AnyP::PROTO_WAIS: |
26ac0430 | 148 | return libecap::protocolWais; |
39a19cb7 | 149 | case AnyP::PROTO_WHOIS: |
26ac0430 | 150 | return libecap::protocolWhois; |
39a19cb7 | 151 | case AnyP::PROTO_URN: |
26ac0430 | 152 | return libecap::protocolUrn; |
39a19cb7 | 153 | case AnyP::PROTO_ICP: |
26ac0430 | 154 | return protocolIcp; |
cf331c99 | 155 | #if USE_HTCP |
39a19cb7 | 156 | case AnyP::PROTO_HTCP: |
26ac0430 | 157 | return protocolHtcp; |
cf331c99 | 158 | #endif |
39a19cb7 | 159 | case AnyP::PROTO_CACHE_OBJECT: |
26ac0430 | 160 | return protocolCacheObj; |
39a19cb7 | 161 | case AnyP::PROTO_INTERNAL: |
26ac0430 | 162 | return protocolInternal; |
39a19cb7 | 163 | case AnyP::PROTO_ICY: |
555aedbf | 164 | return protocolIcy; |
a90ea541 AJ |
165 | case AnyP::PROTO_COAP: |
166 | case AnyP::PROTO_COAPS: // use 'unknown' until libecap supports coap:// and coaps:// | |
555aedbf AR |
167 | case AnyP::PROTO_UNKNOWN: |
168 | return protocolUnknown; // until we remember the protocol image | |
39a19cb7 | 169 | case AnyP::PROTO_NONE: |
26ac0430 AJ |
170 | return Name(); |
171 | ||
39a19cb7 | 172 | case AnyP::PROTO_MAX: |
26ac0430 | 173 | break; // should not happen |
39a19cb7 | 174 | // no default to catch AnyP::PROTO_ additions |
cf331c99 AR |
175 | } |
176 | Must(false); // not reached | |
177 | return Name(); | |
178 | } | |
179 | ||
180 | void | |
574b508c | 181 | Adaptation::Ecap::FirstLineRep::protocol(const Name &p) |
cf331c99 AR |
182 | { |
183 | // TODO: what happens if we fail to translate some protocol? | |
184 | theMessage.protocol = TranslateProtocolId(p); | |
185 | } | |
186 | ||
555aedbf | 187 | AnyP::ProtocolType |
574b508c | 188 | Adaptation::Ecap::FirstLineRep::TranslateProtocolId(const Name &name) |
77773405 AR |
189 | { |
190 | if (name.assignedHostId()) | |
555aedbf AR |
191 | return static_cast<AnyP::ProtocolType>(name.hostId()); |
192 | return AnyP::PROTO_UNKNOWN; | |
77773405 AR |
193 | } |
194 | ||
cf331c99 AR |
195 | /* RequestHeaderRep */ |
196 | ||
574b508c | 197 | Adaptation::Ecap::RequestLineRep::RequestLineRep(HttpRequest &aMessage): |
26ac0430 | 198 | FirstLineRep(aMessage), theMessage(aMessage) |
cf331c99 AR |
199 | { |
200 | } | |
201 | ||
202 | void | |
574b508c | 203 | Adaptation::Ecap::RequestLineRep::uri(const Area &aUri) |
cf331c99 AR |
204 | { |
205 | // TODO: if method is not set, urlPath will assume it is not connect; | |
206 | // Can we change urlParse API to remove the method parameter? | |
207 | // TODO: optimize: urlPath should take constant URL buffer | |
208 | char *buf = xstrdup(aUri.toString().c_str()); | |
209 | const bool ok = urlParse(theMessage.method, buf, &theMessage); | |
210 | xfree(buf); | |
211 | Must(ok); | |
212 | } | |
213 | ||
574b508c AR |
214 | Adaptation::Ecap::RequestLineRep::Area |
215 | Adaptation::Ecap::RequestLineRep::uri() const | |
cf331c99 | 216 | { |
dd31ab8f AR |
217 | const char *fullUrl = urlCanonical(&theMessage); |
218 | Must(fullUrl); | |
219 | // optimize: avoid copying by having an Area::Detail that locks theMessage | |
220 | return Area::FromTempBuffer(fullUrl, strlen(fullUrl)); | |
cf331c99 AR |
221 | } |
222 | ||
223 | void | |
574b508c | 224 | Adaptation::Ecap::RequestLineRep::method(const Name &aMethod) |
cf331c99 AR |
225 | { |
226 | if (aMethod.assignedHostId()) { | |
227 | const int id = aMethod.hostId(); | |
23ef3d70 FC |
228 | Must(Http::METHOD_NONE < id && id < Http::METHOD_ENUM_END); |
229 | Must(id != Http::METHOD_OTHER); | |
c2a7cefd | 230 | theMessage.method = HttpRequestMethod(static_cast<Http::MethodType>(id)); |
cf331c99 AR |
231 | } else { |
232 | const std::string &image = aMethod.image(); | |
233 | theMessage.method = HttpRequestMethod(image.data(), | |
26ac0430 | 234 | image.data() + image.size()); |
cf331c99 AR |
235 | } |
236 | } | |
237 | ||
574b508c AR |
238 | Adaptation::Ecap::RequestLineRep::Name |
239 | Adaptation::Ecap::RequestLineRep::method() const | |
cf331c99 AR |
240 | { |
241 | switch (theMessage.method.id()) { | |
23ef3d70 | 242 | case Http::METHOD_GET: |
26ac0430 | 243 | return libecap::methodGet; |
23ef3d70 | 244 | case Http::METHOD_POST: |
26ac0430 | 245 | return libecap::methodPost; |
23ef3d70 | 246 | case Http::METHOD_PUT: |
26ac0430 | 247 | return libecap::methodPut; |
23ef3d70 | 248 | case Http::METHOD_HEAD: |
26ac0430 | 249 | return libecap::methodHead; |
23ef3d70 | 250 | case Http::METHOD_CONNECT: |
26ac0430 | 251 | return libecap::methodConnect; |
23ef3d70 | 252 | case Http::METHOD_DELETE: |
26ac0430 | 253 | return libecap::methodDelete; |
23ef3d70 | 254 | case Http::METHOD_TRACE: |
26ac0430 AJ |
255 | return libecap::methodTrace; |
256 | default: | |
257 | return Name(theMessage.method.image()); | |
cf331c99 AR |
258 | } |
259 | } | |
260 | ||
77773405 | 261 | libecap::Version |
574b508c | 262 | Adaptation::Ecap::RequestLineRep::version() const |
77773405 AR |
263 | { |
264 | return FirstLineRep::version(); | |
265 | } | |
266 | ||
267 | void | |
574b508c | 268 | Adaptation::Ecap::RequestLineRep::version(const libecap::Version &aVersion) |
77773405 AR |
269 | { |
270 | FirstLineRep::version(aVersion); | |
271 | } | |
272 | ||
273 | libecap::Name | |
574b508c | 274 | Adaptation::Ecap::RequestLineRep::protocol() const |
77773405 AR |
275 | { |
276 | return FirstLineRep::protocol(); | |
277 | } | |
278 | ||
279 | void | |
574b508c | 280 | Adaptation::Ecap::RequestLineRep::protocol(const Name &p) |
77773405 AR |
281 | { |
282 | FirstLineRep::protocol(p); | |
283 | } | |
284 | ||
cf331c99 AR |
285 | /* ReplyHeaderRep */ |
286 | ||
574b508c | 287 | Adaptation::Ecap::StatusLineRep::StatusLineRep(HttpReply &aMessage): |
26ac0430 | 288 | FirstLineRep(aMessage), theMessage(aMessage) |
cf331c99 AR |
289 | { |
290 | } | |
291 | ||
292 | void | |
574b508c | 293 | Adaptation::Ecap::StatusLineRep::statusCode(int code) |
cf331c99 | 294 | { |
9b769c67 | 295 | theMessage.sline.set(theMessage.sline.version, static_cast<Http::StatusCode>(code), theMessage.sline.reason()); |
cf331c99 AR |
296 | } |
297 | ||
298 | int | |
574b508c | 299 | Adaptation::Ecap::StatusLineRep::statusCode() const |
cf331c99 | 300 | { |
9b769c67 AJ |
301 | // TODO: remove cast when possible |
302 | return static_cast<int>(theMessage.sline.status()); | |
cf331c99 AR |
303 | } |
304 | ||
305 | void | |
9b769c67 | 306 | Adaptation::Ecap::StatusLineRep::reasonPhrase(const Area &str) |
cf331c99 | 307 | { |
f9632290 | 308 | theMessage.sline.set(theMessage.sline.version, theMessage.sline.status(), str.toString().c_str()); |
cf331c99 AR |
309 | } |
310 | ||
574b508c AR |
311 | Adaptation::Ecap::StatusLineRep::Area |
312 | Adaptation::Ecap::StatusLineRep::reasonPhrase() const | |
cf331c99 | 313 | { |
9b769c67 | 314 | return Area::FromTempString(std::string(theMessage.sline.reason())); |
cf331c99 AR |
315 | } |
316 | ||
77773405 | 317 | libecap::Version |
574b508c | 318 | Adaptation::Ecap::StatusLineRep::version() const |
77773405 AR |
319 | { |
320 | return FirstLineRep::version(); | |
321 | } | |
322 | ||
323 | void | |
574b508c | 324 | Adaptation::Ecap::StatusLineRep::version(const libecap::Version &aVersion) |
77773405 AR |
325 | { |
326 | FirstLineRep::version(aVersion); | |
327 | } | |
328 | ||
329 | libecap::Name | |
574b508c | 330 | Adaptation::Ecap::StatusLineRep::protocol() const |
77773405 AR |
331 | { |
332 | return FirstLineRep::protocol(); | |
333 | } | |
334 | ||
335 | void | |
574b508c | 336 | Adaptation::Ecap::StatusLineRep::protocol(const Name &p) |
77773405 AR |
337 | { |
338 | FirstLineRep::protocol(p); | |
339 | } | |
cf331c99 AR |
340 | |
341 | /* BodyRep */ | |
342 | ||
574b508c | 343 | Adaptation::Ecap::BodyRep::BodyRep(const BodyPipe::Pointer &aBody): theBody(aBody) |
cf331c99 AR |
344 | { |
345 | } | |
346 | ||
77773405 | 347 | void |
574b508c | 348 | Adaptation::Ecap::BodyRep::tie(const BodyPipe::Pointer &aBody) |
77773405 AR |
349 | { |
350 | Must(!theBody); | |
351 | Must(aBody != NULL); | |
352 | theBody = aBody; | |
353 | } | |
354 | ||
574b508c AR |
355 | Adaptation::Ecap::BodyRep::BodySize |
356 | Adaptation::Ecap::BodyRep::bodySize() const | |
cf331c99 | 357 | { |
77773405 | 358 | return !theBody ? BodySize() : BodySize(theBody->bodySize()); |
cf331c99 AR |
359 | } |
360 | ||
cf331c99 AR |
361 | /* MessageRep */ |
362 | ||
574b508c | 363 | Adaptation::Ecap::MessageRep::MessageRep(HttpMsg *rawHeader): |
26ac0430 AJ |
364 | theMessage(rawHeader), theFirstLineRep(NULL), |
365 | theHeaderRep(NULL), theBodyRep(NULL) | |
cf331c99 AR |
366 | { |
367 | Must(theMessage.header); // we do not want to represent a missing message | |
368 | ||
369 | if (HttpRequest *req = dynamic_cast<HttpRequest*>(theMessage.header)) | |
77773405 | 370 | theFirstLineRep = new RequestLineRep(*req); |
e1381638 AJ |
371 | else if (HttpReply *rep = dynamic_cast<HttpReply*>(theMessage.header)) |
372 | theFirstLineRep = new StatusLineRep(*rep); | |
cf331c99 | 373 | else |
e1381638 | 374 | Must(false); // unknown message header type |
cf331c99 | 375 | |
77773405 AR |
376 | theHeaderRep = new HeaderRep(*theMessage.header); |
377 | ||
cf331c99 AR |
378 | if (theMessage.body_pipe != NULL) |
379 | theBodyRep = new BodyRep(theMessage.body_pipe); | |
380 | } | |
381 | ||
574b508c | 382 | Adaptation::Ecap::MessageRep::~MessageRep() |
cf331c99 | 383 | { |
77773405 | 384 | delete theBodyRep; |
80031342 AR |
385 | delete theHeaderRep; |
386 | delete theFirstLineRep; | |
77773405 AR |
387 | } |
388 | ||
389 | libecap::shared_ptr<libecap::Message> | |
574b508c | 390 | Adaptation::Ecap::MessageRep::clone() const |
77773405 AR |
391 | { |
392 | HttpMsg *hdr = theMessage.header->clone(); | |
393 | hdr->body_pipe = NULL; // if any; TODO: remove pipe cloning from ::clone? | |
394 | libecap::shared_ptr<libecap::Message> res(new MessageRep(hdr)); | |
395 | ||
396 | // restore indication of a body if needed, but not the pipe | |
397 | if (theMessage.header->body_pipe != NULL) | |
398 | res->addBody(); | |
399 | ||
400 | return res; | |
401 | } | |
402 | ||
403 | libecap::FirstLine & | |
574b508c | 404 | Adaptation::Ecap::MessageRep::firstLine() |
77773405 AR |
405 | { |
406 | return *theFirstLineRep; | |
407 | } | |
408 | ||
409 | const libecap::FirstLine & | |
574b508c | 410 | Adaptation::Ecap::MessageRep::firstLine() const |
77773405 AR |
411 | { |
412 | return *theFirstLineRep; | |
cf331c99 AR |
413 | } |
414 | ||
415 | libecap::Header & | |
574b508c | 416 | Adaptation::Ecap::MessageRep::header() |
cf331c99 AR |
417 | { |
418 | return *theHeaderRep; | |
419 | } | |
420 | ||
421 | const libecap::Header & | |
574b508c | 422 | Adaptation::Ecap::MessageRep::header() const |
cf331c99 AR |
423 | { |
424 | return *theHeaderRep; | |
425 | } | |
426 | ||
427 | libecap::Body * | |
574b508c | 428 | Adaptation::Ecap::MessageRep::body() |
cf331c99 AR |
429 | { |
430 | return theBodyRep; | |
431 | } | |
432 | ||
433 | void | |
574b508c | 434 | Adaptation::Ecap::MessageRep::addBody() |
cf331c99 | 435 | { |
cf331c99 | 436 | Must(!theBodyRep); |
77773405 AR |
437 | Must(!theMessage.body_pipe); // set in tieBody() |
438 | theBodyRep = new BodyRep(NULL); | |
439 | } | |
440 | ||
441 | void | |
574b508c | 442 | Adaptation::Ecap::MessageRep::tieBody(Adaptation::Ecap::XactionRep *x) |
77773405 AR |
443 | { |
444 | Must(theBodyRep != NULL); // addBody must be called first | |
ce367911 | 445 | Must(!theMessage.header->body_pipe); |
cf331c99 | 446 | Must(!theMessage.body_pipe); |
ce367911 AR |
447 | theMessage.header->body_pipe = new BodyPipe(x); |
448 | theMessage.body_pipe = theMessage.header->body_pipe; | |
77773405 | 449 | theBodyRep->tie(theMessage.body_pipe); |
cf331c99 AR |
450 | } |
451 | ||
574b508c | 452 | const libecap::Body *Adaptation::Ecap::MessageRep::body() const |
cf331c99 AR |
453 | { |
454 | return theBodyRep; | |
455 | } |