]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/ecap/MessageRep.cc
2 * Copyright (C) 1996-2019 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 93 eCAP Interface */
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"
26 Adaptation::Ecap::HeaderRep::HeaderRep(Http::Message
&aMessage
): theHeader(aMessage
.header
),
32 Adaptation::Ecap::HeaderRep::hasAny(const Name
&name
) const
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
));
40 Adaptation::Ecap::HeaderRep::Value
41 Adaptation::Ecap::HeaderRep::value(const Name
&name
) const
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();
52 Adaptation::Ecap::HeaderRep::add(const Name
&name
, const Value
&value
)
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
);
59 if (squidId
== Http::HdrType::CONTENT_LENGTH
)
60 theMessage
.content_length
= theHeader
.getInt64(Http::HdrType::CONTENT_LENGTH
);
64 Adaptation::Ecap::HeaderRep::removeAny(const Name
&name
)
66 const Http::HdrType squidId
= TranslateHeaderId(name
);
67 if (squidId
== Http::HdrType::OTHER
)
68 theHeader
.delByName(name
.image().c_str());
70 theHeader
.delById(squidId
);
72 if (squidId
== Http::HdrType::CONTENT_LENGTH
)
73 theMessage
.content_length
= theHeader
.getInt64(Http::HdrType::CONTENT_LENGTH
);
77 Adaptation::Ecap::HeaderRep::visitEach(libecap::NamedValueVisitor
&visitor
) const
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()));
88 Adaptation::Ecap::HeaderRep::image() const
92 theMessage
.packInto(&mb
, true);
93 return Area::FromTempBuffer(mb
.content(), mb
.contentSize());
98 Adaptation::Ecap::HeaderRep::parse(const Area
&buf
)
100 Http::StatusCode error
;
101 Must(theMessage
.parse(buf
.start
, buf
.size
, true, &error
));
105 Adaptation::Ecap::HeaderRep::TranslateHeaderId(const Name
&name
)
107 if (name
.assignedHostId())
108 return static_cast<Http::HdrType
>(name
.hostId());
109 return Http::HdrType::OTHER
;
114 Adaptation::Ecap::FirstLineRep::FirstLineRep(Http::Message
&aMessage
): theMessage(aMessage
)
119 Adaptation::Ecap::FirstLineRep::version() const
121 return libecap::Version(theMessage
.http_ver
.major
,
122 theMessage
.http_ver
.minor
);
126 Adaptation::Ecap::FirstLineRep::version(const libecap::Version
&aVersion
)
128 theMessage
.http_ver
.major
= aVersion
.majr
;
129 theMessage
.http_ver
.minor
= aVersion
.minr
;
133 Adaptation::Ecap::FirstLineRep::protocol() const
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
:
154 case AnyP::PROTO_HTCP
:
157 case AnyP::PROTO_CACHE_OBJECT
:
158 return protocolCacheObj
;
159 case AnyP::PROTO_ICY
:
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
:
172 case AnyP::PROTO_MAX
:
173 break; // should not happen
174 // no default to catch AnyP::PROTO_ additions
176 Must(false); // not reached
181 Adaptation::Ecap::FirstLineRep::protocol(const Name
&p
)
183 // TODO: what happens if we fail to translate some protocol?
184 theMessage
.http_ver
.protocol
= TranslateProtocolId(p
);
188 Adaptation::Ecap::FirstLineRep::TranslateProtocolId(const Name
&name
)
190 if (name
.assignedHostId())
191 return static_cast<AnyP::ProtocolType
>(name
.hostId());
192 return AnyP::PROTO_UNKNOWN
;
195 /* RequestHeaderRep */
197 Adaptation::Ecap::RequestLineRep::RequestLineRep(HttpRequest
&aMessage
):
198 FirstLineRep(aMessage
), theMessage(aMessage
)
203 Adaptation::Ecap::RequestLineRep::uri(const Area
&aUri
)
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
, aUri
.toString().c_str());
211 Adaptation::Ecap::RequestLineRep::Area
212 Adaptation::Ecap::RequestLineRep::uri() const
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());
222 Adaptation::Ecap::RequestLineRep::method(const Name
&aMethod
)
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
));
230 const std::string
&image
= aMethod
.image();
231 theMessage
.method
.HttpRequestMethodXXX(image
.c_str());
235 Adaptation::Ecap::RequestLineRep::Name
236 Adaptation::Ecap::RequestLineRep::method() const
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
;
254 return Name(theMessage
.method
.image().toStdString());
259 Adaptation::Ecap::RequestLineRep::version() const
261 return FirstLineRep::version();
265 Adaptation::Ecap::RequestLineRep::version(const libecap::Version
&aVersion
)
267 FirstLineRep::version(aVersion
);
271 Adaptation::Ecap::RequestLineRep::protocol() const
273 return FirstLineRep::protocol();
277 Adaptation::Ecap::RequestLineRep::protocol(const Name
&p
)
279 FirstLineRep::protocol(p
);
284 Adaptation::Ecap::StatusLineRep::StatusLineRep(HttpReply
&aMessage
):
285 FirstLineRep(aMessage
), theMessage(aMessage
)
290 Adaptation::Ecap::StatusLineRep::statusCode(int code
)
292 theMessage
.sline
.set(theMessage
.sline
.version
, static_cast<Http::StatusCode
>(code
), nullptr);
296 Adaptation::Ecap::StatusLineRep::statusCode() const
298 // TODO: remove cast when possible
299 return static_cast<int>(theMessage
.sline
.status());
303 Adaptation::Ecap::StatusLineRep::reasonPhrase(const Area
&)
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();
310 Adaptation::Ecap::StatusLineRep::Area
311 Adaptation::Ecap::StatusLineRep::reasonPhrase() const
313 return Area::FromTempString(std::string(theMessage
.sline
.reason()));
317 Adaptation::Ecap::StatusLineRep::version() const
319 return FirstLineRep::version();
323 Adaptation::Ecap::StatusLineRep::version(const libecap::Version
&aVersion
)
325 FirstLineRep::version(aVersion
);
329 Adaptation::Ecap::StatusLineRep::protocol() const
331 return FirstLineRep::protocol();
335 Adaptation::Ecap::StatusLineRep::protocol(const Name
&p
)
337 FirstLineRep::protocol(p
);
342 Adaptation::Ecap::BodyRep::BodyRep(const BodyPipe::Pointer
&aBody
): theBody(aBody
)
347 Adaptation::Ecap::BodyRep::tie(const BodyPipe::Pointer
&aBody
)
354 Adaptation::Ecap::BodyRep::BodySize
355 Adaptation::Ecap::BodyRep::bodySize() const
357 return (theBody
!= nullptr && theBody
->bodySizeKnown()) ? BodySize(theBody
->bodySize()) : BodySize();
362 Adaptation::Ecap::MessageRep::MessageRep(Http::Message
*rawHeader
):
363 theMessage(rawHeader
), theFirstLineRep(NULL
),
364 theHeaderRep(NULL
), theBodyRep(NULL
)
366 Must(theMessage
.header
); // we do not want to represent a missing message
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
);
373 Must(false); // unknown message header type
375 theHeaderRep
= new HeaderRep(*theMessage
.header
);
377 if (theMessage
.body_pipe
!= NULL
)
378 theBodyRep
= new BodyRep(theMessage
.body_pipe
);
381 Adaptation::Ecap::MessageRep::~MessageRep()
385 delete theFirstLineRep
;
388 libecap::shared_ptr
<libecap::Message
>
389 Adaptation::Ecap::MessageRep::clone() const
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
));
395 // restore indication of a body if needed, but not the pipe
396 if (theMessage
.header
->body_pipe
!= NULL
)
403 Adaptation::Ecap::MessageRep::firstLine()
405 return *theFirstLineRep
;
408 const libecap::FirstLine
&
409 Adaptation::Ecap::MessageRep::firstLine() const
411 return *theFirstLineRep
;
415 Adaptation::Ecap::MessageRep::header()
417 return *theHeaderRep
;
420 const libecap::Header
&
421 Adaptation::Ecap::MessageRep::header() const
423 return *theHeaderRep
;
427 Adaptation::Ecap::MessageRep::body()
433 Adaptation::Ecap::MessageRep::addBody()
436 Must(!theMessage
.body_pipe
); // set in tieBody()
437 theBodyRep
= new BodyRep(NULL
);
441 Adaptation::Ecap::MessageRep::tieBody(Adaptation::Ecap::XactionRep
*x
)
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
);
451 const libecap::Body
*Adaptation::Ecap::MessageRep::body() const