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