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