#pragma once
#include "httpagent.h"
#include "httpparser.h"
#include "http_digest.h"
#include <util/system/compat.h>
#include <util/string/vector.h>
#include <util/network/ip.h>
#include <library/cpp/uri/http_url.h>
#include <library/cpp/http/misc/httpcodes.h>
/********************************************************/
// 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<TSocketHandlerPtr>;
/********************************************************/
// 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<TString> 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;
}
};
/********************************************************/