enet/enet/Http.cpp

729 lines
25 KiB
C++

/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
*/
#include <enet/debug.h>
#include <enet/Http.h>
#include <map>
#include <etk/stdTools.h>
#include <string.h>
#include <unistd.h>
static std::string escapeChar(const std::string& _value) {
return _value;
}
static std::string unEscapeChar(const std::string& _value) {
return _value;
}
static std::string removeStartAndStopSpace(const std::string& _value) {
std::string out;
out.reserve(_value.size());
bool findSpace = false;
for (auto &it : _value) {
if (it != ' ') {
if ( findSpace == true
&& out.size() != 0) {
out += ' ';
}
out += it;
findSpace = false;
} else {
findSpace = true;
}
}
return out;
}
static std::map<enet::HTTPAnswerCode, std::string> protocolName = {
{enet::HTTPAnswerCode::c100_continue, "Continue"},
{enet::HTTPAnswerCode::c101_switchingProtocols, "Switching Protocols"},
{enet::HTTPAnswerCode::c103_checkpoint, "Checkpoint"},
{enet::HTTPAnswerCode::c200_ok, "OK"},
{enet::HTTPAnswerCode::c201_created, "Created"},
{enet::HTTPAnswerCode::c202_accepted, "Accepted"},
{enet::HTTPAnswerCode::c203_nonAuthoritativeInformation, "Non-Authoritative Information"},
{enet::HTTPAnswerCode::c204_noContent, "No Content"},
{enet::HTTPAnswerCode::c205_resetContent, "Reset Content"},
{enet::HTTPAnswerCode::c206_partialContent, "Partial Content"},
{enet::HTTPAnswerCode::c300_multipleChoices, "Multiple Choices"},
{enet::HTTPAnswerCode::c301_movedPermanently, "Moved Permanently"},
{enet::HTTPAnswerCode::c302_found, "Found"},
{enet::HTTPAnswerCode::c303_seeOther, "See Other"},
{enet::HTTPAnswerCode::c304_notModified, "Not Modified"},
{enet::HTTPAnswerCode::c306_switchProxy, "Switch Proxy"},
{enet::HTTPAnswerCode::c307_temporaryRedirect, "Temporary Redirect"},
{enet::HTTPAnswerCode::c308_resumeIncomplete, "Resume Incomplete"},
{enet::HTTPAnswerCode::c400_badRequest, "Bad Request"},
{enet::HTTPAnswerCode::c401_unauthorized, "Unauthorized"},
{enet::HTTPAnswerCode::c402_paymentRequired, "Payment Required"},
{enet::HTTPAnswerCode::c403_forbidden, "Forbidden"},
{enet::HTTPAnswerCode::c404_notFound, "Not Found"},
{enet::HTTPAnswerCode::c405_methodNotAllowed, "Method Not Allowed"},
{enet::HTTPAnswerCode::c406_notAcceptable, "Not Acceptable"},
{enet::HTTPAnswerCode::c407_proxyAuthenticationRequired, "Proxy Authentication Required"},
{enet::HTTPAnswerCode::c408_requestTimeout, "Request Timeout"},
{enet::HTTPAnswerCode::c409_conflict, "Conflict"},
{enet::HTTPAnswerCode::c410_gone, "Gone"},
{enet::HTTPAnswerCode::c411_lengthRequired, "Length Required"},
{enet::HTTPAnswerCode::c412_preconditionFailed, "Precondition Failed"},
{enet::HTTPAnswerCode::c413_requestEntityTooLarge, "Request Entity Too Large"},
{enet::HTTPAnswerCode::c414_requestURITooLong, "Request-URI Too Long"},
{enet::HTTPAnswerCode::c415_unsupportedMediaType, "Unsupported Media Type"},
{enet::HTTPAnswerCode::c416_requestedRangeNotSatisfiable, "Requested Range Not Satisfiable"},
{enet::HTTPAnswerCode::c417_expectationFailed, "Expectation Failed"},
{enet::HTTPAnswerCode::c500_internalServerError, "Internal Server Error"},
{enet::HTTPAnswerCode::c501_notImplemented, "Not Implemented"},
{enet::HTTPAnswerCode::c502_badGateway, "Bad Gateway"},
{enet::HTTPAnswerCode::c503_serviceUnavailable, "Service Unavailable"},
{enet::HTTPAnswerCode::c504_gatewayTimeout, "Gateway Timeout"},
{enet::HTTPAnswerCode::c505_httpVersionNotSupported, "HTTP Version Not Supported"},
{enet::HTTPAnswerCode::c511_networkAuthenticationRequired, "Network Authentication Required"}
};
static std::map<int32_t, std::string> getErrorList() {
static std::map<int32_t, std::string> g_list;
return g_list;
}
enet::Http::Http(enet::Tcp _connection, bool _isServer) :
m_isServer(_isServer),
m_connection(std::move(_connection)),
m_headerIsSend(false),
m_thread(nullptr),
m_threadRunning(false) {
//setSendHeaderProperties("User-Agent", "e-net (ewol network interface)");
/*
if (m_keepAlive == true) {
setSendHeaderProperties("Connection", "Keep-Alive");
}
*/
}
enet::Http::~Http() {
stop();
}
void enet::Http::threadCallback() {
ENET_DEBUG("Start of thread HTTP");
ethread::setName("TcpString-input");
// get datas:
while ( m_threadRunning == true
&& m_connection.getConnectionStatus() == enet::Tcp::status::link) {
// READ section data:
if (m_headerIsSend == false) {
getHeader();
m_headerIsSend = true;
}
if (m_observerRaw != nullptr) {
m_observerRaw(m_connection);
} else {
m_temporaryBuffer.resize(67000);
int32_t len = m_connection.read(&m_temporaryBuffer[0], m_temporaryBuffer.size());
if (len > 0) {
ENET_INFO("Call client with datas ...");
if (m_observer != nullptr) {
m_observer(m_temporaryBuffer);
}
}
}
}
m_threadRunning = false;
ENET_DEBUG("End of thread HTTP");
}
void enet::Http::start() {
ENET_DEBUG("connect [START]");
m_threadRunning = true;
m_thread = new std::thread([&](void *){ this->threadCallback();}, nullptr);
if (m_thread == nullptr) {
m_threadRunning = false;
ENET_ERROR("creating callback thread!");
return;
}
while ( m_threadRunning == true
&& m_connection.getConnectionStatus() != enet::Tcp::status::link) {
usleep(50000);
}
//ethread::setPriority(*m_receiveThread, -6);
ENET_DEBUG("connect [STOP]");
}
void enet::Http::stop(bool _inThreadStop){
ENET_DEBUG("disconnect [START]");
m_threadRunning = false;
/*
if (m_connection.getConnectionStatus() == enet::Tcp::status::link) {
uint32_t size = 0xFFFFFFFF;
m_connection.write(&size, 4);
}
*/
if (m_connection.getConnectionStatus() != enet::Tcp::status::unlink) {
m_connection.unlink();
}
if (_inThreadStop == false) {
if (m_thread != nullptr) {
m_thread->join();
delete m_thread;
m_thread = nullptr;
}
}
ENET_DEBUG("disconnect [STOP]");
}
/*
void enet::Http::writeAnswerHeader(enum enet::HTTPAnswerCode _value) {
std::string out;
out = "HTTP/1.1 ";
out += etk::to_string(int32_t(_value));
auto it = protocolName.find(_value);
if (it == protocolName.end() ) {
out += " ???";
} else {
out += " " + it->second;
}
out += "\r\n\r\n";
ENET_WARNING("Write header :" << out);
write(out, false);
}
*/
namespace etk {
template <>
bool from_string<enum enet::HTTPAnswerCode>(enum enet::HTTPAnswerCode& _variableRet, const std::string& _value) {
_variableRet = enet::HTTPAnswerCode::c000_unknow;
for (auto &it : protocolName) {
if (etk::to_string(int32_t(it.first)) == _value) {
_variableRet = it.first;
return true;
}
}
return false;
}
template <>
std::string to_string<enum enet::HTTPAnswerCode>(const enum enet::HTTPAnswerCode& _value) {
return etk::to_string(int32_t(_value));
}
template <>
bool from_string<enum enet::HTTPReqType>(enum enet::HTTPReqType& _variableRet, const std::string& _value) {
_variableRet = enet::HTTPReqType::GET;
if (_value == "GET") {
_variableRet = enet::HTTPReqType::GET;
return true;
} else if (_value == "HEAD") {
_variableRet = enet::HTTPReqType::HEAD;
return true;
} else if (_value == "POST") {
_variableRet = enet::HTTPReqType::POST;
return true;
} else if (_value == "PUT") {
_variableRet = enet::HTTPReqType::PUT;
return true;
} else if (_value == "DELETE") {
_variableRet = enet::HTTPReqType::DELETE;
return true;
}
return false;
}
template <>
std::string to_string<enum enet::HTTPReqType>(const enum enet::HTTPReqType& _value) {
switch (_value) {
case enet::HTTPReqType::GET: return "GET";
case enet::HTTPReqType::HEAD: return "HEAD";
case enet::HTTPReqType::POST: return "POST";
case enet::HTTPReqType::PUT: return "PUT";
case enet::HTTPReqType::DELETE: return "DELETE";
}
return "UNKNOW";
}
template <>
bool from_string<enum enet::HTTPProtocol>(enum enet::HTTPProtocol& _variableRet, const std::string& _value) {
_variableRet = enet::HTTPProtocol::http_0_1;
if (_value == "HTTP/0.1") { _variableRet = enet::HTTPProtocol::http_0_1; return true; }
if (_value == "HTTP/0.2") { _variableRet = enet::HTTPProtocol::http_0_2; return true; }
if (_value == "HTTP/0.3") { _variableRet = enet::HTTPProtocol::http_0_3; return true; }
if (_value == "HTTP/0.4") { _variableRet = enet::HTTPProtocol::http_0_4; return true; }
if (_value == "HTTP/0.5") { _variableRet = enet::HTTPProtocol::http_0_5; return true; }
if (_value == "HTTP/0.6") { _variableRet = enet::HTTPProtocol::http_0_6; return true; }
if (_value == "HTTP/0.7") { _variableRet = enet::HTTPProtocol::http_0_7; return true; }
if (_value == "HTTP/0.8") { _variableRet = enet::HTTPProtocol::http_0_8; return true; }
if (_value == "HTTP/0.9") { _variableRet = enet::HTTPProtocol::http_0_9; return true; }
if (_value == "HTTP/0.10") { _variableRet = enet::HTTPProtocol::http_0_10; return true; }
if (_value == "HTTP/1.0") { _variableRet = enet::HTTPProtocol::http_1_0; return true; }
if (_value == "HTTP/1.1") { _variableRet = enet::HTTPProtocol::http_1_1; return true; }
if (_value == "HTTP/1.2") { _variableRet = enet::HTTPProtocol::http_1_2; return true; }
if (_value == "HTTP/1.3") { _variableRet = enet::HTTPProtocol::http_1_3; return true; }
if (_value == "HTTP/1.4") { _variableRet = enet::HTTPProtocol::http_1_4; return true; }
if (_value == "HTTP/1.5") { _variableRet = enet::HTTPProtocol::http_1_5; return true; }
if (_value == "HTTP/1.6") { _variableRet = enet::HTTPProtocol::http_1_6; return true; }
if (_value == "HTTP/1.7") { _variableRet = enet::HTTPProtocol::http_1_7; return true; }
if (_value == "HTTP/1.8") { _variableRet = enet::HTTPProtocol::http_1_8; return true; }
if (_value == "HTTP/1.9") { _variableRet = enet::HTTPProtocol::http_1_9; return true; }
if (_value == "HTTP/1.10") { _variableRet = enet::HTTPProtocol::http_1_10; return true; }
if (_value == "HTTP/2.0") { _variableRet = enet::HTTPProtocol::http_2_0; return true; }
if (_value == "HTTP/2.1") { _variableRet = enet::HTTPProtocol::http_2_1; return true; }
if (_value == "HTTP/2.2") { _variableRet = enet::HTTPProtocol::http_2_2; return true; }
if (_value == "HTTP/2.3") { _variableRet = enet::HTTPProtocol::http_2_3; return true; }
if (_value == "HTTP/2.4") { _variableRet = enet::HTTPProtocol::http_2_4; return true; }
if (_value == "HTTP/2.5") { _variableRet = enet::HTTPProtocol::http_2_5; return true; }
if (_value == "HTTP/2.6") { _variableRet = enet::HTTPProtocol::http_2_6; return true; }
if (_value == "HTTP/2.7") { _variableRet = enet::HTTPProtocol::http_2_7; return true; }
if (_value == "HTTP/2.8") { _variableRet = enet::HTTPProtocol::http_2_8; return true; }
if (_value == "HTTP/2.9") { _variableRet = enet::HTTPProtocol::http_2_9; return true; }
if (_value == "HTTP/2.10") { _variableRet = enet::HTTPProtocol::http_2_10; return true; }
if (_value == "HTTP/3.0") { _variableRet = enet::HTTPProtocol::http_3_0; return true; }
if (_value == "HTTP/3.1") { _variableRet = enet::HTTPProtocol::http_3_1; return true; }
if (_value == "HTTP/3.2") { _variableRet = enet::HTTPProtocol::http_3_2; return true; }
if (_value == "HTTP/3.3") { _variableRet = enet::HTTPProtocol::http_3_3; return true; }
if (_value == "HTTP/3.4") { _variableRet = enet::HTTPProtocol::http_3_4; return true; }
if (_value == "HTTP/3.5") { _variableRet = enet::HTTPProtocol::http_3_5; return true; }
if (_value == "HTTP/3.6") { _variableRet = enet::HTTPProtocol::http_3_6; return true; }
if (_value == "HTTP/3.7") { _variableRet = enet::HTTPProtocol::http_3_7; return true; }
if (_value == "HTTP/3.8") { _variableRet = enet::HTTPProtocol::http_3_8; return true; }
if (_value == "HTTP/3.9") { _variableRet = enet::HTTPProtocol::http_3_9; return true; }
if (_value == "HTTP/3.10") { _variableRet = enet::HTTPProtocol::http_3_10; return true; }
return false;
}
template <>
std::string to_string<enum enet::HTTPProtocol>(const enum enet::HTTPProtocol& _value) {
switch (_value) {
case enet::HTTPProtocol::http_0_1: return "HTTP/0.1";
case enet::HTTPProtocol::http_0_2: return "HTTP/0.2";
case enet::HTTPProtocol::http_0_3: return "HTTP/0.3";
case enet::HTTPProtocol::http_0_4: return "HTTP/0.4";
case enet::HTTPProtocol::http_0_5: return "HTTP/0.5";
case enet::HTTPProtocol::http_0_6: return "HTTP/0.6";
case enet::HTTPProtocol::http_0_7: return "HTTP/0.7";
case enet::HTTPProtocol::http_0_8: return "HTTP/0.8";
case enet::HTTPProtocol::http_0_9: return "HTTP/0.9";
case enet::HTTPProtocol::http_0_10: return "HTTP/0.10";
case enet::HTTPProtocol::http_1_0: return "HTTP/1.0";
case enet::HTTPProtocol::http_1_1: return "HTTP/1.1";
case enet::HTTPProtocol::http_1_2: return "HTTP/1.2";
case enet::HTTPProtocol::http_1_3: return "HTTP/1.3";
case enet::HTTPProtocol::http_1_4: return "HTTP/1.4";
case enet::HTTPProtocol::http_1_5: return "HTTP/1.5";
case enet::HTTPProtocol::http_1_6: return "HTTP/1.6";
case enet::HTTPProtocol::http_1_7: return "HTTP/1.7";
case enet::HTTPProtocol::http_1_8: return "HTTP/1.8";
case enet::HTTPProtocol::http_1_9: return "HTTP/1.9";
case enet::HTTPProtocol::http_1_10: return "HTTP/1.10";
case enet::HTTPProtocol::http_2_0: return "HTTP/2.0";
case enet::HTTPProtocol::http_2_1: return "HTTP/2.1";
case enet::HTTPProtocol::http_2_2: return "HTTP/2.2";
case enet::HTTPProtocol::http_2_3: return "HTTP/2.3";
case enet::HTTPProtocol::http_2_4: return "HTTP/2.4";
case enet::HTTPProtocol::http_2_5: return "HTTP/2.5";
case enet::HTTPProtocol::http_2_6: return "HTTP/2.6";
case enet::HTTPProtocol::http_2_7: return "HTTP/2.7";
case enet::HTTPProtocol::http_2_8: return "HTTP/2.8";
case enet::HTTPProtocol::http_2_9: return "HTTP/2.9";
case enet::HTTPProtocol::http_2_10: return "HTTP/2.10";
case enet::HTTPProtocol::http_3_0: return "HTTP/3.0";
case enet::HTTPProtocol::http_3_1: return "HTTP/3.1";
case enet::HTTPProtocol::http_3_2: return "HTTP/3.2";
case enet::HTTPProtocol::http_3_3: return "HTTP/3.3";
case enet::HTTPProtocol::http_3_4: return "HTTP/3.4";
case enet::HTTPProtocol::http_3_5: return "HTTP/3.5";
case enet::HTTPProtocol::http_3_6: return "HTTP/3.6";
case enet::HTTPProtocol::http_3_7: return "HTTP/3.7";
case enet::HTTPProtocol::http_3_8: return "HTTP/3.8";
case enet::HTTPProtocol::http_3_9: return "HTTP/3.9";
case enet::HTTPProtocol::http_3_10: return "HTTP/3.10";
}
return "HTTP/0.1";
}
}
void enet::Http::setRequestHeader(const enet::HttpRequest& _req) {
m_requestHeader = _req;
if (m_requestHeader.getKey("User-Agent") == "") {
m_requestHeader.setKey("User-Agent", "e-net (ewol network interface)");
}
std::string value = m_requestHeader.generate();
write(value, false);
}
void enet::Http::setAnswerHeader(const enet::HttpAnswer& _req) {
m_answerHeader = _req;
if (m_requestHeader.getKey("User-Agent") == "") {
m_requestHeader.setKey("User-Agent", "e-net (ewol network interface)");
}
std::string value = m_answerHeader.generate();
write(value, false);
}
void enet::Http::getHeader() {
ENET_VERBOSE("Read HTTP Header [START]");
bool headerEnded = false;
std::string header;
while (m_connection.getConnectionStatus() == enet::Tcp::status::link) {
char type;
int32_t len = m_connection.read(&type, 1);
if (len == 0) {
usleep(1);
continue;
}
header += type;
if ( header.size() > 4
&& header[header.size()-1] == '\n'
&& header[header.size()-2] == '\r'
&& header[header.size()-3] == '\n'
&& header[header.size()-4] == '\r') {
// Normal end case ...
break;
} else if ( header.size() > 2
&& header[header.size()-1] == '\n'
&& header[header.size()-2] == '\n') {
// linux end case
break;
} else if ( header.size() > 2
&& header[header.size()-1] == '\r'
&& header[header.size()-2] == '\r') {
// Mac end case
break;
}
}
if (m_connection.getConnectionStatus() != enet::Tcp::status::link) {
ENET_ERROR("Read HTTP Header [STOP] : '" << header << "' ==> status move in unlink ...");
return;
}
ENET_VERBOSE("Read HTTP Header [STOP] : '" << header << "'");
m_headerIsSend = true;
// parse header :
std::vector<std::string> list = etk::split(header, '\n');
for (auto &it : list) {
if ( it.size()>0
&& it[it.size()-1] == '\r') {
it.resize(it.size()-1);
}
}
//parse first element:
std::vector<std::string> listLineOne = etk::split(list[0], ' ');
if (listLineOne.size() < 2) {
ENET_ERROR("can not parse answear : " << listLineOne);
// answer bad request and close connection ...
return;
}
if ( listLineOne.size() >= 3
&& ( listLineOne[0] == "GET"
|| listLineOne[0] == "POST"
|| listLineOne[0] == "HEAD"
|| listLineOne[0] == "DELETE"
|| listLineOne[0] == "PUT" ) ) {
// HTTP CALL
if (m_isServer == false) {
// can not have call in client mode
ENET_ERROR("can not parse call in client mode ..." << listLineOne);
m_answerHeader.setErrorCode(enet::HTTPAnswerCode::c400_badRequest);
m_answerHeader.setHelp("Call a client with a request from server ...");
setAnswerHeader(m_answerHeader);
stop(true);
return;
}
// get type call:
enum enet::HTTPReqType valueType;
etk::from_string(valueType, listLineOne[0]);
m_requestHeader.setType(valueType);
// get URI:
m_requestHeader.setUri(listLineOne[1]);
// Get http version:
enum enet::HTTPProtocol valueProtocol;
etk::from_string(valueProtocol, listLineOne[2]);
m_requestHeader.setProtocol(valueProtocol);
} else if ( listLineOne.size() >= 3
&& etk::start_with(listLineOne[0],"HTTP/") == true) {
// HTTP answer
if (m_isServer == true) {
// can not have anser ==> need to be a get ot something like this ...
ENET_ERROR("can not parse answer in server mode ..." << listLineOne);
m_answerHeader.setErrorCode(enet::HTTPAnswerCode::c400_badRequest);
m_answerHeader.setHelp("Call a client with a request from server ...");
setAnswerHeader(m_answerHeader);
stop(true);
return;
}
// Get http version:
enum enet::HTTPProtocol valueProtocol;
etk::from_string(valueProtocol, listLineOne[0]);
m_answerHeader.setProtocol(valueProtocol);
enum HTTPAnswerCode valueErrorCode;
etk::from_string(valueErrorCode, listLineOne[1]);
m_answerHeader.setErrorCode(valueErrorCode);
// get comment:
std::string comment;
for (size_t iii=2; iii<listLineOne.size(); ++iii) {
if (comment.size() != 0) {
comment += " ";
}
comment += listLineOne[iii];
}
m_answerHeader.setHelp(comment);
} else {
// can not have anser ==> need to be a get ot something like this ...
ENET_ERROR("Un understand message ..." << listLineOne);
m_answerHeader.setErrorCode(enet::HTTPAnswerCode::c400_badRequest);
m_answerHeader.setHelp("Un understand message ...");
setAnswerHeader(m_answerHeader);
stop(true);
return;
}
for (size_t iii=1; iii<list.size(); ++iii) {
size_t found = list[iii].find(":");
if (found == std::string::npos) {
// nothing
continue;
}
std::string key = unEscapeChar(std::string(list[iii], 0, found));
key = removeStartAndStopSpace(key);
std::string value = unEscapeChar(std::string(list[iii], found+2));
value = removeStartAndStopSpace(value);
ENET_VERBOSE("header : key='" << key << "' value='" << value << "'");
if (m_isServer == false) {
m_answerHeader.setKey(key,value);
} else {
m_requestHeader.setKey(key,value);
}
if ( key == "Connection"
&& value == "close") {
ENET_DEBUG("connection closed by remote :");
m_connection.unlink();
}
}
if (m_isServer == false) {
if (m_observerAnswer != nullptr) {
m_observerAnswer(m_answerHeader);
}
} else {
if (m_observerRequest != nullptr) {
m_observerRequest(m_requestHeader);
}
}
}
/*
bool enet::Http::get(const std::string& _address) {
m_header.m_map.clear();
std::string req = "GET http://" + m_connection.getName();
if (_address != "") {
req += "/";
req += _address;
}
req += " HTTP/1.1\r\n";
setSendHeaderProperties("Content-Length", "0");
// add header properties :
for (auto &it : m_header.m_map) {
req += escapeChar(it.first) + ": " + escapeChar(it.second) + "\r\n";
}
// end of header
req += "\r\n";
// no body:
int32_t len = m_connection.write(req, false);
ENET_VERBOSE("read write=" << len << " data: " << req);
if (len != req.size()) {
ENET_ERROR("An error occured when sending data " << len << "!=" << req.size());
return false;
}
//return receiveData();
return false;
}
bool enet::Http::post(const std::string& _address, const std::map<std::string, std::string>& _values) {
m_header.m_map.clear();
// First create body :
std::string body;
for (auto &it : _values) {
if (body.size() > 0) {
body += "&";
}
body += escapeChar(it.first) + "=" + escapeChar(it.second);
}
return post(_address, "application/x-www-form-urlencoded", body);
}
bool enet::Http::post(const std::string& _address, const std::string& _contentType, const std::string& _data) {
m_header.m_map.clear();
std::string req = "POST http://" + m_connection.getName();
if (_address != "") {
req += "/";
req += _address;
}
req += " HTTP/1.0\n";
setSendHeaderProperties("Content-Type", _contentType);
setSendHeaderProperties("Content-Length", etk::to_string(_data.size()));
// add header properties :
for (auto &it : m_header.m_map) {
req += escapeChar(it.first) + ": " + escapeChar(it.second) + "\r\n";
}
// end of header
req += "\n";
req += _data;
int32_t len = m_connection.write(req, false);
ENET_VERBOSE("read write=" << len << " data: " << req);
if (len != req.size()) {
ENET_ERROR("An error occured when sending data " << len << "!=" << req.size());
return false;
}
//return receiveData();
return false;
}
*/
int32_t enet::Http::write(const void* _data, int32_t _len) {
return m_connection.write(_data, _len);
}
void enet::HttpHeader::setKey(const std::string& _key, const std::string& _value) {
auto it = m_map.find(_key);
if (it == m_map.end()) {
m_map.insert(make_pair(_key, _value));
} else {
it->second = _value;
}
}
void enet::HttpHeader::rmKey(const std::string& _key) {
auto it = m_map.find(_key);
if (it != m_map.end()) {
m_map.erase(it);
}
}
std::string enet::HttpHeader::getKey(const std::string& _key) const {
auto it = m_map.find(_key);
if (it != m_map.end()) {
return it->second;
}
return "";
}
std::string enet::HttpHeader::generateKeys() const {
std::string out;
for (auto &it : m_map) {
if ( it.first != ""
&& it.second != "") {
out += escapeChar(it.first) + " : " + escapeChar(it.second) + "\r\n";
}
}
return out;
}
enet::HttpHeader::HttpHeader():
m_protocol(enet::HTTPProtocol::http_1_0) {
}
// -----------------------------------------------------------------------------------------
enet::HttpAnswer::HttpAnswer(enum HTTPAnswerCode _code, const std::string& _help):
m_what(_code),
m_helpMessage(_help) {
}
void enet::HttpAnswer::display() const {
ENET_PRINT("display header 'Answer' ");
ENET_PRINT(" protocol=" << m_protocol);
ENET_PRINT(" Code=" << int32_t(m_what));
ENET_PRINT(" message=" << m_helpMessage);
ENET_PRINT(" Options:");
for (auto &it : m_map) {
if ( it.first != ""
&& it.second != "") {
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
}
}
}
std::string enet::HttpAnswer::generate() const {
std::string out;
out += etk::to_string(m_protocol);
out += " ";
out += etk::to_string(int32_t(m_what));
out += " ";
if (m_helpMessage != "") {
out += escapeChar(m_helpMessage);
} else {
auto it = protocolName.find(m_what);
if (it != protocolName.end()) {
out += escapeChar(it->second);
} else {
out += "???";
}
}
out += "\r\n";
out += generateKeys();
out += "\r\n";
return out;
}
enet::HttpServer::HttpServer(enet::Tcp _connection) :
enet::Http(std::move(_connection), true) {
}
enet::HttpClient::HttpClient(enet::Tcp _connection) :
enet::Http(std::move(_connection), false) {
}
// -----------------------------------------------------------------------------------------
enet::HttpRequest::HttpRequest(enum enet::HTTPReqType _type):
m_req(_type),
m_uri() {
}
void enet::HttpRequest::display() const {
ENET_PRINT("display header 'Request' ");
ENET_PRINT(" type=" << m_req);
ENET_PRINT(" protocol=" << m_protocol);
ENET_PRINT(" uri=" << m_uri);
ENET_PRINT(" Options:");
for (auto &it : m_map) {
if ( it.first != ""
&& it.second != "") {
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
}
}
}
std::string enet::HttpRequest::generate() const {
std::string out;
out += etk::to_string(m_req);
out += " ";
out += m_uri;
out += " ";
out += etk::to_string(m_protocol);
out += "\r\n";
out += generateKeys();
out += "\r\n";
return out;
}
std::ostream& enet::operator <<(std::ostream& _os, enum enet::HTTPProtocol _obj) {
_os << "enet::HTTPProtocol::" <<etk::to_string(_obj);
return _os;
}
std::ostream& enet::operator <<(std::ostream& _os, enum enet::HTTPAnswerCode _obj) {
_os << "enet::HTTPAnswerCode::" << etk::to_string(_obj);
return _os;
}
std::ostream& enet::operator <<(std::ostream& _os, enum enet::HTTPReqType _obj) {
_os << "enet::HTTPReqType::" << etk::to_string(_obj);
return _os;
}