]> git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/ecap/MessageRep.cc
12fb703efacf0fecb7484b3f066255c7d330cfb7
[thirdparty/squid.git] / src / adaptation / ecap / MessageRep.cc
1 /*
2 * DEBUG: section 93 eCAP Interface
3 */
4 #include "squid-old.h"
5 #include "HttpRequest.h"
6 #include "HttpReply.h"
7 #include "BodyPipe.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/MessageRep.h"
13 #include "adaptation/ecap/XactionRep.h"
14 #include "adaptation/ecap/Host.h" /* for protocol constants */
15 #include "base/TextException.h"
16
17 /* HeaderRep */
18
19 Adaptation::Ecap::HeaderRep::HeaderRep(HttpMsg &aMessage): theHeader(aMessage.header),
20 theMessage(aMessage)
21 {
22 }
23
24 bool
25 Adaptation::Ecap::HeaderRep::hasAny(const Name &name) const
26 {
27 const http_hdr_type squidId = TranslateHeaderId(name);
28 // XXX: optimize to remove getByName: we do not need the value here
29 return squidId == HDR_OTHER ?
30 theHeader.getByName(name.image().c_str()).size() > 0:
31 (bool)theHeader.has(squidId);
32 }
33
34 Adaptation::Ecap::HeaderRep::Value
35 Adaptation::Ecap::HeaderRep::value(const Name &name) const
36 {
37 const http_hdr_type squidId = TranslateHeaderId(name);
38 const String value = squidId == HDR_OTHER ?
39 theHeader.getByName(name.image().c_str()) :
40 theHeader.getStrOrList(squidId);
41 return value.defined() ?
42 Value::FromTempString(value.termedBuf()) : Value();
43 }
44
45 void
46 Adaptation::Ecap::HeaderRep::add(const Name &name, const Value &value)
47 {
48 const http_hdr_type squidId = TranslateHeaderId(name); // HDR_OTHER OK
49 HttpHeaderEntry *e = new HttpHeaderEntry(squidId, name.image().c_str(),
50 value.toString().c_str());
51 theHeader.addEntry(e);
52
53 if (squidId == HDR_CONTENT_LENGTH)
54 theMessage.content_length = theHeader.getInt64(HDR_CONTENT_LENGTH);
55 }
56
57 void
58 Adaptation::Ecap::HeaderRep::removeAny(const Name &name)
59 {
60 const http_hdr_type squidId = TranslateHeaderId(name);
61 if (squidId == HDR_OTHER)
62 theHeader.delByName(name.image().c_str());
63 else
64 theHeader.delById(squidId);
65
66 if (squidId == HDR_CONTENT_LENGTH)
67 theMessage.content_length = theHeader.getInt64(HDR_CONTENT_LENGTH);
68 }
69
70 void
71 Adaptation::Ecap::HeaderRep::visitEach(libecap::NamedValueVisitor &visitor) const
72 {
73 HttpHeaderPos pos = HttpHeaderInitPos;
74 while (HttpHeaderEntry *e = theHeader.getEntry(&pos)) {
75 const Name name(e->name.termedBuf()); // optimize: find std Names
76 name.assignHostId(e->id);
77 visitor.visit(name, Value(e->value.rawBuf(), e->value.size()));
78 }
79 }
80
81 libecap::Area
82 Adaptation::Ecap::HeaderRep::image() const
83 {
84 MemBuf mb;
85 mb.init();
86
87 Packer p;
88 packerToMemInit(&p, &mb);
89 theMessage.packInto(&p, true);
90 packerClean(&p);
91 return Area::FromTempBuffer(mb.content(), mb.contentSize());
92 }
93
94 // throws on failures
95 void
96 Adaptation::Ecap::HeaderRep::parse(const Area &buf)
97 {
98 MemBuf mb;
99 mb.init();
100 mb.append(buf.start, buf.size);
101 http_status error;
102 Must(theMessage.parse(&mb, true, &error));
103 }
104
105 http_hdr_type
106 Adaptation::Ecap::HeaderRep::TranslateHeaderId(const Name &name)
107 {
108 if (name.assignedHostId())
109 return static_cast<http_hdr_type>(name.hostId());
110 return HDR_OTHER;
111 }
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_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.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
194 /* RequestHeaderRep */
195
196 Adaptation::Ecap::RequestLineRep::RequestLineRep(HttpRequest &aMessage):
197 FirstLineRep(aMessage), theMessage(aMessage)
198 {
199 }
200
201 void
202 Adaptation::Ecap::RequestLineRep::uri(const Area &aUri)
203 {
204 // TODO: if method is not set, urlPath will assume it is not connect;
205 // Can we change urlParse API to remove the method parameter?
206 // TODO: optimize: urlPath should take constant URL buffer
207 char *buf = xstrdup(aUri.toString().c_str());
208 const bool ok = urlParse(theMessage.method, buf, &theMessage);
209 xfree(buf);
210 Must(ok);
211 }
212
213 Adaptation::Ecap::RequestLineRep::Area
214 Adaptation::Ecap::RequestLineRep::uri() const
215 {
216 const char *fullUrl = urlCanonical(&theMessage);
217 Must(fullUrl);
218 // optimize: avoid copying by having an Area::Detail that locks theMessage
219 return Area::FromTempBuffer(fullUrl, strlen(fullUrl));
220 }
221
222 void
223 Adaptation::Ecap::RequestLineRep::method(const Name &aMethod)
224 {
225 if (aMethod.assignedHostId()) {
226 const int id = aMethod.hostId();
227 Must(METHOD_NONE < id && id < METHOD_ENUM_END);
228 Must(id != METHOD_OTHER);
229 theMessage.method = HttpRequestMethod(static_cast<_method_t>(id));
230 } else {
231 const std::string &image = aMethod.image();
232 theMessage.method = HttpRequestMethod(image.data(),
233 image.data() + image.size());
234 }
235 }
236
237 Adaptation::Ecap::RequestLineRep::Name
238 Adaptation::Ecap::RequestLineRep::method() const
239 {
240 switch (theMessage.method.id()) {
241 case METHOD_GET:
242 return libecap::methodGet;
243 case METHOD_POST:
244 return libecap::methodPost;
245 case METHOD_PUT:
246 return libecap::methodPut;
247 case METHOD_HEAD:
248 return libecap::methodHead;
249 case METHOD_CONNECT:
250 return libecap::methodConnect;
251 case METHOD_DELETE:
252 return libecap::methodDelete;
253 case METHOD_TRACE:
254 return libecap::methodTrace;
255 default:
256 return Name(theMessage.method.image());
257 }
258 }
259
260 libecap::Version
261 Adaptation::Ecap::RequestLineRep::version() const
262 {
263 return FirstLineRep::version();
264 }
265
266 void
267 Adaptation::Ecap::RequestLineRep::version(const libecap::Version &aVersion)
268 {
269 FirstLineRep::version(aVersion);
270 }
271
272 libecap::Name
273 Adaptation::Ecap::RequestLineRep::protocol() const
274 {
275 return FirstLineRep::protocol();
276 }
277
278 void
279 Adaptation::Ecap::RequestLineRep::protocol(const Name &p)
280 {
281 FirstLineRep::protocol(p);
282 }
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 // TODO: why is .status a enum? Do we not support unknown statuses?
296 theMessage.sline.status = static_cast<http_status>(code);
297 }
298
299 int
300 Adaptation::Ecap::StatusLineRep::statusCode() const
301 {
302 // TODO: see statusCode(code) TODO above
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 custom reason phrases
310 theMessage.sline.reason = NULL;
311 }
312
313 Adaptation::Ecap::StatusLineRep::Area
314 Adaptation::Ecap::StatusLineRep::reasonPhrase() const
315 {
316 return theMessage.sline.reason ?
317 Area::FromTempString(std::string(theMessage.sline.reason)) : Area();
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 ? BodySize() : BodySize(theBody->bodySize());
362 }
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 }