重写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 "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;
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);
}
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);
_protocol = std::string(next_blank + 1, next_line);
} else {
_strUrl = strFullUrl;
}
_strTail = FindField(line.data(), (strFullUrl + " ").data(), NULL);
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 {
auto field = FindField(line.data(), NULL, ": ");
auto value = FindField(line.data(), ": ", NULL);
if (field.size() != 0) {
_mapHeaders.emplace_force(field, value);
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

View File

@ -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 <typename V>
void emplace(const std::string &k, V &&v) {
template <typename K, typename V>
void emplace(K &&k, V &&v) {
auto it = find(k);
if (it != end()) {
return;
}
Super::emplace(k, std::forward<V>(v));
Super::emplace(std::forward<K>(k), std::forward<V>(v));
}
template <typename V>
void emplace_force(const std::string k, V &&v) {
Super::emplace(k, std::forward<V>(v));
template <typename K, typename V>
void emplace_force(K &&k, V &&v) {
Super::emplace(std::forward<K>(k), std::forward<V>(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的工具类

View File

@ -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()) {

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);
});
_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;
}

View File

@ -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);