mirror of
https://github.com/ossrs/srs.git
synced 2025-02-12 11:21:52 +00:00
SRT: url supports multiple QueryStrings (#2908)
* SRT: parse srt url to supports multiple QueryStrings.(#2893) * SRT: url supports multiple QueryStrings by comma-separated key-value pairs with no nesting (#2893) * SRT: url supports multiple QueryStrings by comma-separated key-value pairs with no nesting (#2893) * SRT: Add comments for url. * Add utest for SRT URL parsing. * Update README. Co-authored-by: winlin <winlin@vip.126.com>
This commit is contained in:
parent
06cff31b24
commit
210cdf04be
8 changed files with 182 additions and 59 deletions
2
trunk/configure
vendored
2
trunk/configure
vendored
|
@ -407,7 +407,7 @@ fi
|
|||
if [ $SRS_UTEST = YES ]; then
|
||||
MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core"
|
||||
"srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload"
|
||||
"srs_utest_mp4" "srs_utest_service" "srs_utest_app" "srs_utest_rtc")
|
||||
"srs_utest_mp4" "srs_utest_service" "srs_utest_app" "srs_utest_rtc" "srs_utest_srt")
|
||||
ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot})
|
||||
if [[ $SRS_RTC == YES ]]; then
|
||||
ModuleLibIncs+=(${LibSrtpRoot})
|
||||
|
|
|
@ -8,6 +8,7 @@ The changelog for SRS.
|
|||
|
||||
## SRS 4.0 Changelog
|
||||
|
||||
* v4.0, 2022-03-19, Merge [#2908](https://github.com/ossrs/srs/pull/2908): SRT: url supports multiple QueryStrings (#2908). v4.0.250
|
||||
* v4.0, 2022-03-17, SRT: Support debug and run with CLion. v4.0.249
|
||||
* v4.0, 2022-03-15, Merge [#2966](https://github.com/ossrs/srs/pull/2966): Bugfix: Fix rtcp nack blp encode bug (#2966). v4.0.248
|
||||
* v4.0, 2022-03-07, RTC: Identify the WebRTC publisher in param for hooks. v4.0.247
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
#define VERSION_MAJOR 4
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 249
|
||||
#define VERSION_REVISION 250
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "srt_log.hpp"
|
||||
#include <vector>
|
||||
|
||||
#include <srs_protocol_utility.hpp>
|
||||
#include <srs_app_config.hpp>
|
||||
|
||||
bool is_streamid_valid(const std::string& streamid) {
|
||||
|
@ -24,20 +25,20 @@ bool is_streamid_valid(const std::string& streamid) {
|
|||
|
||||
int mode;
|
||||
std::string subpath;
|
||||
std::string vhost;
|
||||
|
||||
bool ret = get_streamid_info(streamid, mode, subpath);
|
||||
// Parse the stream info from streamid, see https://github.com/ossrs/srs/issues/2893
|
||||
bool ret = get_streamid_info(streamid, mode, vhost, subpath);
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((mode != PUSH_SRT_MODE) && (mode != PULL_SRT_MODE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> info_vec;
|
||||
string_split(subpath, "/", info_vec);
|
||||
|
||||
if (info_vec.size() < 2) {//it must be appname/stream at least.
|
||||
// TODO: FIXME: Should fail at parsing the original SRT URL.
|
||||
if (info_vec.size() != 2) {
|
||||
srt_log_warn("path format must be appname/stream?key=value...");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -69,12 +70,11 @@ bool get_key_value(const std::string& info, std::string& key, std::string& value
|
|||
return true;
|
||||
}
|
||||
|
||||
//eg. streamid=#!::h:live/livestream,m:publish
|
||||
bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_subpath) {
|
||||
std::vector<std::string> info_vec;
|
||||
std::string real_streamid;
|
||||
|
||||
mode = PUSH_SRT_MODE;
|
||||
// See streamid of https://github.com/ossrs/srs/issues/2893
|
||||
// TODO: FIMXE: We should parse SRT streamid to URL object, rather than a HTTP url subpath.
|
||||
bool get_streamid_info(const std::string& streamid, int& mode, std::string& vhost, std::string& url_subpath)
|
||||
{
|
||||
mode = PULL_SRT_MODE;
|
||||
|
||||
size_t pos = streamid.find("#!::");
|
||||
if (pos != 0) {
|
||||
|
@ -86,36 +86,72 @@ bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_
|
|||
url_subpath = streamid;
|
||||
return true;
|
||||
}
|
||||
|
||||
//SRT url supports multiple QueryStrings, which are passed to RTMP to realize authentication and other capabilities
|
||||
//@see https://github.com/ossrs/srs/issues/2893
|
||||
std::string params;
|
||||
std::string real_streamid;
|
||||
real_streamid = streamid.substr(4);
|
||||
|
||||
string_split(real_streamid, ",", info_vec);
|
||||
if (info_vec.size() < 2) {
|
||||
std::map<std::string, std::string> query;
|
||||
srs_parse_query_string(real_streamid, query);
|
||||
for (std::map<std::string, std::string>::iterator it = query.begin(); it != query.end(); ++it) {
|
||||
if (it->first == "h") {
|
||||
std::string host = it->second;
|
||||
|
||||
// Compatible with previous style, see https://github.com/ossrs/srs/issues/2893#compatible
|
||||
size_t r0 = host.find("/");
|
||||
size_t r1 = host.rfind("/");
|
||||
if (r0 != std::string::npos && r0 != std::string::npos) {
|
||||
if (r0 != r1) {
|
||||
// We got vhost in host.
|
||||
url_subpath = host.substr(r0 + 1);
|
||||
host = host.substr(0, r0);
|
||||
|
||||
params.append("vhost=");
|
||||
params.append(host);
|
||||
params.append("&");
|
||||
vhost = host;
|
||||
} else {
|
||||
// Only stream in host.
|
||||
url_subpath = host;
|
||||
}
|
||||
} else {
|
||||
// Now we get the host as vhost.
|
||||
params.append("vhost=");
|
||||
params.append(host);
|
||||
params.append("&");
|
||||
vhost = host;
|
||||
}
|
||||
} else if (it->first == "r") {
|
||||
url_subpath = it->second;
|
||||
} else if (it->first == "m") {
|
||||
std::string mode_str = it->second; // support m=publish or m=request
|
||||
std::transform(it->second.begin(), it->second.end(), mode_str.begin(), ::tolower);
|
||||
if (mode_str == "publish") {
|
||||
mode = PUSH_SRT_MODE;
|
||||
} else if (mode_str == "request") {
|
||||
mode = PULL_SRT_MODE;
|
||||
} else {
|
||||
srt_log_warn("unknown mode_str:%s", mode_str.c_str());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
params.append(it->first);
|
||||
params.append("=");
|
||||
params.append(it->second);
|
||||
params.append("&");
|
||||
}
|
||||
}
|
||||
|
||||
if (url_subpath.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < info_vec.size(); index++) {
|
||||
std::string key;
|
||||
std::string value;
|
||||
|
||||
bool ret = get_key_value(info_vec[index], key, value);
|
||||
if (!ret) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key == "h") {
|
||||
url_subpath = value;//eg. h=live/stream
|
||||
} else if (key == "m") {
|
||||
std::string mode_str = string_lower(value);//m=publish or m=request
|
||||
if (mode_str == "publish") {
|
||||
mode = PUSH_SRT_MODE;
|
||||
} else if (mode_str == "request") {
|
||||
mode = PULL_SRT_MODE;
|
||||
} else {
|
||||
mode = PUSH_SRT_MODE;
|
||||
}
|
||||
} else {//not suport
|
||||
continue;
|
||||
}
|
||||
if (!params.empty()) {
|
||||
url_subpath.append("?");
|
||||
url_subpath.append(params);
|
||||
url_subpath.pop_back(); // remove last '&'
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -123,19 +159,16 @@ bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_
|
|||
|
||||
srt_conn::srt_conn(SRTSOCKET conn_fd, const std::string& streamid):_conn_fd(conn_fd),
|
||||
_streamid(streamid),
|
||||
write_fail_cnt_(0) {
|
||||
get_streamid_info(streamid, _mode, _url_subpath);
|
||||
write_fail_cnt_(0)
|
||||
{
|
||||
get_streamid_info(streamid, _mode, _vhost, _url_subpath);
|
||||
|
||||
_update_timestamp = now_ms();
|
||||
|
||||
std::vector<std::string> path_vec;
|
||||
|
||||
string_split(_url_subpath, "/", path_vec);
|
||||
if (path_vec.size() >= 3) {
|
||||
_vhost = path_vec[0];
|
||||
} else {
|
||||
|
||||
if (_vhost.empty()) {
|
||||
_vhost = "__default_host__";
|
||||
}
|
||||
|
||||
srt_log_trace("srt connect construct streamid:%s, mode:%d, subpath:%s, vhost:%s",
|
||||
streamid.c_str(), _mode, _url_subpath.c_str(), _vhost.c_str());
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
bool is_streamid_valid(const std::string& streamid);
|
||||
bool get_key_value(const std::string& info, std::string& key, std::string& value);
|
||||
bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_subpash);
|
||||
bool get_streamid_info(const std::string& streamid, int& mode, std::string& vhost, std::string& url_subpash);
|
||||
|
||||
class srt_conn {
|
||||
public:
|
||||
|
|
|
@ -349,10 +349,7 @@ void srt_handle::handle_pull_data(SRT_SOCKSTATUS status, const std::string& subp
|
|||
|
||||
void srt_handle::handle_srt_socket(SRT_SOCKSTATUS status, SRTSOCKET conn_fd)
|
||||
{
|
||||
std::string subpath;
|
||||
int mode;
|
||||
auto conn_ptr = get_srt_conn(conn_fd);
|
||||
|
||||
if (!conn_ptr) {
|
||||
if (status != SRTS_CLOSED) {
|
||||
srt_log_error("handle_srt_socket find srt connection error, fd:%d, status:%d",
|
||||
|
@ -360,13 +357,10 @@ void srt_handle::handle_srt_socket(SRT_SOCKSTATUS status, SRTSOCKET conn_fd)
|
|||
}
|
||||
return;
|
||||
}
|
||||
bool ret = get_streamid_info(conn_ptr->get_streamid(), mode, subpath);
|
||||
if (!ret) {
|
||||
conn_ptr->close();
|
||||
conn_ptr = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::string subpath = conn_ptr->get_subpath();
|
||||
|
||||
int mode = conn_ptr->get_mode();
|
||||
if (mode == PUSH_SRT_MODE) {
|
||||
switch (status)
|
||||
{
|
||||
|
|
79
trunk/src/utest/srs_utest_srt.cpp
Normal file
79
trunk/src/utest/srs_utest_srt.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// Copyright (c) 2013-2021 Winlin
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
#include <srs_utest_srt.hpp>
|
||||
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srt_conn.hpp>
|
||||
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
VOID TEST(ProtocolSrtTest, SrtGetStreamInfoNormal) {
|
||||
int mode; string vhost; string subpath;
|
||||
|
||||
if (true) {
|
||||
EXPECT_TRUE(get_streamid_info("#!::r=live/livestream,key1=value1,key2=value2", mode, vhost, subpath));
|
||||
EXPECT_EQ(PULL_SRT_MODE, mode);
|
||||
EXPECT_STREQ("", vhost.c_str());
|
||||
EXPECT_STREQ("live/livestream?key1=value1&key2=value2", subpath.c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
EXPECT_TRUE(get_streamid_info("#!::h=host.com,r=live/livestream,key1=value1,key2=value2", mode, vhost, subpath));
|
||||
EXPECT_EQ(PULL_SRT_MODE, mode);
|
||||
EXPECT_STREQ("host.com", vhost.c_str());
|
||||
EXPECT_STREQ("live/livestream?vhost=host.com&key1=value1&key2=value2", subpath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtocolSrtTest, SrtGetStreamInfoMethod) {
|
||||
int mode; string vhost; string subpath;
|
||||
|
||||
if (true) {
|
||||
EXPECT_TRUE(get_streamid_info("#!::r=live/livestream,m=request", mode, vhost, subpath));
|
||||
EXPECT_EQ(PULL_SRT_MODE, mode);
|
||||
EXPECT_STREQ("live/livestream", subpath.c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
EXPECT_TRUE(get_streamid_info("#!::r=live/livestream,m=publish", mode, vhost, subpath));
|
||||
EXPECT_EQ(PUSH_SRT_MODE, mode);
|
||||
EXPECT_STREQ("live/livestream", subpath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtocolSrtTest, SrtGetStreamInfoCompatible) {
|
||||
int mode; string vhost; string subpath;
|
||||
|
||||
if (true) {
|
||||
EXPECT_TRUE(get_streamid_info("#!::h=live/livestream,m=request", mode, vhost, subpath));
|
||||
EXPECT_EQ(PULL_SRT_MODE, mode);
|
||||
EXPECT_STREQ("", vhost.c_str());
|
||||
EXPECT_STREQ("live/livestream", subpath.c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
EXPECT_TRUE(get_streamid_info("#!::h=live/livestream,m=publish", mode, vhost, subpath));
|
||||
EXPECT_EQ(PUSH_SRT_MODE, mode);
|
||||
EXPECT_STREQ("", vhost.c_str());
|
||||
EXPECT_STREQ("live/livestream", subpath.c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
EXPECT_TRUE(get_streamid_info("#!::h=srs.srt.com.cn/live/livestream,m=request", mode, vhost, subpath));
|
||||
EXPECT_EQ(PULL_SRT_MODE, mode);
|
||||
EXPECT_STREQ("srs.srt.com.cn", vhost.c_str());
|
||||
EXPECT_STREQ("live/livestream?vhost=srs.srt.com.cn", subpath.c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
EXPECT_TRUE(get_streamid_info("#!::h=srs.srt.com.cn/live/livestream,m=publish", mode, vhost, subpath));
|
||||
EXPECT_EQ(PUSH_SRT_MODE, mode);
|
||||
EXPECT_STREQ("srs.srt.com.cn", vhost.c_str());
|
||||
EXPECT_STREQ("live/livestream?vhost=srs.srt.com.cn", subpath.c_str());
|
||||
}
|
||||
}
|
||||
|
16
trunk/src/utest/srs_utest_srt.hpp
Normal file
16
trunk/src/utest/srs_utest_srt.hpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// Copyright (c) 2013-2021 Winlin
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
|
||||
#ifndef SRS_UTEST_SRT_HPP
|
||||
#define SRS_UTEST_SRT_HPP
|
||||
|
||||
/*
|
||||
#include <srs_utest_srt.hpp>
|
||||
*/
|
||||
#include <srs_utest.hpp>
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in a new issue