]> git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/ecap/MessageRep.cc
257a3c491801937b815c16d4632a841f1e00f59b
[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
95 Packer p;
96 packerToMemInit(&p, &mb);
97 theMessage.packInto(&p, true);
98 packerClean(&p);
99 return Area::FromTempBuffer(mb.content(), mb.contentSize());
100 }
101
102 // throws on failures
103 void
104 Adaptation::Ecap::HeaderRep::parse(const Area &buf)
105 {
106 MemBuf mb;
107 mb.init();
108 mb.append(buf.start, buf.size);
109 Http::StatusCode error;
110 Must(theMessage.parse(&mb, true, &error));
111 }
112
113 http_hdr_type
114 Adaptation::Ecap::HeaderRep::TranslateHeaderId(const Name &name)
115 {
116 if (name.assignedHostId())
117 return static_cast<http_hdr_type>(name.hostId());
118 return HDR_OTHER;
119 }
120
121 /* FirstLineRep */
122
123 Adaptation::Ecap::FirstLineRep::FirstLineRep(HttpMsg &aMessage): theMessage(aMessage)
124 {
125 }
126
127 libecap::Version
128 Adaptation::Ecap::FirstLineRep::version() const
129 {
130 return libecap::Version(theMessage.http_ver.major,
131 theMessage.http_ver.minor);
132 }
133
134 void
135 Adaptation::Ecap::FirstLineRep::version(const libecap::Version &aVersion)
136 {
137 theMessage.http_ver.major = aVersion.majr;
138 theMessage.http_ver.minor = aVersion.minr;
139 }
140
141 libecap::Name
142 Adaptation::Ecap::FirstLineRep::protocol() const
143 {
144 // TODO: optimize?
145 switch (theMessage.http_ver.protocol) {
146 case AnyP::PROTO_HTTP:
147 return libecap::protocolHttp;
148 case AnyP::PROTO_HTTPS:
149 return libecap::protocolHttps;
150 case AnyP::PROTO_FTP:
151 return libecap::protocolFtp;
152 case AnyP::PROTO_GOPHER:
153 return libecap::protocolGopher;
154 case AnyP::PROTO_WAIS:
155 return libecap::protocolWais;
156 case AnyP::PROTO_WHOIS:
157 return libecap::protocolWhois;
158 case AnyP::PROTO_URN:
159 return libecap::protocolUrn;
160 case AnyP::PROTO_ICP:
161 return protocolIcp;
162 #if USE_HTCP
163 case AnyP::PROTO_HTCP:
164 return protocolHtcp;
165 #endif
166 case AnyP::PROTO_CACHE_OBJECT:
167 return protocolCacheObj;
168 case AnyP::PROTO_ICY:
169 return protocolIcy;
170 case AnyP::PROTO_COAP:
171 case AnyP::PROTO_COAPS: // use 'unknown' until libecap supports coap:// and coaps://
172 case AnyP::PROTO_UNKNOWN:
173 return protocolUnknown; // until we remember the protocol image
174 case AnyP::PROTO_NONE:
175 return Name();
176
177 case AnyP::PROTO_MAX:
178 break; // should not happen
179 // no default to catch AnyP::PROTO_ additions
180 }
181 Must(false); // not reached
182 return Name();
183 }
184
185 void
186 Adaptation::Ecap::FirstLineRep::protocol(const Name &p)
187 {
188 // TODO: what happens if we fail to translate some protocol?
189 theMessage.http_ver.protocol = TranslateProtocolId(p);
190 }
191
192 AnyP::ProtocolType
193 Adaptation::Ecap::FirstLineRep::TranslateProtocolId(const Name &name)
194 {
195 if (name.assignedHostId())
196 return static_cast<AnyP::ProtocolType>(name.hostId());
197 return AnyP::PROTO_UNKNOWN;
198 }
199
200 /* RequestHeaderRep */
201
202 Adaptation::Ecap::RequestLineRep::RequestLineRep(HttpRequest &aMessage):
203 FirstLineRep(aMessage), theMessage(aMessage)
204 {
205 }
206
207 void
208 Adaptation::Ecap::RequestLineRep::uri(const Area &aUri)
209 {
210 // TODO: if method is not set, urlPath will assume it is not connect;
211 // Can we change urlParse API to remove the method parameter?
212 // TODO: optimize: urlPath should take constant URL buffer
213 char *buf = xstrdup(aUri.toString().c_str());
214 const bool ok = urlParse(theMessage.method, buf, &theMessage);
215 xfree(buf);
216 Must(ok);
217 }
218
219 Adaptation::Ecap::RequestLineRep::Area
220 Adaptation::Ecap::RequestLineRep::uri() const
221 {
222 const char *fullUrl = urlCanonical(&theMessage);
223 Must(fullUrl);
224 // optimize: avoid copying by having an Area::Detail that locks theMessage
225 return Area::FromTempBuffer(fullUrl, strlen(fullUrl));
226 }
227
228 void
229 Adaptation::Ecap::RequestLineRep::method(const Name &aMethod)
230 {
231 if (aMethod.assignedHostId()) {
232 const int id = aMethod.hostId();
233 Must(Http::METHOD_NONE < id && id < Http::METHOD_ENUM_END);
234 Must(id != Http::METHOD_OTHER);
235 theMessage.method = HttpRequestMethod(static_cast<Http::MethodType>(id));
236 } else {
237 const std::string &image = aMethod.image();
238 theMessage.method.HttpRequestMethodXXX(image.c_str());
239 }
240 }
241
242 Adaptation::Ecap::RequestLineRep::Name
243 Adaptation::Ecap::RequestLineRep::method() const
244 {
245 switch (theMessage.method.id()) {
246 case Http::METHOD_GET:
247 return libecap::methodGet;
248 case Http::METHOD_POST:
249 return libecap::methodPost;
250 case Http::METHOD_PUT:
251 return libecap::methodPut;
252 case Http::METHOD_HEAD:
253 return libecap::methodHead;
254 case Http::METHOD_CONNECT:
255 return libecap::methodConnect;
256 case Http::METHOD_DELETE:
257 return libecap::methodDelete;
258 case Http::METHOD_TRACE:
259 return libecap::methodTrace;
260 default:
261 return Name(theMessage.method.image().toStdString());
262 }
263 }
264
265 libecap::Version
266 Adaptation::Ecap::RequestLineRep::version() const
267 {
268 return FirstLineRep::version();
269 }
270
271 void
272 Adaptation::Ecap::RequestLineRep::version(const libecap::Version &aVersion)
273 {
274 FirstLineRep::version(aVersion);
275 }
276
277 libecap::Name
278 Adaptation::Ecap::RequestLineRep::protocol() const
279 {
280 return FirstLineRep::protocol();
281 }
282
283 void
284 Adaptation::Ecap::RequestLineRep::protocol(const Name &p)
285 {
286 FirstLineRep::protocol(p);
287 }
288
289 /* ReplyHeaderRep */
290
291 Adaptation::Ecap::StatusLineRep::StatusLineRep(HttpReply &aMessage):
292 FirstLineRep(aMessage), theMessage(aMessage)
293 {
294 }
295
296 void
297 Adaptation::Ecap::StatusLineRep::statusCode(int code)
298 {
299 theMessage.sline.set(theMessage.sline.version, static_cast<Http::StatusCode>(code), theMessage.sline.reason());
300 }
301
302 int
303 Adaptation::Ecap::StatusLineRep::statusCode() const
304 {
305 // TODO: remove cast when possible
306 return static_cast<int>(theMessage.sline.status());
307 }
308
309 void
310 Adaptation::Ecap::StatusLineRep::reasonPhrase(const Area &str)
311 {
312 theMessage.sline.set(theMessage.sline.version, theMessage.sline.status(), str.toString().c_str());
313 }
314
315 Adaptation::Ecap::StatusLineRep::Area
316 Adaptation::Ecap::StatusLineRep::reasonPhrase() const
317 {
318 return Area::FromTempString(std::string(theMessage.sline.reason()));
319 }
320
321 libecap::Version
322 Adaptation::Ecap::StatusLineRep::version() const
323 {
324 return FirstLineRep::version();
325 }
326
327 void
328 Adaptation::Ecap::StatusLineRep::version(const libecap::Version &aVersion)
329 {
330 FirstLineRep::version(aVersion);
331 }
332
333 libecap::Name
334 Adaptation::Ecap::StatusLineRep::protocol() const
335 {
336 return FirstLineRep::protocol();
337 }
338
339 void
340 Adaptation::Ecap::StatusLineRep::protocol(const Name &p)
341 {
342 FirstLineRep::protocol(p);
343 }
344
345 /* BodyRep */
346
347 Adaptation::Ecap::BodyRep::BodyRep(const BodyPipe::Pointer &aBody): theBody(aBody)
348 {
349 }
350
351 void
352 Adaptation::Ecap::BodyRep::tie(const BodyPipe::Pointer &aBody)
353 {
354 Must(!theBody);
355 Must(aBody != NULL);
356 theBody = aBody;
357 }
358
359 Adaptation::Ecap::BodyRep::BodySize
360 Adaptation::Ecap::BodyRep::bodySize() const
361 {
362 return !theBody ? BodySize() : BodySize(theBody->bodySize());
363 }
364
365 /* MessageRep */
366
367 Adaptation::Ecap::MessageRep::MessageRep(HttpMsg *rawHeader):
368 theMessage(rawHeader), theFirstLineRep(NULL),
369 theHeaderRep(NULL), theBodyRep(NULL)
370 {
371 Must(theMessage.header); // we do not want to represent a missing message
372
373 if (HttpRequest *req = dynamic_cast<HttpRequest*>(theMessage.header))
374 theFirstLineRep = new RequestLineRep(*req);
375 else if (HttpReply *rep = dynamic_cast<HttpReply*>(theMessage.header))
376 theFirstLineRep = new StatusLineRep(*rep);
377 else
378 Must(false); // unknown message header type
379
380 theHeaderRep = new HeaderRep(*theMessage.header);
381
382 if (theMessage.body_pipe != NULL)
383 theBodyRep = new BodyRep(theMessage.body_pipe);
384 }
385
386 Adaptation::Ecap::MessageRep::~MessageRep()
387 {
388 delete theBodyRep;
389 delete theHeaderRep;
390 delete theFirstLineRep;
391 }
392
393 libecap::shared_ptr<libecap::Message>
394 Adaptation::Ecap::MessageRep::clone() const
395 {
396 HttpMsg *hdr = theMessage.header->clone();
397 hdr->body_pipe = NULL; // if any; TODO: remove pipe cloning from ::clone?
398 libecap::shared_ptr<libecap::Message> res(new MessageRep(hdr));
399
400 // restore indication of a body if needed, but not the pipe
401 if (theMessage.header->body_pipe != NULL)
402 res->addBody();
403
404 return res;
405 }
406
407 libecap::FirstLine &
408 Adaptation::Ecap::MessageRep::firstLine()
409 {
410 return *theFirstLineRep;
411 }
412
413 const libecap::FirstLine &
414 Adaptation::Ecap::MessageRep::firstLine() const
415 {
416 return *theFirstLineRep;
417 }
418
419 libecap::Header &
420 Adaptation::Ecap::MessageRep::header()
421 {
422 return *theHeaderRep;
423 }
424
425 const libecap::Header &
426 Adaptation::Ecap::MessageRep::header() const
427 {
428 return *theHeaderRep;
429 }
430
431 libecap::Body *
432 Adaptation::Ecap::MessageRep::body()
433 {
434 return theBodyRep;
435 }
436
437 void
438 Adaptation::Ecap::MessageRep::addBody()
439 {
440 Must(!theBodyRep);
441 Must(!theMessage.body_pipe); // set in tieBody()
442 theBodyRep = new BodyRep(NULL);
443 }
444
445 void
446 Adaptation::Ecap::MessageRep::tieBody(Adaptation::Ecap::XactionRep *x)
447 {
448 Must(theBodyRep != NULL); // addBody must be called first
449 Must(!theMessage.header->body_pipe);
450 Must(!theMessage.body_pipe);
451 theMessage.header->body_pipe = new BodyPipe(x);
452 theMessage.body_pipe = theMessage.header->body_pipe;
453 theBodyRep->tie(theMessage.body_pipe);
454 }
455
456 const libecap::Body *Adaptation::Ecap::MessageRep::body() const
457 {
458 return theBodyRep;
459 }
460