From ec42f9e591aac2598cba4bd7bca8560a9e91ca91 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 7 May 2020 03:44:30 +0700 Subject: [PATCH 1/8] Prepare test for keep-alive --- server-tests/run_tests.py | 43 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/server-tests/run_tests.py b/server-tests/run_tests.py index 060ff6b..1476c0b 100755 --- a/server-tests/run_tests.py +++ b/server-tests/run_tests.py @@ -4,8 +4,13 @@ from pprint import pprint import liblightwebservertest import requests +import socket +import sys +import time -TEST_URL = "http://localhost:1234" +SERVER_HOST = "localhost" +SERVER_PORT = 1234 +TEST_URL = "http://" + SERVER_HOST + ":" + str(1234) try: print(" > > > TESTS: begin ") @@ -41,14 +46,46 @@ if r.text != app_js: raise Exception("app.js - expected content like in file ../web/js/index.js") else: - print("index.css - ok") + print("app.js - ok") print("not-found - testing...") r = requests.get(TEST_URL + "/not-found 0101") if r.status_code != 404: raise Exception("not-found - Wrong status code expected 404, but got " + str(r.status_code)) - print("index.css - ok") + print("not-found 0101 - ok") + + print("\n\n >>>>>>>>>>>>>>>>>>\n") + print(">>>> TEST keep-alive \n") + test_keep_alive_request = '''GET /js/app.js?v1=20200101 HTTP/1.1 +Host: ''' + SERVER_HOST + ''':''' + str(SERVER_PORT) + ''' +User-Agent: tcp +Accept-Encoding: gzip, deflate +Accept: */* +Connection: keep-alive +''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(0.3) + sock.connect((SERVER_HOST, SERVER_PORT)) + print(">>>> send first") + sock.send(test_keep_alive_request.encode("utf8")) + r1 = sock.recv(1024) + r1 = r1.decode("utf8") + # print(r1) + time.sleep(1) + print(">>>> send again by same connection") + sock.send(test_keep_alive_request.encode("utf8")) + r2 = sock.recv(1024) + r2 = r2.decode("utf8") + # print(r2) + if len(r1) != len(r2): + raise Exception("test keep-alive - expected same length. Expected " + str(len(r1)) + " bytes, but got " + str(len(r2)) + " bytes") +except socket.timeout: + print("FAILED by timeout") +except Exception as e: + print("FAILED: ", e) +except: + print("Unexpected error:", sys.exc_info()[0]) finally: liblightwebservertest.stop_server() From 80499b139c18580ece50f2c43a189eee444d061e Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Mon, 22 Jun 2020 02:49:09 +0700 Subject: [PATCH 2/8] Added port to main example, enable/disable logging, fixed TODO --- .../liblightwebservertest/__init__.py | 18 ++-- server-tests/run_tests.py | 15 ++-- src/main.cpp | 21 ++++- src/wsjcpp_light_web_deque_http_requests.cpp | 17 +++- src/wsjcpp_light_web_deque_http_requests.h | 3 + ..._light_web_http_handler_rewrite_folder.cpp | 12 +-- ...pp_light_web_http_handler_rewrite_folder.h | 6 +- ...jcpp_light_web_http_handler_web_folder.cpp | 12 +-- ...wsjcpp_light_web_http_handler_web_folder.h | 6 +- src/wsjcpp_light_web_http_response.cpp | 9 +- src/wsjcpp_light_web_http_response.h | 3 +- src/wsjcpp_light_web_server.cpp | 87 ++++++++++++------- src/wsjcpp_light_web_server.h | 14 ++- 13 files changed, 154 insertions(+), 69 deletions(-) diff --git a/server-tests/liblightwebservertest/__init__.py b/server-tests/liblightwebservertest/__init__.py index 02fb140..7cf66c7 100644 --- a/server-tests/liblightwebservertest/__init__.py +++ b/server-tests/liblightwebservertest/__init__.py @@ -5,8 +5,8 @@ import signal import socket -test_name = 'Start fhq-server' -p_fhq_server = None +test_name = 'Start wsjcpp-light-web-server' +p_server = None def check_port(host, port): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -14,12 +14,12 @@ def check_port(host, port): return result == 0 def start_server(work_directory, program_args, port): - print("Start fhq-server") - global p_fhq_server + print("Start wsjcpp-light-web-server") + global p_server wd = os.getcwd() print(wd) os.chdir(wd + "/" + work_directory) - p_fhq_server = subprocess.Popen(program_args) + p_server = subprocess.Popen(program_args) os.chdir(wd) wait_max = 20 @@ -42,7 +42,7 @@ def start_server(work_directory, program_args, port): def stop_server(): print("Stop fhq-server") - global p_fhq_server - if p_fhq_server != None: - print("Kill process " + str(p_fhq_server.pid)) - os.kill(p_fhq_server.pid, signal.SIGKILL) \ No newline at end of file + global p_server + if p_server != None: + print("Kill process " + str(p_server.pid)) + os.kill(p_server.pid, signal.SIGKILL) \ No newline at end of file diff --git a/server-tests/run_tests.py b/server-tests/run_tests.py index 1476c0b..f8a659d 100755 --- a/server-tests/run_tests.py +++ b/server-tests/run_tests.py @@ -14,7 +14,7 @@ try: print(" > > > TESTS: begin ") - liblightwebservertest.start_server("../", ["./wsjcpp-light-web-server", "folder", "./web"], 1234) + liblightwebservertest.start_server("../", ["./wsjcpp-light-web-server", "folder", "./web", "1234"], 1234) print("index.html - testing...") index_html = open("../web/index.html", 'r').read() r = requests.get(TEST_URL) @@ -65,19 +65,24 @@ ''' sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.settimeout(0.3) + sock.settimeout(0.1) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) + # sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 1) + sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 1) + sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 1) sock.connect((SERVER_HOST, SERVER_PORT)) print(">>>> send first") sock.send(test_keep_alive_request.encode("utf8")) r1 = sock.recv(1024) r1 = r1.decode("utf8") # print(r1) - time.sleep(1) + time.sleep(2) print(">>>> send again by same connection") - sock.send(test_keep_alive_request.encode("utf8")) + r = sock.send(test_keep_alive_request.encode("utf8")) + print(r) r2 = sock.recv(1024) r2 = r2.decode("utf8") - # print(r2) + print(r2) if len(r1) != len(r2): raise Exception("test keep-alive - expected same length. Expected " + str(len(r1)) + " bytes, but got " + str(len(r2)) + " bytes") except socket.timeout: diff --git a/src/main.cpp b/src/main.cpp index e5a4ff5..afc617d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,22 +12,35 @@ int main(int argc, const char* argv[]) { } WsjcppLog::setPrefixLogFile("wsjcpp"); WsjcppLog::setLogDirectory(".logs"); + std::string sUsage = "Usage: " + std::string(argv[0]) + " [folder|rewrite] "; - if (argc != 3) { - std::cout << "Usage: " << argv[0] << " [folder|rewrite] " << std::endl; + if (argc != 4) { + std::cout << sUsage << std::endl; return -1; } std::string sType = std::string(argv[1]); if (sType != "folder" && sType != "rewrite") { - std::cout << "Usage: " << argv[0] << " [folder|rewrite] " << std::endl; + std::cout << sUsage << std::endl; return -1; } std::string sDir = std::string(argv[2]); + std::string sPort = std::string(argv[3]); + int nPort = std::atoi(sPort.c_str()); + if (nPort < 10) { + std::cout << "Please set port more then 0" << std::endl; + return -1; + } + + if (nPort >= 65536) { + std::cout << "Please set port less then 65536" << std::endl; + return -1; + } WsjcppLightWebServer httpServer; - httpServer.setPort(1234); + httpServer.setPort(nPort); httpServer.setMaxWorkers(4); + httpServer.setLoggerEnable(false); if (sType == "folder") { httpServer.addHandler(new WsjcppLightWebHttpHandlerWebFolder("/app/", sDir)); httpServer.addHandler(new WsjcppLightWebHttpHandlerWebFolder("/", sDir)); diff --git a/src/wsjcpp_light_web_deque_http_requests.cpp b/src/wsjcpp_light_web_deque_http_requests.cpp index 2e2c6bb..ba85f91 100644 --- a/src/wsjcpp_light_web_deque_http_requests.cpp +++ b/src/wsjcpp_light_web_deque_http_requests.cpp @@ -7,6 +7,7 @@ WsjcppLightWebDequeHttpRequests::WsjcppLightWebDequeHttpRequests() { TAG = "WsjcppLightWebDequeHttpRequests"; + m_bLoggerEnabled = false; } // ---------------------------------------------------------------------- @@ -30,14 +31,14 @@ WsjcppLightWebHttpRequest *WsjcppLightWebDequeHttpRequests::popRequest() { void WsjcppLightWebDequeHttpRequests::pushRequest(WsjcppLightWebHttpRequest *pRequest) { { std::lock_guard guard(this->m_mtxDequeRequests); - if (m_dequeRequests.size() > 20) { + if (m_dequeRequests.size() > 20 && m_bLoggerEnabled) { WsjcppLog::warn(TAG, " deque more than " + std::to_string(m_dequeRequests.size())); } m_dequeRequests.push_front(pRequest); } if (m_dequeRequests.size() == 1) { - m_mtxWaiterRequests.unlock(); + m_mtxWaiterRequests.unlock(); } } @@ -50,3 +51,15 @@ void WsjcppLightWebDequeHttpRequests::cleanup() { m_dequeRequests.pop_back(); } } + +// ---------------------------------------------------------------------- + +void WsjcppLightWebDequeHttpRequests::setLoggerEnable(bool bEnable) { + m_bLoggerEnabled = bEnable; +} + +// ---------------------------------------------------------------------- + +void WsjcppLightWebDequeHttpRequests::addKeepAliveSocket(int m_nSockFd) { + WsjcppLog::warn(TAG, "WsjcppLightWebDequeHttpRequests::addKeepAliveSocket not implemented"); +} \ No newline at end of file diff --git a/src/wsjcpp_light_web_deque_http_requests.h b/src/wsjcpp_light_web_deque_http_requests.h index 5ce14bb..29365d5 100644 --- a/src/wsjcpp_light_web_deque_http_requests.h +++ b/src/wsjcpp_light_web_deque_http_requests.h @@ -15,12 +15,15 @@ class WsjcppLightWebDequeHttpRequests { WsjcppLightWebHttpRequest *popRequest(); void pushRequest(WsjcppLightWebHttpRequest *pRequest); void cleanup(); + void setLoggerEnable(bool bEnable); + void addKeepAliveSocket(int m_nSockFd); private: std::string TAG; std::mutex m_mtxDequeRequests; std::mutex m_mtxWaiterRequests; + bool m_bLoggerEnabled; std::deque m_dequeRequests; }; diff --git a/src/wsjcpp_light_web_http_handler_rewrite_folder.cpp b/src/wsjcpp_light_web_http_handler_rewrite_folder.cpp index 4e0e6e8..bf72da0 100644 --- a/src/wsjcpp_light_web_http_handler_rewrite_folder.cpp +++ b/src/wsjcpp_light_web_http_handler_rewrite_folder.cpp @@ -35,7 +35,11 @@ bool WsjcppLightWebHttpHandlerRewriteFolder::canHandle(const std::string &sWorke // ---------------------------------------------------------------------- -bool WsjcppLightWebHttpHandlerRewriteFolder::handle(const std::string &sWorkerId, WsjcppLightWebHttpRequest *pRequest) { +bool WsjcppLightWebHttpHandlerRewriteFolder::handle( + const std::string &sWorkerId, + WsjcppLightWebHttpRequest *pRequest, + WsjcppLightWebHttpResponse *pResponse +) { std::string _tag = TAG + "-" + sWorkerId; std::string sRequestPath = pRequest->getRequestPath(); // WsjcppLog::warn(_tag, pRequest->requestPath()); @@ -44,12 +48,10 @@ bool WsjcppLightWebHttpHandlerRewriteFolder::handle(const std::string &sWorkerId std::string sRequestPath2 = sRequestPath.substr(m_sPrefixPath.length(), sRequestPath.length() - m_sPrefixPath.length()); std::string sFilePath = m_sWebFolder + sRequestPath2; if (WsjcppCore::fileExists(sFilePath)) { - WsjcppLightWebHttpResponse resp(pRequest->getSockFd()); - resp.cacheSec(60).ok().sendFile(sFilePath); + pResponse->cacheSec(60).ok().sendFile(sFilePath); } else { std::string sFilePath = m_sWebFolder + "/index.html"; - WsjcppLightWebHttpResponse resp(pRequest->getSockFd()); - resp.cacheSec(60).ok().sendFile(sFilePath); + pResponse->cacheSec(60).ok().sendFile(sFilePath); } return true; } diff --git a/src/wsjcpp_light_web_http_handler_rewrite_folder.h b/src/wsjcpp_light_web_http_handler_rewrite_folder.h index bf7a06e..238619b 100644 --- a/src/wsjcpp_light_web_http_handler_rewrite_folder.h +++ b/src/wsjcpp_light_web_http_handler_rewrite_folder.h @@ -7,7 +7,11 @@ class WsjcppLightWebHttpHandlerRewriteFolder : public WsjcppLightWebHttpHandlerB public: WsjcppLightWebHttpHandlerRewriteFolder(const std::string &sPrefixPath, const std::string &sWebFolder); virtual bool canHandle(const std::string &sWorkerId, WsjcppLightWebHttpRequest *pRequest); - virtual bool handle(const std::string &sWorkerId, WsjcppLightWebHttpRequest *pRequest); + virtual bool handle( + const std::string &sWorkerId, + WsjcppLightWebHttpRequest *pRequest, + WsjcppLightWebHttpResponse *pResponse + ); private: std::string TAG; diff --git a/src/wsjcpp_light_web_http_handler_web_folder.cpp b/src/wsjcpp_light_web_http_handler_web_folder.cpp index 356bc4e..dbe350f 100644 --- a/src/wsjcpp_light_web_http_handler_web_folder.cpp +++ b/src/wsjcpp_light_web_http_handler_web_folder.cpp @@ -35,7 +35,11 @@ bool WsjcppLightWebHttpHandlerWebFolder::canHandle(const std::string &sWorkerId, // ---------------------------------------------------------------------- -bool WsjcppLightWebHttpHandlerWebFolder::handle(const std::string &sWorkerId, WsjcppLightWebHttpRequest *pRequest) { +bool WsjcppLightWebHttpHandlerWebFolder::handle( + const std::string &sWorkerId, + WsjcppLightWebHttpRequest *pRequest, + WsjcppLightWebHttpResponse *pResponse +) { std::string _tag = TAG + "-" + sWorkerId; std::string sRequestPath = pRequest->getRequestPath(); // WsjcppLog::warn(_tag, sRequestPath); @@ -48,11 +52,9 @@ bool WsjcppLightWebHttpHandlerWebFolder::handle(const std::string &sWorkerId, Ws // WsjcppLog::warn(_tag, sFilePath); if (WsjcppCore::fileExists(sFilePath)) { - WsjcppLightWebHttpResponse resp(pRequest->getSockFd()); - resp.cacheSec(60).ok().sendFile(sFilePath); + pResponse->cacheSec(60).ok().sendFile(sFilePath); } else { - WsjcppLightWebHttpResponse resp(pRequest->getSockFd()); - resp.noCache().notFound().sendEmpty(); + pResponse->noCache().notFound().sendEmpty(); } return true; } \ No newline at end of file diff --git a/src/wsjcpp_light_web_http_handler_web_folder.h b/src/wsjcpp_light_web_http_handler_web_folder.h index 8ad7221..8a34679 100644 --- a/src/wsjcpp_light_web_http_handler_web_folder.h +++ b/src/wsjcpp_light_web_http_handler_web_folder.h @@ -7,7 +7,11 @@ class WsjcppLightWebHttpHandlerWebFolder : public WsjcppLightWebHttpHandlerBase public: WsjcppLightWebHttpHandlerWebFolder(const std::string &sPrefixPath, const std::string &sWebFolder); virtual bool canHandle(const std::string &sWorkerId, WsjcppLightWebHttpRequest *pRequest); - virtual bool handle(const std::string &sWorkerId, WsjcppLightWebHttpRequest *pRequest); + virtual bool handle( + const std::string &sWorkerId, + WsjcppLightWebHttpRequest *pRequest, + WsjcppLightWebHttpResponse *pResponse + ); private: std::string TAG; diff --git a/src/wsjcpp_light_web_http_response.cpp b/src/wsjcpp_light_web_http_response.cpp index b3a0178..6c7ed9f 100644 --- a/src/wsjcpp_light_web_http_response.cpp +++ b/src/wsjcpp_light_web_http_response.cpp @@ -13,8 +13,9 @@ std::map *WsjcppLightWebHttpResponse::g_mapReponseDescription // ---------------------------------------------------------------------- -WsjcppLightWebHttpResponse::WsjcppLightWebHttpResponse(int nSockFd) { +WsjcppLightWebHttpResponse::WsjcppLightWebHttpResponse(int nSockFd, bool bLoggerEnabled) { TAG = "WsjcppLightWebHttpResponse"; + m_bLoggerEnabled = bLoggerEnabled; if (WsjcppLightWebHttpResponse::g_mapReponseDescription == nullptr) { WsjcppLightWebHttpResponse::g_mapReponseDescription = new std::map(); WsjcppLightWebHttpResponse::g_mapReponseDescription->insert(std::pair(200,"HTTP/1.1 200 OK")); @@ -166,8 +167,10 @@ void WsjcppLightWebHttpResponse::sendText(const std::string &sBody) { } m_bClosed = true; - WsjcppLog::info(TAG, "\nResponse: \n>>>\n" + sResponse + "\n<<<"); - + if (m_bLoggerEnabled) { + WsjcppLog::info(TAG, "\nResponse: \n>>>\n" + sResponse + "\n<<<"); + } + send(m_nSockFd, sResponse.c_str(), sResponse.length(),0); close(m_nSockFd); } diff --git a/src/wsjcpp_light_web_http_response.h b/src/wsjcpp_light_web_http_response.h index 025f415..107dde8 100644 --- a/src/wsjcpp_light_web_http_response.h +++ b/src/wsjcpp_light_web_http_response.h @@ -11,7 +11,7 @@ class WsjcppLightWebHttpResponse { public: static std::map *g_mapReponseDescription; - WsjcppLightWebHttpResponse(int nSockFd); + WsjcppLightWebHttpResponse(int nSockFd, bool bLoggerEnabled); WsjcppLightWebHttpResponse &ok(); WsjcppLightWebHttpResponse &badRequest(); @@ -41,6 +41,7 @@ class WsjcppLightWebHttpResponse { int m_nSockFd; bool m_bClosed; int m_nResponseCode; + bool m_bLoggerEnabled; std::string m_sDataType; std::string m_sCacheControl; std::string m_sLastModified; diff --git a/src/wsjcpp_light_web_server.cpp b/src/wsjcpp_light_web_server.cpp index 86d9c65..be7c6b9 100644 --- a/src/wsjcpp_light_web_server.cpp +++ b/src/wsjcpp_light_web_server.cpp @@ -31,7 +31,8 @@ void* wsjcppLightWebServerProcessRequest(void *arg) { WsjcppLightWebHttpThreadWorker::WsjcppLightWebHttpThreadWorker( const std::string &sName, WsjcppLightWebDequeHttpRequests *pDeque, - std::vector *pVHandlers + std::vector *pVHandlers, + bool bLoggerEnabled ) { TAG = "WsjcppLightWebHttpThreadWorker-" + sName; m_pDeque = pDeque; @@ -39,6 +40,7 @@ WsjcppLightWebHttpThreadWorker::WsjcppLightWebHttpThreadWorker( m_bStopped = true; m_sName = sName; m_pVHandlers = pVHandlers; + m_bLoggerEnabled = bLoggerEnabled; } // ---------------------------------------------------------------------- @@ -46,7 +48,9 @@ WsjcppLightWebHttpThreadWorker::WsjcppLightWebHttpThreadWorker( void WsjcppLightWebHttpThreadWorker::start() { m_bStop = false; m_bStopped = false; - WsjcppLog::info(TAG, "Start"); + if (m_bLoggerEnabled) { + WsjcppLog::info(TAG, "Start"); + } pthread_create(&m_serverThread, NULL, &wsjcppLightWebServerProcessRequest, (void *)this); } @@ -65,11 +69,14 @@ void WsjcppLightWebHttpThreadWorker::run() { m_bStopped = true; return; } - WsjcppLightWebHttpRequest *pInfo = m_pDeque->popRequest(); + WsjcppLightWebHttpRequest *pRequest = m_pDeque->popRequest(); - if (pInfo != nullptr) { - int nSockFd = pInfo->getSockFd(); - WsjcppLog::info(TAG, "IP-address: " + pInfo->getAddress()); + if (pRequest != nullptr) { + int nSockFd = pRequest->getSockFd(); + if (m_bLoggerEnabled) { + WsjcppLog::info(TAG, "IP-address: " + pRequest->getAddress()); + } + // set timeout options struct timeval timeout; @@ -77,13 +84,12 @@ void WsjcppLightWebHttpThreadWorker::run() { timeout.tv_usec = 0; setsockopt(nSockFd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); - WsjcppLightWebHttpResponse *pResponse = new WsjcppLightWebHttpResponse(nSockFd); + WsjcppLightWebHttpResponse *pResponse = new WsjcppLightWebHttpResponse(nSockFd, m_bLoggerEnabled); int n; // int newsockfd = (long)arg; char msg[nMaxPackageSize]; std::string sRequest; - // std::cout << nSockFd << ": address = " << info->address() << "\n"; // read data from socket bool bErrorRead = false; @@ -95,21 +101,24 @@ void WsjcppLightWebHttpThreadWorker::run() { // std::cout << "N: " << n << std::endl; if (n == -1) { bErrorRead = true; - std::cout << nSockFd << ": error read... \n"; + WsjcppLog::err(TAG, std::to_string(nSockFd) + ": error read... "); break; } if (n == 0) { //close(nSockFd); break; } - WsjcppLog::info(TAG, "Readed " + std::to_string(n) + " bytes..."); + if (m_bLoggerEnabled) { + WsjcppLog::info(TAG, "Readed " + std::to_string(n) + " bytes..."); + } + msg[n] = 0; sRequest = std::string(msg); std::string sRecv(msg); - pInfo->appendRecieveRequest(sRecv); + pRequest->appendRecieveRequest(sRecv); - if (pInfo->isEnoughAppendReceived()) { + if (pRequest->isEnoughAppendReceived()) { break; } // TODO redesign or switch to another socket @@ -117,26 +126,24 @@ void WsjcppLightWebHttpThreadWorker::run() { } // TODO read and replace X-Forwarded-IP // TODO read and replace X-Forwarded-Host - WsjcppLog::info(TAG, "\nRequest: \n>>>\n" + sRequest + "\n<<<"); + if (m_bLoggerEnabled) { + WsjcppLog::info(TAG, "\nRequest: \n>>>\n" + sRequest + "\n<<<"); + } if (bErrorRead) { pResponse->requestTimeout().noCache().sendText( "

