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