From: Alex Rousskov Date: Fri, 16 May 2008 00:35:59 +0000 (-0600) Subject: Implemented libecap::Message-related wrappers for Squid HttpRequest and X-Git-Tag: SQUID_3_1_0_1~45^2~11^2~24^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cf331c99e5ad9befea1ee73d29b6dad324fe5f6b;p=thirdparty%2Fsquid.git Implemented libecap::Message-related wrappers for Squid HttpRequest and HttpResponse. TODO: split the file into a few files to simplify presentation? --- diff --git a/src/eCAP/MessageRep.cc b/src/eCAP/MessageRep.cc index e808c347f8..b5fab20e38 100644 --- a/src/eCAP/MessageRep.cc +++ b/src/eCAP/MessageRep.cc @@ -3,6 +3,353 @@ */ #include "squid.h" +#include "HttpRequest.h" +#include "HttpReply.h" +#include "BodyPipe.h" +#include "TextException.h" #include "adaptation/Message.h" +#include +#include +#include #include "eCAP/MessageRep.h" +#include "eCAP/XactionRep.h" +#include "eCAP/Host.h" /* for protocol constants */ +/* HeaderRep */ + +Ecap::HeaderRep::HeaderRep(HttpMsg &aMessage): theHeader(aMessage.header), + theMessage(aMessage) +{ +} + +http_hdr_type +Ecap::HeaderRep::TranslateHeaderId(const Name &name) +{ + if (name.assignedHostId()) + return static_cast(name.hostId()); + return HDR_OTHER; +} + +protocol_t +Ecap::HeaderRep::TranslateProtocolId(const Name &name) +{ + if (name.assignedHostId()) + return static_cast(name.hostId()); + return PROTO_NONE; // no PROTO_OTHER +} + +bool +Ecap::HeaderRep::hasAny(const Name &name) const +{ + const http_hdr_type squidId = TranslateHeaderId(name); + // XXX: optimize to remove getByName: we do not need the value here + return squidId == HDR_OTHER ? + theHeader.getByName(name.image().c_str()).size() > 0: + (bool)theHeader.has(squidId); +} + +Ecap::HeaderRep::Value +Ecap::HeaderRep::value(const Name &name) const +{ + const http_hdr_type squidId = TranslateHeaderId(name); + const String value = squidId == HDR_OTHER ? + theHeader.getByName(name.image().c_str()) : + theHeader.getStrOrList(squidId); + return Value::FromTempString(value.buf()); +} + +void +Ecap::HeaderRep::add(const Name &name, const Value &value) +{ + const http_hdr_type squidId = TranslateHeaderId(name); // HDR_OTHER OK + HttpHeaderEntry *e = new HttpHeaderEntry(squidId, name.image().c_str(), + value.toString().c_str()); + theHeader.addEntry(e); +} + +void +Ecap::HeaderRep::removeAny(const Name &name) +{ + const http_hdr_type squidId = TranslateHeaderId(name); + if (squidId == HDR_OTHER) + theHeader.delByName(name.image().c_str()); + else + theHeader.delById(squidId); +} + +libecap::Area +Ecap::HeaderRep::image() const +{ + MemBuf mb; + mb.init(); + + Packer p; + packerToMemInit(&p, &mb); + theMessage.packInto(&p, true); + packerClean(&p); + return Area::FromTempBuffer(mb.content(), mb.contentSize()); +} + +// throws on failures +void +Ecap::HeaderRep::parse(const Area &buf) +{ + MemBuf mb; + mb.init(); + mb.append(buf.start, buf.size); + http_status error; + Must(theMessage.parse(&mb, true, &error)); +} + +libecap::Version +Ecap::HeaderRep::version() const +{ + return libecap::Version(theMessage.http_ver.major, + theMessage.http_ver.minor); +} + +void +Ecap::HeaderRep::version(const libecap::Version &aVersion) +{ + theMessage.http_ver.major = aVersion.majr; + theMessage.http_ver.minor = aVersion.minr; +} + +libecap::Name +Ecap::HeaderRep::protocol() const +{ + // TODO: optimize? + switch (theMessage.protocol) { + case PROTO_HTTP: return libecap::protocolHttp; + case PROTO_HTTPS: return libecap::protocolHttps; + case PROTO_FTP: return libecap::protocolFtp; + case PROTO_GOPHER: return libecap::protocolGopher; + case PROTO_WAIS: return libecap::protocolWais; + case PROTO_WHOIS: return libecap::protocolWhois; + case PROTO_URN: return libecap::protocolUrn; + case PROTO_ICP: return protocolIcp; +#if USE_HTCP + case PROTO_HTCP: return protocolHtcp; +#endif + case PROTO_CACHEOBJ: return protocolCacheObj; + case PROTO_INTERNAL: return protocolInternal; + case PROTO_NONE: return Name(); + + case PROTO_MAX: break; // should not happen + // no default to catch PROTO_ additions + } + Must(false); // not reached + return Name(); +} + +void +Ecap::HeaderRep::protocol(const Name &p) +{ + // TODO: what happens if we fail to translate some protocol? + theMessage.protocol = TranslateProtocolId(p); +} + + +/* RequestHeaderRep */ + +Ecap::RequestHeaderRep::RequestHeaderRep(HttpRequest &aMessage): + HeaderRep(aMessage), theMessage(aMessage) +{ +} + +void +Ecap::RequestHeaderRep::uri(const Area &aUri) +{ + // TODO: if method is not set, urlPath will assume it is not connect; + // Can we change urlParse API to remove the method parameter? + // TODO: optimize: urlPath should take constant URL buffer + char *buf = xstrdup(aUri.toString().c_str()); + const bool ok = urlParse(theMessage.method, buf, &theMessage); + xfree(buf); + Must(ok); +} + +Ecap::RequestHeaderRep::Area +Ecap::RequestHeaderRep::uri() const +{ + return Area::FromTempBuffer(theMessage.urlpath.buf(), + theMessage.urlpath.size()); +} + +void +Ecap::RequestHeaderRep::method(const Name &aMethod) +{ + if (aMethod.assignedHostId()) { + const int id = aMethod.hostId(); + Must(METHOD_NONE < id && id < METHOD_ENUM_END); + Must(id != METHOD_OTHER); + theMessage.method = HttpRequestMethod(static_cast<_method_t>(id)); + } else { + const std::string &image = aMethod.image(); + theMessage.method = HttpRequestMethod(image.data(), + image.data() + image.size()); + } +} + +Ecap::RequestHeaderRep::Name +Ecap::RequestHeaderRep::method() const +{ + switch (theMessage.method.id()) { + case METHOD_GET: return libecap::methodGet; + case METHOD_POST: return libecap::methodPost; + case METHOD_PUT: return libecap::methodPut; + case METHOD_HEAD: return libecap::methodHead; + case METHOD_CONNECT: return libecap::methodConnect; + case METHOD_DELETE: return libecap::methodDelete; + case METHOD_TRACE: return libecap::methodTrace; + default: return Name(theMessage.method.image()); + } +} + + +/* ReplyHeaderRep */ + +Ecap::ReplyHeaderRep::ReplyHeaderRep(HttpReply &aMessage): + HeaderRep(aMessage), theMessage(aMessage) +{ +} + +void +Ecap::ReplyHeaderRep::statusCode(int code) +{ + // TODO: why is .status a enum? Do we not support unknown statuses? + theMessage.sline.status = static_cast(code); +} + +int +Ecap::ReplyHeaderRep::statusCode() const +{ + // TODO: see statusCode(code) TODO above + return static_cast(theMessage.sline.status); +} + +void +Ecap::ReplyHeaderRep::reasonPhrase(const Area &) +{ + // Squid does not support custom reason phrases + theMessage.sline.reason = NULL; +} + +Ecap::ReplyHeaderRep::Area +Ecap::ReplyHeaderRep::reasonPhrase() const +{ + return theMessage.sline.reason ? + Area::FromTempString(std::string(theMessage.sline.reason)) : Area(); +} + + +/* BodyRep */ + +Ecap::BodyRep::BodyRep(const BodyPipe::Pointer &aBody): theBody(aBody) +{ +} + +Ecap::BodyRep::BodySize +Ecap::BodyRep::bodySize() const +{ + return BodySize(theBody->bodySize()); +} + +Ecap::BodyRep::size_type +Ecap::BodyRep::consumedSize() const +{ + return theBody->consumedSize(); +} + +bool +Ecap::BodyRep::productionEnded() const +{ + return theBody->productionEnded(); +} + +void +Ecap::BodyRep::bodySize(const Ecap::BodyRep::BodySize &size) +{ + Must(size.known()); + theBody->setBodySize(size.value()); +} + +Ecap::BodyRep::size_type +Ecap::BodyRep::append(const Ecap::BodyRep::Area &area) +{ + return theBody->putMoreData(area.start, area.size); +} + +Ecap::BodyRep::Area +Ecap::BodyRep::prefix(Ecap::BodyRep::size_type size) const +{ + Must(size <= static_cast(theBody->buf().contentSize())); + // XXX: optimize by making theBody a shared_ptr (see FromTemp*() src) + return Area::FromTempBuffer(theBody->buf().content(), size); +} + +void +Ecap::BodyRep::consume(Ecap::BodyRep::size_type size) +{ + theBody->consume(size); +} + + +/* MessageRep */ + +Ecap::MessageRep::MessageRep(Adaptation::Message &aMessage, + Ecap::XactionRep *aXaction): + theMessage(aMessage), theXaction(aXaction), + theHeaderRep(NULL), theBodyRep(NULL) +{ + Must(theMessage.header); // we do not want to represent a missing message + + if (HttpRequest *req = dynamic_cast(theMessage.header)) + theHeaderRep = new RequestHeaderRep(*req); + else + if (HttpReply *rep = dynamic_cast(theMessage.header)) + theHeaderRep = new ReplyHeaderRep(*rep); + else + Must(false); // unknown message header type + + if (theMessage.body_pipe != NULL) + theBodyRep = new BodyRep(theMessage.body_pipe); +} + +Ecap::MessageRep::~MessageRep() +{ + delete theHeaderRep; +} + +libecap::Header & +Ecap::MessageRep::header() +{ + return *theHeaderRep; +} + +const libecap::Header & +Ecap::MessageRep::header() const +{ + return *theHeaderRep; +} + +libecap::Body * +Ecap::MessageRep::body() +{ + return theBodyRep; +} + +void +Ecap::MessageRep::addBody() +{ + Must(theXaction); + Must(!theBodyRep); + Must(!theMessage.body_pipe); + theMessage.body_pipe = new BodyPipe(theXaction); + theBodyRep = new BodyRep(theMessage.body_pipe); +} + +const libecap::Body *Ecap::MessageRep::body() const +{ + return theBodyRep; +} diff --git a/src/eCAP/MessageRep.h b/src/eCAP/MessageRep.h index 374c6d31b5..c2532583cf 100644 --- a/src/eCAP/MessageRep.h +++ b/src/eCAP/MessageRep.h @@ -8,18 +8,126 @@ #include "adaptation/forward.h" #include +#include +#include namespace Ecap { +class XactionRep; + +// Translates Squid HttpMsg into libecap::Header. +class HeaderRep: public libecap::Header +{ +public: + typedef libecap::Name Name; + typedef libecap::Area Area; + +public: + HeaderRep(HttpMsg &aMessage); + + virtual bool hasAny(const Name &name) const; + virtual Value value(const Name &name) const; + + virtual void add(const Name &name, const Value &value); + virtual void removeAny(const Name &name); + + virtual Area image() const; + virtual void parse(const Area &buf); // throws on failures + + virtual libecap::Version version() const; + virtual void version(const libecap::Version &aVersion); + virtual Name protocol() const; + virtual void protocol(const Name &aProtocol); + +protected: + static http_hdr_type TranslateHeaderId(const Name &name); + static protocol_t TranslateProtocolId(const Name &name); + +private: + HttpHeader &theHeader; // the header being translated to libecap + HttpMsg &theMessage; // the message being translated to libecap +}; + + +// Translates Squid HttpRequest into libecap::Header + libecap::RequestLine. +class RequestHeaderRep: public HeaderRep, public libecap::RequestLine +{ +public: + RequestHeaderRep(HttpRequest &aMessage); + + virtual void uri(const Area &aUri); + virtual Area uri() const; + + virtual void method(const Name &aMethod); + virtual Name method() const; + +private: + HttpRequest &theMessage; // the request header being translated to libecap +}; + +// Translates Squid HttpReply into libecap::Header + libecap::StatusLine. +class ReplyHeaderRep: public HeaderRep, public libecap::StatusLine +{ +public: + ReplyHeaderRep(HttpReply &aMessage); + + virtual void statusCode(int code); + virtual int statusCode() const; + + virtual void reasonPhrase(const Area &phrase); + virtual Area reasonPhrase() const; + +private: + HttpReply &theMessage; // the request header being translated to libecap +}; + + +// Translates Squid HttpMsg into libecap::Body. +class BodyRep: public libecap::Body +{ +public: + typedef libecap::Area Area; + typedef libecap::BodySize BodySize; + +public: + BodyRep(const BodyPipe::Pointer &aBody); + + // stats + virtual BodySize bodySize() const; + virtual size_type consumedSize() const; + virtual bool productionEnded() const; // producedSize will not grow + + // called by producers + virtual void bodySize(const BodySize &size); // throws if already ! + virtual size_type append(const Area &area); // throws on overflow + + // called by consumers + virtual Area prefix(size_type size) const; + virtual void consume(size_type size); + +private: + BodyPipe::Pointer theBody; // the body being translated to libecap +}; + // Translates Squid Adaptation::Message into libecap::Message. class MessageRep: public libecap::Message { - public: - MessageRep(Adaptation::Message &aMessage): theMessage(aMessage) {} + MessageRep(Adaptation::Message &aMessage, Ecap::XactionRep *aXaction); + virtual ~MessageRep(); + + virtual libecap::Header &header(); + virtual const libecap::Header &header() const; + + virtual void addBody(); + virtual libecap::Body *body(); + virtual const libecap::Body *body() const; private: Adaptation::Message &theMessage; // the message being translated to libecap + Ecap::XactionRep *theXaction; // host transaction managing the translation + HeaderRep *theHeaderRep; + BodyRep *theBodyRep; }; } // namespace Ecap;