Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SRT: url supports multiple QueryStrings #2908

Merged
merged 8 commits into from
Mar 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion trunk/configure
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down
1 change: 1 addition & 0 deletions trunk/doc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion trunk/src/core/srs_core_version4.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@

#define VERSION_MAJOR 4
#define VERSION_MINOR 0
#define VERSION_REVISION 249
#define VERSION_REVISION 250

#endif
121 changes: 77 additions & 44 deletions trunk/src/srt/srt_conn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand All @@ -86,56 +86,89 @@ 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;
}

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<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") {
} 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 {//not suport
continue;
} else {
params.append(it->first);
params.append("=");
params.append(it->second);
params.append("&");
}
}

if (url_subpath.empty()) {
return false;
}

if (!params.empty()) {
url_subpath.append("?");
url_subpath.append(params);
url_subpath.pop_back(); // remove last '&'
}

return true;
}

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());
}
Expand Down
2 changes: 1 addition & 1 deletion trunk/src/srt/srt_conn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
winlinvip marked this conversation as resolved.
Show resolved Hide resolved

class srt_conn {
public:
Expand Down
14 changes: 4 additions & 10 deletions trunk/src/srt/srt_handle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,24 +349,18 @@ 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",
conn_fd, status);
}
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)
{
Expand Down
79 changes: 79 additions & 0 deletions trunk/src/utest/srs_utest_srt.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 16 additions & 0 deletions trunk/src/utest/srs_utest_srt.hpp
Original file line number Diff line number Diff line change
@@ -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