mirror of
https://github.com/ossrs/srs.git
synced 2025-02-14 12:21:55 +00:00
Add test for http basic handler
This commit is contained in:
parent
6bad973a7c
commit
fa362607b2
6 changed files with 161 additions and 28 deletions
|
@ -145,6 +145,7 @@ For previous versions, please read:
|
|||
|
||||
## V3 changes
|
||||
|
||||
* v3.0, 2019-12-16, For [#1042][bug #1042], add test for HTTP protocol.
|
||||
* <strong>v3.0, 2019-12-13, [3.0 alpha4(3.0.71)][r3.0a4] released. 112928 lines.</strong>
|
||||
* v3.0, 2019-12-12, For [#547][bug #547], [#1506][bug #1506], default hls_dts_directly to on. 3.0.71
|
||||
* v3.0, 2019-12-12, SrsPacket supports converting to message, so can be sent by one API.
|
||||
|
|
|
@ -175,6 +175,19 @@ srs_error_t SrsFileWriter::lseek(off_t offset, int whence, off_t* seeked)
|
|||
return srs_success;
|
||||
}
|
||||
|
||||
ISrsFileReaderFactory::ISrsFileReaderFactory()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsFileReaderFactory::~ISrsFileReaderFactory()
|
||||
{
|
||||
}
|
||||
|
||||
SrsFileReader* ISrsFileReaderFactory::create_file_reader()
|
||||
{
|
||||
return new SrsFileReader();
|
||||
}
|
||||
|
||||
SrsFileReader::SrsFileReader()
|
||||
{
|
||||
fd = -1;
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
class SrsFileReader;
|
||||
|
||||
/**
|
||||
* file writer, to write to file.
|
||||
*/
|
||||
|
@ -73,6 +75,16 @@ public:
|
|||
virtual srs_error_t lseek(off_t offset, int whence, off_t* seeked);
|
||||
};
|
||||
|
||||
// The file reader factory.
|
||||
class ISrsFileReaderFactory
|
||||
{
|
||||
public:
|
||||
ISrsFileReaderFactory();
|
||||
virtual ~ISrsFileReaderFactory();
|
||||
public:
|
||||
virtual SrsFileReader* create_file_reader();
|
||||
};
|
||||
|
||||
/**
|
||||
* file reader, to read from file.
|
||||
*/
|
||||
|
|
|
@ -272,7 +272,7 @@ srs_error_t SrsHttpRedirectHandler::serve_http(ISrsHttpResponseWriter* w, ISrsHt
|
|||
location += "?" + r->query();
|
||||
}
|
||||
|
||||
string msg = "Redirect to" + location;
|
||||
string msg = "Redirect to " + location;
|
||||
|
||||
w->header()->set_content_type("text/plain; charset=utf-8");
|
||||
w->header()->set_content_length(msg.length());
|
||||
|
@ -304,37 +304,60 @@ srs_error_t SrsHttpNotFoundHandler::serve_http(ISrsHttpResponseWriter* w, ISrsHt
|
|||
return srs_go_http_error(w, SRS_CONSTS_HTTP_NotFound);
|
||||
}
|
||||
|
||||
SrsHttpFileServer::SrsHttpFileServer(string root_dir)
|
||||
string srs_http_fs_fullpath(string dir, string upath, string pattern)
|
||||
{
|
||||
dir = root_dir;
|
||||
}
|
||||
|
||||
SrsHttpFileServer::~SrsHttpFileServer()
|
||||
{
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpFileServer::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
string upath = r->path();
|
||||
|
||||
// add default pages.
|
||||
if (srs_string_ends_with(upath, "/")) {
|
||||
upath += SRS_HTTP_DEFAULT_PAGE;
|
||||
}
|
||||
|
||||
|
||||
string fullpath = dir + "/";
|
||||
|
||||
|
||||
// remove the virtual directory.
|
||||
srs_assert(entry);
|
||||
size_t pos = entry->pattern.find("/");
|
||||
if (upath.length() > entry->pattern.length() && pos != string::npos) {
|
||||
fullpath += upath.substr(entry->pattern.length() - pos);
|
||||
size_t pos = pattern.find("/");
|
||||
if (upath.length() > pattern.length() && pos != string::npos) {
|
||||
fullpath += upath.substr(pattern.length() - pos);
|
||||
} else {
|
||||
fullpath += upath;
|
||||
}
|
||||
|
||||
return fullpath;
|
||||
}
|
||||
|
||||
SrsHttpFileServer::SrsHttpFileServer(string root_dir)
|
||||
{
|
||||
dir = root_dir;
|
||||
fs_factory = new ISrsFileReaderFactory();
|
||||
_srs_path_exists = srs_path_exists;
|
||||
}
|
||||
|
||||
SrsHttpFileServer::~SrsHttpFileServer()
|
||||
{
|
||||
srs_freep(fs_factory);
|
||||
}
|
||||
|
||||
SrsHttpFileServer* 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)
|
||||
{
|
||||
_srs_path_exists = pfn;
|
||||
return this;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpFileServer::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
srs_assert(entry);
|
||||
|
||||
string upath = r->path();
|
||||
string fullpath = srs_http_fs_fullpath(dir, upath, entry->pattern);
|
||||
|
||||
// stat current dir, if exists, return error.
|
||||
if (!srs_path_exists(fullpath)) {
|
||||
if (!_srs_path_exists(fullpath)) {
|
||||
srs_warn("http miss file=%s, pattern=%s, upath=%s",
|
||||
fullpath.c_str(), entry->pattern.c_str(), upath.c_str());
|
||||
return SrsHttpNotFoundHandler().serve_http(w, r);
|
||||
|
@ -357,15 +380,15 @@ srs_error_t SrsHttpFileServer::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMes
|
|||
srs_error_t SrsHttpFileServer::serve_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// open the target file.
|
||||
SrsFileReader fs;
|
||||
|
||||
if ((err = fs.open(fullpath)) != srs_success) {
|
||||
|
||||
SrsFileReader* fs = fs_factory->create_file_reader();
|
||||
SrsAutoFree(SrsFileReader, fs);
|
||||
|
||||
if ((err = fs->open(fullpath)) != srs_success) {
|
||||
return srs_error_wrap(err, "open file %s", fullpath.c_str());
|
||||
}
|
||||
|
||||
int64_t length = fs.filesize();
|
||||
int64_t length = fs->filesize();
|
||||
|
||||
// unset the content length to encode in chunked encoding.
|
||||
w->header()->set_content_length(length);
|
||||
|
@ -418,7 +441,7 @@ srs_error_t SrsHttpFileServer::serve_file(ISrsHttpResponseWriter* w, ISrsHttpMes
|
|||
|
||||
// write body.
|
||||
int64_t left = length;
|
||||
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, "copy file=%s size=%d", fullpath.c_str(), left);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ class ISrsHttpMessage;
|
|||
class SrsHttpMuxEntry;
|
||||
class ISrsHttpResponseWriter;
|
||||
class SrsJsonObject;
|
||||
class ISrsFileReaderFactory;
|
||||
|
||||
// From http specification
|
||||
// CR = <US-ASCII CR, carriage return (13)>
|
||||
|
@ -276,6 +277,12 @@ public:
|
|||
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
// For utest to mock it.
|
||||
typedef bool (*_pfn_srs_path_exists)(std::string path);
|
||||
|
||||
// Build the file path from request r.
|
||||
extern std::string srs_http_fs_fullpath(std::string dir, std::string upath, std::string pattern);
|
||||
|
||||
// FileServer returns a handler that serves HTTP requests
|
||||
// with the contents of the file system rooted at root.
|
||||
//
|
||||
|
@ -288,9 +295,17 @@ class SrsHttpFileServer : public ISrsHttpHandler
|
|||
{
|
||||
protected:
|
||||
std::string dir;
|
||||
private:
|
||||
ISrsFileReaderFactory* fs_factory;
|
||||
_pfn_srs_path_exists _srs_path_exists;
|
||||
public:
|
||||
SrsHttpFileServer(std::string root_dir);
|
||||
virtual ~SrsHttpFileServer();
|
||||
private:
|
||||
// For utest to mock the fs.
|
||||
virtual SrsHttpFileServer* set_fs_factory(ISrsFileReaderFactory* v);
|
||||
// For utest to mock the path check function.
|
||||
virtual SrsHttpFileServer* set_path_check(_pfn_srs_path_exists pfn);
|
||||
public:
|
||||
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
private:
|
||||
|
|
|
@ -30,6 +30,8 @@ using namespace std;
|
|||
#include <srs_utest_protocol.hpp>
|
||||
#include <srs_protocol_json.hpp>
|
||||
#include <srs_kernel_utility.hpp>
|
||||
#include <srs_kernel_file.hpp>
|
||||
#include <srs_utest_kernel.hpp>
|
||||
|
||||
class MockResponseWriter : virtual public ISrsHttpResponseWriter, virtual public ISrsHttpHeaderFilter
|
||||
{
|
||||
|
@ -90,6 +92,7 @@ srs_error_t MockResponseWriter::filter(SrsHttpHeader* h)
|
|||
h->del("Content-Type");
|
||||
h->del("Server");
|
||||
h->del("Connection");
|
||||
h->del("Location");
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
|
@ -120,6 +123,9 @@ VOID TEST(ProtocolHTTPTest, ResponseDetect)
|
|||
EXPECT_STREQ("application/octet-stream", srs_go_http_detect(NULL, 0).c_str());
|
||||
}
|
||||
|
||||
#define __MOCK_HTTP_EXPECT_STREQ(status, text, w) \
|
||||
EXPECT_STREQ(mock_http_response(status, text).c_str(), HELPER_BUFFER2STR(&w.io.out_buffer).c_str())
|
||||
|
||||
VOID TEST(ProtocolHTTPTest, ResponseHTTPError)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
@ -127,7 +133,7 @@ VOID TEST(ProtocolHTTPTest, ResponseHTTPError)
|
|||
if (true) {
|
||||
MockResponseWriter w;
|
||||
HELPER_EXPECT_SUCCESS(srs_go_http_error(&w, SRS_CONSTS_HTTP_Found));
|
||||
EXPECT_STREQ(mock_http_response(302,"Found").c_str(), HELPER_BUFFER2STR(&w.io.out_buffer).c_str());
|
||||
__MOCK_HTTP_EXPECT_STREQ(302, "Found", w);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,6 +171,69 @@ VOID TEST(ProtocolHTTPTest, HTTPHeader)
|
|||
srs_freep(o);
|
||||
}
|
||||
|
||||
class MockFileReaderFactory : public ISrsFileReaderFactory
|
||||
{
|
||||
public:
|
||||
string bytes;
|
||||
MockFileReaderFactory(string data) {
|
||||
bytes = data;
|
||||
}
|
||||
virtual ~MockFileReaderFactory() {
|
||||
}
|
||||
virtual SrsFileReader* create_file_reader() {
|
||||
return new MockSrsFileReader((const char*)bytes.data(), (int)bytes.length());
|
||||
}
|
||||
};
|
||||
|
||||
bool _mock_srs_path_exists(std::string path)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
VOID TEST(ProtocolHTTPTest, BasicHandlers)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
if (true) {
|
||||
EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp", "/tmp/index.html", "/").c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
SrsHttpMuxEntry e;
|
||||
e.pattern = "/";
|
||||
|
||||
SrsHttpFileServer h("/tmp");
|
||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"))->set_path_check(_mock_srs_path_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(200, "Hello, world!", w);
|
||||
}
|
||||
|
||||
if (true) {
|
||||
SrsHttpRedirectHandler h("/api", 500);
|
||||
|
||||
MockResponseWriter w;
|
||||
SrsHttpMessage r(NULL, NULL);
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/api?v=2.0", false));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r));
|
||||
__MOCK_HTTP_EXPECT_STREQ(500, "Redirect to /api?v=2.0", w);
|
||||
}
|
||||
|
||||
if (true) {
|
||||
SrsHttpNotFoundHandler h;
|
||||
|
||||
MockResponseWriter w;
|
||||
HELPER_ASSERT_SUCCESS(h.serve_http(&w, NULL));
|
||||
__MOCK_HTTP_EXPECT_STREQ(404, "Not Found", w);
|
||||
}
|
||||
}
|
||||
|
||||
class MockMSegmentsReader : public ISrsReader
|
||||
{
|
||||
public:
|
||||
|
|
Loading…
Reference in a new issue