/** * @brief Process an incoming HTTP request. * * We look at the path of the request and see if it has a matching path handler. If it does, * we invoke the handler function. If it does not, we try and find a file on the file system * that would resolve to the path. * * @param [in] mgConnection The network connection on which the request was received. * @param [in] message The message representing the request. */ void WebServer::processRequest(struct mg_connection* mgConnection, struct http_message* message) { ESP_LOGD(LOG_TAG, "WebServer::processRequest: Matching: %.*s", (int) message->uri.len, message->uri.p); HTTPResponse httpResponse = HTTPResponse(mgConnection); /* * Iterate through each of the path handlers looking for a match with the method and specified path. */ std::vector<PathHandler>::iterator it; for (it = m_pathHandlers.begin(); it != m_pathHandlers.end(); ++it) { if ((*it).match(message->method.p, message->method.len, message->uri.p)) { HTTPRequest httpRequest(message); (*it).invoke(&httpRequest, &httpResponse); ESP_LOGD(LOG_TAG, "Found a match!!"); return; } } // End of examine path handlers. // Because we reached here, it means that we did NOT match a handler. Now we want to attempt // to retrieve the corresponding file content. std::string filePath; filePath.reserve(httpResponse.getRootPath().length() + message->uri.len + 1); filePath += httpResponse.getRootPath(); filePath.append(message->uri.p, message->uri.len); ESP_LOGD(LOG_TAG, "Opening file: %s", filePath.c_str()); FILE* file = nullptr; if (strcmp(filePath.c_str(), "/") != 0) { file = fopen(filePath.c_str(), "rb"); } if (file != nullptr) { auto pData = (uint8_t*)malloc(MAX_CHUNK_LENGTH); size_t read = fread(pData, 1, MAX_CHUNK_LENGTH, file); if (read >= MAX_CHUNK_LENGTH) { httpResponse.sendChunkHead(); httpResponse.sendChunk((char*) pData, read); fclose(unfinishedConnection[mgConnection->sock]); unfinishedConnection[mgConnection->sock] = file; } else { fclose(file); httpResponse.sendData(pData, read); } free(pData); } else { // Handle unable to open file httpResponse.setStatus(404); // Not found httpResponse.sendData(""); } } // processRequest
bool HTTPClient::Run(void* _ptr) { if(_ptr) { is_raise_error_multi_handle = true; code_multi = *(CURLMcode*)_ptr; return true; } if(is_raise_error_multi_handle) return true; if(is_recieve) { UpdateDB(); return true; } else { if(cache_type == HTTPResponse::CacheType_Expires) { code = CURLE_OK; response = HTTPResponse(cache_header_file_path, cache_body_file_path, cache_type); is_use_cache = true; return true; } else if(cache_type == HTTPResponse::CacheType_Last_Modified) { if(db_last_modified && last_modified) { if(last_modified == db_last_modified) { code = CURLE_OK; response = HTTPResponse(cache_header_file_path, cache_body_file_path, cache_type); is_use_cache = true; return true; } else { return false; } } else { return false; } } else { return false; } } }
void WebServer::continueConnection(struct mg_connection* mgConnection) { if (unfinishedConnection.count(mgConnection->sock) == 0) return; HTTPResponse httpResponse = HTTPResponse(mgConnection); FILE* file = unfinishedConnection[mgConnection->sock]; auto pData = (char*) malloc(MAX_CHUNK_LENGTH); size_t length = fread(pData, 1, MAX_CHUNK_LENGTH, file); httpResponse.sendChunk(pData, length); if (length < MAX_CHUNK_LENGTH) { fclose(file); httpResponse.closeConnection(); unfinishedConnection.erase(mgConnection->sock); httpResponse.sendChunk("", 0); } free(pData); }
/** * @brief Process an incoming HTTP request. * * We look at the path of the request and see if it has a matching path handler. If it does, * we invoke the handler function. If it does not, we try and find a file on the file system * that would resolve to the path. * * @param [in] mgConnection The network connection on which the request was received. * @param [in] message The message representing the request. */ void WebServer::processRequest(struct mg_connection *mgConnection, struct http_message* message) { std::string uri = mgStrToString(message->uri); ESP_LOGD(tag, "WebServer::processRequest: Matching: %s", uri.c_str()); HTTPResponse httpResponse = HTTPResponse(mgConnection); httpResponse.setRootPath(getRootPath()); /* * Iterate through each of the path handlers looking for a match with the method and specified path. */ std::vector<PathHandler>::iterator it; for (it = m_pathHandlers.begin(); it != m_pathHandlers.end(); ++it) { if ((*it).match(mgStrToString(message->method), uri)) { HTTPRequest httpRequest(message); (*it).invoke(&httpRequest, &httpResponse); ESP_LOGD(tag, "Found a match!!"); return; } } // End of examine path handlers. // Because we reached here, it means that we did NOT match a handler. Now we want to attempt // to retrieve the corresponding file content. std::string filePath = httpResponse.getRootPath() + uri; ESP_LOGD(tag, "Opening file: %s", filePath.c_str()); FILE *file = fopen(filePath.c_str(), "r"); if (file != nullptr) { fseek(file, 0L, SEEK_END); size_t length = ftell(file); fseek(file, 0L, SEEK_SET); uint8_t *pData = (uint8_t *)malloc(length); fread(pData, length, 1, file); fclose(file); httpResponse.sendData(pData, length); free(pData); } else { // Handle unable to open file httpResponse.setStatus(404); // Not found httpResponse.sendData(""); } } // processRequest
bool HTTPClient::UpdateDB() { if(!is_recieve) return false; if(code != CURLE_OK) return false; if(header.is_open()) { header.close(); CLOSE_FD(); } if(body.is_open()) { body.close(); CLOSE_FD(); } if(request.GetUseCache()) { if(request.force_max_age > 0) { max_age = request.force_max_age; if(expires == 0 && max_age != 0) { expires = HTTP::CurrentTime() + max_age; } } } std::stringstream _query; bool _need_update = false; bool _is_insert = false; if(cache_type == HTTPResponse::CacheType_None) { if(!db_id.length()) { _query << "INSERT OR REPLACE INTO request (url, Expires, Last_Modified, Last_Updated, Max_Age) VALUES ('" << request.url << "', '" << expires << "', '" << last_modified << "', '" << last_updated << "', '" << max_age << "')"; _is_insert = true; } else { _query << "UPDATE request SET Expires='" << expires << "', Last_Modified='" << last_modified << "', Last_Updated='" << last_updated << "', Max_Age='" << max_age << "' WHERE id='" << db_id << "'"; } _need_update = true; } else if(cache_type == HTTPResponse::CacheType_Last_Modified) { if(last_modified && db_last_modified) { if(last_modified != db_last_modified) { _query << "UPDATE request SET Last_Modified='" << last_modified << "', Last_Updated='" << last_updated << "' WHERE id='" << db_id << "'"; _need_update = true; } } } if(!_need_update) { return false; } sqlite3* _db = NULL; char* _db_message = NULL; HTTP_DEBUG((sqlite3_open(HTTPManager::Share()->GetDBPath().c_str(), &_db)), "열기실패" << "\nError Message:" << sqlite3_errmsg(_db) << "\n"); HTTP_DEBUG((sqlite3_exec(_db, _query.str().c_str(), NULL, NULL, &_db_message)), "error:" << _db_message); if(_is_insert) { _query.str(""); _query << "SELECT * FROM request WHERE url='" << request.url << "' LIMIT 1"; HTTP_DEBUG((sqlite3_exec(_db, _query.str().c_str(), SQLMatchURLCallback, this, &_db_message)), "sqllite 디비 검색에 실패하였습니다." << "\nError Message:" << _db_message); } HTTP_DEBUG((sqlite3_close(_db)), "닫기실패" << "\nError Message:" << sqlite3_errmsg(_db) << "\n"); rename(header_file_path.c_str(), cache_header_file_path.c_str()); rename(body_file_path.c_str(), cache_body_file_path.c_str()); response = HTTPResponse(cache_header_file_path, cache_body_file_path, cache_type); return true; }
HTTPResponse FileAction::execute(const HTTPRequest& request) { HTTPResponse response; struct stat statbuf; char md5_hex[33]; string path = document_root + request.path; // TODO: Sanitize path, ie. remove ".." and leading "/" if (request.method == "GET" || request.method == "HEAD") { if (stat(path.c_str(), &statbuf) >= 0) { ostringstream os; os << statbuf.st_size; response = HTTPResponse(200, WebUtil::pathToMimetype(path)); response.addHeader("Content-Length",os.str()); response.addHeader("Last-Modified",WebUtil::formatDate(statbuf.st_mtime)); FILE* f = fopen(path.c_str(), "r"); md5_stream_hex(f,md5_hex); md5_hex[32] = '\0'; response.addHeader("Content-MD5",string(md5_hex)); if (request.method == "GET") { rewind(f); response.setBody(f); } else { fclose(f); } } else { response = HTTPResponse(404, "text/plain"); } } else if (request.method == "DELETE") { // This method isn't strictly HTTP1.1, but we need it // and I don't want to implement a complete WebDAV stack. unlink(path.c_str()); response = HTTPResponse(200, "text/plain"); } else if (request.method == "PUT") { long size = atoi(request.getHeader("Content-length").c_str()); // TODO: If no content-header is sent, return "411 Length required" as per the RFC. bool exists = stat(path.c_str(), &statbuf) != -1; FILE* f = fopen(path.c_str(), "w"); WebUtil::copy(request.bodyFILE, f, size); fclose(f); if (exists) { response = HTTPResponse(200, "text/plain"); response.setBody("File modified"); } else { response = HTTPResponse(201, "text/plain"); response.setBody("File created"); } } else if (request.method == "MKCOL") { // This method isn't strictly HTTP1.1, but we need it // and I don't want to implement a complete WebDAV stack. if (mkdir(path.c_str(), 0777) == -1) { response = HTTPResponse(201, "text/plain"); response.setBody("Dir not created"); } else { response = HTTPResponse(201, "text/plain"); response.setBody("Dir created"); printf("Dir %s created\n", path.c_str()); } } else { cout << "Unknown method " << request.method << endl; response = HTTPResponse(405, "text/plain"); response.addHeader("Allow", "PUT, GET, HEAD, DELETE, MKCOL"); } return response; }
HTTPResponse execute(const HTTPRequest& request) { HTTPResponse response = HTTPResponse(200, "text/plain"); response.setBody("Hello world! RayGay renderserver up and running."); return response; };