1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

Support include directive for config file (#2878)

* Support include import configuration

* Remove support for regular rules

* Remove support for regular rules

* Fix configuration file parsing bug

* Added utest tests for include functionality

* Added utest tests for include functionality

* Modify the UTest function

* optimized code

* Config: Refine parse error with state

* Config: Reorder functions

* Config: Rename parsing type to context

* Config: Refine args for include

* Config: Add utests for include

* Config: Refine code, parsing recursively.

* Config: Change the mock from file to buffer

* Config: Mock buffer in config

* Config: Refine code

* Add utests for include

* Added utest for include

Co-authored-by: pengfei.ma <pengfei.ma@ngaa.com.cn>
Co-authored-by: winlin <winlin@vip.126.com>
This commit is contained in:
mapengfei53 2022-02-14 15:08:51 +08:00 committed by GitHub
parent 5e78c1fe88
commit fde44885d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 389 additions and 74 deletions

View file

@ -842,9 +842,9 @@ bool SrsConfDirective::is_stream_caster()
return name == "stream_caster";
}
srs_error_t SrsConfDirective::parse(SrsConfigBuffer* buffer)
srs_error_t SrsConfDirective::parse(SrsConfigBuffer* buffer, SrsConfig* conf)
{
return parse_conf(buffer, parse_file);
return parse_conf(buffer, SrsDirectiveContextFile, conf);
}
srs_error_t SrsConfDirective::persistence(SrsFileWriter* writer, int level)
@ -971,48 +971,30 @@ SrsJsonAny* SrsConfDirective::dumps_arg0_to_boolean()
// LCOV_EXCL_STOP
// see: ngx_conf_parse
srs_error_t SrsConfDirective::parse_conf(SrsConfigBuffer* buffer, SrsDirectiveType type)
srs_error_t SrsConfDirective::parse_conf(SrsConfigBuffer* buffer, SrsDirectiveContext ctx, SrsConfig* conf)
{
srs_error_t err = srs_success;
while (true) {
std::vector<string> args;
int line_start = 0;
err = read_token(buffer, args, line_start);
/**
* ret maybe:
* ERROR_SYSTEM_CONFIG_INVALID error.
* ERROR_SYSTEM_CONFIG_DIRECTIVE directive terminated by ';' found
* ERROR_SYSTEM_CONFIG_BLOCK_START token terminated by '{' found
* ERROR_SYSTEM_CONFIG_BLOCK_END the '}' found
* ERROR_SYSTEM_CONFIG_EOF the config file is done
*/
if (srs_error_code(err) == ERROR_SYSTEM_CONFIG_INVALID) {
return err;
}
if (srs_error_code(err) == ERROR_SYSTEM_CONFIG_BLOCK_END) {
if (type != parse_block) {
return srs_error_wrap(err, "line %d: unexpected \"}\"", buffer->line);
SrsDirectiveState state = SrsDirectiveStateInit;
if ((err = read_token(buffer, args, line_start, state)) != srs_success) {
return srs_error_wrap(err, "read token, line=%d, state=%d", line_start, state);
}
srs_freep(err);
return srs_success;
if (state == SrsDirectiveStateBlockEnd) {
return ctx == SrsDirectiveContextBlock ? srs_success : srs_error_wrap(err, "line %d: unexpected \"}\"", buffer->line);
}
if (srs_error_code(err) == ERROR_SYSTEM_CONFIG_EOF) {
if (type == parse_block) {
return srs_error_wrap(err, "line %d: unexpected end of file, expecting \"}\"", conf_line);
if (state == SrsDirectiveStateEOF) {
return ctx != SrsDirectiveContextBlock ? srs_success : srs_error_wrap(err, "line %d: unexpected end of file, expecting \"}\"", conf_line);
}
srs_freep(err);
return srs_success;
}
if (args.empty()) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "line %d: empty directive", conf_line);
}
// build directive tree.
// Build normal directive which is not "include".
if (args.at(0) != "include") {
SrsConfDirective* directive = new SrsConfDirective();
directive->conf_line = line_start;
@ -1022,20 +1004,45 @@ srs_error_t SrsConfDirective::parse_conf(SrsConfigBuffer* buffer, SrsDirectiveTy
directives.push_back(directive);
if (srs_error_code(err) == ERROR_SYSTEM_CONFIG_BLOCK_START) {
srs_freep(err);
if ((err = directive->parse_conf(buffer, parse_block)) != srs_success) {
if (state == SrsDirectiveStateBlockStart) {
if ((err = directive->parse_conf(buffer, SrsDirectiveContextBlock, conf)) != srs_success) {
return srs_error_wrap(err, "parse dir");
}
}
srs_freep(err);
continue;
}
// Parse including, allow multiple files.
vector<string> files(args.begin() + 1, args.end());
if (files.empty()) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "line %d: include is empty directive", buffer->line);
}
if (!conf) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "line %d: no config", buffer->line);
}
for (int i = 0; i < (int)files.size(); i++) {
std::string file = files.at(i);
srs_assert(!file.empty());
srs_trace("config parse include %s", file.c_str());
SrsConfigBuffer* include_file_buffer = NULL;
SrsAutoFree(SrsConfigBuffer, include_file_buffer);
if ((err = conf->build_buffer(file, &include_file_buffer)) != srs_success) {
return srs_error_wrap(err, "buffer fullfill %s", file.c_str());
}
if ((err = parse_conf(include_file_buffer, SrsDirectiveContextFile, conf)) != srs_success) {
return srs_error_wrap(err, "parse include buffer");
}
}
}
return err;
}
// see: ngx_conf_read_token
srs_error_t SrsConfDirective::read_token(SrsConfigBuffer* buffer, vector<string>& args, int& line_start)
srs_error_t SrsConfDirective::read_token(SrsConfigBuffer* buffer, vector<string>& args, int& line_start, SrsDirectiveState& state)
{
srs_error_t err = srs_success;
@ -1058,7 +1065,8 @@ srs_error_t SrsConfDirective::read_token(SrsConfigBuffer* buffer, vector<string>
}
srs_trace("config parse complete");
return srs_error_new(ERROR_SYSTEM_CONFIG_EOF, "EOF");
state = SrsDirectiveStateEOF;
return err;
}
char ch = *buffer->pos++;
@ -1079,10 +1087,12 @@ srs_error_t SrsConfDirective::read_token(SrsConfigBuffer* buffer, vector<string>
continue;
}
if (ch == ';') {
return srs_error_new(ERROR_SYSTEM_CONFIG_DIRECTIVE, "dir");
state = SrsDirectiveStateEntire;
return err;
}
if (ch == '{') {
return srs_error_new(ERROR_SYSTEM_CONFIG_BLOCK_START, "block");
state = SrsDirectiveStateBlockStart;
return err;
}
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "line %d: unexpected '%c'", buffer->line, ch);
}
@ -1098,17 +1108,20 @@ srs_error_t SrsConfDirective::read_token(SrsConfigBuffer* buffer, vector<string>
if (args.size() == 0) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "line %d: unexpected ';'", buffer->line);
}
return srs_error_new(ERROR_SYSTEM_CONFIG_DIRECTIVE, "dir");
state = SrsDirectiveStateEntire;
return err;
case '{':
if (args.size() == 0) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "line %d: unexpected '{'", buffer->line);
}
return srs_error_new(ERROR_SYSTEM_CONFIG_BLOCK_START, "block");
state = SrsDirectiveStateBlockStart;
return err;
case '}':
if (args.size() != 0) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "line %d: unexpected '}'", buffer->line);
}
return srs_error_new(ERROR_SYSTEM_CONFIG_BLOCK_END, "block");
state = SrsDirectiveStateBlockEnd;
return err;
case '#':
sharp_comment = 1;
continue;
@ -1163,10 +1176,12 @@ srs_error_t SrsConfDirective::read_token(SrsConfigBuffer* buffer, vector<string>
srs_freepa(aword);
if (ch == ';') {
return srs_error_new(ERROR_SYSTEM_CONFIG_DIRECTIVE, "dir");
state = SrsDirectiveStateEntire;
return err;
}
if (ch == '{') {
return srs_error_new(ERROR_SYSTEM_CONFIG_BLOCK_START, "block");
state = SrsDirectiveStateBlockStart;
return err;
}
}
}
@ -2407,18 +2422,33 @@ srs_error_t SrsConfig::parse_file(const char* filename)
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "empty config");
}
SrsConfigBuffer buffer;
if ((err = buffer.fullfill(config_file.c_str())) != srs_success) {
return srs_error_wrap(err, "buffer fullfil");
SrsConfigBuffer* buffer = NULL;
SrsAutoFree(SrsConfigBuffer, buffer);
if ((err = build_buffer(config_file, &buffer)) != srs_success) {
return srs_error_wrap(err, "buffer fullfill %s", config_file.c_str());
}
if ((err = parse_buffer(&buffer)) != srs_success) {
if ((err = parse_buffer(buffer)) != srs_success) {
return srs_error_wrap(err, "parse buffer");
}
return err;
}
srs_error_t SrsConfig::build_buffer(string src, SrsConfigBuffer** pbuffer)
{
srs_error_t err = srs_success;
SrsConfigBuffer* buffer = new SrsConfigBuffer();
if ((err = buffer->fullfill(src.c_str())) != srs_success) {
srs_freep(buffer);
return srs_error_wrap(err, "read from src %s", src.c_str());
}
*pbuffer = buffer;
return err;
}
// LCOV_EXCL_STOP
srs_error_t SrsConfig::check_config()
@ -2955,7 +2985,7 @@ srs_error_t SrsConfig::parse_buffer(SrsConfigBuffer* buffer)
root = new SrsConfDirective();
// Parse root tree from buffer.
if ((err = root->parse(buffer)) != srs_success) {
if ((err = root->parse(buffer, this)) != srs_success) {
return srs_error_wrap(err, "root parse");
}

View file

@ -210,7 +210,7 @@ public:
// Parse utilities
public:
// Parse config directive from file buffer.
virtual srs_error_t parse(srs_internal::SrsConfigBuffer* buffer);
virtual srs_error_t parse(srs_internal::SrsConfigBuffer* buffer, SrsConfig* conf = NULL);
// Marshal the directive to writer.
// @param level, the root is level0, all its directives are level1, and so on.
virtual srs_error_t persistence(SrsFileWriter* writer, int level);
@ -223,24 +223,36 @@ public:
virtual SrsJsonAny* dumps_arg0_to_boolean();
// private parse.
private:
// The directive parsing type.
enum SrsDirectiveType {
// The directive parsing context.
enum SrsDirectiveContext {
// The root directives, parsing file.
parse_file,
// For each direcitve, parsing text block.
parse_block
SrsDirectiveContextFile,
// For each directive, parsing text block.
SrsDirectiveContextBlock,
};
enum SrsDirectiveState {
// Init state
SrsDirectiveStateInit,
// The directive terminated by ';' found
SrsDirectiveStateEntire,
// The token terminated by '{' found
SrsDirectiveStateBlockStart,
// The '}' found
SrsDirectiveStateBlockEnd,
// The config file is done
SrsDirectiveStateEOF,
};
// Parse the conf from buffer. the work flow:
// 1. read a token(directive args and a ret flag),
// 2. initialize the directive by args, args[0] is name, args[1-N] is args of directive,
// 3. if ret flag indicates there are child-directives, read_conf(directive, block) recursively.
virtual srs_error_t parse_conf(srs_internal::SrsConfigBuffer* buffer, SrsDirectiveType type);
virtual srs_error_t parse_conf(srs_internal::SrsConfigBuffer* buffer, SrsDirectiveContext ctx, SrsConfig* conf);
// Read a token from buffer.
// A token, is the directive args and a flag indicates whether has child-directives.
// @param args, the output directive args, the first is the directive name, left is the args.
// @param line_start, the actual start line of directive.
// @return, an error code indicates error or has child-directives.
virtual srs_error_t read_token(srs_internal::SrsConfigBuffer* buffer, std::vector<std::string>& args, int& line_start);
virtual srs_error_t read_token(srs_internal::SrsConfigBuffer* buffer, std::vector<std::string>& args, int& line_start, SrsDirectiveState& state);
};
// The config service provider.
@ -250,6 +262,7 @@ private:
// You could keep it before st-thread switch, or simply never keep it.
class SrsConfig
{
friend class SrsConfDirective;
// user command
private:
// Whether srs is run in dolphin mode.
@ -356,6 +369,10 @@ private:
public:
// Parse the config file, which is specified by cli.
virtual srs_error_t parse_file(const char* filename);
private:
// Build a buffer from a src, which is string content or filename.
virtual srs_error_t build_buffer(std::string src, srs_internal::SrsConfigBuffer** pbuffer);
public:
// Check the parsed config.
virtual srs_error_t check_config();
protected:

View file

@ -43,10 +43,6 @@
#define ERROR_SYSTEM_ASSERT_FAILED 1021
#define ERROR_READER_BUFFER_OVERFLOW 1022
#define ERROR_SYSTEM_CONFIG_INVALID 1023
#define ERROR_SYSTEM_CONFIG_DIRECTIVE 1024
#define ERROR_SYSTEM_CONFIG_BLOCK_START 1025
#define ERROR_SYSTEM_CONFIG_BLOCK_END 1026
#define ERROR_SYSTEM_CONFIG_EOF 1027
#define ERROR_SYSTEM_STREAM_BUSY 1028
#define ERROR_SYSTEM_IP_INVALID 1029
#define ERROR_SYSTEM_FORWARD_LOOP 1030

View file

@ -71,6 +71,29 @@ srs_error_t MockSrsConfig::parse(string buf)
return err;
}
srs_error_t MockSrsConfig::mock_include(const string file_name, const string content)
{
srs_error_t err = srs_success;
included_files[file_name] = content;
return err;
}
srs_error_t MockSrsConfig::build_buffer(std::string src, srs_internal::SrsConfigBuffer** pbuffer)
{
srs_error_t err = srs_success;
string content = included_files[src];
if(content.empty()) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "file %s: no found", src.c_str());
}
*pbuffer = new MockSrsConfigBuffer(content);
return err;
}
VOID TEST(ConfigTest, CheckMacros)
{
#ifndef SRS_CONSTS_LOCALHOST
@ -303,6 +326,63 @@ VOID TEST(ConfigDirectiveTest, ParseNameArg2_Dir0Arg0_Dir0Arg0)
EXPECT_EQ(0, (int)ddir0.directives.size());
}
VOID TEST(ConfigDirectiveTest, ParseArgsSpace)
{
srs_error_t err;
if (true) {
vector <string> usecases;
usecases.push_back("include;");
usecases.push_back("include ;");
usecases.push_back("include ;");
usecases.push_back("include ;");;
usecases.push_back("include\r;");
usecases.push_back("include\n;");
usecases.push_back("include \r \n \r\n \n\r;");
for (int i = 0; i < (int)usecases.size(); i++) {
string usecase = usecases.at(i);
MockSrsConfigBuffer buf(usecase);
SrsConfDirective conf;
HELPER_ASSERT_FAILED(conf.parse(&buf));
EXPECT_EQ(0, (int) conf.name.length());
EXPECT_EQ(0, (int) conf.args.size());
EXPECT_EQ(0, (int) conf.directives.size());
}
}
if (true) {
vector <string> usecases;
usecases.push_back("include test;");
usecases.push_back("include test;");
usecases.push_back("include test;");
usecases.push_back("include test;");;
usecases.push_back("include\rtest;");
usecases.push_back("include\ntest;");
usecases.push_back("include \r \n \r\n \n\rtest;");
MockSrsConfig config;
config.mock_include("test", "listen 1935;");
for (int i = 0; i < (int)usecases.size(); i++) {
string usecase = usecases.at(i);
MockSrsConfigBuffer buf(usecase);
SrsConfDirective conf;
HELPER_ASSERT_SUCCESS(conf.parse(&buf, &config));
EXPECT_EQ(0, (int) conf.name.length());
EXPECT_EQ(0, (int) conf.args.size());
EXPECT_EQ(1, (int) conf.directives.size());
SrsConfDirective &dir = *conf.directives.at(0);
EXPECT_STREQ("listen", dir.name.c_str());
EXPECT_EQ(1, (int) dir.args.size());
EXPECT_STREQ("1935", dir.arg0().c_str());
EXPECT_EQ(0, (int) dir.directives.size());
}
}
}
VOID TEST(ConfigDirectiveTest, Parse2SingleDirs)
{
srs_error_t err;
@ -3622,3 +3702,190 @@ VOID TEST(ConfigMainTest, CheckVhostConfig5)
}
}
VOID TEST(ConfigMainTest, CheckIncludeConfig)
{
srs_error_t err;
if (true) {
MockSrsConfig conf;
conf.mock_include("./conf/include_test/include.conf", "listen 1935;include ./conf/include_test/include_1.conf;");
conf.mock_include("./conf/include_test/include_1.conf", "max_connections 1000;daemon off;srs_log_tank console;http_server {enabled on;listen xxx;dir xxx2;}vhost ossrs.net {hls {enabled on;hls_path xxx;hls_m3u8_file xxx1;hls_ts_file xxx2;hls_fragment 10;hls_window 60;}}");
HELPER_ASSERT_SUCCESS(conf.parse("include ./conf/include_test/include.conf;"));
vector<string> listens = conf.get_listens();
EXPECT_EQ(1, (int)listens.size());
EXPECT_STREQ("1935", listens.at(0).c_str());
EXPECT_FALSE(conf.get_log_tank_file());
EXPECT_TRUE(conf.get_http_stream_enabled());
EXPECT_STREQ("xxx", conf.get_http_stream_listen().c_str());
EXPECT_STREQ("xxx2", conf.get_http_stream_dir().c_str());
EXPECT_TRUE(conf.get_hls_enabled("ossrs.net"));
EXPECT_STREQ("xxx", conf.get_hls_path("ossrs.net").c_str());
EXPECT_STREQ("xxx1", conf.get_hls_m3u8_file("ossrs.net").c_str());
EXPECT_STREQ("xxx2", conf.get_hls_ts_file("ossrs.net").c_str());
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_hls_fragment("ossrs.net"));
EXPECT_EQ(60*SRS_UTIME_SECONDS, conf.get_hls_window("ossrs.net"));
}
if (true) {
MockSrsConfig conf;
conf.mock_include("./conf/include_test/include_1.conf", "max_connections 1000;daemon off;srs_log_tank console;http_server {enabled on;listen xxx;dir xxx2;}vhost ossrs.net {hls {enabled on;hls_path xxx;hls_m3u8_file xxx1;hls_ts_file xxx2;hls_fragment 10;hls_window 60;}}");
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "include ./conf/include_test/include_1.conf;"));
vector<string> listens = conf.get_listens();
EXPECT_EQ(1, (int)listens.size());
EXPECT_STREQ("1935", listens.at(0).c_str());
EXPECT_FALSE(conf.get_log_tank_file());
EXPECT_TRUE(conf.get_http_stream_enabled());
EXPECT_STREQ("xxx", conf.get_http_stream_listen().c_str());
EXPECT_STREQ("xxx2", conf.get_http_stream_dir().c_str());
EXPECT_TRUE(conf.get_hls_enabled("ossrs.net"));
EXPECT_STREQ("xxx", conf.get_hls_path("ossrs.net").c_str());
EXPECT_STREQ("xxx1", conf.get_hls_m3u8_file("ossrs.net").c_str());
EXPECT_STREQ("xxx2", conf.get_hls_ts_file("ossrs.net").c_str());
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_hls_fragment("ossrs.net"));
EXPECT_EQ(60*SRS_UTIME_SECONDS, conf.get_hls_window("ossrs.net"));
}
if (true) {
MockSrsConfig conf;
conf.mock_include("./conf/include_test/include_2.conf", "listen 1935;max_connections 1000;daemon off;srs_log_tank console;http_server {enabled on;listen xxx;dir xxx2;}vhost ossrs.net {include ./conf/include_test/include_3.conf;}");
conf.mock_include("./conf/include_test/include_3.conf", "hls {enabled on;hls_path xxx;hls_m3u8_file xxx1;hls_ts_file xxx2;hls_fragment 10;hls_window 60;}");
HELPER_ASSERT_SUCCESS(conf.parse("include ./conf/include_test/include_2.conf;"));
vector<string> listens = conf.get_listens();
EXPECT_EQ(1, (int)listens.size());
EXPECT_STREQ("1935", listens.at(0).c_str());
EXPECT_FALSE(conf.get_log_tank_file());
EXPECT_TRUE(conf.get_http_stream_enabled());
EXPECT_STREQ("xxx", conf.get_http_stream_listen().c_str());
EXPECT_STREQ("xxx2", conf.get_http_stream_dir().c_str());
EXPECT_TRUE(conf.get_hls_enabled("ossrs.net"));
EXPECT_STREQ("xxx", conf.get_hls_path("ossrs.net").c_str());
EXPECT_STREQ("xxx1", conf.get_hls_m3u8_file("ossrs.net").c_str());
EXPECT_STREQ("xxx2", conf.get_hls_ts_file("ossrs.net").c_str());
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_hls_fragment("ossrs.net"));
EXPECT_EQ(60*SRS_UTIME_SECONDS, conf.get_hls_window("ossrs.net"));
}
if (true) {
MockSrsConfig conf;
conf.mock_include("./conf/include_test/include_3.conf", "hls {enabled on;hls_path xxx;hls_m3u8_file xxx1;hls_ts_file xxx2;hls_fragment 10;hls_window 60;}");
conf.mock_include("./conf/include_test/include_4.conf", "listen 1935;max_connections 1000;daemon off;srs_log_tank console;include ./conf/include_test/include_5.conf;vhost ossrs.net {include ./conf/include_test/include_3.conf;}include ./conf/include_test/include_6.conf;");
conf.mock_include("./conf/include_test/include_5.conf", "http_server {enabled on;listen xxx;dir xxx2;}");
conf.mock_include("./conf/include_test/include_6.conf", "http_api {enabled on;listen xxx;}");
HELPER_ASSERT_SUCCESS(conf.parse("include ./conf/include_test/include_4.conf;"));
vector<string> listens = conf.get_listens();
EXPECT_EQ(1, (int)listens.size());
EXPECT_STREQ("1935", listens.at(0).c_str());
EXPECT_FALSE(conf.get_log_tank_file());
EXPECT_TRUE(conf.get_http_stream_enabled());
EXPECT_STREQ("xxx", conf.get_http_stream_listen().c_str());
EXPECT_STREQ("xxx2", conf.get_http_stream_dir().c_str());
EXPECT_TRUE(conf.get_hls_enabled("ossrs.net"));
EXPECT_STREQ("xxx", conf.get_hls_path("ossrs.net").c_str());
EXPECT_STREQ("xxx1", conf.get_hls_m3u8_file("ossrs.net").c_str());
EXPECT_STREQ("xxx2", conf.get_hls_ts_file("ossrs.net").c_str());
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_hls_fragment("ossrs.net"));
EXPECT_EQ(60*SRS_UTIME_SECONDS, conf.get_hls_window("ossrs.net"));
EXPECT_TRUE(conf.get_http_api_enabled());
EXPECT_STREQ("xxx", conf.get_http_api_listen().c_str());
}
if (true) {
MockSrsConfig conf;
conf.mock_include("./conf/include_test/include_3.conf", "hls {enabled on;hls_path xxx;hls_m3u8_file xxx1;hls_ts_file xxx2;hls_fragment 10;hls_window 60;}");
conf.mock_include("./conf/include_test/include_4.conf", "listen 1935;max_connections 1000;daemon off;srs_log_tank console;include ./conf/include_test/include_5.conf ./conf/include_test/include_6.conf;vhost ossrs.net {include ./conf/include_test/include_3.conf;}");
conf.mock_include("./conf/include_test/include_5.conf", "http_server {enabled on;listen xxx;dir xxx2;}");
conf.mock_include("./conf/include_test/include_6.conf", "http_api {enabled on;listen xxx;}");
HELPER_ASSERT_SUCCESS(conf.parse("include ./conf/include_test/include_4.conf;"));
vector<string> listens = conf.get_listens();
EXPECT_EQ(1, (int)listens.size());
EXPECT_STREQ("1935", listens.at(0).c_str());
EXPECT_FALSE(conf.get_log_tank_file());
EXPECT_TRUE(conf.get_http_stream_enabled());
EXPECT_STREQ("xxx", conf.get_http_stream_listen().c_str());
EXPECT_STREQ("xxx2", conf.get_http_stream_dir().c_str());
EXPECT_TRUE(conf.get_http_api_enabled());
EXPECT_STREQ("xxx", conf.get_http_api_listen().c_str());
EXPECT_TRUE(conf.get_hls_enabled("ossrs.net"));
EXPECT_STREQ("xxx", conf.get_hls_path("ossrs.net").c_str());
EXPECT_STREQ("xxx1", conf.get_hls_m3u8_file("ossrs.net").c_str());
EXPECT_STREQ("xxx2", conf.get_hls_ts_file("ossrs.net").c_str());
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_hls_fragment("ossrs.net"));
EXPECT_EQ(60*SRS_UTIME_SECONDS, conf.get_hls_window("ossrs.net"));
}
if (true) {
MockSrsConfig conf;
conf.mock_include("./conf/include_test/include_3.conf", "hls {enabled on;hls_path xxx;hls_m3u8_file xxx1;hls_ts_file xxx2;hls_fragment 10;hls_window 60;}");
conf.mock_include("./conf/include_test/include_4.conf", "listen 1935;max_connections 1000;daemon off;srs_log_tank console;include ./conf/include_test/include_5.conf ./conf/include_test/include_6.conf;vhost ossrs.net {include ./conf/include_test/include_3.conf ./conf/include_test/include_7.conf;}");
conf.mock_include("./conf/include_test/include_5.conf", "http_server {enabled on;listen xxx;dir xxx2;}");
conf.mock_include("./conf/include_test/include_6.conf", "http_api {enabled on;listen xxx;}");
conf.mock_include("./conf/include_test/include_7.conf", "dash{enabled on;dash_fragment 10;dash_update_period 10;dash_timeshift 10;dash_path xxx;dash_mpd_file xxx2;}");
HELPER_ASSERT_SUCCESS(conf.parse("include ./conf/include_test/include_4.conf;"));
vector<string> listens = conf.get_listens();
EXPECT_EQ(1, (int)listens.size());
EXPECT_STREQ("1935", listens.at(0).c_str());
EXPECT_FALSE(conf.get_log_tank_file());
EXPECT_TRUE(conf.get_http_stream_enabled());
EXPECT_STREQ("xxx", conf.get_http_stream_listen().c_str());
EXPECT_STREQ("xxx2", conf.get_http_stream_dir().c_str());
EXPECT_TRUE(conf.get_http_api_enabled());
EXPECT_STREQ("xxx", conf.get_http_api_listen().c_str());
EXPECT_TRUE(conf.get_hls_enabled("ossrs.net"));
EXPECT_STREQ("xxx", conf.get_hls_path("ossrs.net").c_str());
EXPECT_STREQ("xxx1", conf.get_hls_m3u8_file("ossrs.net").c_str());
EXPECT_STREQ("xxx2", conf.get_hls_ts_file("ossrs.net").c_str());
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_hls_fragment("ossrs.net"));
EXPECT_EQ(60*SRS_UTIME_SECONDS, conf.get_hls_window("ossrs.net"));
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_dash_fragment("ossrs.net"));
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_dash_update_period("ossrs.net"));
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_dash_timeshift("ossrs.net"));
EXPECT_STREQ("xxx", conf.get_dash_path("ossrs.net").c_str());
EXPECT_STREQ("xxx2", conf.get_dash_mpd_file("ossrs.net").c_str());
}
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_FAILED(conf.parse("include ./conf/include_test/include.conf;"));
}
}

View file

@ -32,8 +32,13 @@ class MockSrsConfig : public SrsConfig
public:
MockSrsConfig();
virtual ~MockSrsConfig();
private:
std::map<std::string, std::string> included_files;
public:
virtual srs_error_t parse(std::string buf);
virtual srs_error_t mock_include(const std::string file_name, const std::string content);
protected:
virtual srs_error_t build_buffer(std::string src, srs_internal::SrsConfigBuffer** pbuffer);
};
#endif