408 Request Time-out

" "Your browser didn't send a complete request in time." "" ); - } else if (pInfo->getRequestType() == "OPTIONS") { + } else if (pRequest->getRequestType() == "OPTIONS") { pResponse->ok().sendOptions("OPTIONS, GET, POST"); - } else if (pInfo->getRequestType() != "GET" && pInfo->getRequestType() != "POST") { + } else if (pRequest->getRequestType() != "GET" && pRequest->getRequestType() != "POST") { pResponse->notImplemented().sendEmpty(); } else { - if (!this->handle(pInfo)) { - pResponse->notFound().sendEmpty(); - } else { - // TODO resp internal error - // this->response(WsjcppLightWebHttpResponse::RESP_INTERNAL_SERVER_ERROR); - } + this->handle(pRequest, pResponse); } - delete pInfo; + m_pDeque->addKeepAliveSocket(pRequest->getSockFd()); + delete pRequest; delete pResponse; } if (m_bStop) { @@ -149,19 +156,22 @@ void WsjcppLightWebHttpThreadWorker::run() { // ---------------------------------------------------------------------- -bool WsjcppLightWebHttpThreadWorker::handle(WsjcppLightWebHttpRequest *pRequest) { +void WsjcppLightWebHttpThreadWorker::handle(WsjcppLightWebHttpRequest *pRequest, WsjcppLightWebHttpResponse *pResponse) { std::vector::iterator it; for (it = m_pVHandlers->begin(); it < m_pVHandlers->end(); it++) { WsjcppLightWebHttpHandlerBase *pHandler = *it; - if (pHandler->canHandle(m_sName, pRequest)) { - if (pHandler->handle(m_sName, pRequest)) { - return true; - } else { + if (!pHandler->canHandle(m_sName, pRequest)) { + continue; + } + if (!pHandler->handle(m_sName, pRequest, pResponse)) { + if (m_bLoggerEnabled) { WsjcppLog::warn(TAG, pHandler->name() + " - could not handle request '" + pRequest->getRequestPath() + "'"); } + pResponse->internalServerError().sendEmpty(); } + return; } - return false; + pResponse->notFound().sendEmpty(); } // ---------------------------------------------------------------------- @@ -174,6 +184,7 @@ WsjcppLightWebServer::WsjcppLightWebServer() { m_pVHandlers = new std::vector(); m_bStop = false; m_nPort = 8080; + m_bLoggerEnabled = false; } // ---------------------------------------------------------------------- @@ -201,6 +212,13 @@ void WsjcppLightWebServer::setMaxWorkers(int nMaxWorkers) { // ---------------------------------------------------------------------- +void WsjcppLightWebServer::setLoggerEnable(bool bEnable) { + m_bLoggerEnabled = bEnable; + m_pDeque->setLoggerEnable(bEnable); +} + +// ---------------------------------------------------------------------- + void WsjcppLightWebServer::startSync() { m_nSockFd = socket(AF_INET, SOCK_STREAM, 0); @@ -233,7 +251,9 @@ void WsjcppLightWebServer::startSync() { socklen_t sosize = sizeof(clientAddress); int nSockFd = accept(m_nSockFd,(struct sockaddr*)&clientAddress,&sosize); std::string sAddress = inet_ntoa(clientAddress.sin_addr); - WsjcppLog::info(TAG, "Connected " + sAddress); + if (m_bLoggerEnabled) { + WsjcppLog::info(TAG, "Connected " + sAddress); + } WsjcppLightWebHttpRequest *pInfo = new WsjcppLightWebHttpRequest(nSockFd, sAddress); // info will be removed inside a thread m_pDeque->pushRequest(pInfo); // here will be unlocked workers @@ -283,7 +303,14 @@ void WsjcppLightWebServer::checkAndRestartWorkers() { if (m_vWorkers.size() < m_nMaxWorkers) { int nSize = m_vWorkers.size(); for (int i = nSize; i < m_nMaxWorkers; i++) { - m_vWorkers.push_back(new WsjcppLightWebHttpThreadWorker("worker" + std::to_string(i), m_pDeque, m_pVHandlers)); + m_vWorkers.push_back( + new WsjcppLightWebHttpThreadWorker( + "worker" + std::to_string(i), + m_pDeque, + m_pVHandlers, + m_bLoggerEnabled + ) + ); } } diff --git a/src/wsjcpp_light_web_server.h b/src/wsjcpp_light_web_server.h index 6a96940..a1d6507 100644 --- a/src/wsjcpp_light_web_server.h +++ b/src/wsjcpp_light_web_server.h @@ -16,7 +16,11 @@ class WsjcppLightWebHttpHandlerBase { WsjcppLightWebHttpHandlerBase(const std::string &sName); const std::string &name(); virtual bool canHandle(const std::string &sWorkerId, WsjcppLightWebHttpRequest *pRequest) = 0; - virtual bool handle(const std::string &sWorkerId, WsjcppLightWebHttpRequest *pRequest) = 0; + virtual bool handle( + const std::string &sWorkerId, + WsjcppLightWebHttpRequest *pRequest, + WsjcppLightWebHttpResponse *pResponse + ) = 0; private: std::string m_sName; @@ -30,7 +34,8 @@ class WsjcppLightWebHttpThreadWorker { WsjcppLightWebHttpThreadWorker( const std::string &sName, WsjcppLightWebDequeHttpRequests *pDeque, - std::vector *pVHandlers + std::vector *pVHandlers, + bool bLoggerEnabled ); void start(); @@ -38,13 +43,14 @@ class WsjcppLightWebHttpThreadWorker { void run(); private: - bool handle(WsjcppLightWebHttpRequest *pRequest); + void handle(WsjcppLightWebHttpRequest *pRequest, WsjcppLightWebHttpResponse *pResponse); std::string TAG; std::string m_sName; WsjcppLightWebDequeHttpRequests *m_pDeque; std::vector *m_pVHandlers; bool m_bStop; bool m_bStopped; + bool m_bLoggerEnabled; pthread_t m_serverThread; }; @@ -56,6 +62,7 @@ class WsjcppLightWebServer { WsjcppLightWebServer(); void setPort(int nPort); void setMaxWorkers(int nMaxWorkers); + void setLoggerEnable(bool bEnable); void startSync(); void start(); void stop(); @@ -68,6 +75,7 @@ class WsjcppLightWebServer { std::string TAG; WsjcppLightWebDequeHttpRequests *m_pDeque; bool m_bStop; + bool m_bLoggerEnabled; int m_nMaxWorkers; int m_nPort; From 4d044e6f7e809ccf74a970512451897244bc34dc Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Mon, 22 Jun 2020 05:21:46 +0700 Subject: [PATCH 3/8] Fixed crash on macos --- src/main.cpp | 1 + src/wsjcpp_light_web_deque_http_requests.cpp | 8 +++-- src/wsjcpp_light_web_http_request.cpp | 32 ++++++++++++++---- src/wsjcpp_light_web_http_request.h | 8 ++--- src/wsjcpp_light_web_http_response.cpp | 27 +++++++--------- src/wsjcpp_light_web_server.cpp | 34 +++++++++++++------- src/wsjcpp_light_web_server.h | 1 + 7 files changed, 71 insertions(+), 40 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index afc617d..bdfea80 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,6 +40,7 @@ int main(int argc, const char* argv[]) { WsjcppLightWebServer httpServer; httpServer.setPort(nPort); httpServer.setMaxWorkers(4); + // httpServer.setLoggerEnable(true); httpServer.setLoggerEnable(false); if (sType == "folder") { httpServer.addHandler(new WsjcppLightWebHttpHandlerWebFolder("/app/", sDir)); diff --git a/src/wsjcpp_light_web_deque_http_requests.cpp b/src/wsjcpp_light_web_deque_http_requests.cpp index ba85f91..29dee04 100644 --- a/src/wsjcpp_light_web_deque_http_requests.cpp +++ b/src/wsjcpp_light_web_deque_http_requests.cpp @@ -29,15 +29,17 @@ WsjcppLightWebHttpRequest *WsjcppLightWebDequeHttpRequests::popRequest() { // ---------------------------------------------------------------------- void WsjcppLightWebDequeHttpRequests::pushRequest(WsjcppLightWebHttpRequest *pRequest) { + int nPreviousSize = 0; { std::lock_guard guard(this->m_mtxDequeRequests); - if (m_dequeRequests.size() > 20 && m_bLoggerEnabled) { - WsjcppLog::warn(TAG, " deque more than " + std::to_string(m_dequeRequests.size())); + nPreviousSize = m_dequeRequests.size(); + if (nPreviousSize > 20 && m_bLoggerEnabled) { + WsjcppLog::warn(TAG, " deque more than " + std::to_string(nPreviousSize)); } m_dequeRequests.push_front(pRequest); } - if (m_dequeRequests.size() == 1) { + if (nPreviousSize == 0) { m_mtxWaiterRequests.unlock(); } } diff --git a/src/wsjcpp_light_web_http_request.cpp b/src/wsjcpp_light_web_http_request.cpp index b14404a..1817616 100644 --- a/src/wsjcpp_light_web_http_request.cpp +++ b/src/wsjcpp_light_web_http_request.cpp @@ -33,9 +33,8 @@ WsjcppLightWebHttpRequest::WsjcppLightWebHttpRequest(int nSockFd, const std::str m_bClosed = false; m_sRequest = ""; m_nParserState = EnumParserState::START; - long nSec = WsjcppCore::currentTime_seconds(); - m_sLastModified = WsjcppCore::formatTimeForWeb(nSec); - m_nContentLength = 0; + m_nHeaderContentLength = 0; + m_sHeaderConnection = ""; } // ---------------------------------------------------------------------- @@ -52,6 +51,12 @@ std::string WsjcppLightWebHttpRequest::getUniqueId() const { // ---------------------------------------------------------------------- +const std::string &WsjcppLightWebHttpRequest::getRequestData() const { + return m_sRequest; +} + +// ---------------------------------------------------------------------- + std::string WsjcppLightWebHttpRequest::getRequestType() const { return m_sRequestType; } @@ -74,6 +79,12 @@ std::string WsjcppLightWebHttpRequest::getRequestHttpVersion() const { // ---------------------------------------------------------------------- +const std::string &WsjcppLightWebHttpRequest::getHeaderConnection() const { + return m_sHeaderConnection; +} + +// ---------------------------------------------------------------------- + const std::vector &WsjcppLightWebHttpRequest::getRequestQueryParams() { return m_vRequestQueryParams; } @@ -89,6 +100,7 @@ std::string WsjcppLightWebHttpRequest::getAddress() const { void WsjcppLightWebHttpRequest::appendRecieveRequest(const std::string &sRequestPart) { m_sRequest += sRequestPart; const std::string sContentLengthPrefix = "content-length:"; + const std::string sConnectionPrefix = "connection:"; if (m_nParserState == EnumParserState::START) { m_vHeaders.clear(); // WsjcppLog::info(TAG, "START \n>>>\n" + m_sRequest + "\n<<<\n"); @@ -108,10 +120,16 @@ void WsjcppLightWebHttpRequest::appendRecieveRequest(const std::string &sRequest m_vHeaders.push_back(sLine); sLine = WsjcppCore::toLower(sLine); - if (!sLine.compare(0, sContentLengthPrefix.size(), sContentLengthPrefix)) { - m_nContentLength = atoi(sLine.substr(sContentLengthPrefix.size()).c_str()); + if (sLine.rfind(sContentLengthPrefix, 0) == 0) { + m_nHeaderContentLength = atoi(sLine.substr(sContentLengthPrefix.size()).c_str()); // WsjcppLog::warn(TAG, "Content-Length: " + std::to_string(m_nContentLength)); } + if (sLine.rfind(sConnectionPrefix, 0) == 0) { + m_sHeaderConnection = sLine.substr(sConnectionPrefix.size()); + // WsjcppLog::warn(TAG, "Content-Length: " + std::to_string(m_nContentLength)); + } + + } if (bHeadersEnded) { @@ -126,9 +144,9 @@ void WsjcppLightWebHttpRequest::appendRecieveRequest(const std::string &sRequest } } - if (m_nParserState == EnumParserState::BODY && m_sRequest.length() >= m_nContentLength) { + if (m_nParserState == EnumParserState::BODY && m_sRequest.length() >= m_nHeaderContentLength) { m_nParserState = EnumParserState::ENDED; - m_sRequestBody = m_sRequest.substr(0, m_nContentLength); + m_sRequestBody = m_sRequest.substr(0, m_nHeaderContentLength); } } diff --git a/src/wsjcpp_light_web_http_request.h b/src/wsjcpp_light_web_http_request.h index 6a3f833..5340b64 100644 --- a/src/wsjcpp_light_web_http_request.h +++ b/src/wsjcpp_light_web_http_request.h @@ -33,10 +33,12 @@ class WsjcppLightWebHttpRequest { bool isEnoughAppendReceived() const; std::string getAddress() const; + const std::string &getRequestData() const; std::string getRequestType() const; std::string getRequestPath() const; std::string getRequestBody() const; std::string getRequestHttpVersion() const; + const std::string &getHeaderConnection() const; const std::vector &getRequestQueryParams(); private: @@ -53,7 +55,8 @@ class WsjcppLightWebHttpRequest { bool m_bClosed; EnumParserState m_nParserState; std::vector m_vHeaders; - int m_nContentLength; + int m_nHeaderContentLength; + std::string m_sHeaderConnection; std::string m_sUniqueId; std::string m_sRequest; std::string m_sAddress; @@ -62,9 +65,6 @@ class WsjcppLightWebHttpRequest { std::string m_sRequestBody; std::vector m_vRequestQueryParams; std::string m_sRequestHttpVersion; - - std::string m_sResponseCacheControl; - std::string m_sLastModified; }; #endif // WSJCPP_LIGHT_WEB_HTTP_REQUEST_H diff --git a/src/wsjcpp_light_web_http_response.cpp b/src/wsjcpp_light_web_http_response.cpp index 6c7ed9f..9b4cd87 100644 --- a/src/wsjcpp_light_web_http_response.cpp +++ b/src/wsjcpp_light_web_http_response.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include // ---------------------------------------------------------------------- @@ -171,8 +172,7 @@ void WsjcppLightWebHttpResponse::sendText(const std::string &sBody) { WsjcppLog::info(TAG, "\nResponse: \n>>>\n" + sResponse + "\n<<<"); } - send(m_nSockFd, sResponse.c_str(), sResponse.length(),0); - close(m_nSockFd); + send(m_nSockFd, sResponse.c_str(), sResponse.length(), 0); } // ---------------------------------------------------------------------- @@ -191,8 +191,7 @@ void WsjcppLightWebHttpResponse::sendJson(const nlohmann::json &json) { WsjcppLog::info(TAG, "\nResponse: \n>>>\n" + sResponse + "\n<<<"); - send(m_nSockFd, sResponse.c_str(), sResponse.length(),0); - close(m_nSockFd); + send(m_nSockFd, sResponse.c_str(), sResponse.length(), 0); } // ---------------------------------------------------------------------- @@ -214,11 +213,11 @@ void WsjcppLightWebHttpResponse::sendOptions(const std::string &sOptions) { return; } m_bClosed = true; - - WsjcppLog::info(TAG, "\nResponse: \n>>>\n" + sResponse + "\n<<<"); + if (m_bLoggerEnabled) { + WsjcppLog::info(TAG, "\nResponse: \n>>>\n" + sResponse + "\n<<<"); + } - send(m_nSockFd, sResponse.c_str(), sResponse.length(),0); - close(m_nSockFd); + send(m_nSockFd, sResponse.c_str(), sResponse.length(), 0); } // ---------------------------------------------------------------------- @@ -232,20 +231,19 @@ void WsjcppLightWebHttpResponse::sendFile(const std::string &sFilePath) { char *pData = new char[nSize]; // std::vector buffer(size); if (nSize > 10*1024*1024) { - this->payloadTooLarge(); - this->sendEmpty(); + this->payloadTooLarge().sendEmpty(); delete[] pData; return; } if (!f.read(pData, nSize)) { - this->forbidden(); - this->sendEmpty(); + this->forbidden().sendEmpty(); delete[] pData; return; // std::cout << sFilePath << "\n filesize: " << nSize << " bytes\n"; } + this->sendBuffer(sFilePath, pData, nSize); delete[] pData; } @@ -266,7 +264,6 @@ void WsjcppLightWebHttpResponse::sendBuffer(const std::string &sFilePath, const return; } m_bClosed = true; - write(m_nSockFd, sResponse.c_str(), sResponse.length()); - write(m_nSockFd, pBuffer, nBufferSize); - close(m_nSockFd); + send(m_nSockFd, sResponse.c_str(), sResponse.length(), 0); + send(m_nSockFd, pBuffer, nBufferSize, 0); } diff --git a/src/wsjcpp_light_web_server.cpp b/src/wsjcpp_light_web_server.cpp index be7c6b9..00c7543 100644 --- a/src/wsjcpp_light_web_server.cpp +++ b/src/wsjcpp_light_web_server.cpp @@ -76,13 +76,14 @@ void WsjcppLightWebHttpThreadWorker::run() { if (m_bLoggerEnabled) { WsjcppLog::info(TAG, "IP-address: " + pRequest->getAddress()); } - // set timeout options struct timeval timeout; timeout.tv_sec = 1; // 1 seconds timeout timeout.tv_usec = 0; - setsockopt(nSockFd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + int nResult = setsockopt(nSockFd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + // TODO check nResult + // setsockopt() with SO_NOSIGPIPE WsjcppLightWebHttpResponse *pResponse = new WsjcppLightWebHttpResponse(nSockFd, m_bLoggerEnabled); int n; @@ -101,11 +102,10 @@ void WsjcppLightWebHttpThreadWorker::run() { // std::cout << "N: " << n << std::endl; if (n == -1) { bErrorRead = true; - WsjcppLog::err(TAG, std::to_string(nSockFd) + ": error read... "); + WsjcppLog::err(TAG, std::to_string(nSockFd) + ": error read... after: " + pRequest->getRequestData()); break; - } - if (n == 0) { - //close(nSockFd); + } else if (n == 0) { + // close(nSockFd); break; } if (m_bLoggerEnabled) { @@ -142,7 +142,12 @@ void WsjcppLightWebHttpThreadWorker::run() { } else { this->handle(pRequest, pResponse); } - m_pDeque->addKeepAliveSocket(pRequest->getSockFd()); + if (pRequest->getHeaderConnection() == "keep-alive") { + // m_pDeque->addKeepAliveSocket(pRequest->getSockFd()); + close(pRequest->getSockFd()); + } else { + close(pRequest->getSockFd()); + } delete pRequest; delete pResponse; } @@ -185,6 +190,7 @@ WsjcppLightWebServer::WsjcppLightWebServer() { m_bStop = false; m_nPort = 8080; m_bLoggerEnabled = false; + m_nBacklog = 5; } // ---------------------------------------------------------------------- @@ -220,7 +226,7 @@ void WsjcppLightWebServer::setLoggerEnable(bool bEnable) { // ---------------------------------------------------------------------- void WsjcppLightWebServer::startSync() { - + signal(SIGCHLD,SIG_IGN); m_nSockFd = socket(AF_INET, SOCK_STREAM, 0); if (m_nSockFd <= 0) { WsjcppLog::err(TAG, "Failed to establish socket connection"); @@ -240,20 +246,26 @@ void WsjcppLightWebServer::startSync() { WsjcppLog::err(TAG, "Error binding to port " + std::to_string(m_nPort)); return; } - listen(m_nSockFd, 5); + listen(m_nSockFd, m_nBacklog); + signal(SIGCHLD, SIG_IGN); WsjcppLog::info("LightHttpServer", "Light Http Server started on " + std::to_string(m_nPort) + " port."); std::string str; m_bStop = false; this->checkAndRestartWorkers(); - while (!m_bStop) { // or problem can be here + while (!m_bStop) { struct sockaddr_in clientAddress; socklen_t sosize = sizeof(clientAddress); int nSockFd = accept(m_nSockFd,(struct sockaddr*)&clientAddress,&sosize); std::string sAddress = inet_ntoa(clientAddress.sin_addr); if (m_bLoggerEnabled) { - WsjcppLog::info(TAG, "Connected " + sAddress); + WsjcppLog::info(TAG, "Connected " + sAddress + ":" + std::to_string(clientAddress.sin_port)); } + int option_value = 1; /* Set NOSIGPIPE to ON */ + if (setsockopt (nSockFd, SOL_SOCKET, SO_NOSIGPIPE, &option_value, sizeof (option_value)) < 0) { + // perror ("setsockopt(,,SO_NOSIGPIPE)"); + } + WsjcppLightWebHttpRequest *pInfo = new WsjcppLightWebHttpRequest(nSockFd, sAddress); // info will be removed inside a thread m_pDeque->pushRequest(pInfo); // here will be unlocked workers diff --git a/src/wsjcpp_light_web_server.h b/src/wsjcpp_light_web_server.h index a1d6507..858993a 100644 --- a/src/wsjcpp_light_web_server.h +++ b/src/wsjcpp_light_web_server.h @@ -83,6 +83,7 @@ class WsjcppLightWebServer { std::vector m_vWorkers; int m_nSockFd; + int m_nBacklog; struct sockaddr_in m_serverAddress; pthread_t m_serverThread; }; From 07230de840fbe8e9911774e26821bccb6f162516 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Mon, 22 Jun 2020 14:48:41 +0700 Subject: [PATCH 4/8] Fixed __pthread_mutex_lock: Assertion mutex->__data.__owner == 0 failed --- src/wsjcpp_light_web_deque_http_requests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wsjcpp_light_web_deque_http_requests.cpp b/src/wsjcpp_light_web_deque_http_requests.cpp index 29dee04..153eb29 100644 --- a/src/wsjcpp_light_web_deque_http_requests.cpp +++ b/src/wsjcpp_light_web_deque_http_requests.cpp @@ -14,7 +14,7 @@ WsjcppLightWebDequeHttpRequests::WsjcppLightWebDequeHttpRequests() { WsjcppLightWebHttpRequest *WsjcppLightWebDequeHttpRequests::popRequest() { if (m_dequeRequests.size() == 0) { - m_mtxWaiterRequests.lock(); + m_mtxWaiterRequests.try_lock(); } std::lock_guard guard(this->m_mtxDequeRequests); WsjcppLightWebHttpRequest *pRequest = nullptr; From 4546073f8c85444d8cc90ed4885864695c79e1af Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Mon, 22 Jun 2020 14:49:29 +0700 Subject: [PATCH 5/8] Redesign WsjcppLightWebDequeHttpRequests::pushRequest --- src/wsjcpp_light_web_deque_http_requests.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/wsjcpp_light_web_deque_http_requests.cpp b/src/wsjcpp_light_web_deque_http_requests.cpp index 153eb29..66ddb3e 100644 --- a/src/wsjcpp_light_web_deque_http_requests.cpp +++ b/src/wsjcpp_light_web_deque_http_requests.cpp @@ -29,16 +29,13 @@ WsjcppLightWebHttpRequest *WsjcppLightWebDequeHttpRequests::popRequest() { // ---------------------------------------------------------------------- void WsjcppLightWebDequeHttpRequests::pushRequest(WsjcppLightWebHttpRequest *pRequest) { - int nPreviousSize = 0; - { - std::lock_guard guard(this->m_mtxDequeRequests); - nPreviousSize = m_dequeRequests.size(); - if (nPreviousSize > 20 && m_bLoggerEnabled) { - WsjcppLog::warn(TAG, " deque more than " + std::to_string(nPreviousSize)); - } - m_dequeRequests.push_front(pRequest); - } + std::lock_guard guard(this->m_mtxDequeRequests); + int nPreviousSize = m_dequeRequests.size(); + if (nPreviousSize > 20 && m_bLoggerEnabled) { + WsjcppLog::warn(TAG, " deque more than " + std::to_string(nPreviousSize)); + } + m_dequeRequests.push_front(pRequest); if (nPreviousSize == 0) { m_mtxWaiterRequests.unlock(); } From 1e077b4da682924aae1af0656724db02624abc91 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Wed, 8 Jul 2020 01:55:44 +0700 Subject: [PATCH 6/8] Precommit - start new processing --- src/main.cpp | 6 +- src/wsjcpp_light_web_deque_http_requests.cpp | 1 + src/wsjcpp_light_web_http_response.cpp | 4 +- src/wsjcpp_light_web_server.cpp | 221 +++++++++++++++++-- src/wsjcpp_light_web_server.h | 5 +- 5 files changed, 212 insertions(+), 25 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index bdfea80..4226152 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,8 +40,7 @@ int main(int argc, const char* argv[]) { WsjcppLightWebServer httpServer; httpServer.setPort(nPort); httpServer.setMaxWorkers(4); - // httpServer.setLoggerEnable(true); - httpServer.setLoggerEnable(false); + httpServer.setLoggerEnable(true); if (sType == "folder") { httpServer.addHandler(new WsjcppLightWebHttpHandlerWebFolder("/app/", sDir)); httpServer.addHandler(new WsjcppLightWebHttpHandlerWebFolder("/", sDir)); @@ -49,7 +48,6 @@ int main(int argc, const char* argv[]) { httpServer.addHandler(new WsjcppLightWebHttpHandlerRewriteFolder("/app/", sDir)); httpServer.addHandler(new WsjcppLightWebHttpHandlerRewriteFolder("/", sDir)); } - httpServer.startSync(); - return 0; + return httpServer.startSync2(); } diff --git a/src/wsjcpp_light_web_deque_http_requests.cpp b/src/wsjcpp_light_web_deque_http_requests.cpp index 66ddb3e..7066f25 100644 --- a/src/wsjcpp_light_web_deque_http_requests.cpp +++ b/src/wsjcpp_light_web_deque_http_requests.cpp @@ -61,4 +61,5 @@ void WsjcppLightWebDequeHttpRequests::setLoggerEnable(bool bEnable) { void WsjcppLightWebDequeHttpRequests::addKeepAliveSocket(int m_nSockFd) { WsjcppLog::warn(TAG, "WsjcppLightWebDequeHttpRequests::addKeepAliveSocket not implemented"); + } \ No newline at end of file diff --git a/src/wsjcpp_light_web_http_response.cpp b/src/wsjcpp_light_web_http_response.cpp index 9b4cd87..156f8c3 100644 --- a/src/wsjcpp_light_web_http_response.cpp +++ b/src/wsjcpp_light_web_http_response.cpp @@ -264,6 +264,6 @@ void WsjcppLightWebHttpResponse::sendBuffer(const std::string &sFilePath, const return; } m_bClosed = true; - send(m_nSockFd, sResponse.c_str(), sResponse.length(), 0); - send(m_nSockFd, pBuffer, nBufferSize, 0); + send(m_nSockFd, sResponse.c_str(), sResponse.length(), MSG_NOSIGNAL); + send(m_nSockFd, pBuffer, nBufferSize, MSG_NOSIGNAL); } diff --git a/src/wsjcpp_light_web_server.cpp b/src/wsjcpp_light_web_server.cpp index 00c7543..45a5349 100644 --- a/src/wsjcpp_light_web_server.cpp +++ b/src/wsjcpp_light_web_server.cpp @@ -3,6 +3,16 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + // --------------------------------------------------------------------- // WsjcppLightWebHttpHandlerBase @@ -63,6 +73,9 @@ void WsjcppLightWebHttpThreadWorker::stop() { // ---------------------------------------------------------------------- void WsjcppLightWebHttpThreadWorker::run() { + if (m_bLoggerEnabled) { + WsjcppLog::info(TAG, "Running"); + } const int nMaxPackageSize = 4096; while (1) { if (m_bStop) { @@ -157,6 +170,9 @@ void WsjcppLightWebHttpThreadWorker::run() { } } m_bStopped = true; + if (m_bLoggerEnabled) { + WsjcppLog::info(TAG, "Stopped"); + } } // ---------------------------------------------------------------------- @@ -188,21 +204,20 @@ WsjcppLightWebServer::WsjcppLightWebServer() { m_pDeque = new WsjcppLightWebDequeHttpRequests(); m_pVHandlers = new std::vector(); m_bStop = false; - m_nPort = 8080; - m_bLoggerEnabled = false; - m_nBacklog = 5; + setPort(8080); + setLoggerEnable(false); + m_nBacklog = 10; } // ---------------------------------------------------------------------- void WsjcppLightWebServer::setPort(int nPort) { // TODO use a port validators - if (nPort > 10 && nPort < 65536) { - m_nPort = nPort; - } else { - WsjcppLog::throw_err(TAG, "Port must be 10...65535"); + if (nPort <= 10 || nPort > 65535) { + WsjcppLog::throw_err(TAG, "Port must be 11...65535"); } m_nPort = nPort; + m_sPort = std::to_string(m_nPort); } // ---------------------------------------------------------------------- @@ -226,14 +241,14 @@ void WsjcppLightWebServer::setLoggerEnable(bool bEnable) { // ---------------------------------------------------------------------- void WsjcppLightWebServer::startSync() { - signal(SIGCHLD,SIG_IGN); - m_nSockFd = socket(AF_INET, SOCK_STREAM, 0); - if (m_nSockFd <= 0) { + + m_nListenerSockFd = socket(AF_INET, SOCK_STREAM, 0); + if (m_nListenerSockFd <= 0) { WsjcppLog::err(TAG, "Failed to establish socket connection"); return; } int enable = 1; - if (setsockopt(m_nSockFd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) { + if (setsockopt(m_nListenerSockFd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) { WsjcppLog::err(TAG, "setsockopt(SO_REUSEADDR) failed"); return; } @@ -242,12 +257,12 @@ void WsjcppLightWebServer::startSync() { m_serverAddress.sin_family = AF_INET; m_serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); m_serverAddress.sin_port = htons(m_nPort); - if (bind(m_nSockFd, (struct sockaddr *)&m_serverAddress, sizeof(m_serverAddress)) == -1) { + if (bind(m_nListenerSockFd, (struct sockaddr *)&m_serverAddress, sizeof(m_serverAddress)) == -1) { WsjcppLog::err(TAG, "Error binding to port " + std::to_string(m_nPort)); return; } - listen(m_nSockFd, m_nBacklog); - signal(SIGCHLD, SIG_IGN); + listen(m_nListenerSockFd, m_nBacklog); + // signal(SIGCHLD, SIG_IGN); WsjcppLog::info("LightHttpServer", "Light Http Server started on " + std::to_string(m_nPort) + " port."); std::string str; @@ -256,15 +271,15 @@ void WsjcppLightWebServer::startSync() { while (!m_bStop) { struct sockaddr_in clientAddress; socklen_t sosize = sizeof(clientAddress); - int nSockFd = accept(m_nSockFd,(struct sockaddr*)&clientAddress,&sosize); + int nSockFd = accept(m_nListenerSockFd,(struct sockaddr*)&clientAddress,&sosize); std::string sAddress = inet_ntoa(clientAddress.sin_addr); if (m_bLoggerEnabled) { WsjcppLog::info(TAG, "Connected " + sAddress + ":" + std::to_string(clientAddress.sin_port)); } int option_value = 1; /* Set NOSIGPIPE to ON */ - if (setsockopt (nSockFd, SOL_SOCKET, SO_NOSIGPIPE, &option_value, sizeof (option_value)) < 0) { + //if (setsockopt (nSockFd, SOL_SOCKET, SO_NOSIGPIPE, &option_value, sizeof (option_value)) < 0) { // perror ("setsockopt(,,SO_NOSIGPIPE)"); - } + //} WsjcppLightWebHttpRequest *pInfo = new WsjcppLightWebHttpRequest(nSockFd, sAddress); // info will be removed inside a thread @@ -277,9 +292,154 @@ void WsjcppLightWebServer::startSync() { } m_pDeque->cleanup(); this->stopAndRemoveWorkers(); - close(m_nSockFd); + close(m_nListenerSockFd); +} + +// +// ---------------------------------------------------------------------- + +// get sockaddr, IPv4 or IPv6: +void *get_in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); } +// used this https://masandilov.ru/network/guide_to_network_programming7 + +int WsjcppLightWebServer::startSync2() { + fd_set master; // master file descriptor list + fd_set read_fds; // temp file descriptor list for select() + int fdmax; // maximum file descriptor number + + int newfd; // newly accept()ed socket descriptor + struct sockaddr_storage clientAddress; // client address + const int nBufferLength = 1024; + char sBuffer[nBufferLength]; // buffer for client data + int nbytes; + + char remoteIP[INET6_ADDRSTRLEN]; + + int yes=1; // for setsockopt() SO_REUSEADDR, below + int i, j, rv; + + struct addrinfo hints, *ai, *p; + + FD_ZERO(&master); // clear the master and temp sets + FD_ZERO(&read_fds); + + // get us a socket and bind it + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + if ((rv = getaddrinfo(NULL, m_sPort.c_str(), &hints, &ai)) != 0) { + fprintf(stderr, "selectserver: %s\n", gai_strerror(rv)); + return 1; + } + + for (p = ai; p != NULL; p = p->ai_next) { + m_nListenerSockFd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (m_nListenerSockFd < 0) { + continue; + } + + // lose the pesky "address already in use" error message + setsockopt(m_nListenerSockFd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); + + if (bind(m_nListenerSockFd, p->ai_addr, p->ai_addrlen) < 0) { + close(m_nListenerSockFd); + continue; + } + + break; + } + + // if we got here, it means we didn't get bound + if (p == NULL) { + WsjcppLog::err(TAG, "Error binding to port " + std::to_string(m_nPort)); + return 2; + } + + freeaddrinfo(ai); // all done with this + + // listen + if (listen(m_nListenerSockFd, m_nBacklog) == -1) { + perror("listen"); + return 3; + } + + // add the listener to the master set + FD_SET(m_nListenerSockFd, &master); + + // keep track of the biggest file descriptor + fdmax = m_nListenerSockFd; // so far, it's this one + + // main loop + for(;;) { + read_fds = master; // copy it + if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) { + perror("select"); + return 4; + } + + // run through the existing connections looking for data to read + for(i = 0; i <= fdmax; i++) { + if (FD_ISSET(i, &read_fds)) { // we got one!! + if (i == m_nListenerSockFd) { + // handle new connections + socklen_t clientAddressLength = sizeof clientAddress; + newfd = accept(m_nListenerSockFd, (struct sockaddr *)&clientAddress, &clientAddressLength); + + if (newfd == -1) { + WsjcppLog::err(TAG, "accept"); + } else { + FD_SET(newfd, &master); // add to master set + if (newfd > fdmax) { // keep track of the max + fdmax = newfd; + } + logNewConnection(clientAddress, clientAddressLength); + } + } else { + // handle data from a client + std::cout << i << std::endl; + if ((nbytes = recv(i, sBuffer, nBufferLength, 0)) <= 0) { + // got error or connection closed by client + if (nbytes == 0) { + // connection closed + WsjcppLog::err(TAG, "selectserver: socket " + std::to_string(i) + " hung up"); + } else { + WsjcppLog::err(TAG, "recv"); + } + close(i); // bye! + FD_CLR(i, &master); // remove from master set + } else { + // TODO add to queue for reading data + WsjcppLog::err(TAG, "recved " + std::string(sBuffer, nbytes)); + // std::cout << std::string(sBuffer) << std::endl; + + // we got some data from a client + for (j = 0; j <= fdmax; j++) { + // send to everyone! + if (FD_ISSET(j, &master)) { + // except the listener and ourselves + if (j != m_nListenerSockFd && j != i) { + if (send(j, sBuffer, nbytes, 0) == -1) { + perror("send"); + } + } + } + } + } + } // END handle data from client + } // END got new incoming connection + } // END looping through file descriptors + } // END for(;;)--and you thought it would never end! + return 0; +} // ---------------------------------------------------------------------- void* wsjcppLightWebServerProcessServerStart(void *arg) { @@ -357,4 +517,29 @@ std::string WsjcppLightWebServer::readAddress(int nSockFd) { return std::string(clientip); } +// ---------------------------------------------------------------------- + +void WsjcppLightWebServer::logNewConnection(sockaddr_storage &clientAddress, socklen_t &clientAddressLength) { + char hoststr[NI_MAXHOST]; + char portstr[NI_MAXSERV]; + + int rc = getnameinfo( + (struct sockaddr *)&clientAddress, + clientAddressLength, + hoststr, + sizeof(hoststr), + portstr, + sizeof(portstr), + NI_NUMERICHOST | NI_NUMERICSERV + ); + + if (rc == 0) { + if (m_bLoggerEnabled) { + WsjcppLog::info(TAG, "New connection from " + std::string(hoststr) + " " + std::string(portstr)); + } + } else { + WsjcppLog::err(TAG, "Failed call getnameinfo by address"); + } +} + // ---------------------------------------------------------------------- \ No newline at end of file diff --git a/src/wsjcpp_light_web_server.h b/src/wsjcpp_light_web_server.h index 858993a..ce7d359 100644 --- a/src/wsjcpp_light_web_server.h +++ b/src/wsjcpp_light_web_server.h @@ -64,6 +64,7 @@ class WsjcppLightWebServer { void setMaxWorkers(int nMaxWorkers); void setLoggerEnable(bool bEnable); void startSync(); + int startSync2(); void start(); void stop(); void addHandler(WsjcppLightWebHttpHandlerBase *pHandler); @@ -72,6 +73,7 @@ class WsjcppLightWebServer { void checkAndRestartWorkers(); void stopAndRemoveWorkers(); std::string readAddress(int nSockFd); + void logNewConnection(sockaddr_storage &clientAddress, socklen_t &clientAddressLength); std::string TAG; WsjcppLightWebDequeHttpRequests *m_pDeque; bool m_bStop; @@ -79,10 +81,11 @@ class WsjcppLightWebServer { int m_nMaxWorkers; int m_nPort; + std::string m_sPort; std::vector *m_pVHandlers; std::vector m_vWorkers; - int m_nSockFd; + int m_nListenerSockFd; int m_nBacklog; struct sockaddr_in m_serverAddress; pthread_t m_serverThread; From 2d5230724c10bfe8f7fcf7bf0bcf3a268614d8ae Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 23 Jul 2020 12:39:44 +0700 Subject: [PATCH 7/8] Prepared map with income requests --- src/wsjcpp_light_web_http_request.cpp | 9 +++++++++ src/wsjcpp_light_web_http_request.h | 3 ++- src/wsjcpp_light_web_server.cpp | 28 +++++++++++++++++++++++++-- src/wsjcpp_light_web_server.h | 4 +++- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/wsjcpp_light_web_http_request.cpp b/src/wsjcpp_light_web_http_request.cpp index 1817616..4fa1ea1 100644 --- a/src/wsjcpp_light_web_http_request.cpp +++ b/src/wsjcpp_light_web_http_request.cpp @@ -152,6 +152,15 @@ void WsjcppLightWebHttpRequest::appendRecieveRequest(const std::string &sRequest // ---------------------------------------------------------------------- +void WsjcppLightWebHttpRequest::appendRecieveRequest(const char *sRequestPart, int nLength) { + WsjcppLog::warn(TAG, "Append request " + std::string(sRequestPart, nLength)); + + // TODO parse what income + // +} + +// ---------------------------------------------------------------------- + bool WsjcppLightWebHttpRequest::isEnoughAppendReceived() const { return m_nParserState == EnumParserState::ENDED; } diff --git a/src/wsjcpp_light_web_http_request.h b/src/wsjcpp_light_web_http_request.h index 5340b64..b7beaa7 100644 --- a/src/wsjcpp_light_web_http_request.h +++ b/src/wsjcpp_light_web_http_request.h @@ -29,7 +29,8 @@ class WsjcppLightWebHttpRequest { int getSockFd() const; std::string getUniqueId() const; - void appendRecieveRequest(const std::string &sRequestPart); + void appendRecieveRequest(const std::string &sRequestPart); // depraceted + void appendRecieveRequest(const char *sRequestPart, int nLength); bool isEnoughAppendReceived() const; std::string getAddress() const; diff --git a/src/wsjcpp_light_web_server.cpp b/src/wsjcpp_light_web_server.cpp index 45a5349..1479038 100644 --- a/src/wsjcpp_light_web_server.cpp +++ b/src/wsjcpp_light_web_server.cpp @@ -410,6 +410,7 @@ int WsjcppLightWebServer::startSync2() { // got error or connection closed by client if (nbytes == 0) { // connection closed + eraseIncomeRequest(i); WsjcppLog::err(TAG, "selectserver: socket " + std::to_string(i) + " hung up"); } else { WsjcppLog::err(TAG, "recv"); @@ -417,7 +418,12 @@ int WsjcppLightWebServer::startSync2() { close(i); // bye! FD_CLR(i, &master); // remove from master set } else { - // TODO add to queue for reading data + addIncomeRequest(i); + m_mapIncomeRequests[i]->appendRecieveRequest(sBuffer, nbytes); + if (m_mapIncomeRequests[i]->isEnoughAppendReceived()) { + // TODO put to qeque requets and erase from m_mapIncomeRequests + } + WsjcppLog::err(TAG, "recved " + std::string(sBuffer, nbytes)); // std::cout << std::string(sBuffer) << std::endl; @@ -542,4 +548,22 @@ void WsjcppLightWebServer::logNewConnection(sockaddr_storage &clientAddress, soc } } -// ---------------------------------------------------------------------- \ No newline at end of file +// ---------------------------------------------------------------------- + +void WsjcppLightWebServer::addIncomeRequest(int i) { + std::map::iterator it = m_mapIncomeRequests.find(i); + if (it == m_mapIncomeRequests.end()) { // create a new one + // TODO set address + // std::string sAddress = inet_ntoa(clientAddress.sin_addr); + m_mapIncomeRequests[i] = new WsjcppLightWebHttpRequest(i, ""); + } +} + +// ---------------------------------------------------------------------- + +void WsjcppLightWebServer::eraseIncomeRequest(int i) { + std::map::iterator it = m_mapIncomeRequests.find(i); + if (it != m_mapIncomeRequests.end()) { // create a new one + m_mapIncomeRequests.erase(it); + } +} \ No newline at end of file diff --git a/src/wsjcpp_light_web_server.h b/src/wsjcpp_light_web_server.h index ce7d359..fe0a744 100644 --- a/src/wsjcpp_light_web_server.h +++ b/src/wsjcpp_light_web_server.h @@ -74,6 +74,8 @@ class WsjcppLightWebServer { void stopAndRemoveWorkers(); std::string readAddress(int nSockFd); void logNewConnection(sockaddr_storage &clientAddress, socklen_t &clientAddressLength); + void addIncomeRequest(int i); + void eraseIncomeRequest(int i); std::string TAG; WsjcppLightWebDequeHttpRequests *m_pDeque; bool m_bStop; @@ -84,7 +86,7 @@ class WsjcppLightWebServer { std::string m_sPort; std::vector *m_pVHandlers; std::vector m_vWorkers; - + std::map m_mapIncomeRequests; int m_nListenerSockFd; int m_nBacklog; struct sockaddr_in m_serverAddress; From 7a8e16ac14d68d79a97eb2ad5aa6d394b9af328d Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 23 Jul 2020 14:11:03 +0700 Subject: [PATCH 8/8] New parsing for request --- src/wsjcpp_light_web_http_request.cpp | 141 +++++++++++++++++++++++++- src/wsjcpp_light_web_http_request.h | 10 +- src/wsjcpp_light_web_server.cpp | 7 +- 3 files changed, 153 insertions(+), 5 deletions(-) diff --git a/src/wsjcpp_light_web_http_request.cpp b/src/wsjcpp_light_web_http_request.cpp index 4fa1ea1..9ee1da8 100644 --- a/src/wsjcpp_light_web_http_request.cpp +++ b/src/wsjcpp_light_web_http_request.cpp @@ -152,11 +152,67 @@ void WsjcppLightWebHttpRequest::appendRecieveRequest(const std::string &sRequest // ---------------------------------------------------------------------- -void WsjcppLightWebHttpRequest::appendRecieveRequest(const char *sRequestPart, int nLength) { +bool WsjcppLightWebHttpRequest::appendRecieveRequest(const char *sRequestPart, int nLength) { WsjcppLog::warn(TAG, "Append request " + std::string(sRequestPart, nLength)); - // TODO parse what income - // + int nPos = 0; + // fast preprocessing (only split) + if (m_nParserState == EnumParserState::START) { + int nPosEndType = parseRequestType(nPos, sRequestPart, nLength); + if (nPosEndType == -1) { + WsjcppLog::err(TAG, "Problem with parsing: parseRequestType"); + return false; + } else { + nPos = nPosEndType; + } + + int nPosEndPathAndGetParams = parseRequestPathAndGetParams(nPos, sRequestPart, nLength); + if (nPosEndPathAndGetParams == -1) { + WsjcppLog::err(TAG, "Problem with parsing: parseRequestPathAndGetParams"); + return false; + } else { + nPos = nPosEndPathAndGetParams; + } + + int nPosEndHttpVersion = parseRequestHttpVersion(nPos, sRequestPart, nLength); + if (nPosEndHttpVersion == -1) { + WsjcppLog::err(TAG, "Problem with parsing: parseRequestHttpVersion"); + return false; + } else { + nPos = nPosEndHttpVersion; + } + WsjcppLog::warn(TAG, "Request Type " + m_sRequestType); + WsjcppLog::warn(TAG, "Request PathAndGet " + m_sRequestPathAndGetParams); + WsjcppLog::warn(TAG, "Request HttpVersion " + m_sRequestHttpVersion); + m_nParserState = EnumParserState::HEADERS; + } + + if (m_nParserState == EnumParserState::HEADERS) { + // fast preprocessing + while (nPos < nLength) { + nPos = parseRequestNextHeader(nPos, sRequestPart, nLength); + if (sRequestPart[nPos] == '\n') { + nPos++; + if (m_nHeaderContentLength == 0) { + m_nParserState = EnumParserState::ENDED; + } else { + // TODO check max body size + m_bRequestBody = new char[m_nHeaderContentLength]; + m_nRequestBodyWritePosition = 0; + m_nParserState = EnumParserState::BODY; + } + break; + } + } + } + + if (m_nParserState == EnumParserState::BODY) { + for (int i = nPos; i < nLength; i++) { + m_bRequestBody[m_nRequestBodyWritePosition] = sRequestPart[i]; + m_nRequestBodyWritePosition++; + } + } + return true; } // ---------------------------------------------------------------------- @@ -220,3 +276,82 @@ void WsjcppLightWebHttpRequest::parseFirstLine(const std::string &sHeader) { // ---------------------------------------------------------------------- +int WsjcppLightWebHttpRequest::parseRequestType(int nPos, const char *sRequestPart, int nLength) { + // fast preprocessing + m_sRequestType = ""; + for (int i = 0; i < nLength; i++) { + char c = sRequestPart[i]; + if (c == ' ') { + return i + 1; + } else { + m_sRequestType += c; + } + } +} + +// ---------------------------------------------------------------------- + +int WsjcppLightWebHttpRequest::parseRequestPathAndGetParams(int nPos, const char *sRequestPart, int nLength) { + // fast preprocessing + m_sRequestPathAndGetParams = ""; + for (int i = nPos; i < nLength; i++) { + char c = sRequestPart[i]; + if (c == ' ') { + return i + 1; + } else { + m_sRequestPathAndGetParams += c; + } + } + return -1; +} + +// ---------------------------------------------------------------------- + +int WsjcppLightWebHttpRequest::parseRequestHttpVersion(int nPos, const char *sRequestPart, int nLength) { + // fast preprocessing + m_sRequestHttpVersion = ""; + for (int i = nPos; i < nLength; i++) { + char c = sRequestPart[i]; + if (c == '\n') { + return i + 1; + } else { + m_sRequestHttpVersion += c; + } + } + return -1; +} + +// ---------------------------------------------------------------------- + +int WsjcppLightWebHttpRequest::parseRequestNextHeader(int nPos, const char *sRequestPart, int nLength) { + // fast preprocessing + std::string sHeaderName = ""; + for (int i = nPos; i < nLength; i++) { + char c = sRequestPart[i]; + if (c == ':') { + nPos = i + 1; + break; + } else { + sHeaderName += c; + } + } + sHeaderName = WsjcppCore::toLower(sHeaderName); + std::string sHeaderValue = ""; + for (int i = nPos; i < nLength; i++) { + char c = sRequestPart[i]; + if (c == '\n') { + WsjcppLog::warn(TAG, "sHeaderName = " + sHeaderName); + WsjcppLog::warn(TAG, "sHeaderValue = " + sHeaderValue); + if (sHeaderName == "content-length") { + m_nHeaderContentLength = atoi(sHeaderValue.c_str()); + } else if (sHeaderName == "connection") { + m_sHeaderConnection = sHeaderValue; + } + return i + 1; + } else { + sHeaderValue += c; + } + } + return nPos; +} + diff --git a/src/wsjcpp_light_web_http_request.h b/src/wsjcpp_light_web_http_request.h index b7beaa7..61a7081 100644 --- a/src/wsjcpp_light_web_http_request.h +++ b/src/wsjcpp_light_web_http_request.h @@ -30,7 +30,7 @@ class WsjcppLightWebHttpRequest { int getSockFd() const; std::string getUniqueId() const; void appendRecieveRequest(const std::string &sRequestPart); // depraceted - void appendRecieveRequest(const char *sRequestPart, int nLength); + bool appendRecieveRequest(const char *sRequestPart, int nLength); bool isEnoughAppendReceived() const; std::string getAddress() const; @@ -46,9 +46,14 @@ class WsjcppLightWebHttpRequest { std::string TAG; void parseFirstLine(const std::string &sHeader); + int parseRequestType(int nPos, const char *sRequestPart, int nLength); + int parseRequestPathAndGetParams(int nPos, const char *sRequestPart, int nLength); + int parseRequestHttpVersion(int nPos, const char *sRequestPart, int nLength); + int parseRequestNextHeader(int nPos, const char *sRequestPart, int nLength); enum EnumParserState { START, + HEADERS, BODY, ENDED }; @@ -63,7 +68,10 @@ class WsjcppLightWebHttpRequest { std::string m_sAddress; std::string m_sRequestType; std::string m_sRequestPath; + std::string m_sRequestPathAndGetParams; std::string m_sRequestBody; + char *m_bRequestBody; + int m_nRequestBodyWritePosition; std::vector m_vRequestQueryParams; std::string m_sRequestHttpVersion; }; diff --git a/src/wsjcpp_light_web_server.cpp b/src/wsjcpp_light_web_server.cpp index 1479038..4ccbad3 100644 --- a/src/wsjcpp_light_web_server.cpp +++ b/src/wsjcpp_light_web_server.cpp @@ -419,8 +419,13 @@ int WsjcppLightWebServer::startSync2() { FD_CLR(i, &master); // remove from master set } else { addIncomeRequest(i); - m_mapIncomeRequests[i]->appendRecieveRequest(sBuffer, nbytes); + if (!m_mapIncomeRequests[i]->appendRecieveRequest(sBuffer, nbytes)) { + WsjcppLog::err(TAG, "Something wrong with " + std::string(sBuffer, nbytes)); + // TODO close connection + } + if (m_mapIncomeRequests[i]->isEnoughAppendReceived()) { + // TODO put to qeque requets and erase from m_mapIncomeRequests }