重写Parser代码实现

This commit is contained in:
xia-chu 2023-06-10 12:22:28 +08:00 committed by 夏楚
parent af0ebf4633
commit 31944a92ad
5 changed files with 95 additions and 86 deletions

View File

@ -12,17 +12,18 @@
#include "Parser.h" #include "Parser.h"
#include "macros.h" #include "macros.h"
#include "Network/sockutil.h" #include "Network/sockutil.h"
#include "Common/macros.h"
using namespace std; using namespace std;
using namespace toolkit; using namespace toolkit;
namespace mediakit{ namespace mediakit {
string FindField(const char* buf, const char* start, const char *end ,size_t bufSize) { string FindField(const char *buf, const char *start, const char *end, size_t buf_size) {
if(bufSize <=0 ){ if (buf_size <= 0) {
bufSize = strlen(buf); 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; size_t len = 0;
if (start != NULL) { if (start != NULL) {
len = strlen(start); 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); return string(msg_start, msg_end);
} }
void Parser::Parse(const char *buf) { void Parser::parse(const char *buf, size_t size) {
//解析
const char *start = buf;
clear(); clear();
auto ptr = buf;
while (true) { while (true) {
auto line = FindField(start, NULL, "\r\n"); auto next_line = strstr(ptr, "\r\n");
if (line.size() == 0) { CHECK(next_line);
break; 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);
} }
if (start == buf) { _protocol = std::string(next_blank + 1, next_line);
_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 { } else {
_strUrl = strFullUrl; auto pos = strchr(ptr, ':');
} CHECK(pos > ptr && pos < next_line);
_strTail = FindField(line.data(), (strFullUrl + " ").data(), NULL); std::string key { ptr, pos };
std::string value;
if (pos[1] == ' ') {
value.assign(pos + 2, next_line);
} else { } else {
auto field = FindField(line.data(), NULL, ": "); value.assign(pos + 1, next_line);
auto value = FindField(line.data(), ": ", NULL);
if (field.size() != 0) {
_mapHeaders.emplace_force(field, value);
} }
_headers.emplace_force(trim(std::move(key)), trim(std::move(value)));
} }
start = start + line.size() + 2; ptr = next_line + 2;
if (strncmp(start, "\r\n", 2) == 0) { //协议解析完毕 if (strncmp(ptr, "\r\n", 2) == 0) { // 协议解析完毕
_strContent = FindField(start, "\r\n", NULL); _content.assign(ptr + 2, buf + size);
break; break;
} }
} }
} }
const string &Parser::method() const { const string &Parser::method() const {
return _strMethod; return _method;
} }
const string &Parser::url() const { const string &Parser::url() const {
return _strUrl; return _url;
} }
const std::string &Parser::status() const { const std::string &Parser::status() const {
@ -91,39 +96,41 @@ const std::string &Parser::status() const {
string Parser::fullUrl() const { string Parser::fullUrl() const {
if (_params.empty()) { if (_params.empty()) {
return _strUrl; return _url;
} }
return _strUrl + "?" + _params; return _url + "?" + _params;
} }
const string &Parser::protocol() const { const string &Parser::protocol() const {
return _strTail; return _protocol;
} }
const std::string &Parser::statusStr() const { const std::string &Parser::statusStr() const {
return protocol(); return protocol();
} }
static std::string kNull;
const string &Parser::operator[](const char *name) const { const string &Parser::operator[](const char *name) const {
auto it = _mapHeaders.find(name); auto it = _headers.find(name);
if (it == _mapHeaders.end()) { if (it == _headers.end()) {
return _strNull; return kNull;
} }
return it->second; return it->second;
} }
const string &Parser::content() const { const string &Parser::content() const {
return _strContent; return _content;
} }
void Parser::clear() { void Parser::clear() {
_strMethod.clear(); _method.clear();
_strUrl.clear(); _url.clear();
_params.clear(); _params.clear();
_strTail.clear(); _protocol.clear();
_strContent.clear(); _content.clear();
_mapHeaders.clear(); _headers.clear();
_mapUrlArgs.clear(); _url_args.clear();
} }
const string &Parser::params() const { const string &Parser::params() const {
@ -131,44 +138,46 @@ const string &Parser::params() const {
} }
void Parser::setUrl(string url) { void Parser::setUrl(string url) {
this->_strUrl = std::move(url); _url = std::move(url);
} }
void Parser::setContent(string content) { void Parser::setContent(string content) {
this->_strContent = std::move(content); _content = std::move(content);
} }
StrCaseMap &Parser::getHeader() const { StrCaseMap &Parser::getHeader() const {
return _mapHeaders; return _headers;
} }
StrCaseMap &Parser::getUrlArgs() const { StrCaseMap &Parser::getUrlArgs() const {
return _mapUrlArgs; return _url_args;
} }
StrCaseMap Parser::parseArgs(const string &str, const char *pair_delim, const char *key_delim) { StrCaseMap Parser::parseArgs(const string &str, const char *pair_delim, const char *key_delim) {
StrCaseMap ret; StrCaseMap ret;
auto arg_vec = split(str, pair_delim); auto arg_vec = split(str, pair_delim);
for (string &key_val : arg_vec) { for (auto &key_val : arg_vec) {
if (key_val.empty()) { if (key_val.empty()) {
//忽略 // 忽略
continue; continue;
} }
auto key = trim(FindField(key_val.data(), NULL, key_delim)); auto pos = key_val.find(key_delim);
if (!key.empty()) { if (pos != string::npos) {
auto val = trim(FindField(key_val.data(), key_delim, NULL)); auto key = trim(std::string(key_val, 0, pos));
ret.emplace_force(key, val); auto val = trim(key_val.substr(pos + strlen(key_delim)));
ret.emplace_force(std::move(key), std::move(val));
} else { } else {
trim(key_val); trim(key_val);
if (!key_val.empty()) { if (!key_val.empty()) {
ret.emplace_force(key_val, ""); ret.emplace_force(std::move(key_val), "");
} }
} }
} }
return ret; return ret;
} }
std::string Parser::mergeUrl(const string &base_url, const string &path) { 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()) { if (base_url.empty()) {
return path; return path;
} }
@ -242,21 +251,22 @@ std::string Parser::mergeUrl(const string &base_url, const string &path) {
} }
return final_url.str(); return final_url.str();
} }
void RtspUrl::parse(const string &strUrl) { void RtspUrl::parse(const string &strUrl) {
auto schema = FindField(strUrl.data(), nullptr, "://"); auto schema = FindField(strUrl.data(), nullptr, "://");
bool is_ssl = strcasecmp(schema.data(), "rtsps") == 0; bool is_ssl = strcasecmp(schema.data(), "rtsps") == 0;
//查找"://"与"/"之间的字符串,用于提取用户名密码 // 查找"://"与"/"之间的字符串,用于提取用户名密码
auto middle_url = FindField(strUrl.data(), "://", "/"); auto middle_url = FindField(strUrl.data(), "://", "/");
if (middle_url.empty()) { if (middle_url.empty()) {
middle_url = FindField(strUrl.data(), "://", nullptr); middle_url = FindField(strUrl.data(), "://", nullptr);
} }
auto pos = middle_url.rfind('@'); auto pos = middle_url.rfind('@');
if (pos == string::npos) { if (pos == string::npos) {
//并没有用户名密码 // 并没有用户名密码
return setup(is_ssl, strUrl, "", ""); return setup(is_ssl, strUrl, "", "");
} }
//包含用户名密码 // 包含用户名密码
auto user_pwd = middle_url.substr(0, pos); auto user_pwd = middle_url.substr(0, pos);
auto suffix = strUrl.substr(schema.size() + 3 + pos + 1); auto suffix = strUrl.substr(schema.size() + 3 + pos + 1);
auto url = StrPrinter << "rtsp://" << suffix << endl; 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"); CHECK(!url.empty(), "empty url");
auto pos = url.rfind(':'); auto pos = url.rfind(':');
if (pos == string::npos || url.back() == ']') { if (pos == string::npos || url.back() == ']') {
//没有冒号,未指定端口;或者是纯粹的ipv6地址 // 没有冒号,未指定端口;或者是纯粹的ipv6地址
host = url; host = url;
checkHost(host); checkHost(host);
return; return;
@ -320,4 +330,4 @@ static onceToken token([](){
}); });
#endif #endif
}//namespace mediakit } // namespace mediakit

View File

@ -18,7 +18,7 @@
namespace mediakit { 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 // 把url解析为主机地址和端口号,兼容ipv4/ipv6/dns
void splitUrl(const std::string &url, std::string &host, uint16_t &port); void splitUrl(const std::string &url, std::string &host, uint16_t &port);
@ -40,18 +40,18 @@ public:
return it->second; return it->second;
} }
template <typename V> template <typename K, typename V>
void emplace(const std::string &k, V &&v) { void emplace(K &&k, V &&v) {
auto it = find(k); auto it = find(k);
if (it != end()) { if (it != end()) {
return; return;
} }
Super::emplace(k, std::forward<V>(v)); Super::emplace(std::forward<K>(k), std::forward<V>(v));
} }
template <typename V> template <typename K, typename V>
void emplace_force(const std::string k, V &&v) { void emplace_force(K &&k, V &&v) {
Super::emplace(k, std::forward<V>(v)); Super::emplace(std::forward<K>(k), std::forward<V>(v));
} }
}; };
@ -61,23 +61,23 @@ public:
Parser() = default; Parser() = default;
~Parser() = default; ~Parser() = default;
// 解析信令 // 解析http/rtsp/sip请求需要确保buf以\0结尾
void Parse(const char *buf); void parse(const char *buf, size_t size);
// 获取命令字 // 获取命令字如GET/POST
const std::string &method() const; const std::string &method() const;
// 请求时获取中间url不包含?后面的参数 // 请求时获取中间url不包含?后面的参数
const std::string &url() const; const std::string &url() const;
// 回复时,获取状态码 // 回复时,获取状态码如200/404
const std::string &status() const; const std::string &status() const;
// 获取中间url包含?后面的参数 // 获取中间url包含?后面的参数
std::string fullUrl() const; std::string fullUrl() const;
// 请求时,获取协议名 // 请求时,获取协议名如HTTP/1.1
const std::string &protocol() const; const std::string &protocol() const;
// 回复时,获取状态字符串 // 回复时,获取状态字符串,如 OK/Not Found
const std::string &statusStr() const; const std::string &statusStr() const;
// 根据header key名获取请求header value值 // 根据header key名获取请求header value值
@ -110,14 +110,13 @@ public:
static std::string mergeUrl(const std::string &base_url, const std::string &path); static std::string mergeUrl(const std::string &base_url, const std::string &path);
private: private:
std::string _strMethod; std::string _method;
std::string _strUrl; std::string _url;
std::string _strTail; std::string _protocol;
std::string _strContent; std::string _content;
std::string _strNull;
std::string _params; std::string _params;
mutable StrCaseMap _mapHeaders; mutable StrCaseMap _headers;
mutable StrCaseMap _mapUrlArgs; mutable StrCaseMap _url_args;
}; };
// 解析rtsp url的工具类 // 解析rtsp url的工具类

