diff --git a/enet/Http.cpp b/enet/Http.cpp index 63f658e..d77c9d2 100644 --- a/enet/Http.cpp +++ b/enet/Http.cpp @@ -9,37 +9,146 @@ #include #include #include -#if 0 +#include + +static std::map 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 getErrorList() { static std::map g_list; return g_list; } -enet::Http::Http() : +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), m_keepAlive(false) { - m_connection.setPort(80); - m_connection.setServer(false); + setSendHeaderProperties("User-Agent", "e-net (ewol network interface)"); + if (m_keepAlive == true) { + setSendHeaderProperties("Connection", "Keep-Alive"); + } } enet::Http::~Http() { - reset(); + stop(); } -bool enet::Http::connect() { +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; + } + 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(*this, 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) { - return true; + uint32_t size = 0xFFFFFFFF; + m_connection.write(&size, 4); } - if (m_connection.link() == false) { - ENET_ERROR("can not link to the socket..."); - return false; + */ + if (m_connection.getConnectionStatus() != enet::Tcp::status::unlink) { + m_connection.unlink(); } - return true; + if (_inThreadStop == false) { + if (m_thread != nullptr) { + m_thread->join(); + delete m_thread; + m_thread = nullptr; + } + } + ENET_DEBUG("disconnect [STOP]"); } void enet::Http::setSendHeaderProperties(const std::string& _key, const std::string& _val) { - auto it = m_sendHeader.find(_key); - if (it == m_sendHeader.end()) { - m_sendHeader.insert(make_pair(_key, _val)); + auto it = m_header.m_map.find(_key); + if (it == m_header.m_map.end()) { + m_header.m_map.insert(make_pair(_key, _val)); } else { it->second = _val; } @@ -54,96 +163,68 @@ std::string enet::Http::getReceiveHeaderProperties(const std::string& _key) { ENET_TODO("get header key=" << _key); return ""; } - -bool enet::Http::reset() { - if (m_connection.getConnectionStatus() != enet::Tcp::status::link) { - m_connection.unlink(); +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; } - m_receiveData.clear(); - m_sendHeader.clear(); - m_receiveHeader.clear(); - setSendHeaderProperties("User-Agent", "e-net (ewol network interface)"); - if (m_keepAlive == true) { - setSendHeaderProperties("Connection", "Keep-Alive"); - } - return true; + out += "\r\n\r\n"; + ENET_WARNING("Write header :" << out); + write(out, false); } -bool enet::Http::setServer(const std::string& _hostName) { - // if change server ==> restart connection ... - if (_hostName == m_connection.getHostName()) { - return true; - } - reset(); - m_connection.setHostNane(_hostName); - return true; -} - -bool enet::Http::setPort(uint16_t _port) { - // if change server ==> restart connection ... - if (_port == m_connection.getPort()) { - return true; - } - reset(); - m_connection.setPort(_port); - return true; -} - -bool enet::Http::receiveData() { - std::string header; - // Get data - char data[1025]; - int32_t len = 1; +void enet::Http::getHeader() { + ENET_VERBOSE("Read HTTP Header [START]"); bool headerEnded = false; - while ( m_connection.getConnectionStatus() == enet::Tcp::status::link - && len > 0) { - len = m_connection.read(data, 1024); - // TODO : Parse header ... - - if (headerEnded == false) { - char previous = '\0'; - if (header.size()>0) { - previous = header[header.size()-1]; - } - for (int32_t iii=0; iii 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_WARNING("server disconnected"); - return false; - } + ENET_VERBOSE("Read HTTP Header [STOP] : '" << header << "'"); + m_headerIsSend = true; // parse header : std::vector list = etk::split(header, '\n'); + for (auto &it : list) { + if ( it.size()>0 + && it[it.size()-1] == '\r') { + it.resize(it.size()-1); + } + } headerEnded = false; - m_receiveHeader.clear(); + m_header.m_map.clear(); for (auto element : list) { if (headerEnded == false) { - header = element; headerEnded = true; + m_header.setReq(element); } else { size_t found = element.find(":"); if (found == std::string::npos) { @@ -151,10 +232,10 @@ bool enet::Http::receiveData() { continue; } ENET_VERBOSE("header : key='" << std::string(element, 0, found) << "' value='" << std::string(element, found+2) << "'"); - m_receiveHeader.insert(make_pair(unEscapeChar(std::string(element, 0, found)), unEscapeChar(std::string(element, found+2)))); + m_header.m_map.insert(make_pair(unEscapeChar(std::string(element, 0, found)), unEscapeChar(std::string(element, found+2)))); } } - for (auto &it : m_receiveHeader) { + for (auto &it : m_header.m_map) { if (it.first == "Connection") { if (it.second == "close") { ENET_DEBUG("connection closed by remote :"); @@ -164,67 +245,29 @@ bool enet::Http::receiveData() { } } } - /* - ENET_INFO("header : '" << header << "'"); - for (auto &it : m_receiveHeader) { - ENET_INFO("header : key='" << it.first << "' value='" << it.second << "'"); + m_header.display(); + if (m_observerRequest != nullptr) { + m_observerRequest(*this, m_header); } - */ - // parse base answear: - list = etk::split(header, ' '); - if (list.size() < 2) { - ENET_ERROR("can not parse answear : " << list); - return false; - } - int32_t ret = etk::string_to_int32_t(list[1]); - switch (ret/100) { - case 1: - // information message - return true; - break; - case 2: - // OK - return true; - break; - case 3: - // Redirect - ENET_WARNING("Rediret request"); - return false; - break; - case 4: - // client Error - ENET_WARNING("Client error"); - return false; - break; - case 5: - // server error - ENET_WARNING("Server error"); - return false; - break; - } - return true; } bool enet::Http::get(const std::string& _address) { m_receiveData.clear(); - m_receiveHeader.clear(); - if (connect() == false) { - return false; - } - std::string req = "GET http://" + m_connection.getHostName(); + m_header.m_map.clear(); + std::string req = "GET http://" + m_connection.getName(); if (_address != "") { req += "/"; req += _address; } - req += " HTTP/1.0\n"; + req += " HTTP/1.1\r\n"; setSendHeaderProperties("Content-Length", "0"); // add header properties : - for (auto &it : m_sendHeader) { - req += escapeChar(it.first) + ": " + escapeChar(it.second) + "\n"; + for (auto &it : m_header.m_map) { + req += escapeChar(it.first) + ": " + escapeChar(it.second) + "\r\n"; } // end of header - req += "\n"; + req += "\r\n"; // no body: int32_t len = m_connection.write(req, false); @@ -233,7 +276,8 @@ bool enet::Http::get(const std::string& _address) { ENET_ERROR("An error occured when sending data " << len << "!=" << req.size()); return false; } - return receiveData(); + //return receiveData(); + return false; } std::string enet::Http::escapeChar(const std::string& _value) { @@ -245,10 +289,7 @@ std::string enet::Http::unEscapeChar(const std::string& _value) { bool enet::Http::post(const std::string& _address, const std::map& _values) { m_receiveData.clear(); - m_receiveHeader.clear(); - if (connect() == false) { - return false; - } + m_header.m_map.clear(); // First create body : std::string body; for (auto &it : _values) { @@ -262,11 +303,8 @@ bool enet::Http::post(const std::string& _address, const std::map #include #include +#include +#include -#if 0 namespace enet { + enum class HTTPAnswerCode { + //1xx: Information + c100_continue = 100, //!< The server has received the request headers, and the client should proceed to send the request body + c101_switchingProtocols, //!< The requester has asked the server to switch protocols + c103_checkpoint, //!< Used in the resumable requests proposal to resume aborted PUT or POST requests + //2xx: Successful + c200_ok = 200, //!< The request is OK (this is the standard response for successful HTTP requests) + c201_created, //!< The request has been fulfilled, and a new resource is created + c202_accepted, //!< The request has been accepted for processing, but the processing has not been completed + c203_nonAuthoritativeInformation, //!< The request has been successfully processed, but is returning information that may be from another source + c204_noContent, //!< The request has been successfully processed, but is not returning any content + c205_resetContent, //!< The request has been successfully processed, but is not returning any content, and requires that the requester reset the document view + c206_partialContent, //!< The server is delivering only part of the resource due to a range header sent by the client + //3xx: Redirection + c300_multipleChoices = 300, //!< A link list. The user can select a link and go to that location. Maximum five addresses + c301_movedPermanently, //!< The requested page has moved to a new URL + c302_found, //!< The requested page has moved temporarily to a new URL + c303_seeOther, //!< The requested page can be found under a different URL + c304_notModified, //!< Indicates the requested page has not been modified since last requested + c306_switchProxy, //!< No longer used + c307_temporaryRedirect, //!< The requested page has moved temporarily to a new URL + c308_resumeIncomplete, //!< Used in the resumable requests proposal to resume aborted PUT or POST requests + //4xx: Client Error, + c400_badRequest = 400, //!< The request cannot be fulfilled due to bad syntax + c401_unauthorized, //!< The request was a legal request, but the server is refusing to respond to it. For use when authentication is possible but has failed or not yet been provided + c402_paymentRequired, //!< Reserved for future use + c403_forbidden, //!< The request was a legal request, but the server is refusing to respond to it + c404_notFound, //!< The requested page could not be found but may be available again in the future + c405_methodNotAllowed, //!< A request was made of a page using a request method not supported by that page + c406_notAcceptable, //!< The server can only generate a response that is not accepted by the client + c407_proxyAuthenticationRequired, //!< The client must first authenticate itself with the proxy + c408_requestTimeout, //!< The server timed out waiting for the request + c409_conflict, //!< The request could not be completed because of a conflict in the request + c410_gone, //!< The requested page is no longer available + c411_lengthRequired, //!< The "Content-Length" is not defined. The server will not accept the request without it + c412_preconditionFailed, //!< The precondition given in the request evaluated to false by the server + c413_requestEntityTooLarge, //!< The server will not accept the request, because the request entity is too large + c414_requestURITooLong, //!< The server will not accept the request, because the URL is too long. Occurs when you convert a POST request to a GET request with a long query information + c415_unsupportedMediaType, //!< The server will not accept the request, because the media type is not supported + c416_requestedRangeNotSatisfiable, //!< The client has asked for a portion of the file, but the server cannot supply that portion + c417_expectationFailed, //!< The server cannot meet the requirements of the Expect request-header field + //5xx: Server Error + c500_internalServerError = 500, //!< A generic error message, given when no more specific message is suitable + c501_notImplemented, //!< The server either does not recognize the request method, or it lacks the ability to fulfill the request + c502_badGateway, //!< The server was acting as a gateway or proxy and received an invalid response from the upstream server + c503_serviceUnavailable, //!< The server is currently unavailable (overloaded or down) + c504_gatewayTimeout, //!< The server was acting as a gateway or proxy and did not receive a timely response from the upstream server + c505_httpVersionNotSupported, //!< The server does not support the HTTP protocol version used in the request + c511_networkAuthenticationRequired, //!< The client needs to authenticate to gain network access + }; + + enum class HTTPProtocol { + http_1_0, + http_1_1, + }; + class HttpHeader { + private: + // key, val + std::map m_map; + enum HTTPProtocol m_protocol; + public: + void addKey(const std::string& _key, const std::string& _value); + void rmKey(const std::string& _key); + std::string getKey(const std::string& _key); + enum HTTPProtocol getProtocol() { + return m_protocol; + } + void setProtocol(enum HTTPProtocol _protocol) { + m_protocol = _protocol; + } + virtual ~HttpHeader() = default; + }; + class HttpAnswer : public HttpHeader { + private: + + enet::HTTPAnswerCode m_what; + int64_t m_messageSize; // parameter + public: + HttpAnswer(); + HttpAnswer(const std::string& _value); + get(const std::string& _uri); + setSize(int64_t _messageSize=-1); + void display() const; + std::string generate(); + }; + enum class HTTPReqType { + GET, + HEAD, + POST, + PUT, + DELETE, + }; + class HttpRequest : public HttpHeader{ + private: + // key, val + std::map m_parameters; + enum HTTPReqType m_req; + std::string m_uri; + enum HTTPProtocol m_protocol; + bool m_keepAlive; + public: + HttpRequest(enum HTTPReqType _type, + void display() const; + std::string generate(); + + }; class Http { public: - Http(); + Http(enet::Tcp _connection, bool _isServer=false); virtual ~Http(); + private: + bool m_isServer; + public: + bool getServerState() { + return m_isServer; + } private: enet::Tcp m_connection; + bool m_headerIsSend; + std::thread* m_thread; + bool m_threadRunning; + std::vector m_temporaryBuffer; private: bool m_keepAlive; + void threadCallback(); public: void setKeepAlive(bool _keepAlive) { m_keepAlive = true; @@ -27,32 +145,104 @@ namespace enet { return m_keepAlive; } private: - // key, val - std::map m_sendHeader; - std::map m_receiveHeader; + + HttpHeader m_header; std::vector m_receiveData; - bool connect(); - bool reset(); + void getHeader(); public: + void start(); + void stop(bool _inThread=false); + bool isAlive() { + return m_connection.getConnectionStatus() == enet::Tcp::status::link; + } void setSendHeaderProperties(const std::string& _key, const std::string& _val); std::string getSendHeaderProperties(const std::string& _key); std::string getReceiveHeaderProperties(const std::string& _key); - bool setServer(const std::string& _hostName); - bool setPort(uint16_t _port); bool get(const std::string& _address); bool post(const std::string& _address, const std::map& _values); bool post(const std::string& _address, const std::string& _contentType, const std::string& _data); - - int32_t dataSize() { - return m_receiveData.size(); - } - const std::vector& data() { - return m_receiveData; - } std::string dataString(); + void writeAnswerHeader(enum enet::HTTPAnswerCode _value); std::string escapeChar(const std::string& _value); std::string unEscapeChar(const std::string& _value); - bool receiveData(); + public: + using Observer = std::function&)>; //!< Define an Observer: function pointer + Observer m_observer; + /** + * @brief Connect an function member on the signal with the shared_ptr object. + * @param[in] _class shared_ptr Object on whe we need to call ==> the object is get in keeped in weak_ptr. + * @param[in] _func Function to call. + * @param[in] _args Argument optinnal the user want to add. + */ + template + void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(enet::Http& _interface, std::vector&)) { + m_observer = [=](enet::Http& _interface, std::vector& _value){ + (*_class.*_func)(_interface,_value); + }; + } + void connect(Observer _func) { + m_observer = _func; + } + public: + using ObserverRequest = std::function; //!< Define an Observer: function pointer + ObserverRequest m_observerRequest; + /** + * @brief Connect an function member on the signal with the shared_ptr object. + * @param[in] _class shared_ptr Object on whe we need to call ==> the object is get in keeped in weak_ptr. + * @param[in] _func Function to call. + * @param[in] _args Argument optinnal the user want to add. + */ + template + void connectHeader(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(enet::Http& _interface, const enet::HttpHeader&)) { + m_observerRequest = [=](enet::Http& _interface, std::vector& _value){ + (*_class.*_func)(_value); + }; + } + void connectHeader(ObserverRequest _func) { + m_observerRequest = _func; + } + /** + * @brief Write a chunk of data on the socket + * @param[in] _data pointer on the data might be write + * @param[in] _len Size that must be written socket + * @return >0 byte size on the socket write + * @return -1 an error occured. + */ + int32_t write(const void* _data, int32_t _len); + /** + * @brief Write a chunk of data on the socket + * @param[in] _data String to rite on the soccket + * @param[in] _writeBackSlashZero if false, the \0 is not write + * @return >0 byte size on the socket write + * @return -1 an error occured. + */ + int32_t write(const std::string& _data, bool _writeBackSlashZero = true) { + if (_data.size() == 0) { + return 0; + } + if (_writeBackSlashZero == true) { + return write(_data.c_str(), _data.size()+1); + } + return write(_data.c_str(), _data.size()); + } + /** + * @brief Write a chunk of data on the socket + * @param[in] _data String to rite on the soccket + * @param[in] _writeBackSlashZero if false, the \0 is not write + * @return >0 T element write on the socket + * @return -1 an error occured. + */ + template + int32_t write(const std::vector& _data) { + if (_data.size() == 0) { + return 0; + } + size_t ret = write(&_data[0], _data.size()*sizeof(T)); + if (ret <=0) { + return ret; + } + return ret/sizeof(T); + } }; } -#endif + diff --git a/enet/Tcp.cpp b/enet/Tcp.cpp index 3969039..97c60d9 100644 --- a/enet/Tcp.cpp +++ b/enet/Tcp.cpp @@ -81,7 +81,6 @@ bool enet::Tcp::unlink() { int32_t enet::Tcp::read(void* _data, int32_t _maxLen) { - ENET_VERBOSE("read [START]"); if (m_status != status::link) { ENET_ERROR("Can not read on unlink connection"); return -1; @@ -91,7 +90,6 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) { // Initialize the timeout to 3 minutes. If no activity after 3 minutes this program will end. timeout value is based on milliseconds. int timeout = (3 * 60 * 1000); // Call poll() and wait 3 minutes for it to complete. - ENET_VERBOSE("Waiting on poll()..."); int rc = poll(m_fds, nfds, timeout); // Check to see if the poll call failed. if (rc < 0) { @@ -116,20 +114,18 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) { } // Check to see if the connection has been closed by the client if (rc == 0) { - ENET_ERROR(" Connection closed"); + ENET_INFO(" Connection closed"); closeConn = true; } if (closeConn == false) { // Data was received size = rc; - ENET_VERBOSE(" " << size << " bytes received"); } else { // If the close_conn flag was turned on, we need to clean up this active connection. // This clean up process includes removing the descriptor. - ENET_ERROR(" Set status at remote close ..."); + ENET_DEBUG(" Set status at remote close ..."); m_status = status::linkRemoteClose; } - ENET_VERBOSE("read [STOP]"); return size; } diff --git a/enet/Tcp.h b/enet/Tcp.h index 4153cee..318deed 100644 --- a/enet/Tcp.h +++ b/enet/Tcp.h @@ -12,9 +12,7 @@ namespace enet { class Tcp { private: int32_t m_socketId; //!< socket linux interface generic - #if 1 - struct pollfd m_fds[1]; - #endif + struct pollfd m_fds[1]; public: Tcp(); Tcp(int32_t _idSocket, const std::string& _name); diff --git a/enet/WebSocket.cpp b/enet/WebSocket.cpp new file mode 100644 index 0000000..9801d27 --- /dev/null +++ b/enet/WebSocket.cpp @@ -0,0 +1,38 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include +#include +#include +#include + + + +enet::WebSocket::WebSocket(enet::Tcp _connection, bool _isServer) : + m_interface(std::move(_connection), _isServer) { + +} + +enet::WebSocket::~WebSocket() { + +} + + +void enet::WebSocket::start(const std::string& _uri) { + if (m_interface.isServer() == true) { + + } + m_interface.start(); + if (m_interface.isServer() == false) { + m_interface.get( + } +} + +void enet::WebSocket::stop(bool _inThread=false) { + +} + diff --git a/enet/WebSocket.h b/enet/WebSocket.h new file mode 100644 index 0000000..f4c6f54 --- /dev/null +++ b/enet/WebSocket.h @@ -0,0 +1,22 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ +#pragma once + +#include +#include +#include + +namespace enet { + class WebSocket{ + private: + enet::Http m_interface; + public: + WebSocket(enet::Tcp _connection, bool _isServer=false); + virtual ~WebSocket(); + void start(const std::string& _uri); + void stop(bool _inThread=false); + }; +} diff --git a/lutin_enet-test-server-http.py b/lutin_enet-test-server-http.py new file mode 100644 index 0000000..f4996c5 --- /dev/null +++ b/lutin_enet-test-server-http.py @@ -0,0 +1,41 @@ +#!/usr/bin/python +import lutin.module as module +import lutin.tools as tools + + +def get_type(): + return "BINARY" + +def get_sub_type(): + return "TEST" + +def get_desc(): + return "e-net TEST test software for enet" + +def get_licence(): + return "APACHE-2" + +def get_compagny_type(): + return "com" + +def get_compagny_name(): + return "atria-soft" + +def get_maintainer(): + return ["Mr DUPIN Edouard "] + +def create(target, module_name): + my_module = module.Module(__file__, module_name, get_type()) + my_module.add_export_path(tools.get_current_path(__file__)) + my_module.add_module_depend(['enet', 'gtest', 'test-debug']) + my_module.add_src_file([ + 'test/main-server-http.cpp' + ]) + return my_module + + + + + + + diff --git a/test/main-client-http.cpp b/test/main-client-http.cpp index 58c3384..3ba6c42 100644 --- a/test/main-client-http.cpp +++ b/test/main-client-http.cpp @@ -6,10 +6,19 @@ #include #include +#include #include #include #include +#include + +namespace appl { + void onReceiveData(enet::Http& _interface, std::vector& _data) { + TEST_INFO("Receive Datas : " << _data.size() << " bytes"); + TEST_INFO("data:" << (char*)&_data[0] << ""); + } +} int main(int _argc, const char *_argv[]) { etk::init(_argc, _argv); @@ -27,35 +36,25 @@ int main(int _argc, const char *_argv[]) { TEST_INFO("== Test HTTP client =="); TEST_INFO("=================================="); #ifndef __TARGET_OS__Windows - // client mode ... - enet::Http connection; - connection.setServer("127.0.0.1"); + // connect on TCP server: + enet::Tcp tcpConnection = std::move(enet::connectTcpClient("127.0.0.1", 12345)); + // TODO : Check if connection is valid ... + + // Create a HTTP connection in Client mode + enet::Http connection(std::move(tcpConnection), false); connection.setKeepAlive(true); - TEST_INFO("----------------------------"); - TEST_INFO("GET data : "); - if (connection.get("") == false) { - TEST_ERROR("can not GET data..."); - return -1; - } - TEST_INFO("data : " << connection.dataString()); + // Set callbacks: + connection.connect(appl::onReceiveData); - TEST_INFO("----------------------------"); - TEST_INFO("POST data : "); - std::map values; - values.insert(std::make_pair("plop", "valuePlop")); - if (connection.post("", values) == false) { - TEST_ERROR("can not POST data..."); - return -1; - } - TEST_INFO("data : " << connection.dataString()); + // start http connection (the actual state is just TCP start ...) + connection.start(); + connection.get("plop.txt"); - TEST_INFO("----------------------------"); - TEST_INFO("POST xml : "); - if (connection.post("", /*"application/xml"*/ "text/xml; charset=utf-8", "value1") == false) { - TEST_ERROR("can not POST XML data..."); - return -1; + + while (connection.isAlive() == true) { + usleep(100000); } - TEST_INFO("data : " << connection.dataString()); + #else TEST_CRITICAL("not implemented"); #endif diff --git a/test/main-server-http.cpp b/test/main-server-http.cpp new file mode 100644 index 0000000..5cf7dcf --- /dev/null +++ b/test/main-server-http.cpp @@ -0,0 +1,111 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include +#include +#include +#include + +#include +#include +namespace appl { + void onReceiveData(enet::Http& _interface, std::vector& _data) { + TEST_INFO("Receive Datas : " << _data.size() << " bytes"); + } + void onReceiveHeader(enet::Http& _interface, const enet::HttpHeader& _data) { + TEST_INFO("Receive Header data:"); + _data.display(); + if (_data.m_req == "GET") { + if (_data.m_what == "http://127.0.0.1:12345/plop.txt") { + _interface.writeAnswerHeader(enet::HTTPAnswerCode::c200_ok); + std::string data = "coucou"; + _interface.write(data); + _interface.stop(); + return; + } + } + _interface.writeAnswerHeader(enet::HTTPAnswerCode::c200_ok); + _interface.stop(); + } +} + +int main(int _argc, const char *_argv[]) { + etk::init(_argc, _argv); + for (int32_t iii=0; iii<_argc ; ++iii) { + std::string data = _argv[iii]; + if ( data == "-h" + || data == "--help") { + TEST_PRINT(etk::getApplicationName() << " - help : "); + TEST_PRINT(" " << _argv[0] << " [options]"); + TEST_PRINT(" No options ..."); + return -1; + } + } + TEST_INFO("=================================="); + TEST_INFO("== Test HTTP server =="); + TEST_INFO("=================================="); +#ifndef __TARGET_OS__Windows + //Wait on TCP connection: + enet::TcpServer interface; + // Configure server interface: + interface.setHostNane("127.0.0.1"); + interface.setPort(12345); + // Start listening ... + interface.link(); + // Wait a new connection .. + enet::Tcp tcpConnection = std::move(interface.waitNext()); + // Free Connected port + interface.unlink(); + // TODO : Check if connection is valid ... + + // Create a HTTP connection in Server mode + enet::Http connection(std::move(tcpConnection), true); + connection.setKeepAlive(true); + // Set callbacks: + connection.connect(appl::onReceiveData); + connection.connectHeader(appl::onReceiveHeader); + + // start http connection (the actual state is just TCP start ...) + connection.start(); + + while (connection.isAlive() == true) { + usleep(100000); + } + + + /* + TEST_INFO("----------------------------"); + TEST_INFO("GET data : "); + if (connection.get("") == false) { + TEST_ERROR("can not GET data..."); + return -1; + } + TEST_INFO("data : " << connection.dataString()); + + TEST_INFO("----------------------------"); + TEST_INFO("POST data : "); + std::map values; + values.insert(std::make_pair("plop", "valuePlop")); + if (connection.post("", values) == false) { + TEST_ERROR("can not POST data..."); + return -1; + } + TEST_INFO("data : " << connection.dataString()); + + TEST_INFO("----------------------------"); + TEST_INFO("POST xml : "); + if (connection.post("", "text/xml; charset=utf-8", "value1") == false) { + TEST_ERROR("can not POST XML data..."); + return -1; + } + TEST_INFO("data : " << connection.dataString()); + */ +#else + TEST_CRITICAL("not implemented"); +#endif + return 0; +}