]> git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/ecap/MessageRep.cc
SourceFormat: enforcement
[thirdparty/squid.git] / src / adaptation / ecap / MessageRep.cc
1 /*
2 * DEBUG: section XXX
3 */
4
5 #include "squid.h"
6 #include "HttpRequest.h"
7 #include "HttpReply.h"
8 #include "BodyPipe.h"
9 #include "TextException.h"
10 #include <libecap/common/names.h>
11 #include <libecap/common/area.h>
12 #include <libecap/common/version.h>
13 #include "adaptation/ecap/MessageRep.h"
14 #include "adaptation/ecap/XactionRep.h"
15 #include "adaptation/ecap/Host.h" /* for protocol constants */
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::FromTempString(value.termedBuf());
42 }
43
44 void
45 Adaptation::Ecap::HeaderRep::add(const Name &name, const Value &value)
46 {
47 const http_hdr_type squidId = TranslateHeaderId(name); // HDR_OTHER OK
48 HttpHeaderEntry *e = new HttpHeaderEntry(squidId, name.image().c_str(),
49 value.toString().c_str());
50 theHeader.addEntry(e);
51 }
52
53 void
54 Adaptation::Ecap::HeaderRep::removeAny(const Name &name)
55 {
56 const http_hdr_type squidId = TranslateHeaderId(name);
57 if (squidId == HDR_OTHER)
58 theHeader.delByName(name.image().c_str());
59 else
60 theHeader.delById(squidId);
61 }
62
63 libecap::Area
64 Adaptation::Ecap::HeaderRep::image() const
65 {
66 MemBuf mb;
67 mb.init();
68
69 Packer p;
70 packerToMemInit(&p, &mb);
71 theMessage.packInto(&p, true);
72 packerClean(&p);
73 return Area::FromTempBuffer(mb.content(), mb.contentSize());
74 }
75
76 // throws on failures
77 void
78 Adaptation::Ecap::HeaderRep::parse(const Area &buf)
79 {
80 MemBuf mb;
81 mb.init();
82 mb.append(buf.start, buf.size);
83 http_status error;
84 Must(theMessage.parse(&mb, true, &error));
85 }
86
87 http_hdr_type
88 Adaptation::Ecap::HeaderRep::TranslateHeaderId(const Name &name)
89 {
90 if (name.assignedHostId())
91 return static_cast<http_hdr_type>(name.hostId());
92 return HDR_OTHER;
93 }
94
95
96 /* FirstLineRep */
97
98 Adaptation::Ecap::FirstLineRep::FirstLineRep(HttpMsg &aMessage): theMessage(aMessage)
99 {
100 }
101
102 libecap::Version
103 Adaptation::Ecap::FirstLineRep::version() const
104 {
105 return libecap::Version(theMessage.http_ver.major,
106 theMessage.http_ver.minor);
107 }
108
109 void
110 Adaptation::Ecap::FirstLineRep::version(const libecap::Version &aVersion)
111 {
112 theMessage.http_ver.major = aVersion.majr;
113 theMessage.http_ver.minor = aVersion.minr;
114 }
115
116 libecap::Name
117 Adaptation::Ecap::FirstLineRep::protocol() const
118 {
119 // TODO: optimize?
120 switch (theMessage.protocol) {
121 case PROTO_HTTP:
122 return libecap::protocolHttp;
123 case PROTO_HTTPS:
124 return libecap::protocolHttps;
125 case PROTO_FTP:
126 return libecap::protocolFtp;
127 case PROTO_GOPHER:
128 return libecap::protocolGopher;
129 case PROTO_WAIS:
130 return libecap::protocolWais;
131 case PROTO_WHOIS:
132 return libecap::protocolWhois;
133 case PROTO_URN:
134 return libecap::protocolUrn;
135 case PROTO_ICP:
136 return protocolIcp;
137 #if USE_HTCP
138 case PROTO_HTCP:
139 return protocolHtcp;
140 #endif
141 case PROTO_CACHEOBJ:
142 return protocolCacheObj;
143 case PROTO_INTERNAL:
144 return protocolInternal;
145 case PROTO_NONE:
146 return Name();
147
148 case PROTO_MAX:
149 break; // should not happen
150 // no default to catch PROTO_ additions
151 }
152 Must(false); // not reached
153 return Name();
154 }
155
156 void
157 Adaptation::Ecap::FirstLineRep::protocol(const Name &p)
158 {
159 // TODO: what happens if we fail to translate some protocol?
160 theMessage.protocol = TranslateProtocolId(p);
161 }
162
163 protocol_t
164 Adaptation::Ecap::FirstLineRep::TranslateProtocolId(const Name &name)
165 {
166 if (name.assignedHostId())
167 return static_cast<protocol_t>(name.hostId());
168 return PROTO_NONE; // no PROTO_OTHER
169 }
170
171
172 /* RequestHeaderRep */
173
174 Adaptation::Ecap::RequestLineRep::RequestLineRep(HttpRequest &aMessage):
175 FirstLineRep(aMessage), theMessage(aMessage)
176 {
177 }
178
179 void
180 Adaptation::Ecap::RequestLineRep::uri(const Area &aUri)
181 {
182 // TODO: if method is not set, urlPath will assume it is not connect;
183 // Can we change urlParse API to remove the method parameter?
184 // TODO: optimize: urlPath should take constant URL buffer
185 char *buf = xstrdup(aUri.toString().c_str());
186 const bool ok = urlParse(theMessage.method, buf, &theMessage);
187 xfree(buf);
188 Must(ok);
189 }
190
191 Adaptation::Ecap::RequestLineRep::Area
192 Adaptation::Ecap::RequestLineRep::uri() const
193 {
194 return Area::FromTempBuffer(theMessage.urlpath.rawBuf(),
195 theMessage.urlpath.size());
196 }
197
198 void
199 Adaptation::Ecap::RequestLineRep::method(const Name &aMethod)
200 {
201 if (aMethod.assignedHostId()) {
202 const int id = aMethod.hostId();
203 Must(METHOD_NONE < id && id < METHOD_ENUM_END);
204 Must(id != METHOD_OTHER);
205 theMessage.method = HttpRequestMethod(static_cast<_method_t>(id));
206 } else {
207 const std::string &image = aMethod.image();
208 theMessage.method = HttpRequestMethod(image.data(),
209 image.data() + image.size());
210 }
211 }
212
213 Adaptation::Ecap::RequestLineRep::Name
214 Adaptation::Ecap::RequestLineRep::method() const
215 {
216 switch (theMessage.method.id()) {
217 case METHOD_GET:
218 return libecap::methodGet;
219 case METHOD_POST:
220 return libecap::methodPost;
221 case METHOD_PUT:
222 return libecap::methodPut;
223 case METHOD_HEAD:
224 return libecap::methodHead;
225 case METHOD_CONNECT:
226 return libecap::methodConnect;
227 case METHOD_DELETE:
228 return libecap::methodDelete;
229 case METHOD_TRACE:
230 return libecap::methodTrace;
231 default:
232 return Name(theMessage.method.image());
233 }
234 }
235
236 libecap::Version
237 Adaptation::Ecap::RequestLineRep::version() const
238 {
239 return FirstLineRep::version();
240 }
241
242 void
243 Adaptation::Ecap::RequestLineRep::version(const libecap::Version &aVersion)
244 {
245 FirstLineRep::version(aVersion);
246 }
247
248 libecap::Name
249 Adaptation::Ecap::RequestLineRep::protocol() const
250 {
251 return FirstLineRep::protocol();
252 }
253
254 void
255 Adaptation::Ecap::RequestLineRep::protocol(const Name &p)
256 {
257 FirstLineRep::protocol(p);
258 }
259
260
261 /* ReplyHeaderRep */
262
263 Adaptation::Ecap::StatusLineRep::StatusLineRep(HttpReply &aMessage):
264 FirstLineRep(aMessage), theMessage(aMessage)
265 {
266 }
267
268 void
269 Adaptation::Ecap::StatusLineRep::statusCode(int code)
270 {
271 // TODO: why is .status a enum? Do we not support unknown statuses?
272 theMessage.sline.status = static_cast<http_status>(code);
273 }
274
275 int
276 Adaptation::Ecap::StatusLineRep::statusCode() const
277 {
278 // TODO: see statusCode(code) TODO above
279 return static_cast<int>(theMessage.sline.status);
280 }
281
282 void
283 Adaptation::Ecap::StatusLineRep::reasonPhrase(const Area &)
284 {
285 // Squid does not support custom reason phrases
286 theMessage.sline.reason = NULL;
287 }
288
289 Adaptation::Ecap::StatusLineRep::Area
290 Adaptation::Ecap::StatusLineRep::reasonPhrase() const
291 {
292 return theMessage.sline.reason ?
293 Area::FromTempString(std::string(theMessage.sline.reason)) : Area();
294 }
295
296 libecap::Version
297 Adaptation::Ecap::StatusLineRep::version() const
298 {
299 return FirstLineRep::version();
300 }
301
302 void
303 Adaptation::Ecap::StatusLineRep::version(const libecap::Version &aVersion)
304 {
305 FirstLineRep::version(aVersion);
306 }
307
308 libecap::Name
309 Adaptation::Ecap::StatusLineRep::protocol() const
310 {
311 return FirstLineRep::protocol();
312 }
313
314 void
315 Adaptation::Ecap::StatusLineRep::protocol(const Name &p)
316 {
317 FirstLineRep::protocol(p);
318 }
319
320 /* BodyRep */
321
322 Adaptation::Ecap::BodyRep::BodyRep(const BodyPipe::Pointer &aBody): theBody(aBody)
323 {
324 }
325
326 void
327 Adaptation::Ecap::BodyRep::tie(const BodyPipe::Pointer &aBody)
328 {
329 Must(!theBody);
330 Must(aBody != NULL);
331 theBody = aBody;
332 }
333
334 Adaptation::Ecap::BodyRep::BodySize
335 Adaptation::Ecap::BodyRep::bodySize() const
336 {
337 return !theBody ? BodySize() : BodySize(theBody->bodySize());
338 }
339
340
341 /* MessageRep */
342
343 Adaptation::Ecap::MessageRep::MessageRep(HttpMsg *rawHeader):
344 theMessage(rawHeader), theFirstLineRep(NULL),
345 theHeaderRep(NULL), theBodyRep(NULL)
346 {
347 Must(theMessage.header); // we do not want to represent a missing message
348
349 if (HttpRequest *req = dynamic_cast<HttpRequest*>(theMessage.header))
350 theFirstLineRep = new RequestLineRep(*req);
351 else if (HttpReply *rep = dynamic_cast<HttpReply*>(theMessage.header))
352 theFirstLineRep = new StatusLineRep(*rep);
353 else
354 Must(false); // unknown message header type
355
356 theHeaderRep = new HeaderRep(*theMessage.header);
357
358 if (theMessage.body_pipe != NULL)
359 theBodyRep = new BodyRep(theMessage.body_pipe);
360 }
361
362 Adaptation::Ecap::MessageRep::~MessageRep()
363 {
364 delete theBodyRep;
365 delete theHeaderRep;
366 delete theFirstLineRep;
367 }
368
369 libecap::shared_ptr<libecap::Message>
370 Adaptation::Ecap::MessageRep::clone() const
371 {
372 HttpMsg *hdr = theMessage.header->clone();
373 hdr->body_pipe = NULL; // if any; TODO: remove pipe cloning from ::clone?
374 libecap::shared_ptr<libecap::Message> res(new MessageRep(hdr));
375
376 // restore indication of a body if needed, but not the pipe
377 if (theMessage.header->body_pipe != NULL)
378 res->addBody();
379
380 return res;
381 }
382
383 libecap::FirstLine &
384 Adaptation::Ecap::MessageRep::firstLine()
385 {
386 return *theFirstLineRep;
387 }
388
389 const libecap::FirstLine &
390 Adaptation::Ecap::MessageRep::firstLine() const
391 {
392 return *theFirstLineRep;
393 }
394
395 libecap::Header &
396 Adaptation::Ecap::MessageRep::header()
397 {
398 return *theHeaderRep;
399 }
400
401 const libecap::Header &
402 Adaptation::Ecap::MessageRep::header() const
403 {
404 return *theHeaderRep;
405 }
406
407 libecap::Body *
408 Adaptation::Ecap::MessageRep::body()
409 {
410 return theBodyRep;
411 }
412
413 void
414 Adaptation::Ecap::MessageRep::addBody()
415 {
416 Must(!theBodyRep);
417 Must(!theMessage.body_pipe); // set in tieBody()
418 theBodyRep = new BodyRep(NULL);
419 }
420
421 void
422 Adaptation::Ecap::MessageRep::tieBody(Adaptation::Ecap::XactionRep *x)
423 {
424 Must(theBodyRep != NULL); // addBody must be called first
425 Must(!theMessage.header->body_pipe);
426 Must(!theMessage.body_pipe);
427 theMessage.header->body_pipe = new BodyPipe(x);
428 theMessage.body_pipe = theMessage.header->body_pipe;
429 theBodyRep->tie(theMessage.body_pipe);
430 }
431
432 const libecap::Body *Adaptation::Ecap::MessageRep::body() const
433 {
434 return theBodyRep;
435 }