Squid Web Cache master
Loading...
Searching...
No Matches
MessageRep.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 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"
15#include "base/TextException.h"
16#include "HttpReply.h"
17
18#if HAVE_LIBECAP_COMMON_AREA_H
19#include <libecap/common/area.h>
20#endif
21#if HAVE_LIBECAP_COMMON_NAMED_VALUES_H
22#include <libecap/common/named_values.h>
23#endif
24#if HAVE_LIBECAP_COMMON_NAMES_H
25#include <libecap/common/names.h>
26#endif
27#if HAVE_LIBECAP_COMMON_VERSION_H
28#include <libecap/common/version.h>
29#endif
30
31Adaptation::Ecap::HeaderRep::HeaderRep(Http::Message &aMessage): theHeader(aMessage.header),
32 theMessage(aMessage)
33{
34}
35
36bool
38{
39 const Http::HdrType squidId = TranslateHeaderId(name);
40 return squidId == Http::HdrType::OTHER ?
41 theHeader.hasNamed(name.image().c_str(), name.image().size()) :
42 static_cast<bool>(theHeader.has(squidId));
43}
44
45Adaptation::Ecap::HeaderRep::Value
47{
48 const Http::HdrType squidId = TranslateHeaderId(name);
49 const String value = squidId == Http::HdrType::OTHER ?
50 theHeader.getByName(name.image().c_str()) :
51 theHeader.getStrOrList(squidId);
52 return value.size() > 0 ?
53 Value::FromTempString(value.termedBuf()) : Value();
54}
55
56void
57Adaptation::Ecap::HeaderRep::add(const Name &name, const Value &value)
58{
59 const Http::HdrType squidId = TranslateHeaderId(name); // Http::HdrType::OTHER OK
60 HttpHeaderEntry *e = new HttpHeaderEntry(squidId, SBuf(name.image()),
61 value.toString().c_str());
62 theHeader.addEntry(e);
63
64 if (squidId == Http::HdrType::CONTENT_LENGTH)
65 theMessage.content_length = theHeader.getInt64(Http::HdrType::CONTENT_LENGTH);
66}
67
68void
70{
71 const Http::HdrType squidId = TranslateHeaderId(name);
72 if (squidId == Http::HdrType::OTHER)
73 theHeader.delByName(name.image().c_str());
74 else
75 theHeader.delById(squidId);
76
77 if (squidId == Http::HdrType::CONTENT_LENGTH)
78 theMessage.content_length = theHeader.getInt64(Http::HdrType::CONTENT_LENGTH);
79}
80
81void
82Adaptation::Ecap::HeaderRep::visitEach(libecap::NamedValueVisitor &visitor) const
83{
85 while (HttpHeaderEntry *e = theHeader.getEntry(&pos)) {
86 const Name name(std::string(e->name.rawContent(), e->name.length())); // optimize: find std Names
87 name.assignHostId(e->id);
88 visitor.visit(name, Value(e->value.rawBuf(), e->value.size()));
89 }
90}
91
92libecap::Area
94{
95 MemBuf mb;
96 mb.init();
97 theMessage.packInto(&mb, true);
98 return Area::FromTempBuffer(mb.content(), mb.contentSize());
99}
100
101// throws on failures
102void
104{
106 Must(theMessage.parse(buf.start, buf.size, true, &error));
107}
108
111{
112 if (name.assignedHostId())
113 return static_cast<Http::HdrType>(name.hostId());
115}
116
117/* FirstLineRep */
118
120{
121}
122
123libecap::Version
125{
126 return libecap::Version(theMessage.http_ver.major,
127 theMessage.http_ver.minor);
128}
129
130void
131Adaptation::Ecap::FirstLineRep::version(const libecap::Version &aVersion)
132{
133 theMessage.http_ver.major = aVersion.majr;
134 theMessage.http_ver.minor = aVersion.minr;
135}
136
137libecap::Name
139{
140 // TODO: optimize?
141 switch (theMessage.http_ver.protocol) {
142 case AnyP::PROTO_HTTP:
143 return libecap::protocolHttp;
145 return libecap::protocolHttps;
146 case AnyP::PROTO_FTP:
147 return libecap::protocolFtp;
148 case AnyP::PROTO_WAIS:
149 return libecap::protocolWais;
151 return libecap::protocolWhois;
152 case AnyP::PROTO_URN:
153 return libecap::protocolUrn;
154 case AnyP::PROTO_ICP:
155 return protocolIcp;
156#if USE_HTCP
157 case AnyP::PROTO_HTCP:
158 return protocolHtcp;
159#endif
160 case AnyP::PROTO_ICY:
161 return protocolIcy;
162 case AnyP::PROTO_COAP:
163 case AnyP::PROTO_COAPS: // use 'unknown' until libecap supports coap:// and coaps://
164 // other protocols defined in Squid but not libecap use 'unknown'
166 case AnyP::PROTO_SSL:
167 case AnyP::PROTO_TLS:
169 return protocolUnknown; // until we remember the protocol image
170 case AnyP::PROTO_NONE:
171 return Name();
172
173 case AnyP::PROTO_MAX:
174 break; // should not happen
175 // no default to catch AnyP::PROTO_ additions
176 }
177 Must(false); // not reached
178 return Name();
179}
180
181void
183{
184 // TODO: what happens if we fail to translate some protocol?
185 theMessage.http_ver.protocol = TranslateProtocolId(p);
186}
187
190{
191 if (name.assignedHostId())
192 return static_cast<AnyP::ProtocolType>(name.hostId());
193 return AnyP::PROTO_UNKNOWN;
194}
195
196/* RequestHeaderRep */
197
199 FirstLineRep(aMessage), theMessage(aMessage)
200{
201}
202
203void
205{
206 // TODO: if method is not set, AnyP::Uri::parse will assume it is not connect;
207 // Can we change AnyP::Uri::parse API to remove the method parameter?
208 const auto ok = theMessage.url.parse(theMessage.method, SBuf(aUri.toString()));
209 Must(ok);
210}
211
214{
215 const SBuf &fullUrl = theMessage.effectiveRequestUri();
216 // XXX: effectiveRequestUri() cannot return NULL or even empty string, some other problem?
217 Must(!fullUrl.isEmpty());
218 // optimize: avoid copying by having an Area::Detail that locks theMessage
219 return Area::FromTempBuffer(fullUrl.rawContent(), fullUrl.length());
220}
221
222void
224{
225 if (aMethod.assignedHostId()) {
226 const int id = aMethod.hostId();
229 theMessage.method = HttpRequestMethod(static_cast<Http::MethodType>(id));
230 } else {
231 const std::string &image = aMethod.image();
232 theMessage.method.HttpRequestMethodXXX(image.c_str());
233 }
234}
235
238{
239 switch (theMessage.method.id()) {
240 case Http::METHOD_GET:
241 return libecap::methodGet;
243 return libecap::methodPost;
244 case Http::METHOD_PUT:
245 return libecap::methodPut;
247 return libecap::methodHead;
249 return libecap::methodConnect;
251 return libecap::methodDelete;
253 return libecap::methodTrace;
254 default:
255 return Name(theMessage.method.image().toStdString());
256 }
257}
258
259libecap::Version
264
265void
266Adaptation::Ecap::RequestLineRep::version(const libecap::Version &aVersion)
267{
268 FirstLineRep::version(aVersion);
269}
270
271libecap::Name
276
277void
282
283/* ReplyHeaderRep */
284
286 FirstLineRep(aMessage), theMessage(aMessage)
287{
288}
289
290void
292{
293 theMessage.sline.set(theMessage.sline.version, static_cast<Http::StatusCode>(code), nullptr);
294}
295
296int
298{
299 // TODO: remove cast when possible
300 return static_cast<int>(theMessage.sline.status());
301}
302
303void
305{
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();
309}
310
313{
314 return Area::FromTempString(std::string(theMessage.sline.reason()));
315}
316
317libecap::Version
322
323void
324Adaptation::Ecap::StatusLineRep::version(const libecap::Version &aVersion)
325{
326 FirstLineRep::version(aVersion);
327}
328
329libecap::Name
334
335void
340
341/* BodyRep */
342
344{
345}
346
347void
349{
350 Must(!theBody);
351 Must(aBody != nullptr);
352 theBody = aBody;
353}
354
357{
358 return (theBody != nullptr && theBody->bodySizeKnown()) ? BodySize(theBody->bodySize()) : BodySize();
359}
360
361/* MessageRep */
362
364 theMessage(rawHeader), theFirstLineRep(nullptr),
365 theHeaderRep(nullptr), theBodyRep(nullptr)
366{
367 Must(theMessage.header); // we do not want to represent a missing message
368
369 if (HttpRequest *req = dynamic_cast<HttpRequest*>(theMessage.header))
371 else if (HttpReply *rep = dynamic_cast<HttpReply*>(theMessage.header))
372 theFirstLineRep = new StatusLineRep(*rep);
373 else
374 Must(false); // unknown message header type
375
377
378 if (theMessage.body_pipe != nullptr)
380}
381
383{
384 delete theBodyRep;
385 delete theHeaderRep;
386 delete theFirstLineRep;
387}
388
389libecap::shared_ptr<libecap::Message>
391{
392 Http::Message *hdr = theMessage.header->clone();
393 hdr->body_pipe = nullptr; // 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 != nullptr)
398 res->addBody();
399
400 return res;
401}
402
403libecap::FirstLine &
405{
406 return *theFirstLineRep;
407}
408
409const libecap::FirstLine &
411{
412 return *theFirstLineRep;
413}
414
415libecap::Header &
417{
418 return *theHeaderRep;
419}
420
421const libecap::Header &
423{
424 return *theHeaderRep;
425}
426
427libecap::Body *
429{
430 return theBodyRep;
431}
432
433void
435{
436 Must(!theBodyRep);
437 Must(!theMessage.body_pipe); // set in tieBody()
438 theBodyRep = new BodyRep(nullptr);
439}
440
441void
443{
444 Must(theBodyRep != nullptr); // addBody must be called first
445 Must(!theMessage.header->body_pipe);
446 Must(!theMessage.body_pipe);
447 theMessage.header->body_pipe = new BodyPipe(x);
448 theMessage.body_pipe = theMessage.header->body_pipe;
449 theBodyRep->tie(theMessage.body_pipe);
450}
451
452const libecap::Body *Adaptation::Ecap::MessageRep::body() const
453{
454 return theBodyRep;
455}
456
ssize_t HttpHeaderPos
Definition HttpHeader.h:45
#define HttpHeaderInitPos
Definition HttpHeader.h:48
#define Must(condition)
void error(char *format,...)
BodyRep(const BodyPipe::Pointer &aBody)
BodySize bodySize() const override
libecap::BodySize BodySize
Definition MessageRep.h:138
void tie(const BodyPipe::Pointer &aBody)
libecap::Version version() const
static AnyP::ProtocolType TranslateProtocolId(const Name &name)
FirstLineRep(Http::Message &aMessage)
Value value(const Name &name) const override
Definition MessageRep.cc:46
void add(const Name &name, const Value &value) override
Definition MessageRep.cc:57
HeaderRep(Http::Message &aMessage)
Definition MessageRep.cc:31
void parse(const Area &buf) override
static Http::HdrType TranslateHeaderId(const Name &name)
bool hasAny(const Name &name) const override
Definition MessageRep.cc:37
void removeAny(const Name &name) override
Definition MessageRep.cc:69
Area image() const override
Definition MessageRep.cc:93
void visitEach(libecap::NamedValueVisitor &visitor) const override
Definition MessageRep.cc:82
Adaptation::Message theMessage
Definition MessageRep.h:175
MessageRep(Http::Message *rawHeader)
libecap::FirstLine * theFirstLineRep
Definition MessageRep.h:176
libecap::Body * body() override
libecap::FirstLine & firstLine() override
libecap::Header & header() override
libecap::shared_ptr< libecap::Message > clone() const override
void tieBody(Ecap::XactionRep *x)
libecap::Version version() const override
Name method() const override
Area uri() const override
RequestLineRep(HttpRequest &aMessage)
Name protocol() const override
int statusCode() const override
libecap::Version version() const override
Name protocol() const override
Area reasonPhrase() const override
StatusLineRep(HttpReply &aMessage)
Header * header
Definition Message.h:42
BodyPipePointer body_pipe
Definition Message.h:46
common parts of HttpRequest and HttpReply
Definition Message.h:26
HttpHeader header
Definition Message.h:74
BodyPipe::Pointer body_pipe
optional pipeline to receive message body
Definition Message.h:97
void init(mb_size_t szInit, mb_size_t szMax)
Definition MemBuf.cc:93
char * content()
start of the added data
Definition MemBuf.h:41
mb_size_t contentSize() const
available data size
Definition MemBuf.h:47
Definition SBuf.h:94
const char * rawContent() const
Definition SBuf.cc:509
const char * c_str()
Definition SBuf.cc:516
size_type length() const
Returns the number of bytes stored in SBuf.
Definition SBuf.h:419
bool isEmpty() const
Definition SBuf.h:435
char const * termedBuf() const
Definition SquidString.h:93
size_type size() const
Definition SquidString.h:74
const libecap::Name protocolIcp
const libecap::Name protocolUnknown
const libecap::Name protocolHtcp
const libecap::Name protocolIcy
@ PROTO_NONE
@ PROTO_HTTPS
@ PROTO_UNKNOWN
@ PROTO_HTCP
@ PROTO_TLS
@ PROTO_AUTHORITY_FORM
@ PROTO_ICY
@ PROTO_HTTP
@ PROTO_COAP
@ PROTO_FTP
@ PROTO_WHOIS
@ PROTO_MAX
@ PROTO_SSL
@ PROTO_COAPS
@ PROTO_ICP
@ PROTO_URN
@ PROTO_WAIS
enum Http::_method_t MethodType
StatusCode
Definition StatusCode.h:20
@ METHOD_TRACE
Definition MethodType.h:30
@ METHOD_NONE
Definition MethodType.h:22
@ METHOD_OTHER
Definition MethodType.h:93
@ METHOD_PUT
Definition MethodType.h:27
@ METHOD_POST
Definition MethodType.h:26
@ METHOD_CONNECT
Definition MethodType.h:29
@ METHOD_ENUM_END
Definition MethodType.h:94
@ METHOD_GET
Definition MethodType.h:25
@ METHOD_DELETE
Definition MethodType.h:32
@ METHOD_HEAD
Definition MethodType.h:28