]> git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/ecap/MessageRep.cc
MemBuf implements Packable interface
[thirdparty/squid.git] / src / adaptation / ecap / MessageRep.cc
1 /*
2 * Copyright (C) 1996-2015 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(HttpMsg &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_hdr_type squidId = TranslateHeaderId(name);
36 // XXX: optimize to remove getByName: we do not need the value here
37 return squidId == HDR_OTHER ?
38 theHeader.getByName(name.image().c_str()).size() > 0:
39 (bool)theHeader.has(squidId);
40 }
41
42 Adaptation::Ecap::HeaderRep::Value
43 Adaptation::Ecap::HeaderRep::value(const Name &name) const
44 {
45 const http_hdr_type squidId = TranslateHeaderId(name);
46 const String value = squidId == HDR_OTHER ?
47 theHeader.getByName(name.image().c_str()) :
48 theHeader.getStrOrList(squidId);
49 return value.size() > 0 ?
50 Value::FromTempString(value.termedBuf()) : Value();
51 }
52
53 void
54 Adaptation::Ecap::HeaderRep::add(const Name &name, const Value &value)
55 {
56 const http_hdr_type squidId = TranslateHeaderId(name); // HDR_OTHER OK
57 HttpHeaderEntry *e = new HttpHeaderEntry(squidId, name.image().c_str(),
58 value.toString().c_str());
59 theHeader.addEntry(e);
60
61 if (squidId == HDR_CONTENT_LENGTH)
62 theMessage.content_length = theHeader.getInt64(HDR_CONTENT_LENGTH);
63 }
64
65 void
66 Adaptation::Ecap::HeaderRep::removeAny(const Name &name)
67 {
68 const http_hdr_type squidId = TranslateHeaderId(name);
69 if (squidId == HDR_OTHER)
70 theHeader.delByName(name.image().c_str());
71 else
72 theHeader.delById(squidId);
73
74 if (squidId == HDR_CONTENT_LENGTH)
75 theMessage.content_length = theHeader.getInt64(HDR_CONTENT_LENGTH);
76 }
77
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
89 libecap::Area
90 Adaptation::Ecap::HeaderRep::image() const
91 {
92 MemBuf mb;
93 mb.init();
94 theMessage.packInto(&mb, true);
95 return Area::FromTempBuffer(mb.content(), mb.contentSize());
96 }
97
98 // throws on failures
99 void
100 Adaptation::Ecap::HeaderRep::parse(const Area &buf)
101 {
102 Http::StatusCode error;
103 Must(theMessage.parse(buf.start, buf.size, true, &error));
104 }
105
106 http_hdr_type
107 Adaptation::Ecap::HeaderRep::TranslateHeaderId(const Name &name)
108 {
109 if (name.assignedHostId())
110 return static_cast<http_hdr_type>(name.hostId());
111 return HDR_OTHER;
112 }
113
114 /* FirstLineRep */
115
116 Adaptation::Ecap::FirstLineRep::FirstLineRep(HttpMsg &aMessage): theMessage(aMessage)
117 {
118 }
119
120 libecap::Version
121 Adaptation::Ecap::FirstLineRep::version() const
122 {
123 return libecap::Version(theMessage.http_ver.major,
124 theMessage.http_ver.minor);
125 }
126
127 void
128 Adaptation::Ecap::FirstLineRep::version(const libecap::Version &aVersion)
129 {
130 theMessage.http_ver.major = aVersion.majr;
131 theMessage.http_ver.minor = aVersion.minr;
132 }
133
134 libecap::Name
135 Adaptation::Ecap::FirstLineRep::protocol() const
136 {
137 // TODO: optimize?
138 switch (theMessage.http_ver.protocol) {
139 case AnyP::PROTO_HTTP:
140 return libecap::protocolHttp;
141 case AnyP::PROTO_HTTPS:
142 return libecap::protocolHttps;
143 case AnyP::PROTO_FTP:
144 return libecap::protocolFtp;
145 case AnyP::PROTO_GOPHER:
146 return libecap::protocolGopher;
147 case AnyP::PROTO_WAIS:
148 return libecap::protocolWais;
149 case AnyP::PROTO_WHOIS:
150 return libecap::protocolWhois;
151 case AnyP::PROTO_URN:
152 return libecap::protocolUrn;
153 case AnyP::PROTO_ICP:
154 return protocolIcp;
155 #if USE_HTCP
156 case AnyP::PROTO_HTCP:
157 return protocolHtcp;
158 #endif
159 case AnyP::PROTO_CACHE_OBJECT:
160 return protocolCacheObj;
161 case AnyP::PROTO_ICY:
162 return protocolIcy;
163 case AnyP::PROTO_COAP:
164 case AnyP::PROTO_COAPS: // use 'unknown' until libecap supports coap:// and coaps://
165 case AnyP::PROTO_UNKNOWN:
166 return protocolUnknown; // until we remember the protocol image
167 case AnyP::PROTO_NONE:
168 return Name();
169
170 case AnyP::PROTO_MAX:
171 break; // should not happen
172 // no default to catch AnyP::PROTO_ additions
173 }
174 Must(false); // not reached
175 return Name();
176 }
177
178 void
179 Adaptation::Ecap::FirstLineRep::protocol(const Name &p)
180 {
181 // TODO: what happens if we fail to translate some protocol?
182 theMessage.http_ver.protocol = TranslateProtocolId(p);
183 }
184
185 AnyP::ProtocolType
186 Adaptation::Ecap::FirstLineRep::TranslateProtocolId(const Name &name)
187 {
188 if (name.assignedHostId())
189 return static_cast<AnyP::ProtocolType>(name.hostId());
190 return AnyP::PROTO_UNKNOWN;
191 }
192
193 /* RequestHeaderRep */
194
195 Adaptation::Ecap::RequestLineRep::RequestLineRep(HttpRequest &aMessage):
196 FirstLineRep(aMessage), theMessage(aMessage)
197 {
198 }
199
200 void
201 Adaptation::Ecap::RequestLineRep::uri(const Area &aUri)
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
212 Adaptation::Ecap::RequestLineRep::Area
213 Adaptation::Ecap::RequestLineRep::uri() const
214 {
215 const char *fullUrl = urlCanonical(&theMessage);
216 Must(fullUrl);
217 // optimize: avoid copying by having an Area::Detail that locks theMessage
218 return Area::FromTempBuffer(fullUrl, strlen(fullUrl));
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), theMessage.sline.reason());
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 &str)
304 {
305 theMessage.sline.set(theMessage.sline.version, theMessage.sline.status(), str.toString().c_str());
306 }
307
308 Adaptation::Ecap::StatusLineRep::Area
309 Adaptation::Ecap::StatusLineRep::reasonPhrase() const
310 {
311 return Area::FromTempString(std::string(theMessage.sline.reason()));
312 }
313
314 libecap::Version
315 Adaptation::Ecap::StatusLineRep::version() const
316 {
317 return FirstLineRep::version();
318 }
319
320 void
321 Adaptation::Ecap::StatusLineRep::version(const libecap::Version &aVersion)
322 {
323 FirstLineRep::version(aVersion);
324 }
325
326 libecap::Name
327 Adaptation::Ecap::StatusLineRep::protocol() const
328 {
329 return FirstLineRep::protocol();
330 }
331
332 void
333 Adaptation::Ecap::StatusLineRep::protocol(const Name &p)
334 {
335 FirstLineRep::protocol(p);
336 }
337
338 /* BodyRep */
339
340 Adaptation::Ecap::BodyRep::BodyRep(const BodyPipe::Pointer &aBody): theBody(aBody)
341 {
342 }
343
344 void
345 Adaptation::Ecap::BodyRep::tie(const BodyPipe::Pointer &aBody)
346 {
347 Must(!theBody);
348 Must(aBody != NULL);
349 theBody = aBody;
350 }
351
352 Adaptation::Ecap::BodyRep::BodySize
353 Adaptation::Ecap::BodyRep::bodySize() const
354 {
355 return !theBody ? BodySize() : BodySize(theBody->bodySize());
356 }
357
358 /* MessageRep */
359
360 Adaptation::Ecap::MessageRep::MessageRep(HttpMsg *rawHeader):
361 theMessage(rawHeader), theFirstLineRep(NULL),
362 theHeaderRep(NULL), theBodyRep(NULL)
363 {
364 Must(theMessage.header); // we do not want to represent a missing message
365
366 if (HttpRequest *req = dynamic_cast<HttpRequest*>(theMessage.header))
367 theFirstLineRep = new RequestLineRep(*req);
368 else if (HttpReply *rep = dynamic_cast<HttpReply*>(theMessage.header))
369 theFirstLineRep = new StatusLineRep(*rep);
370 else
371 Must(false); // unknown message header type
372
373 theHeaderRep = new HeaderRep(*theMessage.header);
374
375 if (theMessage.body_pipe != NULL)
376 theBodyRep = new BodyRep(theMessage.body_pipe);
377 }
378
379 Adaptation::Ecap::MessageRep::~MessageRep()
380 {
381 delete theBodyRep;
382 delete theHeaderRep;
383 delete theFirstLineRep;
384 }
385
386 libecap::shared_ptr<libecap::Message>
387 Adaptation::Ecap::MessageRep::clone() const
388 {
389 HttpMsg *hdr = theMessage.header->clone();
390 hdr->body_pipe = NULL; // if any; TODO: remove pipe cloning from ::clone?
391 libecap::shared_ptr<libecap::Message> res(new MessageRep(hdr));
392
393 // restore indication of a body if needed, but not the pipe
394 if (theMessage.header->body_pipe != NULL)
395 res->addBody();
396
397 return res;
398 }
399
400 libecap::FirstLine &
401 Adaptation::Ecap::MessageRep::firstLine()
402 {
403 return *theFirstLineRep;
404 }
405
406 const libecap::FirstLine &
407 Adaptation::Ecap::MessageRep::firstLine() const
408 {
409 return *theFirstLineRep;
410 }
411
412 libecap::Header &
413 Adaptation::Ecap::MessageRep::header()
414 {
415 return *theHeaderRep;
416 }
417
418 const libecap::Header &
419 Adaptation::Ecap::MessageRep::header() const
420 {
421 return *theHeaderRep;
422 }
423
424 libecap::Body *
425 Adaptation::Ecap::MessageRep::body()
426 {
427 return theBodyRep;
428 }
429
430 void
431 Adaptation::Ecap::MessageRep::addBody()
432 {
433 Must(!theBodyRep);
434 Must(!theMessage.body_pipe); // set in tieBody()
435 theBodyRep = new BodyRep(NULL);
436 }
437
438 void
439 Adaptation::Ecap::MessageRep::tieBody(Adaptation::Ecap::XactionRep *x)
440 {
441 Must(theBodyRep != NULL); // addBody must be called first
442 Must(!theMessage.header->body_pipe);
443 Must(!theMessage.body_pipe);
444 theMessage.header->body_pipe = new BodyPipe(x);
445 theMessage.body_pipe = theMessage.header->body_pipe;
446 theBodyRep->tie(theMessage.body_pipe);
447 }
448
449 const libecap::Body *Adaptation::Ecap::MessageRep::body() const
450 {
451 return theBodyRep;
452 }
453