#include "WHttpServer.h" #include #include //#include "stdafx.h" WHttpServer::WHttpServer() { mg_mgr_init(&_mgr); } WHttpServer::~WHttpServer() { stop(); delete _threadPool; _threadPool = nullptr; } //实现usleep void WHttpServer::usleep(unsigned long usec) { HANDLE timer; LARGE_INTEGER interval; interval.QuadPart = (10 * usec); timer = CreateWaitableTimer(NULL, TRUE, NULL); SetWaitableTimer(timer, &interval, 0, NULL, NULL, 0); WaitForSingleObject(timer, INFINITE); CloseHandle(timer); } bool WHttpServer::init(int maxEventThreadNum) { std::unique_lock locker(_httpLocker); _threadPool = new WThreadPool(); _threadPool->setMaxThreadNum(maxEventThreadNum); return true; } bool WHttpServer::startHttp(string strIp, int port) { std::unique_lock locker(_httpLocker); if (!_threadPool) { Logw("WHttpServer::StartHttp do not init"); return false; } if (_httpPort != -1) { Logw("WHttpServer::StartHttp http server is already start port:%d", _httpPort); return false; } std::stringstream sstream; sstream << strIp << ":" << port; _httpCbMsg.httpServer = this; _httpCbMsg.httpsFlag = false; mg_connection *serverConn = mg_http_listen(&_mgr, sstream.str().c_str(), WHttpServer::recvHttpRequestCallback, (void *)&_httpCbMsg); if (!serverConn) { Logw("WHttpServer::StartHttp http server start failed: %s", sstream.str().c_str()); return false; } Logi("WHttpServer::StartHttp http server start success: %s", sstream.str().c_str()); _httpPort = port; return true; } bool WHttpServer::startHttps(int port, string certPath, string keyPath) { std::unique_lock locker(_httpLocker); if (!_threadPool) { Logw("WHttpServer::StartHttps do not init"); return false; } if (_httpsPort != -1) { Logw("WHttpServer::StartHttps https server is already start port:%d", _httpsPort); return false; } _certPath = certPath; _keyPath = keyPath; std::stringstream sstream; sstream << "https://0.0.0.0:" << port; _httpsCbMsg.httpServer = this; _httpsCbMsg.httpsFlag = true; mg_connection *serverConn = mg_http_listen(&_mgr, sstream.str().c_str(), WHttpServer::recvHttpRequestCallback, (void *)&_httpsCbMsg); if (!serverConn) { Logw("WHttpServer::StartHttps https server start failed: %s", sstream.str().c_str()); return false; } Logi("WHttpServer::StartHttps https server start success: %s", sstream.str().c_str()); _httpsPort = port; return true; } bool WHttpServer::stop() { std::unique_lock locker(_httpLocker); if (_httpPort == -1 && _httpsPort == -1) { return true; } _httpPort = -1; _httpsPort = -1; usleep(100*1000); // make sure run() can not call mg_mgr_poll mg_mgr_free(&_mgr); reset(); return true; } bool WHttpServer::run() { if (_httpPort == -1 && _httpsPort == -1) { usleep(1000); return false; } sendHttpMsgPoll(); mg_mgr_poll(&_mgr, 1); return true; } bool WHttpServer::isRunning() { return (_httpPort != -1 || _httpsPort != -1); } void WHttpServer::addHttpApi(const string &uri, HttpCbFun fun, int httpMethods) { HttpApiData httpApiData; httpApiData.httpCbFun = fun; httpApiData.httpMethods = httpMethods; _httpApiMap[uri] = httpApiData; } void WHttpServer::addChunkHttpApi(const string &uri, HttpCbFun fun, int httpMethods) { HttpApiData httpApiData; httpApiData.httpCbFun = fun; httpApiData.httpMethods = httpMethods; _chunkHttpApiMap[uri] = httpApiData; } void WHttpServer::setHttpFilter(HttpFilterFun filter) { _httpFilterFun = filter; } void WHttpServer::forceCloseHttpConnection(shared_ptr httpMsg) { mg_connection *conn = httpMsg->httpConnection; conn->is_closing = 1; } void WHttpServer::closeHttpConnection(struct mg_connection *conn, bool isDirectClose) { if (conn->label[W_FD_STATUS_BIT] == HTTP_NORMAL_CLOSE) { return; } if (isDirectClose) { conn->is_draining = 1; } conn->label[W_FD_STATUS_BIT] = HTTP_NORMAL_CLOSE; } std::set WHttpServer::getSupportMethods(int httpMethods) { std::set methodsSet; if (httpMethods & W_HTTP_GET) { methodsSet.insert("GET"); } if (httpMethods & W_HTTP_GET) { methodsSet.insert("GET"); } if (httpMethods & W_HTTP_POST) { methodsSet.insert("POST"); } if (httpMethods & W_HTTP_PUT) { methodsSet.insert("PUT"); } if (httpMethods & W_HTTP_DELETE) { methodsSet.insert("DELETE"); } if (httpMethods & W_HTTP_HEAD) { methodsSet.insert("HEAD"); } return methodsSet; } bool WHttpServer::handleStaticWebDir(shared_ptr httpMsg, HttpStaticWebDir &webDir) { string filePath = webDir.dirPath + httpMsg->uri; FILE *file = fopen(filePath.c_str(), "r"); if (!file) { // Logw("WHttpServer::handleStaticWebDir can not open file:%s", filePath.c_str()); // httpReplyJson(httpMsg, 500, "", formJsonBody(101, "can not find this file")); return false; } struct stat statbuf; stat(filePath.c_str(), &statbuf); int64_t fileSize = statbuf.st_size; stringstream sstream; if (httpMsg->method == "HEAD") { formStaticWebDirResHeader(sstream, httpMsg, webDir, filePath, 200); sstream << "Content-Length: " << fileSize << "\r\n"; sstream << "\r\n"; // 空行表示http头部完成 addSendMsgToQueue(httpMsg, sstream.str().c_str(), sstream.str().size()); } else { if (httpMsg->headers.find("range") != httpMsg->headers.end()) { string rangeStr = httpMsg->headers["range"]; int64_t startByte = 0, endByte = 0; parseRangeStr(rangeStr, startByte, endByte, fileSize); startByte = startByte < 0 ? 0 : startByte; endByte = (endByte > fileSize - 1) ? (fileSize - 1) : endByte; int64_t contentLength = endByte - startByte + 1; contentLength = contentLength < 0 ? 0 : contentLength; if (contentLength < fileSize) { formStaticWebDirResHeader(sstream, httpMsg, webDir, filePath, 206); } else { formStaticWebDirResHeader(sstream, httpMsg, webDir, filePath, 200); } sstream << "Content-Range: bytes " << startByte << "-" << endByte << "/" << fileSize << "\r\n"; sstream << "Accept-Ranges: bytes\r\n"; sstream << "Content-Length: " << contentLength << "\r\n"; sstream << "\r\n"; addSendMsgToQueue(httpMsg, sstream.str().c_str(), sstream.str().size()); readStaticWebFile(httpMsg, file, contentLength, startByte); } else { formStaticWebDirResHeader(sstream, httpMsg, webDir, filePath, 200); sstream << "Content-Length: " << fileSize << "\r\n"; sstream << "\r\n"; addSendMsgToQueue(httpMsg, sstream.str().c_str(), sstream.str().size()); readStaticWebFile(httpMsg, file, fileSize, 0); } } fclose(file); if (httpMsg->isKeepingAlive) { httpMsg->lastKeepAliveTime = getSysTickCountInMilliseconds(); } return true; } void WHttpServer::formStaticWebDirResHeader(stringstream &sstream, shared_ptr &httpMsg, HttpStaticWebDir &webDir, string &filePath, int code) { sstream << "HTTP/1.1 "<< code << " " << mg_http_status_code_str(code) << "\r\n"; sstream << "Content-Type: " << guess_content_type(filePath.c_str()) << "\r\n"; map &reqHeaders = httpMsg->headers; if (httpMsg->isKeepingAlive) { sstream << "Connection: " << "keep-alive" << "\r\n"; } else if ((reqHeaders.find("connection") != reqHeaders.end()) && (reqHeaders["connection"] == "keep-alive")) { if (_currentKeepAliveNum < MAX_KEEP_ALIVE_NUM) { sstream << "Connection: " << "keep-alive" << "\r\n"; _currentKeepAliveNum++; httpMsg->isKeepingAlive = true; } else { sstream << "Connection: " << "close" << "\r\n"; } } if (!webDir.header.empty()) { sstream << webDir.header; } // sstream << "Content-Disposition: attachment;filename=" << fileName << "\r\n"; } void WHttpServer::readStaticWebFile(shared_ptr httpMsg, FILE *file, int64_t contentSize, int64_t startByte) { int64_t currentReadSize = 0; int64_t maxPerReadSize = 1024*1024; int64_t perReadSize = contentSize > maxPerReadSize ? maxPerReadSize : contentSize; int64_t remainSize; uint64_t currentMs = 0; uint64_t lastWriteMs = getSysTickCountInMilliseconds(); fseek(file, startByte, SEEK_SET); while((remainSize = contentSize - currentReadSize) > 0 && isRunning()) { if (isClientDisconnect(httpMsg)) { Logw("WHttpServer::readStaticWebFile http client close the connection actively"); break; } // 为了防止发送队列里的数据太大,占用大量内存,当发送队列里面的数据达到一定量,先等待 if (httpMsg->sendQueue->size() >= HTTP_SEND_QUEUE_SIZE) { currentMs = getSysTickCountInMilliseconds(); if (currentMs - lastWriteMs > MAX_DOWNLOAD_PAUSE_TIME * 1000) { Logi("WHttpServer::readStaticWebFile download file timeout %s", httpMsg->uri.c_str()); forceCloseHttpConnection(httpMsg); return; } usleep(1000); continue; } string *fileStr = new string(); fileStr->resize(perReadSize); int64_t currentWantReadSize = remainSize > perReadSize ? perReadSize : remainSize; int64_t readSize = fread((char *)fileStr->c_str(), 1, currentWantReadSize, file); currentReadSize += readSize; if (readSize == 0) { Logw("WHttpServer::readStaticWebFile read size is 0"); delete fileStr; break; } if (readSize != perReadSize) { fileStr->resize(readSize); } addSendMsgToQueue(httpMsg, fileStr); lastWriteMs = getSysTickCountInMilliseconds(); } } void WHttpServer::parseRangeStr(string rangeStr, int64_t &startByte, int64_t &endByte, int64_t fileSize) { startByte = 0; endByte = 0; size_t equalMarkIndex = rangeStr.find('='); size_t lineMarkIndex = rangeStr.find('-'); if (equalMarkIndex == string::npos || lineMarkIndex == string::npos) { return; } startByte = stoll(rangeStr.substr(equalMarkIndex + 1, lineMarkIndex - equalMarkIndex - 1)); if (lineMarkIndex == rangeStr.size() - 1) { endByte = fileSize - 1; } else { endByte = stoll(rangeStr.substr(lineMarkIndex + 1)); } } void WHttpServer::reset() { _currentKeepAliveNum = 0; } void WHttpServer::logHttpRequestMsg(mg_connection *conn, mg_http_message *httpCbData) { if (httpCbData->message.len < 1024) { Logi("WHttpServer::logHttpRequestMsg %s request id:%ld, message: %s", conn->is_tls ? "https" : "http", conn->id, httpCbData->message.ptr); } else { char msg[1024] = {0}; memcpy(msg, httpCbData->message.ptr, 1024); Logi("WHttpServer::logHttpRequestMsg %s request id:%ld, message: %s", conn->is_tls ? "https" : "http", conn->id, msg); } } void WHttpServer::httpReplyJson(shared_ptr httpMsg, int httpCode, string head, string body) { stringstream sstream; sstream << "HTTP/1.1 " << httpCode << " " << mg_http_status_code_str(httpCode) << "\r\n"; sstream << "Content-Type: application/json\r\n"; if (!head.empty()) { sstream << head; } sstream << "Content-Length: " << body.size() << "\r\n\r\n"; sstream << body; string data = sstream.str(); // xy_sync_mg_send(conn, data.c_str(), data.size()); addSendMsgToQueue(httpMsg, data.c_str(), data.size()); } void WHttpServer::addSendMsgToQueue(shared_ptr httpMsg, const char *data, int len) { string *sendMsg = new string(); sendMsg->resize(len); memcpy((char *)sendMsg->c_str(), data, len); bool res = httpMsg->sendQueue->enQueue(sendMsg); assert(res); } void WHttpServer::addSendMsgToQueue(shared_ptr httpMsg, string *sendMsg) { bool res = httpMsg->sendQueue->enQueue(sendMsg); assert(res); } string WHttpServer::formJsonBody(int code, string message, string body) { stringstream sstream; sstream << "{"; sstream << R"("code":)" << code << ","; sstream << R"("message":")" << message << R"(")" << ","; sstream << R"("url":")" << body << R"(")" ; sstream << "}"; return sstream.str(); } bool WHttpServer::isClientDisconnect(shared_ptr httpMsg) { return (httpMsg->httpConnection->label[W_CLIENT_CLOSE_BIT] == 1); } shared_ptr WHttpServer::deQueueHttpChunk(shared_ptr httpMsg) { string *res = nullptr; httpMsg->chunkQueue->deQueue(res); return shared_ptr(res); } bool WHttpServer::addStaticWebDir(const string &dir, const string &header) { char tempDir[PATH_MAX]; if (!realpath(dir.c_str(), tempDir)) { Loge("WHttpServer::addStaticWebDir the dir path is wrong: %s", dir.c_str()); return false; } if (!mg_is_dir(tempDir)) { Loge("WHttpServer::addStaticWebDir is not dir: %s", dir.c_str()); return false; } HttpStaticWebDir staticDir; staticDir.dirPath = tempDir; staticDir.header = header; _staticDirVect.push_back(staticDir); return true; } void WHttpServer::recvHttpRequest(mg_connection *conn, int msgType, void *msgData, void *cbData) { if (_httpPort == -1 && _httpsPort == -1) { return; } HttpCbMsg *cbMsg = (HttpCbMsg *)cbData; int64_t fd = (int64_t)conn->fd; if (msgType == MG_EV_ACCEPT && cbMsg->httpsFlag) { struct mg_tls_opts opts; opts.ca = nullptr; opts.cert = _certPath.c_str(); opts.certkey = _keyPath.c_str(); opts.ciphers = nullptr; opts.srvname.ptr = nullptr; opts.srvname.len = 0; Logi("WHttpServer::recvHttpRequest https connect come id:%ld", conn->id); mg_tls_init(conn, &opts); } else if (msgType == MG_EV_HTTP_MSG) { struct mg_http_message *httpCbData = (struct mg_http_message *) msgData; if (isValidHttpChunk(httpCbData)) { return; } logHttpRequestMsg(conn, httpCbData); if (httpCbData->head.len > HTTP_MAX_HEAD_SIZE) { mg_http_reply(conn, 500, "", formJsonBody(HTTP_BEYOND_HEAD_SIZE, "head size beyond 2M").c_str()); closeHttpConnection(conn, true); return; } HttpApiData cbApiData; if (!findHttpCbFun(httpCbData, cbApiData)) { if ((mg_vcasecmp(&(httpCbData->method), "GET") != 0) && (mg_vcasecmp(&(httpCbData->method), "HEAD") != 0)) { mg_http_reply(conn, 400, "", formJsonBody(HTTP_UNKNOWN_REQUEST, "unknown request").c_str()); closeHttpConnection(conn, true); return; } else { cbApiData.findStaticFileFlag = true; } } shared_ptr httpMsg = nullptr; // if keep-alive fd, erase last http msg if (_workingMsgMap.find(fd) != _workingMsgMap.end()) { releaseHttpReqMsg(_workingMsgMap[fd]); _workingMsgMap.erase(fd); httpMsg = parseHttpMsg(conn, httpCbData); httpMsg->isKeepingAlive = true; _workingMsgMap[fd] = httpMsg; } else { httpMsg = parseHttpMsg(conn, httpCbData); } _workingMsgMap[fd] = httpMsg; _threadPool->concurrentRun(&WHttpServer::handleHttpMsg, this, std::ref(_workingMsgMap[fd]), cbApiData); } else if (msgType == MG_EV_HTTP_CHUNK) { struct mg_http_message *httpCbData = (struct mg_http_message *) msgData; HttpApiData chunkCbApiData; if (!findChunkHttpCbFun(httpCbData, chunkCbApiData)) { return; } if (httpCbData->head.len > HTTP_MAX_HEAD_SIZE) { mg_http_reply(conn, 500, "", formJsonBody(HTTP_BEYOND_HEAD_SIZE, "head size beyond 2M").c_str()); closeHttpConnection(conn, true); return; } if (_workingMsgMap.find(fd) == _workingMsgMap.end()) { logHttpRequestMsg(conn, httpCbData); shared_ptr httpMsg = parseHttpMsg(conn, httpCbData, true); _workingMsgMap[fd] = httpMsg; _threadPool->concurrentRun(&WHttpServer::handleChunkHttpMsg, this, std::ref(_workingMsgMap[fd]), chunkCbApiData); } else { shared_ptr httpMsg = _workingMsgMap[fd]; enQueueHttpChunk(httpMsg, httpCbData); } } else if (msgType == MG_EV_CLOSE) { Logi("WHttpServer::RecvHttpRequest http disconnect id:%ld", conn->id); if (conn->label[W_VALID_CONNECT_BIT] != 1) { return; } if (conn->label[W_FD_STATUS_BIT] == HTTP_NORMAL_CLOSE) { releaseHttpReqMsg(_workingMsgMap[fd]); _workingMsgMap.erase(fd); return; } conn->label[W_CLIENT_CLOSE_BIT] = 1; while(conn->label[W_FD_STATUS_BIT] == HTTP_IN_USE) { usleep(1); } releaseHttpReqMsg(_workingMsgMap[fd]); _workingMsgMap.erase(fd); } } void WHttpServer::handleHttpMsg(shared_ptr &httpMsg, HttpApiData httpCbData) { if (httpCbData.findStaticFileFlag) { bool findFlag = false; for(int i = 0; i < (int)_staticDirVect.size(); i++) { if (handleStaticWebDir(httpMsg, _staticDirVect[i])) { findFlag = true; break; } } if (!findFlag) { httpReplyJson(httpMsg, 400, "", formJsonBody(HTTP_UNKNOWN_REQUEST, "unknown request").c_str()); } } else { if (_httpFilterFun && !_httpFilterFun(httpMsg)) { closeHttpConnection(httpMsg->httpConnection); return; } set methods = getSupportMethods(httpCbData.httpMethods); if (methods.find(httpMsg->method) == methods.end()) { httpReplyJson(httpMsg, 400, "", formJsonBody(HTTP_UNKNOWN_REQUEST, "do not support this method")); closeHttpConnection(httpMsg->httpConnection); return; } httpCbData.httpCbFun(httpMsg); } if (httpMsg->isKeepingAlive) { httpMsg->httpConnection->label[W_FD_STATUS_BIT] = HTTP_NOT_USE; } else { closeHttpConnection(httpMsg->httpConnection); } } void WHttpServer::handleChunkHttpMsg(shared_ptr &httpMsg, HttpApiData chunkHttpCbData) { if (_httpFilterFun && !_httpFilterFun(httpMsg)) { closeHttpConnection(httpMsg->httpConnection); return; } set methods = getSupportMethods(chunkHttpCbData.httpMethods); if (methods.find(httpMsg->method) == methods.end()) { httpReplyJson(httpMsg, 400, "", formJsonBody(HTTP_UNKNOWN_REQUEST, "do not support this method")); closeHttpConnection(httpMsg->httpConnection); return; } chunkHttpCbData.httpCbFun(httpMsg); closeHttpConnection(httpMsg->httpConnection); } void WHttpServer::sendHttpMsgPoll() { static int64_t pollCount = 0; pollCount++; int64_t currentTime = -1; if (pollCount % 1000 == 0) { currentTime = getSysTickCountInMilliseconds(); } std::map>::iterator it; for (it = _workingMsgMap.begin(); it != _workingMsgMap.end(); it++) { shared_ptr httpMsg = it->second; mg_connection *conn = httpMsg->httpConnection; // identify if keep-alive timeout if (httpMsg->isKeepingAlive && (currentTime != -1) && (conn->label[W_FD_STATUS_BIT] == HTTP_NOT_USE)) { if ((currentTime - httpMsg->lastKeepAliveTime > KEEP_ALIVE_TIME * 1000)) { conn->label[W_FD_STATUS_BIT] = HTTP_NORMAL_CLOSE; _currentKeepAliveNum--; } } if ((conn->label[W_FD_STATUS_BIT] == HTTP_NORMAL_CLOSE) && (httpMsg->sendQueue->size() == 0)) { conn->is_draining = 1; continue; } if (conn->send.len > SEND_BUF_SIZE_BOUNDARY) { continue; } if (httpMsg->sendQueue->size() == 0) { continue; } shared_ptr sendMsg = deQueueHttpSendMsg(httpMsg); assert(sendMsg.get()); mg_send(conn, (const void *)sendMsg->c_str(), sendMsg->size()); } } shared_ptr WHttpServer::deQueueHttpSendMsg(shared_ptr httpMsg) { string *sendMsg = nullptr; httpMsg->sendQueue->deQueue(sendMsg); return shared_ptr(sendMsg); } bool WHttpServer::findChunkHttpCbFun(mg_http_message *httpCbData, HttpApiData &cbApiData) { bool res = false; for (auto it = _chunkHttpApiMap.begin(); it != _chunkHttpApiMap.end(); it++) { if (httpCbData->uri.len < it->first.size()) { continue; } size_t cmpSize = it->first.size(); if (strncmp(it->first.c_str(), httpCbData->uri.ptr, cmpSize) == 0) { if (((it->first)[cmpSize - 1] == '/') || (httpCbData->uri.len == cmpSize) || (httpCbData->uri.len > cmpSize && httpCbData->uri.ptr[cmpSize] == '/')) { cbApiData = it->second; res = true; break; } } } return res; } bool WHttpServer::isValidHttpChunk(mg_http_message *httpCbData) { bool res = false; for (auto it = _chunkHttpApiMap.begin(); it != _chunkHttpApiMap.end(); it++) { if (httpCbData->uri.len < it->first.size()) { continue; } size_t cmpSize = it->first.size(); if (strncmp(it->first.c_str(), httpCbData->uri.ptr, cmpSize) == 0) { if (((it->first)[cmpSize - 1] == '/') || (httpCbData->uri.len == cmpSize) || (httpCbData->uri.len > cmpSize && httpCbData->uri.ptr[cmpSize] == '/')) { res = true; break; } } } return res; } bool WHttpServer::findHttpCbFun(mg_http_message *httpCbData, HttpApiData &cbApiData) { bool res = false; for (auto it = _httpApiMap.begin(); it != _httpApiMap.end(); it++) { if (httpCbData->uri.len < it->first.size()) { continue; } size_t cmpSize = it->first.size(); if (strncmp(it->first.c_str(), httpCbData->uri.ptr, cmpSize) == 0) { if (((it->first)[cmpSize - 1] == '/') || (httpCbData->uri.len == cmpSize) || (httpCbData->uri.len > cmpSize && httpCbData->uri.ptr[cmpSize] == '/')) { cbApiData = it->second; res = true; break; } } } return res; } shared_ptr WHttpServer::parseHttpMsg(mg_connection *conn, mg_http_message *httpCbData, bool chunkFlag) { shared_ptr res = shared_ptr(new HttpReqMsg()); res->httpConnection = conn; conn->label[W_VALID_CONNECT_BIT] = 1; conn->label[W_FD_STATUS_BIT] = HTTP_IN_USE; res->sendQueue = shared_ptr(new HttpSendQueue()); res->method.resize(httpCbData->method.len); memcpy((char*)res->method.c_str(), httpCbData->method.ptr, httpCbData->method.len); toUpperString(res->method); res->uri.resize(httpCbData->uri.len); memcpy((char*)res->uri.c_str(), httpCbData->uri.ptr, httpCbData->uri.len); string queryKey = ""; string queryValue = ""; bool valueFlag = false; for (int i = 0; i < (int)httpCbData->query.len; i++) { if (httpCbData->query.ptr[i] == '=') { valueFlag = true; continue; } else if(httpCbData->query.ptr[i] == '&') { valueFlag = false; res->querys[queryKey] = queryValue; queryKey.clear(); queryValue.clear(); continue; } if (!valueFlag) { queryKey.append(1, httpCbData->query.ptr[i]); } else { queryValue.append(1, httpCbData->query.ptr[i]); } } res->querys[queryKey] = queryValue; res->proto.resize(httpCbData->proto.len); memcpy((char*)res->proto.c_str(), httpCbData->proto.ptr, httpCbData->proto.len); for(int i = 0; i < MG_MAX_HTTP_HEADERS; i++) { if (httpCbData->headers[i].name.len == 0 || !httpCbData->headers[i].name.ptr) { break; } string name; string value; name.resize(httpCbData->headers[i].name.len); value.resize(httpCbData->headers[i].value.len); memcpy((char*)name.c_str(), httpCbData->headers[i].name.ptr, httpCbData->headers[i].name.len); memcpy((char*)value.c_str(), httpCbData->headers[i].value.ptr, httpCbData->headers[i].value.len); toLowerString(name); res->headers[name] = value; // std::cout << "show headers, " << name << ": " << value << endl; } if (res->headers.find("content-length") != res->headers.end()) { res->totalBodySize = (int64_t)stoll(res->headers["content-length"]); } else { Logi("WHttpServer::ParseHttpMsg request id:%ld have no content-length", conn->id); res->totalBodySize = httpCbData->body.len; } if (chunkFlag) { res->chunkQueue = shared_ptr(new HttpChunkQueue()); string *chunk = new string(); chunk->resize(httpCbData->chunk.len); memcpy((char*)chunk->c_str(), httpCbData->chunk.ptr, httpCbData->chunk.len); conn->recv.len -= httpCbData->chunk.len; res->chunkQueue->enQueue(chunk); res->recvChunkSize += httpCbData->chunk.len; res->finishRecvChunk = (res->recvChunkSize >= res->totalBodySize); } else { res->body.resize(httpCbData->body.len); memcpy((char*)res->body.c_str(), httpCbData->body.ptr, httpCbData->body.len); } return res; } void WHttpServer::enQueueHttpChunk(shared_ptr httpMsg, mg_http_message *httpCbData) { string *chunk = new string(); chunk->resize(httpCbData->chunk.len); memcpy((char*)chunk->c_str(), httpCbData->chunk.ptr, httpCbData->chunk.len); httpMsg->httpConnection->recv.len -= httpCbData->chunk.len; bool res = httpMsg->chunkQueue->enQueue(chunk); assert(res); if (httpMsg->chunkQueue->size() > CHUNK_QUEUE_SIZE_BOUNDARY) { usleep(500); } /* while(!httpMsg->chunkQueue->enQueue(chunk)) { usleep(500); } */ httpMsg->recvChunkSize += httpCbData->chunk.len; httpMsg->finishRecvChunk = (httpMsg->recvChunkSize >= httpMsg->totalBodySize); } void WHttpServer::releaseHttpReqMsg(shared_ptr httpMsg) { while (httpMsg->chunkQueue.get() && httpMsg->chunkQueue->size() > 0) { string *res = nullptr; httpMsg->chunkQueue->deQueue(res); delete res; } while (httpMsg->sendQueue.get() && httpMsg->sendQueue->size() > 0) { string *res = nullptr; httpMsg->sendQueue->deQueue(res); delete res; } } void WHttpServer::toLowerString(string &str) { for(int i = 0; i < (int)str.size(); i++) { str[i] = tolower(str[i]); } } void WHttpServer::toUpperString(string &str) { for(int i = 0; i < (int)str.size(); i++) { str[i] = toupper(str[i]); } } void WHttpServer::recvHttpRequestCallback(mg_connection *conn, int msgType, void *msgData, void *cbData) { HttpCbMsg *cbMsg = (HttpCbMsg *)cbData; cbMsg->httpServer->recvHttpRequest(conn, msgType, msgData, cbData); } uint64_t WHttpServer::getSysTickCountInMilliseconds() { /* timespec time; int ret = clock_gettime(CLOCK_MONOTONIC, &time); if (ret != 0) { printf("get clock error!\n"); } uint64_t result = ((uint64_t)time.tv_sec) * 1000 + ((uint64_t)time.tv_nsec) / 1000000; return result;*/ return 0; }