View File

@ -181,7 +181,7 @@ void HttpClient::onError(const SockException &ex) {
} }
ssize_t HttpClient::onRecvHeader(const char *data, size_t len) { 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") { if (_parser.status() == "302" || _parser.status() == "301" || _parser.status() == "303") {
auto new_url = Parser::mergeUrl(_url, _parser["Location"]); auto new_url = Parser::mergeUrl(_url, _parser["Location"]);
if (new_url.empty()) { if (new_url.empty()) {

View File

@ -63,14 +63,14 @@ ssize_t HttpSession::onRecvHeader(const char *header, size_t len) {
s_func_map.emplace("OPTIONS", &HttpSession::Handle_Req_OPTIONS); s_func_map.emplace("OPTIONS", &HttpSession::Handle_Req_OPTIONS);
}); });
_parser.Parse(header); _parser.parse(header, len);
CHECK(_parser.url()[0] == '/'); CHECK(_parser.url()[0] == '/');
urlDecode(_parser); urlDecode(_parser);
string cmd = _parser.method(); string cmd = _parser.method();
auto it = s_func_map.find(cmd); auto it = s_func_map.find(cmd);
if (it == s_func_map.end()) { if (it == s_func_map.end()) {
WarnP(this) << "不支持该命令:" << cmd; WarnP(this) << "Http method not supported: " << cmd;
sendResponse(405, true); sendResponse(405, true);
return 0; return 0;
} }

View File

@ -61,7 +61,7 @@ ssize_t RtspSplitter::onRecvHeader(const char *data, size_t len) {
onRtpPacket(data,len); onRtpPacket(data,len);
return 0; return 0;
} }
_parser.Parse(data); _parser.parse(data, len);
auto ret = getContentLength(_parser); auto ret = getContentLength(_parser);
if(ret == 0){ if(ret == 0){
onWholeRtspPacket(_parser); onWholeRtspPacket(_parser);