From 31944a92ad0fa870e133650470dccc3f3a6d374f Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Sat, 10 Jun 2023 12:22:28 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=86=99Parser=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/Parser.cpp | 134 ++++++++++++++++++++------------------ src/Common/Parser.h | 39 ++++++----- src/Http/HttpClient.cpp | 2 +- src/Http/HttpSession.cpp | 4 +- src/Rtsp/RtspSplitter.cpp | 2 +- 5 files changed, 95 insertions(+), 86 deletions(-) diff --git a/src/Common/Parser.cpp b/src/Common/Parser.cpp index 6aa75a48..b47a0013 100644 --- a/src/Common/Parser.cpp +++ b/src/Common/Parser.cpp @@ -12,17 +12,18 @@ #include "Parser.h" #include "macros.h" #include "Network/sockutil.h" +#include "Common/macros.h" using namespace std; using namespace toolkit; -namespace mediakit{ +namespace mediakit { -string FindField(const char* buf, const char* start, const char *end ,size_t bufSize) { - if(bufSize <=0 ){ - bufSize = strlen(buf); +string FindField(const char *buf, const char *start, const char *end, size_t buf_size) { + if (buf_size <= 0) { + buf_size = strlen(buf); } - const char *msg_start = buf, *msg_end = buf + bufSize; + const char *msg_start = buf, *msg_end = buf + buf_size; size_t len = 0; if (start != NULL) { len = strlen(start); @@ -41,48 +42,52 @@ string FindField(const char* buf, const char* start, const char *end ,size_t buf return string(msg_start, msg_end); } -void Parser::Parse(const char *buf) { - //解析 - const char *start = buf; +void Parser::parse(const char *buf, size_t size) { clear(); + auto ptr = buf; while (true) { - auto line = FindField(start, NULL, "\r\n"); - if (line.size() == 0) { - break; - } - if (start == buf) { - _strMethod = FindField(line.data(), NULL, " "); - auto strFullUrl = FindField(line.data(), " ", " "); - auto args_pos = strFullUrl.find('?'); - if (args_pos != string::npos) { - _strUrl = strFullUrl.substr(0, args_pos); - _params = strFullUrl.substr(args_pos + 1); - _mapUrlArgs = parseArgs(_params); - } else { - _strUrl = strFullUrl; + auto next_line = strstr(ptr, "\r\n"); + CHECK(next_line); + if (ptr == buf) { + auto blank = strchr(ptr, ' '); + CHECK(blank > ptr && blank < next_line); + _method = std::string(ptr, blank); + auto next_blank = strchr(blank + 1, ' '); + CHECK(next_blank && next_blank < next_line); + _url.assign(blank + 1, next_blank); + auto pos = _url.find('?'); + if (pos != string::npos) { + _params = _url.substr(pos + 1); + _url_args = parseArgs(_params); + _url = _url.substr(0, pos); } - _strTail = FindField(line.data(), (strFullUrl + " ").data(), NULL); + _protocol = std::string(next_blank + 1, next_line); } else { - auto field = FindField(line.data(), NULL, ": "); - auto value = FindField(line.data(), ": ", NULL); - if (field.size() != 0) { - _mapHeaders.emplace_force(field, value); + auto pos = strchr(ptr, ':'); + CHECK(pos > ptr && pos < next_line); + std::string key { ptr, pos }; + std::string value; + if (pos[1] == ' ') { + value.assign(pos + 2, next_line); + } else { + value.assign(pos + 1, next_line); } + _headers.emplace_force(trim(std::move(key)), trim(std::move(value))); } - start = start + line.size() + 2; - if (strncmp(start, "\r\n", 2) == 0) { //协议解析完毕 - _strContent = FindField(start, "\r\n", NULL); + ptr = next_line + 2; + if (strncmp(ptr, "\r\n", 2) == 0) { // 协议解析完毕 + _content.assign(ptr + 2, buf + size); break; } } } const string &Parser::method() const { - return _strMethod; + return _method; } const string &Parser::url() const { - return _strUrl; + return _url; } const std::string &Parser::status() const { @@ -91,39 +96,41 @@ const std::string &Parser::status() const { string Parser::fullUrl() const { if (_params.empty()) { - return _strUrl; + return _url; } - return _strUrl + "?" + _params; + return _url + "?" + _params; } const string &Parser::protocol() const { - return _strTail; + return _protocol; } const std::string &Parser::statusStr() const { return protocol(); } +static std::string kNull; + const string &Parser::operator[](const char *name) const { - auto it = _mapHeaders.find(name); - if (it == _mapHeaders.end()) { - return _strNull; + auto it = _headers.find(name); + if (it == _headers.end()) { + return kNull; } return it->second; } const string &Parser::content() const { - return _strContent; + return _content; } void Parser::clear() { - _strMethod.clear(); - _strUrl.clear(); + _method.clear(); + _url.clear(); _params.clear(); - _strTail.clear(); - _strContent.clear(); - _mapHeaders.clear(); - _mapUrlArgs.clear(); + _protocol.clear(); + _content.clear(); + _headers.clear(); + _url_args.clear(); } const string &Parser::params() const { @@ -131,44 +138,46 @@ const string &Parser::params() const { } void Parser::setUrl(string url) { - this->_strUrl = std::move(url); + _url = std::move(url); } void Parser::setContent(string content) { - this->_strContent = std::move(content); + _content = std::move(content); } StrCaseMap &Parser::getHeader() const { - return _mapHeaders; + return _headers; } StrCaseMap &Parser::getUrlArgs() const { - return _mapUrlArgs; + return _url_args; } StrCaseMap Parser::parseArgs(const string &str, const char *pair_delim, const char *key_delim) { StrCaseMap ret; auto arg_vec = split(str, pair_delim); - for (string &key_val : arg_vec) { + for (auto &key_val : arg_vec) { if (key_val.empty()) { - //忽略 + // 忽略 continue; } - auto key = trim(FindField(key_val.data(), NULL, key_delim)); - if (!key.empty()) { - auto val = trim(FindField(key_val.data(), key_delim, NULL)); - ret.emplace_force(key, val); + auto pos = key_val.find(key_delim); + if (pos != string::npos) { + auto key = trim(std::string(key_val, 0, pos)); + auto val = trim(key_val.substr(pos + strlen(key_delim))); + ret.emplace_force(std::move(key), std::move(val)); } else { trim(key_val); if (!key_val.empty()) { - ret.emplace_force(key_val, ""); + ret.emplace_force(std::move(key_val), ""); } } } return ret; } + std::string Parser::mergeUrl(const string &base_url, const string &path) { - //以base_url为基础, 合并path路径生成新的url, path支持相对路径和绝对路径 + // 以base_url为基础, 合并path路径生成新的url, path支持相对路径和绝对路径 if (base_url.empty()) { return path; } @@ -242,21 +251,22 @@ std::string Parser::mergeUrl(const string &base_url, const string &path) { } return final_url.str(); } + void RtspUrl::parse(const string &strUrl) { auto schema = FindField(strUrl.data(), nullptr, "://"); bool is_ssl = strcasecmp(schema.data(), "rtsps") == 0; - //查找"://"与"/"之间的字符串,用于提取用户名密码 + // 查找"://"与"/"之间的字符串,用于提取用户名密码 auto middle_url = FindField(strUrl.data(), "://", "/"); if (middle_url.empty()) { middle_url = FindField(strUrl.data(), "://", nullptr); } auto pos = middle_url.rfind('@'); if (pos == string::npos) { - //并没有用户名密码 + // 并没有用户名密码 return setup(is_ssl, strUrl, "", ""); } - //包含用户名密码 + // 包含用户名密码 auto user_pwd = middle_url.substr(0, pos); auto suffix = strUrl.substr(schema.size() + 3 + pos + 1); auto url = StrPrinter << "rtsp://" << suffix << endl; @@ -297,7 +307,7 @@ void splitUrl(const std::string &url, std::string &host, uint16_t &port) { CHECK(!url.empty(), "empty url"); auto pos = url.rfind(':'); if (pos == string::npos || url.back() == ']') { - //没有冒号,未指定端口;或者是纯粹的ipv6地址 + // 没有冒号,未指定端口;或者是纯粹的ipv6地址 host = url; checkHost(host); return; @@ -320,4 +330,4 @@ static onceToken token([](){ }); #endif -}//namespace mediakit +} // namespace mediakit diff --git a/src/Common/Parser.h b/src/Common/Parser.h index fa8298be..3d81cea3 100644 --- a/src/Common/Parser.h +++ b/src/Common/Parser.h @@ -18,7 +18,7 @@ namespace mediakit { // 从字符串中提取子字符串 -std::string FindField(const char *buf, const char *start, const char *end, size_t bufSize = 0); +std::string FindField(const char *buf, const char *start, const char *end, size_t buf_size = 0); // 把url解析为主机地址和端口号,兼容ipv4/ipv6/dns void splitUrl(const std::string &url, std::string &host, uint16_t &port); @@ -40,18 +40,18 @@ public: return it->second; } - template - void emplace(const std::string &k, V &&v) { + template + void emplace(K &&k, V &&v) { auto it = find(k); if (it != end()) { return; } - Super::emplace(k, std::forward(v)); + Super::emplace(std::forward(k), std::forward(v)); } - template - void emplace_force(const std::string k, V &&v) { - Super::emplace(k, std::forward(v)); + template + void emplace_force(K &&k, V &&v) { + Super::emplace(std::forward(k), std::forward(v)); } }; @@ -61,23 +61,23 @@ public: Parser() = default; ~Parser() = default; - // 解析信令 - void Parse(const char *buf); + // 解析http/rtsp/sip请求,需要确保buf以\0结尾 + void parse(const char *buf, size_t size); - // 获取命令字 + // 获取命令字,如GET/POST const std::string &method() const; // 请求时,获取中间url,不包含?后面的参数 const std::string &url() const; - // 回复时,获取状态码 + // 回复时,获取状态码,如200/404 const std::string &status() const; // 获取中间url,包含?后面的参数 std::string fullUrl() const; - // 请求时,获取协议名 + // 请求时,获取协议名,如HTTP/1.1 const std::string &protocol() const; - // 回复时,获取状态字符串 + // 回复时,获取状态字符串,如 OK/Not Found const std::string &statusStr() const; // 根据header key名,获取请求header value值 @@ -110,14 +110,13 @@ public: static std::string mergeUrl(const std::string &base_url, const std::string &path); private: - std::string _strMethod; - std::string _strUrl; - std::string _strTail; - std::string _strContent; - std::string _strNull; + std::string _method; + std::string _url; + std::string _protocol; + std::string _content; std::string _params; - mutable StrCaseMap _mapHeaders; - mutable StrCaseMap _mapUrlArgs; + mutable StrCaseMap _headers; + mutable StrCaseMap _url_args; }; // 解析rtsp url的工具类 diff --git a/src/Http/HttpClient.cpp b/src/Http/HttpClient.cpp index daf757ad..99581ea9 100644 --- a/src/Http/HttpClient.cpp +++ b/src/Http/HttpClient.cpp @@ -181,7 +181,7 @@ void HttpClient::onError(const SockException &ex) { } ssize_t HttpClient::onRecvHeader(const char *data, size_t len) { - _parser.Parse(data); + _parser.parse(data, len); if (_parser.status() == "302" || _parser.status() == "301" || _parser.status() == "303") { auto new_url = Parser::mergeUrl(_url, _parser["Location"]); if (new_url.empty()) { diff --git a/src/Http/HttpSession.cpp b/src/Http/HttpSession.cpp index 7170fd63..7d5689a2 100644 --- a/src/Http/HttpSession.cpp +++ b/src/Http/HttpSession.cpp @@ -63,14 +63,14 @@ ssize_t HttpSession::onRecvHeader(const char *header, size_t len) { s_func_map.emplace("OPTIONS", &HttpSession::Handle_Req_OPTIONS); }); - _parser.Parse(header); + _parser.parse(header, len); CHECK(_parser.url()[0] == '/'); urlDecode(_parser); string cmd = _parser.method(); auto it = s_func_map.find(cmd); if (it == s_func_map.end()) { - WarnP(this) << "不支持该命令:" << cmd; + WarnP(this) << "Http method not supported: " << cmd; sendResponse(405, true); return 0; } diff --git a/src/Rtsp/RtspSplitter.cpp b/src/Rtsp/RtspSplitter.cpp index e88af355..f5d1e792 100644 --- a/src/Rtsp/RtspSplitter.cpp +++ b/src/Rtsp/RtspSplitter.cpp @@ -61,7 +61,7 @@ ssize_t RtspSplitter::onRecvHeader(const char *data, size_t len) { onRtpPacket(data,len); return 0; } - _parser.Parse(data); + _parser.parse(data, len); auto ret = getContentLength(_parser); if(ret == 0){ onWholeRtspPacket(_parser);