From 5e7425317384cc01c47f9d416a5f325b916e29b0 Mon Sep 17 00:00:00 2001 From: wuyougongzi <1211385701@qq.com> Date: Sun, 3 Dec 2017 22:20:39 +0800 Subject: [PATCH 1/2] use a state machine to parse 'mimes.conf' function --- src/server/config/ConfigParser.cpp | 98 ++++++++++++++++++++---------- src/server/config/ConfigParser.h | 7 +++ 2 files changed, 73 insertions(+), 32 deletions(-) diff --git a/src/server/config/ConfigParser.cpp b/src/server/config/ConfigParser.cpp index 7ae4490..5bd3d4b 100644 --- a/src/server/config/ConfigParser.cpp +++ b/src/server/config/ConfigParser.cpp @@ -412,59 +412,93 @@ namespace HttpServer const std::string str_buf(buf.cbegin(), buf.cend() ); size_t cur_pos = 0; - size_t end_pos = str_buf.find('\n', cur_pos); - while (std::string::npos != end_pos) - { - cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - size_t delimiter = str_buf.find_first_of(whitespace, cur_pos); + ConfigFileDataState dataState = CONFIGFILEDATASNONE; - if (delimiter < end_pos) + while (std::string::npos != cur_pos) + { + //std::cout << "parse Mine dataState: " << dataState << std::endl; + switch(dataState) { - std::string mime_type = str_buf.substr(cur_pos, delimiter - cur_pos); - - if ('#' != mime_type.front() ) - { - delimiter = str_buf.find_first_not_of(whitespace, delimiter); + case CONFIGFILEDATASNONE: - if (delimiter < end_pos) + case CONFIGFILEDATASNOTE: + { - std::string ext = str_buf.substr(delimiter, end_pos - delimiter); - - delimiter = ext.find_first_of(whitespace); + cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); + if (cur_pos < 0) + { + return true; + } - if (std::string::npos != delimiter) + //start from next line + if ('#' == buf[cur_pos]) { - for (size_t ext_pos = 0; std::string::npos != ext_pos; ) + //last line + cur_pos = str_buf.find_first_of("\n", cur_pos); + if (cur_pos < 0) { - std::string ext_unit = ext.substr(ext_pos, std::string::npos != delimiter ? delimiter - ext_pos : std::string::npos); - - if (false == ext_unit.empty() ) - { - mimes_types.emplace(std::move(ext_unit), mime_type); - } + return true; + } - ext_pos = ext.find_first_not_of(whitespace, delimiter); + cur_pos += 1; - delimiter = ext.find_first_of(whitespace, ext_pos); - } + dataState = CONFIGFILEDATASNOTE; + } + else if ('\n' == buf[cur_pos]) + { + cur_pos += 1; + dataState = CONFIGFILEDATASNONE; } else { - mimes_types.emplace(std::move(ext), std::move(mime_type) ); + dataState = CONFIGFILEDATASTYPE; } } - } - } + break; + case CONFIGFILEDATASTYPE: + { + size_t delimiter = str_buf.find_first_of("\n", cur_pos); + std::string strLine = str_buf.substr(cur_pos, delimiter - cur_pos); + + //get mimetypes + { + size_t ext_pos = strLine.find_first_of(whitespace, 0); + if (ext_pos < 0) + { + return false; + } + std::string strExt = strLine.substr(0, ext_pos); + size_t extUnitPos = strLine.find_first_not_of(whitespace, ext_pos); + std::string strExtUnit = strLine.substr(extUnitPos, strLine.length() - extUnitPos); - cur_pos = end_pos + 1; + mimes_types.emplace(std::move(strExt), std::move(strExtUnit)); - end_pos = str_buf.find('\n', cur_pos); - } + //std::cout << strExt << " " << strExtUnit << std::endl; + } + + //change line + cur_pos = str_buf.find_first_of("\n", cur_pos); + if (cur_pos < 0) + { + return true; + } + cur_pos += 1; + + dataState = CONFIGFILEDATASNONE; + + } + break; + default: + break; + } + } + return true; } + static size_t findBlockEnd(const std::string &str_buf, size_t str_pos) { size_t pos = str_buf.find('}', str_pos); diff --git a/src/server/config/ConfigParser.h b/src/server/config/ConfigParser.h index 5614237..c9b0e23 100644 --- a/src/server/config/ConfigParser.h +++ b/src/server/config/ConfigParser.h @@ -7,6 +7,13 @@ namespace HttpServer { + enum ConfigFileDataState + { + CONFIGFILEDATASNONE = 0, + CONFIGFILEDATASNOTE, //comment + CONFIGFILEDATASTYPE, + + }; class ConfigParser { private: From 2bda69185757358f8a41af77de1d59f7e861a88c Mon Sep 17 00:00:00 2001 From: wuyougongzi <1211385701@qq.com> Date: Tue, 12 Dec 2017 23:09:45 +0800 Subject: [PATCH 2/2] change parse 'main.conf' ways using state machine --- src/server/config/ConfigParser.cpp | 303 ++++++++++++++++++----------- src/server/config/ConfigParser.h | 10 +- 2 files changed, 201 insertions(+), 112 deletions(-) diff --git a/src/server/config/ConfigParser.cpp b/src/server/config/ConfigParser.cpp index 5bd3d4b..fee0df6 100644 --- a/src/server/config/ConfigParser.cpp +++ b/src/server/config/ConfigParser.cpp @@ -7,6 +7,8 @@ #include #include +const long FILESIZE = 1024 * 1024; + namespace HttpServer { /** @@ -14,6 +16,7 @@ namespace HttpServer */ bool ConfigParser::includeConfigFile(const std::string &fileName, std::string &strBuf, const std::size_t offset) { + std:: cout << "config file name: " << fileName << std::endl; std::ifstream file(fileName); if ( ! file) @@ -29,7 +32,7 @@ namespace HttpServer std::streamsize file_size = file.tellg(); file.seekg(0, std::ifstream::beg); - constexpr std::streamsize file_size_max = 2 * 1024 * 1024; + constexpr std::streamsize file_size_max = 2 * FILESIZE; if (file_size_max < file_size) { @@ -426,7 +429,7 @@ namespace HttpServer { cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - if (cur_pos < 0) + if (cur_pos == std::string::npos) { return true; } @@ -436,7 +439,7 @@ namespace HttpServer { //last line cur_pos = str_buf.find_first_of("\n", cur_pos); - if (cur_pos < 0) + if (cur_pos == std::string::npos) { return true; } @@ -464,7 +467,7 @@ namespace HttpServer //get mimetypes { size_t ext_pos = strLine.find_first_of(whitespace, 0); - if (ext_pos < 0) + if (ext_pos == std::string::npos) { return false; } @@ -479,7 +482,7 @@ namespace HttpServer //change line cur_pos = str_buf.find_first_of("\n", cur_pos); - if (cur_pos < 0) + if (cur_pos == std::string::npos) { return true; } @@ -534,6 +537,7 @@ namespace HttpServer */ bool ConfigParser::loadConfig(const std::string &conf_file_name, ServerSettings &settings, std::vector &modules) { + //std::cout << "enter loadCofig" << std::endl; std::string str_buf; if (false == includeConfigFile(conf_file_name, str_buf) ) @@ -550,163 +554,238 @@ namespace HttpServer const std::string whitespace(" \t\n\v\f\r"); size_t cur_pos = 0; - size_t end_pos = str_buf.find(';', cur_pos); - size_t block_pos = 0; - while (std::string::npos != end_pos) - { - block_pos = str_buf.find('{', cur_pos); + ConfigFileDataState dataState = CONFIGFILEDATASNONE; + InBlockDataState inBlockState = INBLOCKNONE; + + std::unordered_multimap app; - if (end_pos < block_pos) + int iStatus = 0; + while (std::string::npos != cur_pos) + { + //std::cout << "parse Mine dataState: " << dataState << std::endl; + if (iStatus == 1 || iStatus == 2) { - cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - size_t delimiter = str_buf.find_first_of(whitespace, cur_pos); + break; + } - if (delimiter < end_pos) - { - std::string param_name = str_buf.substr(cur_pos, delimiter - cur_pos); + switch (dataState) + { + case CONFIGFILEDATASNONE: - if ('#' != param_name.front() ) + case CONFIGFILEDATASNOTE: { - cur_pos = str_buf.find_first_not_of(whitespace, delimiter + 1); - delimiter = str_buf.find_last_not_of(whitespace, end_pos); + cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); + if (cur_pos == std::string::npos) + { + iStatus = 1; + } - std::string param_value = str_buf.substr(cur_pos, delimiter - cur_pos); + //start from next line + if ('#' == str_buf[cur_pos]) + { + //last line + cur_pos = str_buf.find_first_of("\n", cur_pos); + if (cur_pos == std::string::npos) + { + iStatus = 1; + } + + cur_pos += 1; - if ("include" == param_name) + dataState = CONFIGFILEDATASNOTE; + } + else if ('\n' == str_buf[cur_pos]) { - this->includeConfigFile(param_value, str_buf, end_pos + 1); + cur_pos += 1; + dataState = CONFIGFILEDATASNONE; } else { - global.emplace(std::move(param_name), std::move(param_value) ); + dataState = CONFIGFILEDATASTYPE; } } - else // if comment line + break; + case CONFIGFILEDATASTYPE: { - end_pos = str_buf.find_first_of("\r\n", cur_pos); - } - } - - cur_pos = end_pos; - - if (std::string::npos != cur_pos) - { - ++cur_pos; - } - } - else if (std::string::npos != block_pos) - { - cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - size_t delimiter = str_buf.find_first_of(whitespace, cur_pos); + //in app and main config file "; and \n " has different meaning + size_t delimiter = str_buf.find_first_of("\n", cur_pos); + //std:: cout << "str_buf.length()" << str_buf.length() << " delimiter " << delimiter + // << " cur_pos " << cur_pos << std::endl; + //std::cout << "npos: " << std::string::npos << std::endl; + if (delimiter == std::string::npos) + { + iStatus = 1; + } - const std::string block_type_name = str_buf.substr(cur_pos, delimiter - cur_pos); + std::string strLine = str_buf.substr(cur_pos, delimiter - cur_pos); + //std::cout << "strLine: " << strLine << std::endl; + do { + size_t ext_pos = strLine.find_first_of(whitespace, 0); + if (ext_pos == std::string::npos) + { + iStatus = 2; + } + std::string param_name = strLine.substr(0, ext_pos); + size_t extUnitPos = strLine.find_first_not_of(whitespace, ext_pos); - if ('#' != block_type_name.front() ) - { - delimiter = str_buf.find_first_not_of(whitespace, delimiter); + //mines the last ";" + std::string param_value; + if (strLine[strLine.length() - 1] == ';') + { + param_value = strLine.substr(extUnitPos, strLine.length() - extUnitPos - 1); + } + else + { + param_value = strLine.substr(extUnitPos, strLine.length() - extUnitPos); + } - cur_pos = block_pos + 1; - size_t block_end = findBlockEnd(str_buf, cur_pos); + //std::cout << param_name << " " << param_value << std::endl; + if (param_name == "server" && param_value == "{") + { + dataState = CONFIGFILEDATAINBLOCK; + inBlockState = INBLOCKNONE; + } + else if(param_name == "include") + { + this->loadConfig(param_value, settings, modules); + dataState = CONFIGFILEDATASNONE; + } + else + { + global.emplace(std::move(param_name), std::move(param_value) ); + dataState = CONFIGFILEDATASNONE; + } + break; + } while (1); - if (std::string::npos == block_end) - { - std::cout << "Error: symbol '}' after '" << block_type_name << "' has not been found;" << std::endl - << "Parsing config aborted;" << std::endl; + //change line + cur_pos = str_buf.find_first_of("\n", cur_pos); + if (cur_pos == std::string::npos) + { + iStatus = 1; + } - return false; + cur_pos += 1; } - else if (delimiter == block_pos) + break; + case CONFIGFILEDATAINBLOCK: { - if ("server" == block_type_name) + switch(inBlockState) { - std::unordered_multimap app; - - end_pos = str_buf.find(';', cur_pos); - - while (block_end > end_pos) - { - cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - delimiter = str_buf.find_first_of(whitespace, cur_pos); - - if (delimiter < end_pos) + case INBLOCKNONE: + case INBLOCKNOTE: { - std::string param_name = str_buf.substr(cur_pos, delimiter - cur_pos); + cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); + if (cur_pos == std::string::npos) + { + iStatus = 1; + } - if ('#' != param_name.front() ) + //start from next line + if ('#' == str_buf[cur_pos]) { - cur_pos = str_buf.find_first_not_of(whitespace, delimiter + 1); - delimiter = str_buf.find_last_not_of(whitespace, end_pos); + //last line + cur_pos = str_buf.find_first_of("\n", cur_pos); + if (cur_pos == std::string::npos) + { + iStatus = 1; + } - std::string param_value = str_buf.substr(cur_pos, delimiter - cur_pos); + cur_pos += 1; - if ("include" == param_name) + inBlockState = INBLOCKNOTE; + } + else if ('\n' == str_buf[cur_pos]) + { + cur_pos += 1; + inBlockState = INBLOCKNONE; + } + else + { + inBlockState = INBLOCKTPYE; + } + } + break; + case INBLOCKTPYE: + { + size_t delimiter = str_buf.find_first_of("\n", cur_pos); + std::string strLine = str_buf.substr(cur_pos, delimiter - cur_pos); + + //std::cout << "inblockLineStr: " << strLine << std::endl; + + do { + if ("}" == strLine) { - cur_pos = end_pos + 1; - this->includeConfigFile(param_value, str_buf, cur_pos); - block_end = findBlockEnd(str_buf, cur_pos); + dataState = CONFIGFILEDATASNOTE; + applications.push_back(app); + app.clear(); + break; } - else + + size_t ext_pos = strLine.find_first_of(whitespace, 0); + if (ext_pos == std::string::npos) { - app.emplace(std::move(param_name), std::move(param_value) ); + iStatus = 2; } - } - else // if comment line + std::string strExt = strLine.substr(0, ext_pos); + size_t extUnitPos = strLine.find_first_not_of(whitespace, ext_pos); + std::string strExtUnit = strLine.substr(extUnitPos, strLine.length() - extUnitPos - 1); + + //std::cout << "inblockLine " << strExt << " " << strExtUnit << std::endl; + app.emplace(std::move(strExt), std::move(strExtUnit)); + + break; + + } while(1); + + //change line + cur_pos = str_buf.find_first_of("\n", cur_pos); + if (cur_pos == std::string::npos) { - end_pos = str_buf.find_first_of("\r\n", cur_pos); + iStatus = 2; } - } - - if (std::string::npos != end_pos) - { - ++end_pos; - } - cur_pos = end_pos; + cur_pos += 1; - end_pos = str_buf.find(';', cur_pos); - } - - applications.emplace_back(std::move(app) ); - } - else - { - std::cout << "Warning: " << block_type_name << " - unknown block type;" << std::endl; + inBlockState = INBLOCKNONE; + } + break; + default: + break; } } - else - { - std::cout << "Warning: after " << block_type_name << " expected '{' ;" << std::endl; - } - - cur_pos = block_end; - - if (std::string::npos != cur_pos) - { - ++cur_pos; - } - } - else // if comment line - { - cur_pos = str_buf.find_first_of("\r\n", cur_pos); - } + break; + default: + break; } - - end_pos = str_buf.find(';', cur_pos); } + // std::cout << "app value start" << std::endl; + // for (size_t i = 0; i < applications.size(); ++i) + // { + // std::unordered_multimap sa = applications[i]; + // for (auto iter = sa.begin(); iter != sa.end(); iter++) + // { + // std::cout << iter->first << " " << iter->second << std::endl; + // } + + // } + // std::cout << "app value end" << std::endl; + auto const it_mimes = global.find("mimes"); if (global.cend() != it_mimes) { this->parseMimes(it_mimes->second, mimes_types); + //std::cout << "parse mimes end" << std::endl; } else { std::cout << "Warning: mime types file is not set in configuration;" << std::endl; } - if (false == applications.empty() ) + if (!applications.empty()) { auto const it_default_temp_dir = global.find("default_temp_dir"); @@ -724,6 +803,7 @@ namespace HttpServer for (auto const &app : applications) { this->addApplication(app, defaults, modules, apps_tree); + std::cout << "addApplication end" << std::endl; } } @@ -732,6 +812,7 @@ namespace HttpServer std::cout << "Notice: server does not contain applications;" << std::endl; } - return true; + //std::cout << "out loadCofig" << std::endl; + return iStatus == 1; } }; diff --git a/src/server/config/ConfigParser.h b/src/server/config/ConfigParser.h index c9b0e23..c501d5d 100644 --- a/src/server/config/ConfigParser.h +++ b/src/server/config/ConfigParser.h @@ -12,8 +12,16 @@ namespace HttpServer CONFIGFILEDATASNONE = 0, CONFIGFILEDATASNOTE, //comment CONFIGFILEDATASTYPE, - + //CONFIGFILEDATAGLOBAL, + CONFIGFILEDATAINBLOCK, //in block + }; + enum InBlockDataState + { + INBLOCKNONE, //in block none + INBLOCKNOTE, //in block note + INBLOCKTPYE, //in block type }; + class ConfigParser { private: