Add test for vod stream handler

pull/1568/head
winlin 5 years ago
parent 97f2c5bf0c
commit 8cdb7cc727

@ -51,8 +51,7 @@ using namespace std;
#include <srs_app_source.hpp>
#include <srs_app_server.hpp>
SrsVodStream::SrsVodStream(string root_dir)
: SrsHttpFileServer(root_dir)
SrsVodStream::SrsVodStream(string root_dir) : SrsHttpFileServer(root_dir)
{
}
@ -64,22 +63,23 @@ srs_error_t SrsVodStream::serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMe
{
srs_error_t err = srs_success;
SrsFileReader fs;
SrsFileReader* fs = fs_factory->create_file_reader();
SrsAutoFree(SrsFileReader, fs);
// open flv file
if ((err = fs.open(fullpath)) != srs_success) {
if ((err = fs->open(fullpath)) != srs_success) {
return srs_error_wrap(err, "open file");
}
if (offset > fs.filesize()) {
if (offset > fs->filesize()) {
return srs_error_new(ERROR_HTTP_REMUX_OFFSET_OVERFLOW, "http flv streaming %s overflow. size=%" PRId64 ", offset=%d",
fullpath.c_str(), fs.filesize(), offset);
fullpath.c_str(), fs->filesize(), offset);
}
SrsFlvVodStreamDecoder ffd;
// open fast decoder
if ((err = ffd.initialize(&fs)) != srs_success) {
if ((err = ffd.initialize(fs)) != srs_success) {
return srs_error_wrap(err, "init ffd");
}
@ -107,12 +107,12 @@ srs_error_t SrsVodStream::serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMe
}
sh_data = new char[sh_size];
SrsAutoFreeA(char, sh_data);
if ((err = fs.read(sh_data, sh_size, NULL)) != srs_success) {
if ((err = fs->read(sh_data, sh_size, NULL)) != srs_success) {
return srs_error_wrap(err, "fs read");
}
// seek to data offset
int64_t left = fs.filesize() - offset;
int64_t left = fs->filesize() - offset;
// write http header for ts.
w->header()->set_content_length((int)(sizeof(flv_header) + sh_size + left));
@ -132,7 +132,7 @@ srs_error_t SrsVodStream::serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMe
}
// send data
if ((err = copy(w, &fs, r, (int)left)) != srs_success) {
if ((err = copy(w, fs, r, (int)left)) != srs_success) {
return srs_error_wrap(err, "read flv=%s size=%d", fullpath.c_str(), left);
}
@ -146,21 +146,22 @@ srs_error_t SrsVodStream::serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMe
srs_assert(start >= 0);
srs_assert(end == -1 || end >= 0);
SrsFileReader fs;
SrsFileReader* fs = fs_factory->create_file_reader();
SrsAutoFree(SrsFileReader, fs);
// open flv file
if ((err = fs.open(fullpath)) != srs_success) {
if ((err = fs->open(fullpath)) != srs_success) {
return srs_error_wrap(err, "fs open");
}
// parse -1 to whole file.
if (end == -1) {
end = (int)fs.filesize();
end = (int)fs->filesize();
}
if (end > fs.filesize() || start > end) {
if (end > fs->filesize() || start > end) {
return srs_error_new(ERROR_HTTP_REMUX_OFFSET_OVERFLOW, "http mp4 streaming %s overflow. size=%" PRId64 ", offset=%d",
fullpath.c_str(), fs.filesize(), start);
fullpath.c_str(), fs->filesize(), start);
}
// seek to data offset, [start, end] for range.
@ -174,15 +175,16 @@ srs_error_t SrsVodStream::serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMe
w->write_header(SRS_CONSTS_HTTP_PartialContent);
// response the content range header.
// https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Range_requests
std::stringstream content_range;
content_range << "bytes " << start << "-" << end << "/" << fs.filesize();
content_range << "bytes " << start << "-" << end << "/" << fs->filesize();
w->header()->set("Content-Range", content_range.str());
// write body.
fs.seek2(start);
fs->seek2(start);
// send data
if ((err = copy(w, &fs, r, (int)left)) != srs_success) {
if ((err = copy(w, fs, r, (int)left)) != srs_success) {
return srs_error_wrap(err, "read mp4=%s size=%d", fullpath.c_str(), left);
}

@ -345,17 +345,15 @@ SrsHttpFileServer::~SrsHttpFileServer()
srs_freep(fs_factory);
}
SrsHttpFileServer* SrsHttpFileServer::set_fs_factory(ISrsFileReaderFactory* f)
void SrsHttpFileServer::set_fs_factory(ISrsFileReaderFactory* f)
{
srs_freep(fs_factory);
fs_factory = f;
return this;
}
SrsHttpFileServer* SrsHttpFileServer::set_path_check(_pfn_srs_path_exists pfn)
void SrsHttpFileServer::set_path_check(_pfn_srs_path_exists pfn)
{
_srs_path_exists = pfn;
return this;
}
srs_error_t SrsHttpFileServer::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
@ -396,8 +394,9 @@ srs_error_t SrsHttpFileServer::serve_file(ISrsHttpResponseWriter* w, ISrsHttpMes
if ((err = fs->open(fullpath)) != srs_success) {
return srs_error_wrap(err, "open file %s", fullpath.c_str());
}
int64_t length = fs->filesize();
// The length of bytes we could response to.
int64_t length = fs->filesize() - fs->tellg();
// unset the content length to encode in chunked encoding.
w->header()->set_content_length(length);
@ -479,10 +478,8 @@ srs_error_t SrsHttpFileServer::serve_flv_file(ISrsHttpResponseWriter* w, ISrsHtt
srs_error_t SrsHttpFileServer::serve_mp4_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath)
{
// for flash to request mp4 range in query string.
// for example, http://digitalprimates.net/dash/DashTest.html?url=http://dashdemo.edgesuite.net/digitalprimates/nexus/oops-20120802-manifest.mpd
std::string range = r->query_get("range");
// or, use bytes to request range,
// for example, http://dashas.castlabs.com/demo/try.html
// or, use bytes to request range.
if (range.empty()) {
range = r->query_get("bytes");
}
@ -515,11 +512,15 @@ srs_error_t SrsHttpFileServer::serve_mp4_file(ISrsHttpResponseWriter* w, ISrsHtt
srs_error_t SrsHttpFileServer::serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath, int offset)
{
// @remark For common http file server, we don't support stream request, please use SrsVodStream instead.
// TODO: FIXME: Support range in header https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Range_requests
return serve_file(w, r, fullpath);
}
srs_error_t SrsHttpFileServer::serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath, int start, int end)
{
// @remark For common http file server, we don't support stream request, please use SrsVodStream instead.
// TODO: FIXME: Support range in header https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Range_requests
return serve_file(w, r, fullpath);
}
@ -535,19 +536,15 @@ srs_error_t SrsHttpFileServer::copy(ISrsHttpResponseWriter* w, SrsFileReader* fs
ssize_t nread = -1;
int max_read = srs_min(left, SRS_HTTP_TS_SEND_BUFFER_SIZE);
if ((err = fs->read(buf, max_read, &nread)) != srs_success) {
break;
return srs_error_wrap(err, "read limit=%d, left=%d", max_read, left);
}
left -= nread;
if ((err = w->write(buf, (int)nread)) != srs_success) {
break;
return srs_error_wrap(err, "write limit=%d, bytes=%d, left=%d", max_read, nread, left);
}
}
if (err != srs_success) {
return srs_error_wrap(err, "copy");
}
return err;
}

@ -295,7 +295,7 @@ class SrsHttpFileServer : public ISrsHttpHandler
{
protected:
std::string dir;
private:
protected:
ISrsFileReaderFactory* fs_factory;
_pfn_srs_path_exists _srs_path_exists;
public:
@ -303,9 +303,9 @@ public:
virtual ~SrsHttpFileServer();
private:
// For utest to mock the fs.
virtual SrsHttpFileServer* set_fs_factory(ISrsFileReaderFactory* v);
virtual void set_fs_factory(ISrsFileReaderFactory* v);
// For utest to mock the path check function.
virtual SrsHttpFileServer* set_path_check(_pfn_srs_path_exists pfn);
virtual void set_path_check(_pfn_srs_path_exists pfn);
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
private:

@ -32,6 +32,7 @@ using namespace std;
#include <srs_kernel_utility.hpp>
#include <srs_kernel_file.hpp>
#include <srs_utest_kernel.hpp>
#include <srs_app_http_static.hpp>
class MockResponseWriter : virtual public ISrsHttpResponseWriter, virtual public ISrsHttpHeaderFilter
{
@ -93,6 +94,7 @@ srs_error_t MockResponseWriter::filter(SrsHttpHeader* h)
h->del("Server");
h->del("Connection");
h->del("Location");
h->del("Content-Range");
return srs_success;
}
@ -185,25 +187,120 @@ public:
}
};
bool _mock_srs_path_exists(std::string /*path*/)
bool _mock_srs_path_always_exists(std::string /*path*/)
{
return true;
}
bool _mock_srs_path_not_exists(std::string /*path*/)
{
return false;
}
VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
{
srs_error_t err;
if (true) {
SrsHttpMuxEntry e;
e.pattern = "/";
string fs;
int nn_flv_prefix = 0;
if (true) {
char flv_header[13];
nn_flv_prefix += sizeof(flv_header);
HELPER_ARRAY_INIT(flv_header, 13, 0);
fs.append(flv_header, 13);
}
if (true) {
uint8_t tag[15] = {9};
nn_flv_prefix += sizeof(tag);
HELPER_ARRAY_INIT(tag+1, 14, 0);
fs.append((const char*)tag, sizeof(tag));
}
if (true) {
uint8_t tag[15] = {8};
nn_flv_prefix += sizeof(tag);
HELPER_ARRAY_INIT(tag+1, 14, 0);
fs.append((const char*)tag, sizeof(tag));
}
string flv_content = "Hello, world!";
fs.append(flv_content);
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory(fs));
h.set_path_check(_mock_srs_path_always_exists);
h.entry = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
HELPER_ASSERT_SUCCESS(r.set_url("/index.flv?start=" + srs_int2str(nn_flv_prefix + 2), false));
HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r));
// We only compare the last content, ignore HTTP and FLV header.
string av2 = HELPER_BUFFER2STR(&w.io.out_buffer);
string av = av2.substr(av2.length() - flv_content.length() + 2);
string ev2 = mock_http_response(200, "llo, world!");
string ev = ev2.substr(ev2.length() - flv_content.length() + 2);
EXPECT_STREQ(ev.c_str(), av.c_str());
}
if (true) {
SrsHttpMuxEntry e;
e.pattern = "/";
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path_check(_mock_srs_path_always_exists);
h.entry = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
HELPER_ASSERT_SUCCESS(r.set_url("/index.mp4?range=2-3", false));
HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r));
__MOCK_HTTP_EXPECT_STREQ(206, "ll", w);
}
if (true) {
SrsHttpMuxEntry e;
e.pattern = "/";
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path_check(_mock_srs_path_always_exists);
h.entry = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
HELPER_ASSERT_SUCCESS(r.set_url("/index.mp4?bytes=2-5", false));
HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r));
__MOCK_HTTP_EXPECT_STREQ(206, "llo,", w);
}
}
VOID TEST(ProtocolHTTPTest, BasicHandlers)
{
srs_error_t err;
if (true) {
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp", "/", "/").c_str());
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp", "/", "/index.html").c_str());
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp/", "/", "/index.html").c_str());
EXPECT_STREQ("/tmp/ndex.html", srs_http_fs_fullpath("/tmp/", "//", "/index.html").c_str());
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp/", "/api", "/api/index.html").c_str());
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp/", "ossrs.net/api", "/api/index.html").c_str());
EXPECT_STREQ("/tmp/views/index.html", srs_http_fs_fullpath("/tmp/", "/api", "/api/views/index.html").c_str());
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp/", "/api/", "/api/index.html").c_str());
EXPECT_STREQ("/tmp/ndex.html", srs_http_fs_fullpath("/tmp/", "/api//", "/api/index.html").c_str());
SrsHttpMuxEntry e;
e.pattern = "/";
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path_check(_mock_srs_path_always_exists);
h.entry = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
HELPER_ASSERT_SUCCESS(r.set_url("/index.mp4?start=2", false));
HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r));
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
}
if (true) {
@ -211,7 +308,42 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
e.pattern = "/";
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"))->set_path_check(_mock_srs_path_exists);
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path_check(_mock_srs_path_always_exists);
h.entry = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
HELPER_ASSERT_SUCCESS(r.set_url("/index.flv?start=2", false));
HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r));
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
}
if (true) {
SrsHttpMuxEntry e;
e.pattern = "/";
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path_check(_mock_srs_path_always_exists);
h.entry = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
HELPER_ASSERT_SUCCESS(r.set_url("/index.flv", false));
HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r));
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
}
if (true) {
SrsHttpMuxEntry e;
e.pattern = "/";
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path_check(_mock_srs_path_always_exists);
h.entry = &e;
MockResponseWriter w;
@ -222,6 +354,35 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
}
if (true) {
SrsHttpMuxEntry e;
e.pattern = "/";
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path_check(_mock_srs_path_not_exists);
h.entry = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false));
HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r));
__MOCK_HTTP_EXPECT_STREQ(404, "Not Found", w);
}
if (true) {
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp", "/", "/").c_str());
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp", "/", "/index.html").c_str());
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp/", "/", "/index.html").c_str());
EXPECT_STREQ("/tmp/ndex.html", srs_http_fs_fullpath("/tmp/", "//", "/index.html").c_str());
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp/", "/api", "/api/index.html").c_str());
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp/", "ossrs.net/api", "/api/index.html").c_str());
EXPECT_STREQ("/tmp/views/index.html", srs_http_fs_fullpath("/tmp/", "/api", "/api/views/index.html").c_str());
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp/", "/api/", "/api/index.html").c_str());
EXPECT_STREQ("/tmp/ndex.html", srs_http_fs_fullpath("/tmp/", "/api//", "/api/index.html").c_str());
}
if (true) {
SrsHttpRedirectHandler h("/api", 500);
@ -239,6 +400,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
MockResponseWriter w;
HELPER_ASSERT_SUCCESS(h.serve_http(&w, NULL));
__MOCK_HTTP_EXPECT_STREQ(404, "Not Found", w);
EXPECT_TRUE(h.is_not_found());
}
}

Loading…
Cancel
Save