]>
Commit | Line | Data |
---|---|---|
fdc96a39 | 1 | /* |
4ac4a490 | 2 | * Copyright (C) 1996-2017 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" |
b1bd952a | 23 | #include "URL.h" |
fdc96a39 | 24 | |
cf331c99 AR |
25 | /* HeaderRep */ |
26 | ||
574b508c | 27 | Adaptation::Ecap::HeaderRep::HeaderRep(HttpMsg &aMessage): theHeader(aMessage.header), |
f53969cc | 28 | theMessage(aMessage) |
cf331c99 AR |
29 | { |
30 | } | |
31 | ||
cf331c99 | 32 | bool |
574b508c | 33 | Adaptation::Ecap::HeaderRep::hasAny(const Name &name) const |
cf331c99 | 34 | { |
789217a2 | 35 | const Http::HdrType squidId = TranslateHeaderId(name); |
cf331c99 | 36 | // XXX: optimize to remove getByName: we do not need the value here |
789217a2 | 37 | return squidId == Http::HdrType::OTHER ? |
26ac0430 AJ |
38 | theHeader.getByName(name.image().c_str()).size() > 0: |
39 | (bool)theHeader.has(squidId); | |
cf331c99 AR |
40 | } |
41 | ||
574b508c AR |
42 | Adaptation::Ecap::HeaderRep::Value |
43 | Adaptation::Ecap::HeaderRep::value(const Name &name) const | |
cf331c99 | 44 | { |
789217a2 FC |
45 | const Http::HdrType squidId = TranslateHeaderId(name); |
46 | const String value = squidId == Http::HdrType::OTHER ? | |
26ac0430 AJ |
47 | theHeader.getByName(name.image().c_str()) : |
48 | theHeader.getStrOrList(squidId); | |
b38b26cb | 49 | return value.size() > 0 ? |
001eaf80 | 50 | Value::FromTempString(value.termedBuf()) : Value(); |
cf331c99 AR |
51 | } |
52 | ||
53 | void | |
574b508c | 54 | Adaptation::Ecap::HeaderRep::add(const Name &name, const Value &value) |
cf331c99 | 55 | { |
789217a2 | 56 | const Http::HdrType squidId = TranslateHeaderId(name); // Http::HdrType::OTHER OK |
cf331c99 | 57 | HttpHeaderEntry *e = new HttpHeaderEntry(squidId, name.image().c_str(), |
26ac0430 | 58 | value.toString().c_str()); |
cf331c99 | 59 | theHeader.addEntry(e); |
809fd5d3 | 60 | |
789217a2 FC |
61 | if (squidId == Http::HdrType::CONTENT_LENGTH) |
62 | theMessage.content_length = theHeader.getInt64(Http::HdrType::CONTENT_LENGTH); | |
cf331c99 AR |
63 | } |
64 | ||
65 | void | |
574b508c | 66 | Adaptation::Ecap::HeaderRep::removeAny(const Name &name) |
cf331c99 | 67 | { |
789217a2 FC |
68 | const Http::HdrType squidId = TranslateHeaderId(name); |
69 | if (squidId == Http::HdrType::OTHER) | |
cf331c99 AR |
70 | theHeader.delByName(name.image().c_str()); |
71 | else | |
72 | theHeader.delById(squidId); | |
809fd5d3 | 73 | |
789217a2 FC |
74 | if (squidId == Http::HdrType::CONTENT_LENGTH) |
75 | theMessage.content_length = theHeader.getInt64(Http::HdrType::CONTENT_LENGTH); | |
cf331c99 AR |
76 | } |
77 | ||
12a410c3 AR |
78 | void |
79 | Adaptation::Ecap::HeaderRep::visitEach(libecap::NamedValueVisitor &visitor) const | |
80 | { | |
81 | HttpHeaderPos pos = HttpHeaderInitPos; | |
82 | while (HttpHeaderEntry *e = theHeader.getEntry(&pos)) { | |
83 | const Name name(e->name.termedBuf()); // optimize: find std Names | |
84 | name.assignHostId(e->id); | |
85 | visitor.visit(name, Value(e->value.rawBuf(), e->value.size())); | |
86 | } | |
87 | } | |
88 | ||
cf331c99 | 89 | libecap::Area |
574b508c | 90 | Adaptation::Ecap::HeaderRep::image() const |
cf331c99 AR |
91 | { |
92 | MemBuf mb; | |
93 | mb.init(); | |
10201568 | 94 | theMessage.packInto(&mb, true); |
cf331c99 AR |
95 | return Area::FromTempBuffer(mb.content(), mb.contentSize()); |
96 | } | |
97 | ||
98 | // throws on failures | |
99 | void | |
574b508c | 100 | Adaptation::Ecap::HeaderRep::parse(const Area &buf) |
cf331c99 | 101 | { |
955394ce | 102 | Http::StatusCode error; |
9b491ddf | 103 | Must(theMessage.parse(buf.start, buf.size, true, &error)); |
cf331c99 AR |
104 | } |
105 | ||
789217a2 | 106 | Http::HdrType |
574b508c | 107 | Adaptation::Ecap::HeaderRep::TranslateHeaderId(const Name &name) |
77773405 AR |
108 | { |
109 | if (name.assignedHostId()) | |
789217a2 FC |
110 | return static_cast<Http::HdrType>(name.hostId()); |
111 | return Http::HdrType::OTHER; | |
77773405 AR |
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? | |
7b167513 | 138 | switch (theMessage.http_ver.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_ICY: |
555aedbf | 162 | return protocolIcy; |
a90ea541 AJ |
163 | case AnyP::PROTO_COAP: |
164 | case AnyP::PROTO_COAPS: // use 'unknown' until libecap supports coap:// and coaps:// | |
555aedbf AR |
165 | case AnyP::PROTO_UNKNOWN: |
166 | return protocolUnknown; // until we remember the protocol image | |
39a19cb7 | 167 | case AnyP::PROTO_NONE: |
26ac0430 AJ |
168 | return Name(); |
169 | ||
39a19cb7 | 170 | case AnyP::PROTO_MAX: |
26ac0430 | 171 | break; // should not happen |
39a19cb7 | 172 | // no default to catch AnyP::PROTO_ additions |
cf331c99 AR |
173 | } |
174 | Must(false); // not reached | |
175 | return Name(); | |
176 | } | |
177 | ||
178 | void | |
574b508c | 179 | Adaptation::Ecap::FirstLineRep::protocol(const Name &p) |
cf331c99 AR |
180 | { |
181 | // TODO: what happens if we fail to translate some protocol? | |
7b167513 | 182 | theMessage.http_ver.protocol = TranslateProtocolId(p); |
cf331c99 AR |
183 | } |
184 | ||
555aedbf | 185 | AnyP::ProtocolType |
574b508c | 186 | Adaptation::Ecap::FirstLineRep::TranslateProtocolId(const Name &name) |
77773405 AR |
187 | { |
188 | if (name.assignedHostId()) | |
555aedbf AR |
189 | return static_cast<AnyP::ProtocolType>(name.hostId()); |
190 | return AnyP::PROTO_UNKNOWN; | |
77773405 AR |
191 | } |
192 | ||
cf331c99 AR |
193 | /* RequestHeaderRep */ |
194 | ||
574b508c | 195 | Adaptation::Ecap::RequestLineRep::RequestLineRep(HttpRequest &aMessage): |
f53969cc | 196 | FirstLineRep(aMessage), theMessage(aMessage) |
cf331c99 AR |
197 | { |
198 | } | |
199 | ||
200 | void | |
574b508c | 201 | Adaptation::Ecap::RequestLineRep::uri(const Area &aUri) |
cf331c99 AR |
202 | { |
203 | // TODO: if method is not set, urlPath will assume it is not connect; | |
204 | // Can we change urlParse API to remove the method parameter? | |
205 | // TODO: optimize: urlPath should take constant URL buffer | |
206 | char *buf = xstrdup(aUri.toString().c_str()); | |
207 | const bool ok = urlParse(theMessage.method, buf, &theMessage); | |
208 | xfree(buf); | |
209 | Must(ok); | |
210 | } | |
211 | ||
574b508c AR |
212 | Adaptation::Ecap::RequestLineRep::Area |
213 | Adaptation::Ecap::RequestLineRep::uri() const | |
cf331c99 | 214 | { |
851feda6 AJ |
215 | const SBuf &fullUrl = theMessage.effectiveRequestUri(); |
216 | // XXX: effectiveRequestUri() cannot return NULL or even empty string, some other problem? | |
217 | Must(!fullUrl.isEmpty()); | |
dd31ab8f | 218 | // optimize: avoid copying by having an Area::Detail that locks theMessage |
851feda6 | 219 | return Area::FromTempBuffer(fullUrl.rawContent(), fullUrl.length()); |
cf331c99 AR |
220 | } |
221 | ||
222 | void | |
574b508c | 223 | Adaptation::Ecap::RequestLineRep::method(const Name &aMethod) |
cf331c99 AR |
224 | { |
225 | if (aMethod.assignedHostId()) { | |
226 | const int id = aMethod.hostId(); | |
23ef3d70 FC |
227 | Must(Http::METHOD_NONE < id && id < Http::METHOD_ENUM_END); |
228 | Must(id != Http::METHOD_OTHER); | |
c2a7cefd | 229 | theMessage.method = HttpRequestMethod(static_cast<Http::MethodType>(id)); |
cf331c99 AR |
230 | } else { |
231 | const std::string &image = aMethod.image(); | |
f42a67c5 | 232 | theMessage.method.HttpRequestMethodXXX(image.c_str()); |
cf331c99 AR |
233 | } |
234 | } | |
235 | ||
574b508c AR |
236 | Adaptation::Ecap::RequestLineRep::Name |
237 | Adaptation::Ecap::RequestLineRep::method() const | |
cf331c99 AR |
238 | { |
239 | switch (theMessage.method.id()) { | |
23ef3d70 | 240 | case Http::METHOD_GET: |
26ac0430 | 241 | return libecap::methodGet; |
23ef3d70 | 242 | case Http::METHOD_POST: |
26ac0430 | 243 | return libecap::methodPost; |
23ef3d70 | 244 | case Http::METHOD_PUT: |
26ac0430 | 245 | return libecap::methodPut; |
23ef3d70 | 246 | case Http::METHOD_HEAD: |
26ac0430 | 247 | return libecap::methodHead; |
23ef3d70 | 248 | case Http::METHOD_CONNECT: |
26ac0430 | 249 | return libecap::methodConnect; |
23ef3d70 | 250 | case Http::METHOD_DELETE: |
26ac0430 | 251 | return libecap::methodDelete; |
23ef3d70 | 252 | case Http::METHOD_TRACE: |
26ac0430 AJ |
253 | return libecap::methodTrace; |
254 | default: | |
e44adabd | 255 | return Name(theMessage.method.image().toStdString()); |
cf331c99 AR |
256 | } |
257 | } | |
258 | ||
77773405 | 259 | libecap::Version |
574b508c | 260 | Adaptation::Ecap::RequestLineRep::version() const |
77773405 AR |
261 | { |
262 | return FirstLineRep::version(); | |
263 | } | |
264 | ||
265 | void | |
574b508c | 266 | Adaptation::Ecap::RequestLineRep::version(const libecap::Version &aVersion) |
77773405 AR |
267 | { |
268 | FirstLineRep::version(aVersion); | |
269 | } | |
270 | ||
271 | libecap::Name | |
574b508c | 272 | Adaptation::Ecap::RequestLineRep::protocol() const |
77773405 AR |
273 | { |
274 | return FirstLineRep::protocol(); | |
275 | } | |
276 | ||
277 | void | |
574b508c | 278 | Adaptation::Ecap::RequestLineRep::protocol(const Name &p) |
77773405 AR |
279 | { |
280 | FirstLineRep::protocol(p); | |
281 | } | |
282 | ||
cf331c99 AR |
283 | /* ReplyHeaderRep */ |
284 | ||
574b508c | 285 | Adaptation::Ecap::StatusLineRep::StatusLineRep(HttpReply &aMessage): |
f53969cc | 286 | FirstLineRep(aMessage), theMessage(aMessage) |
cf331c99 AR |
287 | { |
288 | } | |
289 | ||
290 | void | |
574b508c | 291 | Adaptation::Ecap::StatusLineRep::statusCode(int code) |
cf331c99 | 292 | { |
3ca77494 | 293 | theMessage.sline.set(theMessage.sline.version, static_cast<Http::StatusCode>(code), nullptr); |
cf331c99 AR |
294 | } |
295 | ||
296 | int | |
574b508c | 297 | Adaptation::Ecap::StatusLineRep::statusCode() const |
cf331c99 | 298 | { |
9b769c67 AJ |
299 | // TODO: remove cast when possible |
300 | return static_cast<int>(theMessage.sline.status()); | |
cf331c99 AR |
301 | } |
302 | ||
303 | void | |
65b0aca4 | 304 | Adaptation::Ecap::StatusLineRep::reasonPhrase(const Area &) |
cf331c99 | 305 | { |
65b0aca4 AR |
306 | // Squid does not support external custom reason phrases so we have |
307 | // to just reset it (in case there was a custom internal reason set) | |
308 | theMessage.sline.resetReason(); | |
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 | { |
e4a88e44 | 358 | return (theBody != nullptr && theBody->bodySizeKnown()) ? BodySize(theBody->bodySize()) : BodySize(); |
cf331c99 AR |
359 | } |
360 | ||
cf331c99 AR |
361 | /* MessageRep */ |
362 | ||
574b508c | 363 | Adaptation::Ecap::MessageRep::MessageRep(HttpMsg *rawHeader): |
f53969cc SM |
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 | } | |
f53969cc | 456 |