#pragma once #include "httpagent.h" #include "httpparser.h" #include "http_digest.h" #include #include #include #include #include /********************************************************/ // Section 1: socket handlers /********************************************************/ // The following classes allows to adopt template scheme // THttpAgent for work with socket by flexible // object-style scheme. /********************************************************/ // This class is used as a base one for flexible // socket handling class socketAbstractHandler { public: virtual bool Good() = 0; virtual int Connect(const TAddrList& addrs, TDuration Timeout) = 0; virtual void Disconnect() = 0; virtual void shutdown() = 0; virtual bool send(const char* message, ssize_t messlen) = 0; virtual bool peek() = 0; virtual ssize_t read(void* buffer, ssize_t buflen) = 0; virtual ~socketAbstractHandler() { } protected: socketAbstractHandler() { } }; /********************************************************/ // This class is used as a proxy between THttpAgent and // socketAbstractHandler // (it is used by template scheme, // so it does not have virtual methods) class TSocketHandlerPtr { protected: socketAbstractHandler* Handler_; public: TSocketHandlerPtr() : Handler_(nullptr) { } virtual ~TSocketHandlerPtr() { delete Handler_; } int Good() { return (Handler_ && Handler_->Good()); } int Connect(const TAddrList& addrs, TDuration Timeout) { return (Handler_) ? Handler_->Connect(addrs, Timeout) : 1; } void Disconnect() { if (Handler_) Handler_->Disconnect(); } void shutdown() { if (Handler_) Handler_->shutdown(); } bool send(const char* message, ssize_t messlen) { return (Handler_) ? Handler_->send(message, messlen) : false; } virtual bool peek() { return (Handler_) ? Handler_->peek() : false; } virtual ssize_t read(void* buffer, ssize_t buflen) { return (Handler_) ? Handler_->read(buffer, buflen) : 0; } void setHandler(socketAbstractHandler* handler) { if (Handler_) delete Handler_; Handler_ = handler; } }; /********************************************************/ // Here is httpAgent that uses socketAbstractHandler class // ant its derivatives using httpSpecialAgent = THttpAgent; /********************************************************/ // Regular handler is used as implementation of // socketAbstractHandler for work through HTTP protocol class socketRegularHandler: public socketAbstractHandler { protected: TSimpleSocketHandler Socket_; public: socketRegularHandler() : Socket_() { } bool Good() override { return Socket_.Good(); } int Connect(const TAddrList& addrs, TDuration Timeout) override { return Socket_.Connect(addrs, Timeout); } void Disconnect() override { Socket_.Disconnect(); } void shutdown() override { //Do not block writing to socket //There are servers that works in a bad way with this //mSocket.shutdown(); } bool send(const char* message, ssize_t messlen) override { return Socket_.send(message, messlen); } bool peek() override { return Socket_.peek(); } ssize_t read(void* buffer, ssize_t buflen) override { return Socket_.read(buffer, buflen); } }; /********************************************************/ // The base factory that allows to choose an appropriate // socketAbstractHandler implementation by url schema class socketHandlerFactory { public: virtual ~socketHandlerFactory() { } //returns mHandler_HTTP for correct HTTP-based url virtual socketAbstractHandler* chooseHandler(const THttpURL& url); static socketHandlerFactory sInstance; }; /********************************************************/ // Section 2: the configurates tool to parse an HTTP-response /********************************************************/ class httpAgentReader: public THttpParserGeneric<1> { protected: THttpAuthHeader Header_; httpSpecialAgent& Agent_; char* Buffer_; void* BufPtr_; int BufSize_; long BufRest_; void readBuf(); bool step() { if (BufRest_ == 0) readBuf(); if (eof()) return false; return true; } public: httpAgentReader(httpSpecialAgent& agent, const char* baseUrl, bool assumeConnectionClosed, bool use_auth = false, int bufSize = 0x1000); ~httpAgentReader(); bool eof() { return BufRest_ < 0; } int error() { return Header_.error; } void setError(int errCode) { Header_.error = errCode; } const THttpAuthHeader* getAuthHeader() { return &Header_; } const THttpHeader* readHeader(); long readPortion(void*& buf); bool skipTheRest(); }; /********************************************************/ // Section 3: the main class /********************************************************/ class httpLoadAgent: public httpSpecialAgent { protected: socketHandlerFactory& Factory_; bool HandleAuthorization_; THttpURL URL_; bool PersistentConn_; httpAgentReader* Reader_; TVector Headers_; int ErrCode_; char* RealHost_; httpDigestHandler Digest_; void clearReader(); bool doSetHost(const TAddrList& addrs); bool doStartRequest(); public: httpLoadAgent(bool handleAuthorization = false, socketHandlerFactory& factory = socketHandlerFactory::sInstance); ~httpLoadAgent(); void setRealHost(const char* host); void setIMS(const char* ifModifiedSince); void addHeaderInstruction(const char* instr); void dropHeaderInstructions(); bool startRequest(const char* url, const char* url_to_merge = nullptr, bool persistent = false, const TAddrList& addrs = TAddrList()); // deprecated v4-only bool startRequest(const char* url, const char* url_to_merge, bool persistent, ui32 ip); bool startRequest(const THttpURL& url, bool persistent = false, const TAddrList& addrs = TAddrList()); bool setHost(const char* host_url, const TAddrList& addrs = TAddrList()); bool startOneRequest(const char* local_url); const THttpAuthHeader* getAuthHeader() { if (Reader_ && Reader_->getAuthHeader()->use_auth) return Reader_->getAuthHeader(); return nullptr; } const THttpHeader* getHeader() { if (Reader_) return Reader_->getAuthHeader(); return nullptr; } const THttpURL& getURL() { return URL_; } bool eof() { if (Reader_) return Reader_->eof(); return true; } int error() { if (ErrCode_) return ErrCode_; if (Reader_) return Reader_->error(); return HTTP_BAD_URL; } long readPortion(void*& buf) { if (Reader_) return Reader_->readPortion(buf); return -1; } }; /********************************************************/