mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-26 12:37:09 +08:00
重写Parser代码实现
This commit is contained in:
parent
af0ebf4633
commit
31944a92ad
@ -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
|
||||||
|
@ -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的工具类
|
||||||
|
@ -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()) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user