]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Implemented libecap::Message-related wrappers for Squid HttpRequest and
authorAlex Rousskov <rousskov@measurement-factory.com>
Fri, 16 May 2008 00:35:59 +0000 (18:35 -0600)
committerAlex Rousskov <rousskov@measurement-factory.com>
Fri, 16 May 2008 00:35:59 +0000 (18:35 -0600)
HttpResponse. TODO: split the file into a few files to simplify presentation?

src/eCAP/MessageRep.cc
src/eCAP/MessageRep.h

index e808c347f808b3d57d6e9261c8a335f4e8e24430..b5fab20e388a57959d1ab5b60a9905e113a28c08 100644 (file)
@@ -3,6 +3,353 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
+#include "HttpReply.h"
+#include "BodyPipe.h"
+#include "TextException.h"
 #include "adaptation/Message.h"
+#include <libecap/common/names.h>
+#include <libecap/common/area.h>
+#include <libecap/common/version.h>
 #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<http_hdr_type>(name.hostId());
+    return HDR_OTHER;
+}
+
+protocol_t
+Ecap::HeaderRep::TranslateProtocolId(const Name &name)
+{
+    if (name.assignedHostId())
+        return static_cast<protocol_t>(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<http_status>(code);
+}
+
+int
+Ecap::ReplyHeaderRep::statusCode() const
+{
+    // TODO: see statusCode(code) TODO above
+    return static_cast<int>(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<size_type>(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<HttpRequest*>(theMessage.header))
+        theHeaderRep = new RequestHeaderRep(*req);
+    else
+    if (HttpReply *rep = dynamic_cast<HttpReply*>(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;
+}
index 374c6d31b576d8b371769d7220a6fe50986e3266..c2532583cfead03abf343c409e9b3b82259924c3 100644 (file)
 
 #include "adaptation/forward.h"
 #include <libecap/common/message.h>
+#include <libecap/common/header.h>
+#include <libecap/common/body.h>
 
 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;