]> git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/ecap/MessageRep.cc
Merged from trunk
[thirdparty/squid.git] / src / adaptation / ecap / MessageRep.cc
1 /*
2 * DEBUG: section 93 eCAP Interface
3 */
4 #include "squid.h"
5 #include "BodyPipe.h"
6 #include "HttpReply.h"
7 #include "HttpRequest.h"
8 #include <libecap/common/names.h>
9 #include <libecap/common/area.h>
10 #include <libecap/common/version.h>
11 #include <libecap/common/named_values.h>
12 #include "adaptation/ecap/Host.h" /* for protocol constants */
13 #include "adaptation/ecap/MessageRep.h"
14 #include "adaptation/ecap/XactionRep.h"
15 #include "base/TextException.h"
16 #include "URL.h"
17
18 /* HeaderRep */
19
20 Adaptation::Ecap::HeaderRep::HeaderRep(HttpMsg &aMessage): theHeader(aMessage.header),
21 theMessage(aMessage)
22 {
23 }
24
25 bool
26 Adaptation::Ecap::HeaderRep::hasAny(const Name &name) const
27 {
28 const http_hdr_type squidId = TranslateHeaderId(name);
29 // XXX: optimize to remove getByName: we do not need the value here
30 return squidId == HDR_OTHER ?
31 theHeader.getByName(name.image().c_str()).size() > 0:
32 (bool)theHeader.has(squidId);
33 }
34
35 Adaptation::Ecap::HeaderRep::Value
36 Adaptation::Ecap::HeaderRep::value(const Name &name) const
37 {
38 const http_hdr_type squidId = TranslateHeaderId(name);
39 const String value = squidId == HDR_OTHER ?
40 theHeader.getByName(name.image().c_str()) :
41 theHeader.getStrOrList(squidId);
42 return value.size() > 0 ?
43 Value::FromTempString(value.termedBuf()) : Value();
44 }
45
46 void
47 Adaptation::Ecap::HeaderRep::add(const Name &name, const Value &value)
48 {
49 const http_hdr_type squidId = TranslateHeaderId(name); // HDR_OTHER OK
50 HttpHeaderEntry *e = new HttpHeaderEntry(squidId, name.image().c_str(),
51 value.toString().c_str());
52 theHeader.addEntry(e);
53
54 if (squidId == HDR_CONTENT_LENGTH)
55 theMessage.content_length = theHeader.getInt64(HDR_CONTENT_LENGTH);
56 }
57
58 void
59 Adaptation::Ecap::HeaderRep::removeAny(const Name &name)
60 {
61 const http_hdr_type squidId = TranslateHeaderId(name);
62 if (squidId == HDR_OTHER)
63 theHeader.delByName(name.image().c_str());
64 else
65 theHeader.delById(squidId);
66
67 if (squidId == HDR_CONTENT_LENGTH)
68 theMessage.content_length = theHeader.getInt64(HDR_CONTENT_LENGTH);
69 }
70
71 void
72 Adaptation::Ecap::HeaderRep::visitEach(libecap::NamedValueVisitor &visitor) const
73 {
74 HttpHeaderPos pos = HttpHeaderInitPos;
75 while (HttpHeaderEntry *e = theHeader.getEntry(&pos)) {
76 const Name name(e->name.termedBuf()); // optimize: find std Names
77 name.assignHostId(e->id);
78 visitor.visit(name, Value(e->value.rawBuf(), e->value.size()));
79 }
80 }
81
82 libecap::Area
83 Adaptation::Ecap::HeaderRep::image() const
84 {
85 MemBuf mb;
86 mb.init();
87
88 Packer p;
89 packerToMemInit(&p, &mb);
90 theMessage.packInto(&p, true);
91 packerClean(&p);
92 return Area::FromTempBuffer(mb.content(), mb.contentSize());
93 }
94
95 // throws on failures
96 void
97 Adaptation::Ecap::HeaderRep::parse(const Area &buf)
98 {
99 MemBuf mb;
100 mb.init();
101 mb.append(buf.start, buf.size);
102 Http::StatusCode error;
103 Must(theMessage.parse(&mb, 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.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_INTERNAL:
162 return protocolInternal;
163 case AnyP::PROTO_ICY:
164 return protocolIcy;
165 case AnyP::PROTO_COAP:
166 case AnyP::PROTO_COAPS: // use 'unknown' until libecap supports coap:// and coaps://
167 case AnyP::PROTO_UNKNOWN:
168 return protocolUnknown; // until we remember the protocol image
169 case AnyP::PROTO_NONE:
170 return Name();
171
172 case AnyP::PROTO_MAX:
173 break; // should not happen
174 // no default to catch AnyP::PROTO_ additions
175 }
176 Must(false); // not reached
177 return Name();
178 }
179
180 void
181 Adaptation::Ecap::FirstLineRep::protocol(const Name &p)
182 {
183 // TODO: what happens if we fail to translate some protocol?
184 theMessage.protocol = TranslateProtocolId(p);
185 }
186
187 AnyP::ProtocolType
188 Adaptation::Ecap::FirstLineRep::TranslateProtocolId(const Name &name)
189 {
190 if (name.assignedHostId())
191 return static_cast<AnyP::ProtocolType>(name.hostId());
192 return AnyP::PROTO_UNKNOWN;
193 }
194
195 /* RequestHeaderRep */
196
197 Adaptation::Ecap::RequestLineRep::RequestLineRep(HttpRequest &aMessage):
198 FirstLineRep(aMessage), theMessage(aMessage)
199 {
200 }
201
202 void
203 Adaptation::Ecap::RequestLineRep::uri(const Area &aUri)
204 {
205 // TODO: if method is not set, urlPath will assume it is not connect;
206 // Can we change urlParse API to remove the method parameter?
207 // TODO: optimize: urlPath should take constant URL buffer
208 char *buf = xstrdup(aUri.toString().c_str());
209 const bool ok = urlParse(theMessage.method, buf, &theMessage);
210 xfree(buf);
211 Must(ok);
212 }
213
214 Adaptation::Ecap::RequestLineRep::Area
215 Adaptation::Ecap::RequestLineRep::uri() const
216 {
217 const char *fullUrl = urlCanonical(&theMessage);
218 Must(fullUrl);
219 // optimize: avoid copying by having an Area::Detail that locks theMessage
220 return Area::FromTempBuffer(fullUrl, strlen(fullUrl));
221 }
222
223 void
224 Adaptation::Ecap::RequestLineRep::method(const Name &aMethod)
225 {
226 if (aMethod.assignedHostId()) {
227 const int id = aMethod.hostId();
228 Must(Http::METHOD_NONE < id && id < Http::METHOD_ENUM_END);
229 Must(id != Http::METHOD_OTHER);
230 theMessage.method = HttpRequestMethod(static_cast<Http::MethodType>(id));
231 } else {
232 const std::string &image = aMethod.image();
233 theMessage.method = HttpRequestMethod(image.data(),
234 image.data() + image.size());
235 }
236 }
237
238 Adaptation::Ecap::RequestLineRep::Name
239 Adaptation::Ecap::RequestLineRep::method() const
240 {
241 switch (theMessage.method.id()) {
242 case Http::METHOD_GET:
243 return libecap::methodGet;
244 case Http::METHOD_POST:
245 return libecap::methodPost;
246 case Http::METHOD_PUT:
247 return libecap::methodPut;
248 case Http::METHOD_HEAD:
249 return libecap::methodHead;
250 case Http::METHOD_CONNECT:
251 return libecap::methodConnect;
252 case Http::METHOD_DELETE:
253 return libecap::methodDelete;
254 case Http::METHOD_TRACE:
255 return libecap::methodTrace;
256 default:
257 return Name(theMessage.method.image());
258 }
259 }
260
261 libecap::Version
262 Adaptation::Ecap::RequestLineRep::version() const
263 {
264 return FirstLineRep::version();
265 }
266
267 void
268 Adaptation::Ecap::RequestLineRep::version(const libecap::Version &aVersion)
269 {
270 FirstLineRep::version(aVersion);
271 }
272
273 libecap::Name
274 Adaptation::Ecap::RequestLineRep::protocol() const
275 {
276 return FirstLineRep::protocol();
277 }
278
279 void
280 Adaptation::Ecap::RequestLineRep::protocol(const Name &p)
281 {
282 FirstLineRep::protocol(p);
283 }
284
285 /* ReplyHeaderRep */
286
287 Adaptation::Ecap::StatusLineRep::StatusLineRep(HttpReply &aMessage):
288 FirstLineRep(aMessage), theMessage(aMessage)
289 {
290 }
291
292 void
293 Adaptation::Ecap::StatusLineRep::statusCode(int code)
294 {
295 theMessage.sline.set(theMessage.sline.version, static_cast<Http::StatusCode>(code), theMessage.sline.reason());
296 }
297
298 int
299 Adaptation::Ecap::StatusLineRep::statusCode() const
300 {
301 // TODO: remove cast when possible
302 return static_cast<int>(theMessage.sline.status());
303 }
304
305 void
306 Adaptation::Ecap::StatusLineRep::reasonPhrase(const Area &str)
307 {
308 theMessage.sline.set(theMessage.sline.version, theMessage.sline.status(), str.toString().c_str());
309 }
310
311 Adaptation::Ecap::StatusLineRep::Area
312 Adaptation::Ecap::StatusLineRep::reasonPhrase() const
313 {
314 return Area::FromTempString(std::string(theMessage.sline.reason()));
315 }
316
317 libecap::Version
318 Adaptation::Ecap::StatusLineRep::version() const
319 {
320 return FirstLineRep::version();
321 }
322
323 void
324 Adaptation::Ecap::StatusLineRep::version(const libecap::Version &aVersion)
325 {
326 FirstLineRep::version(aVersion);
327 }
328
329 libecap::Name
330 Adaptation::Ecap::StatusLineRep::protocol() const
331 {
332 return FirstLineRep::protocol();
333 }
334
335 void
336 Adaptation::Ecap::StatusLineRep::protocol(const Name &p)
337 {
338 FirstLineRep::protocol(p);
339 }
340
341 /* BodyRep */
342
343 Adaptation::Ecap::BodyRep::BodyRep(const BodyPipe::Pointer &aBody): theBody(aBody)
344 {
345 }
346
347 void
348 Adaptation::Ecap::BodyRep::tie(const BodyPipe::Pointer &aBody)
349 {
350 Must(!theBody);
351 Must(aBody != NULL);
352 theBody = aBody;
353 }
354
355 Adaptation::Ecap::BodyRep::BodySize
356 Adaptation::Ecap::BodyRep::bodySize() const
357 {
358 return !theBody ? BodySize() : BodySize(theBody->bodySize());
359 }
360
361 /* MessageRep */
362
363 Adaptation::Ecap::MessageRep::MessageRep(HttpMsg *rawHeader):
364 theMessage(rawHeader), theFirstLineRep(NULL),
365 theHeaderRep(NULL), theBodyRep(NULL)
366 {
367 Must(theMessage.header); // we do not want to represent a missing message
368
369 if (HttpRequest *req = dynamic_cast<HttpRequest*>(theMessage.header))
370 theFirstLineRep = new RequestLineRep(*req);
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
376 theHeaderRep = new HeaderRep(*theMessage.header);
377
378 if (theMessage.body_pipe != NULL)
379 theBodyRep = new BodyRep(theMessage.body_pipe);
380 }
381
382 Adaptation::Ecap::MessageRep::~MessageRep()
383 {
384 delete theBodyRep;
385 delete theHeaderRep;
386 delete theFirstLineRep;
387 }
388
389 libecap::shared_ptr<libecap::Message>
390 Adaptation::Ecap::MessageRep::clone() const
391 {
392 HttpMsg *hdr = theMessage.header->clone();
393 hdr->body_pipe = NULL; // 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 != NULL)
398 res->addBody();
399
400 return res;
401 }
402
403 libecap::FirstLine &
404 Adaptation::Ecap::MessageRep::firstLine()
405 {
406 return *theFirstLineRep;
407 }
408
409 const libecap::FirstLine &
410 Adaptation::Ecap::MessageRep::firstLine() const
411 {
412 return *theFirstLineRep;
413 }
414
415 libecap::Header &
416 Adaptation::Ecap::MessageRep::header()
417 {
418 return *theHeaderRep;
419 }
420
421 const libecap::Header &
422 Adaptation::Ecap::MessageRep::header() const
423 {
424 return *theHeaderRep;
425 }
426
427 libecap::Body *
428 Adaptation::Ecap::MessageRep::body()
429 {
430 return theBodyRep;
431 }
432
433 void
434 Adaptation::Ecap::MessageRep::addBody()
435 {
436 Must(!theBodyRep);
437 Must(!theMessage.body_pipe); // set in tieBody()
438 theBodyRep = new BodyRep(NULL);
439 }
440
441 void
442 Adaptation::Ecap::MessageRep::tieBody(Adaptation::Ecap::XactionRep *x)
443 {
444 Must(theBodyRep != NULL); // 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
452 const libecap::Body *Adaptation::Ecap::MessageRep::body() const
453 {
454 return theBodyRep;
455 }