From 6d4066816a779c68be760fff553dfe14ce14d665 Mon Sep 17 00:00:00 2001 From: zhouxiaojun <279686030@qq.com> Date: Wed, 9 Feb 2022 18:02:31 +0800 Subject: [PATCH 1/6] SRT: parse srt url to supports multiple QueryStrings.(#2893) --- trunk/src/srt/srt_conn.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/trunk/src/srt/srt_conn.cpp b/trunk/src/srt/srt_conn.cpp index dc2e97cacc..a238ee8840 100644 --- a/trunk/src/srt/srt_conn.cpp +++ b/trunk/src/srt/srt_conn.cpp @@ -89,10 +89,14 @@ bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_ real_streamid = streamid.substr(4); string_split(real_streamid, ",", info_vec); - if (info_vec.size() < 2) { + if (info_vec.size() < 1) { return false; } + + std::string secret; + std::string token; + for (size_t index = 0; index < info_vec.size(); index++) { std::string key; std::string value; @@ -113,11 +117,33 @@ bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_ } else { mode = PUSH_SRT_MODE; } - } else {//not suport + }else if (key == "secret") { + secret = value; + }else if (key == "token"){ + token = value; + }else { continue; } } + //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 = "?"; + if (!secret.empty()) { + params += "secret=" + secret; + if (!token.empty()) + params += "&token=" + token; + }else { + if (!token.empty()) + params += "token=" + token; + } + + pos = url_subpath.rfind("/"); + if ((params.length() > 1) && + pos != std::string::npos) { + url_subpath.insert(pos, params); + } + return true; } From 33b03f41455e1f08b251e21911126cb3654be6c2 Mon Sep 17 00:00:00 2001 From: zhouxiaojun <279686030@qq.com> Date: Wed, 9 Feb 2022 20:50:08 +0800 Subject: [PATCH 2/6] SRT: url supports multiple QueryStrings by comma-separated key-value pairs with no nesting (#2893) --- trunk/src/srt/srt_conn.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/trunk/src/srt/srt_conn.cpp b/trunk/src/srt/srt_conn.cpp index a238ee8840..ab895042c5 100644 --- a/trunk/src/srt/srt_conn.cpp +++ b/trunk/src/srt/srt_conn.cpp @@ -89,7 +89,7 @@ bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_ real_streamid = streamid.substr(4); string_split(real_streamid, ",", info_vec); - if (info_vec.size() < 1) { + if (info_vec.size() < 2) { return false; } @@ -117,11 +117,11 @@ bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_ } else { mode = PUSH_SRT_MODE; } - }else if (key == "secret") { + } else if (key == "secret") { secret = value; - }else if (key == "token"){ + } else if (key == "token"){ token = value; - }else { + } else { continue; } } From 6b95bb82bbe1d2b64c2519d8df736cfc80df5208 Mon Sep 17 00:00:00 2001 From: zhouxiaojun <279686030@qq.com> Date: Sun, 13 Feb 2022 17:29:51 +0800 Subject: [PATCH 3/6] SRT: url supports multiple QueryStrings by comma-separated key-value pairs with no nesting (#2893) --- trunk/src/srt/srt_conn.cpp | 106 ++++++++++++++--------------------- trunk/src/srt/srt_conn.hpp | 2 +- trunk/src/srt/srt_handle.cpp | 14 ++--- 3 files changed, 48 insertions(+), 74 deletions(-) diff --git a/trunk/src/srt/srt_conn.cpp b/trunk/src/srt/srt_conn.cpp index ab895042c5..3e6b02e4f7 100644 --- a/trunk/src/srt/srt_conn.cpp +++ b/trunk/src/srt/srt_conn.cpp @@ -10,6 +10,7 @@ #include "srt_log.hpp" #include +#include #include bool is_streamid_valid(const std::string& streamid) { @@ -24,20 +25,18 @@ bool is_streamid_valid(const std::string& streamid) { int mode; std::string subpath; + std::string vhost; - bool ret = get_streamid_info(streamid, mode, subpath); + 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 info_vec; string_split(subpath, "/", info_vec); - if (info_vec.size() < 2) {//it must be appname/stream at least. + if (info_vec.size() != 2) { + srt_log_warn("path format must be appname/stream?key=value..."); return false; } @@ -70,11 +69,9 @@ bool get_key_value(const std::string& info, std::string& key, std::string& value } //eg. streamid=#!::h:live/livestream,m:publish -bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_subpath) { - std::vector info_vec; - std::string real_streamid; +bool get_streamid_info(const std::string& streamid, int& mode, std::string& vhost, std::string& url_subpath) { - mode = PUSH_SRT_MODE; + mode = PULL_SRT_MODE; size_t pos = streamid.find("#!::"); if (pos != 0) { @@ -86,62 +83,49 @@ bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_ url_subpath = streamid; return true; } - real_streamid = streamid.substr(4); - string_split(real_streamid, ",", info_vec); - if (info_vec.size() < 2) { - return false; - } - - - std::string secret; - std::string token; - - for (size_t index = 0; index < info_vec.size(); index++) { - std::string key; - std::string value; + //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); - 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 + std::map query; + srs_parse_query_string(real_streamid, query); + for (std::map::iterator it = query.begin(); it != query.end(); ++it) { + if (it->first == "h") { + params.append("vhost="); + params.append(it->second); + params.append("&"); + vhost = it->second; + } 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") { + } else if (mode_str == "request") { mode = PULL_SRT_MODE; - } else { - mode = PUSH_SRT_MODE; + } else { + srt_log_warn("unknown mode_str:%s", mode_str.c_str()); + return false; } - } else if (key == "secret") { - secret = value; - } else if (key == "token"){ - token = value; } else { - continue; + params.append(it->first); + params.append("="); + params.append(it->second); + params.append("&"); } } - //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 = "?"; - if (!secret.empty()) { - params += "secret=" + secret; - if (!token.empty()) - params += "&token=" + token; - }else { - if (!token.empty()) - params += "token=" + token; - } + if (url_subpath.empty()) + return false; - pos = url_subpath.rfind("/"); - if ((params.length() > 1) && - pos != std::string::npos) { - url_subpath.insert(pos, params); + if (!params.empty()) { + url_subpath.append("?"); + url_subpath.append(params); + url_subpath.pop_back(); // remove last '&' } return true; @@ -150,18 +134,14 @@ 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); + get_streamid_info(streamid, _mode, _vhost, _url_subpath); _update_timestamp = now_ms(); - - std::vector 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()); } diff --git a/trunk/src/srt/srt_conn.hpp b/trunk/src/srt/srt_conn.hpp index 44fa9bd17e..981cb43bba 100644 --- a/trunk/src/srt/srt_conn.hpp +++ b/trunk/src/srt/srt_conn.hpp @@ -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: diff --git a/trunk/src/srt/srt_handle.cpp b/trunk/src/srt/srt_handle.cpp index 20547d673c..ef013955ca 100644 --- a/trunk/src/srt/srt_handle.cpp +++ b/trunk/src/srt/srt_handle.cpp @@ -336,10 +336,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", @@ -347,13 +344,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) { From 87fdf1a0d4d51a436494daa6559cbd7ff72dc285 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 17 Mar 2022 07:25:36 +0800 Subject: [PATCH 4/6] SRT: Add comments for url. --- trunk/src/srt/srt_conn.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/trunk/src/srt/srt_conn.cpp b/trunk/src/srt/srt_conn.cpp index 3e6b02e4f7..c8e92639b1 100644 --- a/trunk/src/srt/srt_conn.cpp +++ b/trunk/src/srt/srt_conn.cpp @@ -27,6 +27,7 @@ bool is_streamid_valid(const std::string& streamid) { std::string subpath; std::string vhost; + // 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; From f68067cd4d9f9a909a3afcc9e2f14ee046fac480 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 19 Mar 2022 07:59:46 +0800 Subject: [PATCH 5/6] Add utest for SRT URL parsing. --- trunk/configure | 2 +- trunk/src/srt/srt_conn.cpp | 44 +++++++++++++---- trunk/src/utest/srs_utest_srt.cpp | 79 +++++++++++++++++++++++++++++++ trunk/src/utest/srs_utest_srt.hpp | 16 +++++++ 4 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 trunk/src/utest/srs_utest_srt.cpp create mode 100644 trunk/src/utest/srs_utest_srt.hpp diff --git a/trunk/configure b/trunk/configure index 5c28041be1..d26771137a 100755 --- a/trunk/configure +++ b/trunk/configure @@ -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}) diff --git a/trunk/src/srt/srt_conn.cpp b/trunk/src/srt/srt_conn.cpp index c8e92639b1..b933a95783 100644 --- a/trunk/src/srt/srt_conn.cpp +++ b/trunk/src/srt/srt_conn.cpp @@ -36,6 +36,7 @@ bool is_streamid_valid(const std::string& streamid) { std::vector info_vec; string_split(subpath, "/", info_vec); + // 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,9 +70,10 @@ 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& vhost, std::string& url_subpath) { - +// 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("#!::"); @@ -95,10 +97,32 @@ bool get_streamid_info(const std::string& streamid, int& mode, std::string& vhos srs_parse_query_string(real_streamid, query); for (std::map::iterator it = query.begin(); it != query.end(); ++it) { if (it->first == "h") { - params.append("vhost="); - params.append(it->second); - params.append("&"); - vhost = it->second; + 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") { @@ -120,8 +144,9 @@ bool get_streamid_info(const std::string& streamid, int& mode, std::string& vhos } } - if (url_subpath.empty()) + if (url_subpath.empty()) { return false; + } if (!params.empty()) { url_subpath.append("?"); @@ -134,7 +159,8 @@ bool get_streamid_info(const std::string& streamid, int& mode, std::string& vhos srt_conn::srt_conn(SRTSOCKET conn_fd, const std::string& streamid):_conn_fd(conn_fd), _streamid(streamid), - write_fail_cnt_(0) { + write_fail_cnt_(0) +{ get_streamid_info(streamid, _mode, _vhost, _url_subpath); _update_timestamp = now_ms(); diff --git a/trunk/src/utest/srs_utest_srt.cpp b/trunk/src/utest/srs_utest_srt.cpp new file mode 100644 index 0000000000..6a7c2830b9 --- /dev/null +++ b/trunk/src/utest/srs_utest_srt.cpp @@ -0,0 +1,79 @@ +// +// Copyright (c) 2013-2021 Winlin +// +// SPDX-License-Identifier: MIT +// +#include + +#include +#include + +#include +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()); + } +} + diff --git a/trunk/src/utest/srs_utest_srt.hpp b/trunk/src/utest/srs_utest_srt.hpp new file mode 100644 index 0000000000..63c0a663a1 --- /dev/null +++ b/trunk/src/utest/srs_utest_srt.hpp @@ -0,0 +1,16 @@ +// +// Copyright (c) 2013-2021 Winlin +// +// SPDX-License-Identifier: MIT +// + +#ifndef SRS_UTEST_SRT_HPP +#define SRS_UTEST_SRT_HPP + +/* +#include +*/ +#include + +#endif + From c2d74d5420272c180fc98a621929cfeab30a2854 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 19 Mar 2022 08:04:38 +0800 Subject: [PATCH 6/6] Update README. --- trunk/doc/CHANGELOG.md | 1 + trunk/src/core/srs_core_version4.hpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index bbdd185314..9fe6174c3f 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -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 diff --git a/trunk/src/core/srs_core_version4.hpp b/trunk/src/core/srs_core_version4.hpp index 553ceeff9a..6b6ee5dd7a 100644 --- a/trunk/src/core/srs_core_version4.hpp +++ b/trunk/src/core/srs_core_version4.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 4 #define VERSION_MINOR 0 -#define VERSION_REVISION 249 +#define VERSION_REVISION 250 #endif