mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Merge branch '3.0release' into develop
This commit is contained in:
commit
5e57afc11e
31 changed files with 1981 additions and 379 deletions
|
@ -147,6 +147,12 @@ For previous versions, please read:
|
|||
|
||||
## V3 changes
|
||||
|
||||
* v3.0, 2019-12-17, Fix HTTP CORS bug when sending response for OPTIONS. 3.0.72
|
||||
* v3.0, 2019-12-17, Enhance HTTP response write for final_request.
|
||||
* v3.0, 2019-12-17, Refactor HTTP stream to disconnect client when unpublish.
|
||||
* v3.0, 2019-12-17, Fix HTTP-FLV and VOD-FLV conflicting bug.
|
||||
* v3.0, 2019-12-17, Refactor HttpResponseWriter.write, default to single text mode.
|
||||
* 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.
|
||||
|
|
2
trunk/configure
vendored
2
trunk/configure
vendored
|
@ -315,7 +315,7 @@ fi
|
|||
# utest, the unit-test cases of srs, base on gtest1.6
|
||||
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_protostack" "srs_utest_reload" "srs_utest_service" "srs_utest_app")
|
||||
"srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_reload" "srs_utest_service" "srs_utest_app")
|
||||
ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot})
|
||||
ModuleLibFiles=(${LibSTfile} ${LibSSLfile})
|
||||
MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP")
|
||||
|
|
|
@ -907,7 +907,7 @@ SrsJsonAny* SrsConfDirective::dumps_arg0_to_str()
|
|||
|
||||
SrsJsonAny* SrsConfDirective::dumps_arg0_to_integer()
|
||||
{
|
||||
return SrsJsonAny::integer(::atol(arg0().c_str()));
|
||||
return SrsJsonAny::integer(::atoll(arg0().c_str()));
|
||||
}
|
||||
|
||||
SrsJsonAny* SrsConfDirective::dumps_arg0_to_number()
|
||||
|
|
|
@ -181,10 +181,12 @@ srs_error_t SrsConnection::cycle()
|
|||
|
||||
// client close peer.
|
||||
// TODO: FIXME: Only reset the error when client closed it.
|
||||
if (srs_is_client_gracefully_close(srs_error_code(err))) {
|
||||
if (srs_is_client_gracefully_close(err)) {
|
||||
srs_warn("client disconnect peer. ret=%d", srs_error_code(err));
|
||||
} else if (srs_is_server_gracefully_close(err)) {
|
||||
srs_warn("server disconnect. ret=%d", srs_error_code(err));
|
||||
} else {
|
||||
srs_error("connect error %s", srs_error_desc(err).c_str());
|
||||
srs_error("serve error %s", srs_error_desc(err).c_str());
|
||||
}
|
||||
|
||||
srs_freep(err);
|
||||
|
|
|
@ -664,12 +664,7 @@ srs_error_t SrsGoApiRequests::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
|
|||
// request headers
|
||||
SrsJsonObject* headers = SrsJsonAny::object();
|
||||
data->set("headers", headers);
|
||||
|
||||
for (int i = 0; i < r->request_header_count(); i++) {
|
||||
std::string key = r->request_header_key_at(i);
|
||||
std::string value = r->request_header_value_at(i);
|
||||
headers->set(key, SrsJsonAny::str(value.c_str()));
|
||||
}
|
||||
r->header()->dumps(headers);
|
||||
|
||||
// server informations
|
||||
SrsJsonObject* server = SrsJsonAny::object();
|
||||
|
|
|
@ -81,11 +81,9 @@ srs_error_t SrsHttpConn::do_cycle()
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
srs_trace("HTTP client ip=%s", ip.c_str());
|
||||
|
||||
// initialize parser
|
||||
if ((err = parser->initialize(HTTP_REQUEST, false)) != srs_success) {
|
||||
return srs_error_wrap(err, "init parser");
|
||||
return srs_error_wrap(err, "init parser for %s", ip.c_str());
|
||||
}
|
||||
|
||||
// set the recv timeout, for some clients never disconnect the connection.
|
||||
|
@ -102,10 +100,12 @@ srs_error_t SrsHttpConn::do_cycle()
|
|||
}
|
||||
|
||||
// process http messages.
|
||||
while ((err = trd->pull()) == srs_success) {
|
||||
ISrsHttpMessage* req = NULL;
|
||||
|
||||
for (int req_id = 0; (err = trd->pull()) == srs_success; req_id++) {
|
||||
// Try to receive a message from http.
|
||||
srs_trace("HTTP client ip=%s, request=%d, to=%dms", ip.c_str(), req_id, srsu2ms(SRS_HTTP_RECV_TIMEOUT));
|
||||
|
||||
// get a http message
|
||||
ISrsHttpMessage* req = NULL;
|
||||
if ((err = parser->parse_message(skt, &req)) != srs_success) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -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,16 +107,17 @@ 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));
|
||||
w->header()->set_content_type("video/x-flv");
|
||||
w->write_header(SRS_CONSTS_HTTP_OK);
|
||||
|
||||
// write flv header and sequence header.
|
||||
if ((err = w->write(flv_header, sizeof(flv_header))) != srs_success) {
|
||||
|
@ -132,7 +133,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 +147,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.
|
||||
|
@ -169,20 +171,19 @@ srs_error_t SrsVodStream::serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMe
|
|||
// write http header for ts.
|
||||
w->header()->set_content_length(left);
|
||||
w->header()->set_content_type("video/mp4");
|
||||
|
||||
// status code 206 to make dash.as happy.
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -540,6 +540,9 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
|
|||
return srs_error_new(ERROR_HTTP_LIVE_STREAM_EXT, "invalid pattern=%s", entry->pattern.c_str());
|
||||
}
|
||||
SrsAutoFree(ISrsBufferEncoder, enc);
|
||||
|
||||
// Enter chunked mode, because we didn't set the content-length.
|
||||
w->write_header(SRS_CONSTS_HTTP_OK);
|
||||
|
||||
// create consumer of souce, ignore gop cache, use the audio gop cache.
|
||||
SrsConsumer* consumer = NULL;
|
||||
|
@ -594,7 +597,7 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
|
|||
if ((err = hc->set_socket_buffer(mw_sleep)) != srs_success) {
|
||||
return srs_error_wrap(err, "set mw_sleep %" PRId64, mw_sleep);
|
||||
}
|
||||
|
||||
|
||||
SrsHttpRecvThread* trd = new SrsHttpRecvThread(hc);
|
||||
SrsAutoFree(SrsHttpRecvThread, trd);
|
||||
|
||||
|
@ -607,6 +610,7 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
|
|||
enc->has_cache(), msgs.max);
|
||||
|
||||
// TODO: free and erase the disabled entry after all related connections is closed.
|
||||
// TODO: FXIME: Support timeout for player, quit infinite-loop.
|
||||
while (entry->enabled) {
|
||||
pprint->elapse();
|
||||
|
||||
|
@ -656,8 +660,10 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
|
|||
return srs_error_wrap(err, "send messages");
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
|
||||
// Here, the entry is disabled by encoder un-publishing or reloading,
|
||||
// so we must return a io.EOF error to disconnect the client, or the client will never quit.
|
||||
return srs_error_new(ERROR_HTTP_STREAM_EOF, "Stream EOF");
|
||||
}
|
||||
|
||||
srs_error_t SrsLiveStream::http_hooks_on_play(ISrsHttpMessage* r)
|
||||
|
@ -1046,6 +1052,18 @@ srs_error_t SrsHttpStreamServer::hijack(ISrsHttpMessage* request, ISrsHttpHandle
|
|||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// For HTTP-FLV stream, the template must have the same schema with upath.
|
||||
// The template is defined in config, the mout of http stream. The upath is specified by http request path.
|
||||
// If template is "[vhost]/[app]/[stream].flv", the upath should be:
|
||||
// matched for "/live/livestream.flv"
|
||||
// matched for "ossrs.net/live/livestream.flv"
|
||||
// not-matched for "/livestream.flv", which is actually "/__defaultApp__/livestream.flv", HTTP not support default app.
|
||||
// not-matched for "/live/show/livestream.flv"
|
||||
string upath = request->path();
|
||||
if (srs_string_count(upath, "/") != srs_string_count(entry->mount, "/")) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// convert to concreate class.
|
||||
SrsHttpMessage* hreq = dynamic_cast<SrsHttpMessage*>(request);
|
||||
|
|
|
@ -390,8 +390,8 @@ srs_error_t SrsRtmpConn::service_cycle()
|
|||
|
||||
// stream service must terminated with error, never success.
|
||||
// when terminated with success, it's user required to stop.
|
||||
if (srs_error_code(err) == ERROR_SUCCESS) {
|
||||
srs_freep(err);
|
||||
// TODO: FIXME: Support RTMP client timeout, https://github.com/ossrs/srs/issues/1134
|
||||
if (err == srs_success) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -387,10 +387,9 @@ srs_error_t SrsRtspConn::cycle()
|
|||
|
||||
if (err == srs_success) {
|
||||
srs_trace("client finished.");
|
||||
} else if (srs_is_client_gracefully_close(srs_error_code(err))) {
|
||||
} else if (srs_is_client_gracefully_close(err)) {
|
||||
srs_warn("client disconnect peer. code=%d", srs_error_code(err));
|
||||
srs_freep(err);
|
||||
err = srs_success;
|
||||
}
|
||||
|
||||
if (video_rtp) {
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
// The version config.
|
||||
#define VERSION_MAJOR 3
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 71
|
||||
#define VERSION_REVISION 72
|
||||
|
||||
// The macros generated by configure script.
|
||||
#include <srs_auto_headers.hpp>
|
||||
|
|
|
@ -213,7 +213,7 @@
|
|||
#define SRS_CONSTS_HTTP_QUERY_SEP '?'
|
||||
|
||||
// The default recv timeout.
|
||||
#define SRS_HTTP_RECV_TIMEOUT (60 * SRS_UTIME_SECONDS)
|
||||
#define SRS_HTTP_RECV_TIMEOUT (15 * SRS_UTIME_SECONDS)
|
||||
|
||||
// 6.1.1 Status Code and Reason Phrase
|
||||
#define SRS_CONSTS_HTTP_Continue 100
|
||||
|
|
|
@ -30,30 +30,26 @@
|
|||
#include <stdarg.h>
|
||||
using namespace std;
|
||||
|
||||
bool srs_is_system_control_error(int error_code)
|
||||
bool srs_is_system_control_error(srs_error_t err)
|
||||
{
|
||||
int error_code = srs_error_code(err);
|
||||
return error_code == ERROR_CONTROL_RTMP_CLOSE
|
||||
|| error_code == ERROR_CONTROL_REPUBLISH
|
||||
|| error_code == ERROR_CONTROL_REDIRECT;
|
||||
}
|
||||
|
||||
bool srs_is_system_control_error(srs_error_t err)
|
||||
bool srs_is_client_gracefully_close(srs_error_t err)
|
||||
{
|
||||
int error_code = srs_error_code(err);
|
||||
return srs_is_system_control_error(error_code);
|
||||
}
|
||||
|
||||
bool srs_is_client_gracefully_close(int error_code)
|
||||
{
|
||||
return error_code == ERROR_SOCKET_READ
|
||||
|| error_code == ERROR_SOCKET_READ_FULLY
|
||||
|| error_code == ERROR_SOCKET_WRITE;
|
||||
}
|
||||
|
||||
bool srs_is_client_gracefully_close(srs_error_t err)
|
||||
bool srs_is_server_gracefully_close(srs_error_t err)
|
||||
{
|
||||
int error_code = srs_error_code(err);
|
||||
return srs_is_client_gracefully_close(error_code);
|
||||
int code = srs_error_code(err);
|
||||
return code == ERROR_HTTP_STREAM_EOF;
|
||||
}
|
||||
|
||||
SrsCplxError::SrsCplxError()
|
||||
|
|
|
@ -320,6 +320,7 @@
|
|||
#define ERROR_HTTP_REQUEST_EOF 4029
|
||||
#define ERROR_HTTP_302_INVALID 4038
|
||||
#define ERROR_BASE64_DECODE 4039
|
||||
#define ERROR_HTTP_STREAM_EOF 4040
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// HTTP API error.
|
||||
|
@ -336,10 +337,11 @@
|
|||
|
||||
// Whether the error code is an system control error.
|
||||
// TODO: FIXME: Remove it from underlayer for confused with error and logger.
|
||||
extern bool srs_is_system_control_error(int error_code);
|
||||
extern bool srs_is_system_control_error(srs_error_t err);
|
||||
extern bool srs_is_client_gracefully_close(int error_code);
|
||||
// It's closed by client.
|
||||
extern bool srs_is_client_gracefully_close(srs_error_t err);
|
||||
// It's closed by server, such as streaming EOF.
|
||||
extern bool srs_is_server_gracefully_close(srs_error_t err);
|
||||
|
||||
// The complex error carries code, message, callstack and instant variables,
|
||||
// which is more strong and easy to locate problem by log,
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
#include <srs_core_autofree.hpp>
|
||||
|
@ -451,6 +452,16 @@ bool srs_string_contains(string str, string flag0, string flag1, string flag2)
|
|||
return str.find(flag0) != string::npos || str.find(flag1) != string::npos || str.find(flag2) != string::npos;
|
||||
}
|
||||
|
||||
int srs_string_count(string str, string flag)
|
||||
{
|
||||
int nn = 0;
|
||||
for (int i = 0; i < (int)flag.length(); i++) {
|
||||
char ch = flag.at(i);
|
||||
nn += std::count(str.begin(), str.end(), ch);
|
||||
}
|
||||
return nn;
|
||||
}
|
||||
|
||||
vector<string> srs_string_split(string str, string flag)
|
||||
{
|
||||
vector<string> arr;
|
||||
|
|
|
@ -98,6 +98,8 @@ extern bool srs_string_starts_with(std::string str, std::string flag0, std::stri
|
|||
extern bool srs_string_contains(std::string str, std::string flag);
|
||||
extern bool srs_string_contains(std::string str, std::string flag0, std::string flag1);
|
||||
extern bool srs_string_contains(std::string str, std::string flag0, std::string flag1, std::string flag2);
|
||||
// Count each char of flag in string
|
||||
extern int srs_string_count(std::string str, std::string flag);
|
||||
// Find the min match in str for flags.
|
||||
extern std::string srs_string_min_match(std::string str, std::vector<std::string> flags);
|
||||
// Split the string by flag to array.
|
||||
|
|
|
@ -35,9 +35,13 @@ using namespace std;
|
|||
#include <srs_kernel_utility.hpp>
|
||||
#include <srs_kernel_file.hpp>
|
||||
#include <srs_protocol_json.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
|
||||
#define SRS_HTTP_DEFAULT_PAGE "index.html"
|
||||
|
||||
// @see ISrsHttpMessage._http_ts_send_buffer
|
||||
#define SRS_HTTP_TS_SEND_BUFFER_SIZE 4096
|
||||
|
||||
// get the status text of code.
|
||||
string srs_generate_http_status_text(int status)
|
||||
{
|
||||
|
@ -99,9 +103,9 @@ string srs_generate_http_status_text(int status)
|
|||
// permits a body. See RFC2616, section 4.4.
|
||||
bool srs_go_http_body_allowd(int status)
|
||||
{
|
||||
if (status >= 100 && status <= 199) {
|
||||
if (status >= SRS_CONSTS_HTTP_Continue && status < SRS_CONSTS_HTTP_OK) {
|
||||
return false;
|
||||
} else if (status == 204 || status == 304) {
|
||||
} else if (status == SRS_CONSTS_HTTP_NoContent || status == SRS_CONSTS_HTTP_NotModified) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -116,9 +120,7 @@ bool srs_go_http_body_allowd(int status)
|
|||
// returns "application/octet-stream".
|
||||
string srs_go_http_detect(char* data, int size)
|
||||
{
|
||||
// detect only when data specified.
|
||||
if (data) {
|
||||
}
|
||||
// TODO: Implement the request content-type detecting.
|
||||
return "application/octet-stream"; // fallback
|
||||
}
|
||||
|
||||
|
@ -158,14 +160,37 @@ void SrsHttpHeader::set(string key, string value)
|
|||
string SrsHttpHeader::get(string key)
|
||||
{
|
||||
std::string v;
|
||||
|
||||
if (headers.find(key) != headers.end()) {
|
||||
v = headers[key];
|
||||
|
||||
map<string, string>::iterator it = headers.find(key);
|
||||
if (it != headers.end()) {
|
||||
v = it->second;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void SrsHttpHeader::del(string key)
|
||||
{
|
||||
map<string, string>::iterator it = headers.find(key);
|
||||
if (it != headers.end()) {
|
||||
headers.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
int SrsHttpHeader::count()
|
||||
{
|
||||
return (int)headers.size();
|
||||
}
|
||||
|
||||
void SrsHttpHeader::dumps(SrsJsonObject* o)
|
||||
{
|
||||
map<string, string>::iterator it;
|
||||
for (it = headers.begin(); it != headers.end(); ++it) {
|
||||
string v = it->second;
|
||||
o->set(it->first, SrsJsonAny::str(v.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
int64_t SrsHttpHeader::content_length()
|
||||
{
|
||||
std::string cl = get("Content-Length");
|
||||
|
@ -194,7 +219,7 @@ void SrsHttpHeader::set_content_type(string ct)
|
|||
|
||||
void SrsHttpHeader::write(stringstream& ss)
|
||||
{
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
map<string, string>::iterator it;
|
||||
for (it = headers.begin(); it != headers.end(); ++it) {
|
||||
ss << it->first << ": " << it->second << SRS_HTTP_CRLF;
|
||||
}
|
||||
|
@ -247,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());
|
||||
|
@ -279,37 +304,67 @@ 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 pattern, string upath)
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
fullpath += upath;
|
||||
|
||||
// Remove the virtual directory.
|
||||
// For example:
|
||||
// pattern=/api, the virtual directory is api, upath=/api/index.html, fullpath={dir}/index.html
|
||||
// pattern=/api, the virtual directory is api, upath=/api/views/index.html, fullpath={dir}/views/index.html
|
||||
// The vhost prefix is ignored, for example:
|
||||
// pattern=ossrs.net/api, the vhost is ossrs.net, the pattern equals to /api under this vhost,
|
||||
// so the virtual directory is also api
|
||||
size_t pos = pattern.find("/");
|
||||
string filename = upath;
|
||||
if (upath.length() > pattern.length() && pos != string::npos) {
|
||||
filename = upath.substr(pattern.length() - pos);
|
||||
}
|
||||
|
||||
string fullpath = srs_string_trim_end(dir, "/");
|
||||
if (!srs_string_starts_with(filename, "/")) {
|
||||
fullpath += "/";
|
||||
}
|
||||
fullpath += filename;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void SrsHttpFileServer::set_fs_factory(ISrsFileReaderFactory* f)
|
||||
{
|
||||
srs_freep(fs_factory);
|
||||
fs_factory = f;
|
||||
}
|
||||
|
||||
void SrsHttpFileServer::set_path_check(_pfn_srs_path_exists pfn)
|
||||
{
|
||||
_srs_path_exists = pfn;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpFileServer::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
srs_assert(entry);
|
||||
|
||||
string upath = r->path();
|
||||
string fullpath = srs_http_fs_fullpath(dir, entry->pattern, upath);
|
||||
|
||||
// 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);
|
||||
|
@ -332,15 +387,16 @@ 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();
|
||||
|
||||
// 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);
|
||||
|
@ -390,10 +446,13 @@ srs_error_t SrsHttpFileServer::serve_file(ISrsHttpResponseWriter* w, ISrsHttpMes
|
|||
w->header()->set_content_type(_mime[ext]);
|
||||
}
|
||||
}
|
||||
|
||||
// Enter chunked mode, because we didn't set the content-length.
|
||||
w->write_header(SRS_CONSTS_HTTP_OK);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -422,10 +481,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");
|
||||
}
|
||||
|
@ -458,11 +515,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);
|
||||
}
|
||||
|
||||
|
@ -471,25 +532,22 @@ srs_error_t SrsHttpFileServer::copy(ISrsHttpResponseWriter* w, SrsFileReader* fs
|
|||
srs_error_t err = srs_success;
|
||||
|
||||
int left = size;
|
||||
char* buf = r->http_ts_send_buffer();
|
||||
char* buf = new char[SRS_HTTP_TS_SEND_BUFFER_SIZE];
|
||||
SrsAutoFreeA(char, buf);
|
||||
|
||||
while (left > 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -609,16 +667,13 @@ srs_error_t SrsHttpServeMux::handle(std::string pattern, ISrsHttpHandler* handle
|
|||
std::string rpattern = pattern.substr(0, pattern.length() - 1);
|
||||
SrsHttpMuxEntry* entry = NULL;
|
||||
|
||||
// free the exists not explicit entry
|
||||
// free the exists implicit entry
|
||||
if (entries.find(rpattern) != entries.end()) {
|
||||
SrsHttpMuxEntry* exists = entries[rpattern];
|
||||
if (!exists->explicit_match) {
|
||||
entry = exists;
|
||||
}
|
||||
entry = entries[rpattern];
|
||||
}
|
||||
|
||||
// create implicit redirect.
|
||||
if (!entry || entry->explicit_match) {
|
||||
if (!entry || !entry->explicit_match) {
|
||||
srs_freep(entry);
|
||||
|
||||
entry = new SrsHttpMuxEntry();
|
||||
|
@ -666,7 +721,7 @@ srs_error_t SrsHttpServeMux::find_handler(ISrsHttpMessage* r, ISrsHttpHandler**
|
|||
|
||||
// always hijack.
|
||||
if (!hijackers.empty()) {
|
||||
// notice all hijacker the match failed.
|
||||
// notify all hijackers unless matching failed.
|
||||
std::vector<ISrsHttpMatchHijacker*>::iterator it;
|
||||
for (it = hijackers.begin(); it != hijackers.end(); ++it) {
|
||||
ISrsHttpMatchHijacker* hijacker = *it;
|
||||
|
@ -765,17 +820,10 @@ srs_error_t SrsHttpCorsMux::initialize(ISrsHttpServeMux* worker, bool cros_enabl
|
|||
|
||||
srs_error_t SrsHttpCorsMux::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// If CORS enabled, and there is a "Origin" header, it's CORS.
|
||||
if (enabled) {
|
||||
for (int i = 0; i < r->request_header_count(); i++) {
|
||||
string k = r->request_header_key_at(i);
|
||||
if (k == "Origin" || k == "origin") {
|
||||
required = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SrsHttpHeader* h = r->header();
|
||||
required = !h->get("Origin").empty();
|
||||
}
|
||||
|
||||
// When CORS required, set the CORS headers.
|
||||
|
@ -795,9 +843,7 @@ srs_error_t SrsHttpCorsMux::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessag
|
|||
} else {
|
||||
w->write_header(SRS_CONSTS_HTTP_MethodNotAllowed);
|
||||
}
|
||||
if ((err = w->final_request()) != srs_success) {
|
||||
return srs_error_wrap(err, "final request");
|
||||
}
|
||||
return w->final_request();
|
||||
}
|
||||
|
||||
srs_assert(next);
|
||||
|
@ -806,17 +852,10 @@ srs_error_t SrsHttpCorsMux::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessag
|
|||
|
||||
ISrsHttpMessage::ISrsHttpMessage()
|
||||
{
|
||||
_http_ts_send_buffer = new char[SRS_HTTP_TS_SEND_BUFFER_SIZE];
|
||||
}
|
||||
|
||||
ISrsHttpMessage::~ISrsHttpMessage()
|
||||
{
|
||||
srs_freepa(_http_ts_send_buffer);
|
||||
}
|
||||
|
||||
char* ISrsHttpMessage::http_ts_send_buffer()
|
||||
{
|
||||
return _http_ts_send_buffer;
|
||||
}
|
||||
|
||||
SrsHttpUri::SrsHttpUri()
|
||||
|
@ -912,6 +951,8 @@ string SrsHttpUri::get_uri_field(string uri, void* php_u, int ifield)
|
|||
// For #if !defined(SRS_EXPORT_LIBRTMP)
|
||||
#endif
|
||||
|
||||
// LCOV_EXCL_START
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -3436,3 +3477,13 @@ http_parser_set_max_header_size(uint32_t size) {
|
|||
max_header_size = size;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
|
|
@ -45,6 +45,8 @@ class SrsHttpHeader;
|
|||
class ISrsHttpMessage;
|
||||
class SrsHttpMuxEntry;
|
||||
class ISrsHttpResponseWriter;
|
||||
class SrsJsonObject;
|
||||
class ISrsFileReaderFactory;
|
||||
|
||||
// From http specification
|
||||
// CR = <US-ASCII CR, carriage return (13)>
|
||||
|
@ -62,9 +64,6 @@ class ISrsHttpResponseWriter;
|
|||
#define SRS_HTTP_CRLF "\r\n" // 0x0D0A
|
||||
#define SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
|
||||
|
||||
// @see ISrsHttpMessage._http_ts_send_buffer
|
||||
#define SRS_HTTP_TS_SEND_BUFFER_SIZE 4096
|
||||
|
||||
// For ead all of http body, read each time.
|
||||
#define SRS_HTTP_READ_CACHE_BYTES 4096
|
||||
|
||||
|
@ -108,6 +107,11 @@ enum SrsHttpParseState {
|
|||
class SrsHttpHeader
|
||||
{
|
||||
private:
|
||||
// The order in which header fields with differing field names are
|
||||
// received is not significant. However, it is "good practice" to send
|
||||
// general-header fields first, followed by request-header or response-
|
||||
// header fields, and ending with the entity-header fields.
|
||||
// @doc https://tools.ietf.org/html/rfc2616#section-4.2
|
||||
std::map<std::string, std::string> headers;
|
||||
public:
|
||||
SrsHttpHeader();
|
||||
|
@ -121,6 +125,14 @@ public:
|
|||
// To access multiple values of a key, access the map directly
|
||||
// with CanonicalHeaderKey.
|
||||
virtual std::string get(std::string key);
|
||||
// Delete the http header indicated by key.
|
||||
// Return the removed header field.
|
||||
virtual void del(std::string);
|
||||
// Get the count of headers.
|
||||
virtual int count();
|
||||
public:
|
||||
// Dumps to a JSON object.
|
||||
virtual void dumps(SrsJsonObject* o);
|
||||
public:
|
||||
// Get the content length. -1 if not set.
|
||||
virtual int64_t content_length();
|
||||
|
@ -138,7 +150,11 @@ public:
|
|||
|
||||
// A ResponseWriter interface is used by an HTTP handler to
|
||||
// construct an HTTP response.
|
||||
// Usage 1, response with specified length content:
|
||||
// Usage 0, response with a message once:
|
||||
// ISrsHttpResponseWriter* w; // create or get response.
|
||||
// std::string msg = "Hello, HTTP!";
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// Usage 1, response with specified length content, same to #0:
|
||||
// ISrsHttpResponseWriter* w; // create or get response.
|
||||
// std::string msg = "Hello, HTTP!";
|
||||
// w->header()->set_content_type("text/plain; charset=utf-8");
|
||||
|
@ -265,6 +281,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 pattern, std::string upath);
|
||||
|
||||
// FileServer returns a handler that serves HTTP requests
|
||||
// with the contents of the file system rooted at root.
|
||||
//
|
||||
|
@ -277,9 +299,17 @@ class SrsHttpFileServer : public ISrsHttpHandler
|
|||
{
|
||||
protected:
|
||||
std::string dir;
|
||||
protected:
|
||||
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 void set_fs_factory(ISrsFileReaderFactory* v);
|
||||
// For utest to mock the path check function.
|
||||
virtual void set_path_check(_pfn_srs_path_exists pfn);
|
||||
public:
|
||||
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
private:
|
||||
|
@ -420,9 +450,6 @@ public:
|
|||
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
// For http header.
|
||||
typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
||||
|
||||
// A Request represents an HTTP request received by a server
|
||||
// or to be sent by a client.
|
||||
//
|
||||
|
@ -444,16 +471,9 @@ typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
|||
// @rmark for mode 2, the infinite chunked, all left data is body.
|
||||
class ISrsHttpMessage
|
||||
{
|
||||
private:
|
||||
// Use a buffer to read and send ts file.
|
||||
// TODO: FIXME: remove it.
|
||||
char* _http_ts_send_buffer;
|
||||
public:
|
||||
ISrsHttpMessage();
|
||||
virtual ~ISrsHttpMessage();
|
||||
public:
|
||||
// The http request level cache.
|
||||
virtual char* http_ts_send_buffer();
|
||||
public:
|
||||
virtual uint8_t method() = 0;
|
||||
virtual uint16_t status_code() = 0;
|
||||
|
@ -500,9 +520,7 @@ public:
|
|||
// then query_get("start") is "100", and query_get("end") is "200"
|
||||
virtual std::string query_get(std::string key) = 0;
|
||||
// Get the headers.
|
||||
virtual int request_header_count() = 0;
|
||||
virtual std::string request_header_key_at(int index) = 0;
|
||||
virtual std::string request_header_value_at(int index) = 0;
|
||||
virtual SrsHttpHeader* header() = 0;
|
||||
public:
|
||||
// Whether the current request is JSONP,
|
||||
// which has a "callback=xxx" in QueryString.
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <srs_core.hpp>
|
||||
|
||||
// LCOV_EXCL_START
|
||||
/* vim: set et ts=3 sw=3 sts=3 ft=c:
|
||||
*
|
||||
* Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
|
||||
|
@ -1314,6 +1315,7 @@ void json_value_free (json_value * value)
|
|||
}
|
||||
|
||||
#endif
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
|
|
|
@ -1884,20 +1884,9 @@ srs_error_t SrsRtmpClient::handshake()
|
|||
SrsAutoFree(SrsComplexHandshake, complex_hs);
|
||||
|
||||
if ((err = complex_hs->handshake_with_server(hs_bytes, io)) != srs_success) {
|
||||
if (srs_error_code(err) == ERROR_RTMP_TRY_SIMPLE_HS) {
|
||||
srs_freep(err);
|
||||
|
||||
// always alloc object at heap.
|
||||
// @see https://github.com/ossrs/srs/issues/509
|
||||
SrsSimpleHandshake* simple_hs = new SrsSimpleHandshake();
|
||||
SrsAutoFree(SrsSimpleHandshake, simple_hs);
|
||||
|
||||
if ((err = simple_hs->handshake_with_server(hs_bytes, io)) != srs_success) {
|
||||
return srs_error_wrap(err, "simple handshake");
|
||||
}
|
||||
} else {
|
||||
return srs_error_wrap(err, "complex handshake");
|
||||
}
|
||||
// As client, we never verify s0s1s2, because some server doesn't follow the RTMP spec.
|
||||
// So we never have chance to use simple handshake.
|
||||
return srs_error_wrap(err, "complex handshake");
|
||||
}
|
||||
|
||||
hs_bytes->dispose();
|
||||
|
|
|
@ -887,7 +887,7 @@ srs_error_t SrsRtspStack::do_recv_message(SrsRtspRequest* req)
|
|||
if ((err = recv_token_eof(seq)) != srs_success) {
|
||||
return srs_error_wrap(err, "seq");
|
||||
}
|
||||
req->seq = ::atol(seq.c_str());
|
||||
req->seq = ::atoll(seq.c_str());
|
||||
} else if (token == SRS_RTSP_TOKEN_CONTENT_TYPE) {
|
||||
std::string ct;
|
||||
if ((err = recv_token_eof(ct)) != srs_success) {
|
||||
|
@ -899,7 +899,7 @@ srs_error_t SrsRtspStack::do_recv_message(SrsRtspRequest* req)
|
|||
if ((err = recv_token_eof(cl)) != srs_success) {
|
||||
return srs_error_wrap(err, "cl");
|
||||
}
|
||||
req->content_length = ::atol(cl.c_str());
|
||||
req->content_length = ::atoll(cl.c_str());
|
||||
} else if (token == SRS_RTSP_TOKEN_TRANSPORT) {
|
||||
std::string transport;
|
||||
if ((err = recv_token_eof(transport)) != srs_success) {
|
||||
|
|
|
@ -39,11 +39,13 @@ using namespace std;
|
|||
SrsHttpParser::SrsHttpParser()
|
||||
{
|
||||
buffer = new SrsFastStream();
|
||||
header = NULL;
|
||||
}
|
||||
|
||||
SrsHttpParser::~SrsHttpParser()
|
||||
{
|
||||
srs_freep(buffer);
|
||||
srs_freep(header);
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpParser::initialize(enum http_parser_type type, bool allow_jsonp)
|
||||
|
@ -70,19 +72,20 @@ srs_error_t SrsHttpParser::initialize(enum http_parser_type type, bool allow_jso
|
|||
|
||||
srs_error_t SrsHttpParser::parse_message(ISrsReader* reader, ISrsHttpMessage** ppmsg)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
*ppmsg = NULL;
|
||||
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// reset request data.
|
||||
field_name = "";
|
||||
field_value = "";
|
||||
expect_field_name = true;
|
||||
// Reset request data.
|
||||
state = SrsHttpParseStateInit;
|
||||
header = http_parser();
|
||||
url = "";
|
||||
headers.clear();
|
||||
hp_header = http_parser();
|
||||
// The body that we have read from cache.
|
||||
pbody = NULL;
|
||||
// We must reset the field name and value, because we may get a partial value in on_header_value.
|
||||
field_name = field_value = "";
|
||||
// The header of the request.
|
||||
srs_freep(header);
|
||||
header = new SrsHttpHeader();
|
||||
|
||||
// do parse
|
||||
if ((err = parse_message_imp(reader)) != srs_success) {
|
||||
|
@ -90,10 +93,12 @@ srs_error_t SrsHttpParser::parse_message(ISrsReader* reader, ISrsHttpMessage** p
|
|||
}
|
||||
|
||||
// create msg
|
||||
SrsHttpMessage* msg = new SrsHttpMessage(reader);
|
||||
|
||||
// initalize http msg, parse url.
|
||||
if ((err = msg->update(url, jsonp, &header, buffer, headers)) != srs_success) {
|
||||
SrsHttpMessage* msg = new SrsHttpMessage(reader, buffer);
|
||||
|
||||
// Initialize the basic information.
|
||||
msg->set_basic(hp_header.method, hp_header.status_code, hp_header.content_length);
|
||||
msg->set_header(header, http_should_keep_alive(&hp_header));
|
||||
if ((err = msg->set_url(url, jsonp)) != srs_success) {
|
||||
srs_freep(msg);
|
||||
return srs_error_wrap(err, "update message");
|
||||
}
|
||||
|
@ -137,10 +142,10 @@ srs_error_t SrsHttpParser::parse_message_imp(ISrsReader* reader)
|
|||
return srs_error_wrap(err, "grow buffer");
|
||||
}
|
||||
}
|
||||
|
||||
// parse last header.
|
||||
if (!field_name.empty() && !field_value.empty()) {
|
||||
headers.push_back(std::make_pair(field_name, field_value));
|
||||
|
||||
SrsHttpParser* obj = this;
|
||||
if (!obj->field_value.empty()) {
|
||||
obj->header->set(obj->field_name, obj->field_value);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -163,7 +168,7 @@ int SrsHttpParser::on_headers_complete(http_parser* parser)
|
|||
SrsHttpParser* obj = (SrsHttpParser*)parser->data;
|
||||
srs_assert(obj);
|
||||
|
||||
obj->header = *parser;
|
||||
obj->hp_header = *parser;
|
||||
// save the parser when header parse completed.
|
||||
obj->state = SrsHttpParseStateHeaderComplete;
|
||||
|
||||
|
@ -192,7 +197,7 @@ int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length)
|
|||
srs_assert(obj);
|
||||
|
||||
if (length > 0) {
|
||||
obj->url.append(at, (int)length);
|
||||
obj->url = string(at, (int)length);
|
||||
}
|
||||
|
||||
srs_info("Method: %d, Url: %.*s", parser->method, (int)length, at);
|
||||
|
@ -204,16 +209,11 @@ int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t l
|
|||
{
|
||||
SrsHttpParser* obj = (SrsHttpParser*)parser->data;
|
||||
srs_assert(obj);
|
||||
|
||||
// field value=>name, reap the field.
|
||||
if (!obj->expect_field_name) {
|
||||
obj->headers.push_back(std::make_pair(obj->field_name, obj->field_value));
|
||||
|
||||
// reset the field name when parsed.
|
||||
obj->field_name = "";
|
||||
obj->field_value = "";
|
||||
|
||||
if (!obj->field_value.empty()) {
|
||||
obj->header->set(obj->field_name, obj->field_value);
|
||||
obj->field_name = obj->field_value = "";
|
||||
}
|
||||
obj->expect_field_name = true;
|
||||
|
||||
if (length > 0) {
|
||||
obj->field_name.append(at, (int)length);
|
||||
|
@ -231,7 +231,6 @@ int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t l
|
|||
if (length > 0) {
|
||||
obj->field_value.append(at, (int)length);
|
||||
}
|
||||
obj->expect_field_name = false;
|
||||
|
||||
srs_info("Header value(%d bytes): %.*s", (int)length, (int)length, at);
|
||||
return 0;
|
||||
|
@ -253,58 +252,72 @@ int SrsHttpParser::on_body(http_parser* parser, const char* at, size_t length)
|
|||
return 0;
|
||||
}
|
||||
|
||||
SrsHttpMessage::SrsHttpMessage(ISrsReader* reader) : ISrsHttpMessage()
|
||||
SrsHttpMessage::SrsHttpMessage(ISrsReader* reader, SrsFastStream* buffer) : ISrsHttpMessage()
|
||||
{
|
||||
owner_conn = NULL;
|
||||
chunked = false;
|
||||
infinite_chunked = false;
|
||||
keep_alive = true;
|
||||
_uri = new SrsHttpUri();
|
||||
_body = new SrsHttpResponseReader(this, reader);
|
||||
_http_ts_send_buffer = new char[SRS_HTTP_TS_SEND_BUFFER_SIZE];
|
||||
_body = new SrsHttpResponseReader(this, reader, buffer);
|
||||
|
||||
jsonp = false;
|
||||
|
||||
_method = 0;
|
||||
_status = 0;
|
||||
_content_length = -1;
|
||||
_keep_alive = true;
|
||||
}
|
||||
|
||||
SrsHttpMessage::~SrsHttpMessage()
|
||||
{
|
||||
srs_freep(_body);
|
||||
srs_freep(_uri);
|
||||
srs_freepa(_http_ts_send_buffer);
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpMessage::update(string url, bool allow_jsonp, http_parser* header, SrsFastStream* body, vector<SrsHttpHeaderField>& headers)
|
||||
void SrsHttpMessage::set_basic(uint8_t method, uint16_t status, int64_t content_length)
|
||||
{
|
||||
_method = method;
|
||||
_status = status;
|
||||
if (_content_length == -1) {
|
||||
_content_length = content_length;
|
||||
}
|
||||
}
|
||||
|
||||
void SrsHttpMessage::set_header(SrsHttpHeader* header, bool keep_alive)
|
||||
{
|
||||
_header = *header;
|
||||
_keep_alive = keep_alive;
|
||||
|
||||
// whether chunked.
|
||||
chunked = (header->get("Transfer-Encoding") == "chunked");
|
||||
|
||||
// Update the content-length in header.
|
||||
string clv = header->get("Content-Length");
|
||||
if (!clv.empty()) {
|
||||
_content_length = ::atoll(clv.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpMessage::set_url(string url, bool allow_jsonp)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
_url = url;
|
||||
_header = *header;
|
||||
_headers = headers;
|
||||
|
||||
// whether chunked.
|
||||
std::string transfer_encoding = get_request_header("Transfer-Encoding");
|
||||
chunked = (transfer_encoding == "chunked");
|
||||
|
||||
// whether keep alive.
|
||||
keep_alive = http_should_keep_alive(header);
|
||||
|
||||
// set the buffer.
|
||||
if ((err = _body->initialize(body)) != srs_success) {
|
||||
return srs_error_wrap(err, "init body");
|
||||
}
|
||||
|
||||
// parse uri from url.
|
||||
std::string host = get_request_header("Host");
|
||||
|
||||
// use server public ip when no host specified.
|
||||
|
||||
// use server public ip when host not specified.
|
||||
// to make telnet happy.
|
||||
std::string host = _header.get("Host");
|
||||
if (host.empty()) {
|
||||
host= srs_get_public_internet_address();
|
||||
}
|
||||
|
||||
// parse uri to schema/server:port/path?query
|
||||
std::string uri = "http://" + host + _url;
|
||||
|
||||
// parse uri from schema/server:port/path?query
|
||||
std::string uri = _url;
|
||||
if (!host.empty()) {
|
||||
uri = "http://" + host + _url;
|
||||
}
|
||||
if ((err = _uri->initialize(uri)) != srs_success) {
|
||||
return srs_error_wrap(err, "init uri");
|
||||
return srs_error_wrap(err, "init uri %s", uri.c_str());
|
||||
}
|
||||
|
||||
// parse ext.
|
||||
|
@ -349,13 +362,13 @@ uint8_t SrsHttpMessage::method()
|
|||
return SRS_CONSTS_HTTP_DELETE;
|
||||
}
|
||||
}
|
||||
|
||||
return (uint8_t)_header.method;
|
||||
|
||||
return _method;
|
||||
}
|
||||
|
||||
uint16_t SrsHttpMessage::status_code()
|
||||
{
|
||||
return (uint16_t)_header.status_code;
|
||||
return _status;
|
||||
}
|
||||
|
||||
string SrsHttpMessage::method_str()
|
||||
|
@ -405,7 +418,7 @@ bool SrsHttpMessage::is_http_delete()
|
|||
|
||||
bool SrsHttpMessage::is_http_options()
|
||||
{
|
||||
return _header.method == SRS_CONSTS_HTTP_OPTIONS;
|
||||
return _method == SRS_CONSTS_HTTP_OPTIONS;
|
||||
}
|
||||
|
||||
bool SrsHttpMessage::is_chunked()
|
||||
|
@ -415,7 +428,7 @@ bool SrsHttpMessage::is_chunked()
|
|||
|
||||
bool SrsHttpMessage::is_keep_alive()
|
||||
{
|
||||
return keep_alive;
|
||||
return _keep_alive;
|
||||
}
|
||||
|
||||
bool SrsHttpMessage::is_infinite_chunked()
|
||||
|
@ -447,6 +460,11 @@ string SrsHttpMessage::host()
|
|||
return _uri->get_host();
|
||||
}
|
||||
|
||||
int SrsHttpMessage::port()
|
||||
{
|
||||
return _uri->get_port();
|
||||
}
|
||||
|
||||
string SrsHttpMessage::path()
|
||||
{
|
||||
return _uri->get_path();
|
||||
|
@ -524,7 +542,7 @@ ISrsHttpResponseReader* SrsHttpMessage::body_reader()
|
|||
|
||||
int64_t SrsHttpMessage::content_length()
|
||||
{
|
||||
return _header.content_length;
|
||||
return _content_length;
|
||||
}
|
||||
|
||||
string SrsHttpMessage::query_get(string key)
|
||||
|
@ -538,39 +556,9 @@ string SrsHttpMessage::query_get(string key)
|
|||
return v;
|
||||
}
|
||||
|
||||
int SrsHttpMessage::request_header_count()
|
||||
SrsHttpHeader* SrsHttpMessage::header()
|
||||
{
|
||||
return (int)_headers.size();
|
||||
}
|
||||
|
||||
string SrsHttpMessage::request_header_key_at(int index)
|
||||
{
|
||||
srs_assert(index < request_header_count());
|
||||
SrsHttpHeaderField item = _headers[index];
|
||||
return item.first;
|
||||
}
|
||||
|
||||
string SrsHttpMessage::request_header_value_at(int index)
|
||||
{
|
||||
srs_assert(index < request_header_count());
|
||||
SrsHttpHeaderField item = _headers[index];
|
||||
return item.second;
|
||||
}
|
||||
|
||||
string SrsHttpMessage::get_request_header(string name)
|
||||
{
|
||||
std::vector<SrsHttpHeaderField>::iterator it;
|
||||
|
||||
for (it = _headers.begin(); it != _headers.end(); ++it) {
|
||||
SrsHttpHeaderField& elem = *it;
|
||||
std::string key = elem.first;
|
||||
std::string value = elem.second;
|
||||
if (key == name) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
return &_header;
|
||||
}
|
||||
|
||||
SrsRequest* SrsHttpMessage::to_request(string vhost)
|
||||
|
@ -590,7 +578,7 @@ SrsRequest* SrsHttpMessage::to_request(string vhost)
|
|||
|
||||
// generate others.
|
||||
req->tcUrl = "rtmp://" + vhost + "/" + req->app;
|
||||
req->pageUrl = get_request_header("Referer");
|
||||
req->pageUrl = _header.get("Referer");
|
||||
req->objectEncoding = 0;
|
||||
|
||||
std::string query = _uri->get_query();
|
||||
|
@ -614,7 +602,15 @@ bool SrsHttpMessage::is_jsonp()
|
|||
return jsonp;
|
||||
}
|
||||
|
||||
SrsHttpResponseWriter::SrsHttpResponseWriter(SrsStSocket* io)
|
||||
ISrsHttpHeaderFilter::ISrsHttpHeaderFilter()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsHttpHeaderFilter::~ISrsHttpHeaderFilter()
|
||||
{
|
||||
}
|
||||
|
||||
SrsHttpResponseWriter::SrsHttpResponseWriter(ISrsProtocolReadWriter* io)
|
||||
{
|
||||
skt = io;
|
||||
hdr = new SrsHttpHeader();
|
||||
|
@ -625,6 +621,7 @@ SrsHttpResponseWriter::SrsHttpResponseWriter(SrsStSocket* io)
|
|||
header_sent = false;
|
||||
nb_iovss_cache = 0;
|
||||
iovss_cache = NULL;
|
||||
hf = NULL;
|
||||
}
|
||||
|
||||
SrsHttpResponseWriter::~SrsHttpResponseWriter()
|
||||
|
@ -635,10 +632,17 @@ SrsHttpResponseWriter::~SrsHttpResponseWriter()
|
|||
|
||||
srs_error_t SrsHttpResponseWriter::final_request()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// write the header data in memory.
|
||||
if (!header_wrote) {
|
||||
write_header(SRS_CONSTS_HTTP_OK);
|
||||
}
|
||||
|
||||
// whatever header is wrote, we should try to send header.
|
||||
if ((err = send_header(NULL, 0)) != srs_success) {
|
||||
return srs_error_wrap(err, "send header");
|
||||
}
|
||||
|
||||
// complete the chunked encoding.
|
||||
if (content_length == -1) {
|
||||
|
@ -663,6 +667,10 @@ srs_error_t SrsHttpResponseWriter::write(char* data, int size)
|
|||
|
||||
// write the header data in memory.
|
||||
if (!header_wrote) {
|
||||
if (hdr->content_type().empty()) {
|
||||
hdr->set_content_type("text/plain; charset=utf-8");
|
||||
}
|
||||
hdr->set_content_length(size);
|
||||
write_header(SRS_CONSTS_HTTP_OK);
|
||||
}
|
||||
|
||||
|
@ -678,7 +686,7 @@ srs_error_t SrsHttpResponseWriter::write(char* data, int size)
|
|||
}
|
||||
|
||||
// ignore NULL content.
|
||||
if (!data) {
|
||||
if (!data || size <= 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -823,7 +831,7 @@ srs_error_t SrsHttpResponseWriter::send_header(char* data, int size)
|
|||
|
||||
// detect content type
|
||||
if (srs_go_http_body_allowd(status)) {
|
||||
if (hdr->content_type().empty()) {
|
||||
if (data && hdr->content_type().empty()) {
|
||||
hdr->set_content_type(srs_go_http_detect(data, size));
|
||||
}
|
||||
}
|
||||
|
@ -840,8 +848,13 @@ srs_error_t SrsHttpResponseWriter::send_header(char* data, int size)
|
|||
|
||||
// keep alive to make vlc happy.
|
||||
hdr->set("Connection", "Keep-Alive");
|
||||
|
||||
// Filter the header before writing it.
|
||||
if (hf && ((err = hf->filter(hdr)) != srs_success)) {
|
||||
return srs_error_wrap(err, "filter header");
|
||||
}
|
||||
|
||||
// write headers
|
||||
// write header
|
||||
hdr->write(ss);
|
||||
|
||||
// header_eof
|
||||
|
@ -851,32 +864,20 @@ srs_error_t SrsHttpResponseWriter::send_header(char* data, int size)
|
|||
return skt->write((void*)buf.c_str(), buf.length(), NULL);
|
||||
}
|
||||
|
||||
SrsHttpResponseReader::SrsHttpResponseReader(SrsHttpMessage* msg, ISrsReader* reader)
|
||||
SrsHttpResponseReader::SrsHttpResponseReader(SrsHttpMessage* msg, ISrsReader* reader, SrsFastStream* body)
|
||||
{
|
||||
skt = reader;
|
||||
owner = msg;
|
||||
is_eof = false;
|
||||
nb_total_read = 0;
|
||||
nb_left_chunk = 0;
|
||||
buffer = NULL;
|
||||
buffer = body;
|
||||
}
|
||||
|
||||
SrsHttpResponseReader::~SrsHttpResponseReader()
|
||||
{
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpResponseReader::initialize(SrsFastStream* body)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
nb_chunk = 0;
|
||||
nb_left_chunk = 0;
|
||||
nb_total_read = 0;
|
||||
buffer = body;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
bool SrsHttpResponseReader::eof()
|
||||
{
|
||||
return is_eof;
|
||||
|
|
|
@ -35,7 +35,7 @@ class SrsFastStream;
|
|||
class SrsRequest;
|
||||
class ISrsReader;
|
||||
class SrsHttpResponseReader;
|
||||
class SrsStSocket;
|
||||
class ISrsProtocolReadWriter;
|
||||
|
||||
// A wrapper for http-parser,
|
||||
// provides HTTP message originted service.
|
||||
|
@ -49,14 +49,12 @@ private:
|
|||
// Whether allow jsonp parse.
|
||||
bool jsonp;
|
||||
private:
|
||||
// http parse data, reset before parse message.
|
||||
bool expect_field_name;
|
||||
std::string field_name;
|
||||
std::string field_value;
|
||||
SrsHttpParseState state;
|
||||
http_parser header;
|
||||
http_parser hp_header;
|
||||
std::string url;
|
||||
std::vector<SrsHttpHeaderField> headers;
|
||||
SrsHttpHeader* header;
|
||||
const char* pbody;
|
||||
public:
|
||||
SrsHttpParser();
|
||||
|
@ -85,9 +83,6 @@ private:
|
|||
static int on_body(http_parser* parser, const char* at, size_t length);
|
||||
};
|
||||
|
||||
// for http header.
|
||||
typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
||||
|
||||
// A Request represents an HTTP request received by a server
|
||||
// or to be sent by a client.
|
||||
//
|
||||
|
@ -96,43 +91,52 @@ typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
|||
// documentation for Request.Write and RoundTripper.
|
||||
class SrsHttpMessage : public ISrsHttpMessage
|
||||
{
|
||||
private:
|
||||
// The body object, reader object.
|
||||
// @remark, user can get body in string by get_body().
|
||||
SrsHttpResponseReader* _body;
|
||||
// Whether the body is infinite chunked.
|
||||
bool infinite_chunked;
|
||||
// Use a buffer to read and send ts file.
|
||||
// The transport connection, can be NULL.
|
||||
SrsConnection* owner_conn;
|
||||
private:
|
||||
uint8_t _method;
|
||||
uint16_t _status;
|
||||
int64_t _content_length;
|
||||
private:
|
||||
// The http headers
|
||||
SrsHttpHeader _header;
|
||||
// Whether the request indicates should keep alive for the http connection.
|
||||
bool _keep_alive;
|
||||
// Whether the body is chunked.
|
||||
bool chunked;
|
||||
private:
|
||||
// The parsed url.
|
||||
std::string _url;
|
||||
// The extension of file, for example, .flv
|
||||
std::string _ext;
|
||||
// parsed http header.
|
||||
http_parser _header;
|
||||
// The body object, reader object.
|
||||
// @remark, user can get body in string by get_body().
|
||||
SrsHttpResponseReader* _body;
|
||||
// Whether the body is chunked.
|
||||
bool chunked;
|
||||
// Whether the body is infinite chunked.
|
||||
bool infinite_chunked;
|
||||
// Whether the request indicates should keep alive for the http connection.
|
||||
bool keep_alive;
|
||||
// The uri parser
|
||||
SrsHttpUri* _uri;
|
||||
// Use a buffer to read and send ts file.
|
||||
// TODO: FIXME: remove it.
|
||||
char* _http_ts_send_buffer;
|
||||
// The http headers
|
||||
std::vector<SrsHttpHeaderField> _headers;
|
||||
// The query map
|
||||
std::map<std::string, std::string> _query;
|
||||
// The transport connection, can be NULL.
|
||||
SrsConnection* owner_conn;
|
||||
private:
|
||||
// Whether request is jsonp.
|
||||
bool jsonp;
|
||||
// The method in QueryString will override the HTTP method.
|
||||
std::string jsonp_method;
|
||||
public:
|
||||
SrsHttpMessage(ISrsReader* io);
|
||||
SrsHttpMessage(ISrsReader* reader = NULL, SrsFastStream* buffer = NULL);
|
||||
virtual ~SrsHttpMessage();
|
||||
public:
|
||||
// Set the basic information for HTTP request.
|
||||
// @remark User must call set_basic before set_header, because the content_length will be overwrite by header.
|
||||
virtual void set_basic(uint8_t method, uint16_t status, int64_t content_length);
|
||||
// Set HTTP header and whether the request require keep alive.
|
||||
// @remark User must call set_header before set_url, because the Host in header is used for url.
|
||||
virtual void set_header(SrsHttpHeader* header, bool keep_alive);
|
||||
// set the original messages, then update the message.
|
||||
virtual srs_error_t update(std::string url, bool allow_jsonp, http_parser* header, SrsFastStream* body, std::vector<SrsHttpHeaderField>& headers);
|
||||
virtual srs_error_t set_url(std::string url, bool allow_jsonp);
|
||||
public:
|
||||
// Get the owner connection, maybe NULL.
|
||||
virtual SrsConnection* connection();
|
||||
|
@ -159,6 +163,7 @@ public:
|
|||
// The url maybe the path.
|
||||
virtual std::string url();
|
||||
virtual std::string host();
|
||||
virtual int port();
|
||||
virtual std::string path();
|
||||
virtual std::string query();
|
||||
virtual std::string ext();
|
||||
|
@ -179,10 +184,7 @@ public:
|
|||
// then query_get("start") is "100", and query_get("end") is "200"
|
||||
virtual std::string query_get(std::string key);
|
||||
// Get the headers.
|
||||
virtual int request_header_count();
|
||||
virtual std::string request_header_key_at(int index);
|
||||
virtual std::string request_header_value_at(int index);
|
||||
virtual std::string get_request_header(std::string name);
|
||||
virtual SrsHttpHeader* header();
|
||||
public:
|
||||
// Convert the http message to a request.
|
||||
// @remark user must free the return request.
|
||||
|
@ -195,12 +197,25 @@ public:
|
|||
// for writev, there always one chunk to send it.
|
||||
#define SRS_HTTP_HEADER_CACHE_SIZE 64
|
||||
|
||||
class ISrsHttpHeaderFilter
|
||||
{
|
||||
public:
|
||||
ISrsHttpHeaderFilter();
|
||||
virtual ~ISrsHttpHeaderFilter();
|
||||
public:
|
||||
// Filter the HTTP header h.
|
||||
virtual srs_error_t filter(SrsHttpHeader* h) = 0;
|
||||
};
|
||||
|
||||
// Response writer use st socket
|
||||
class SrsHttpResponseWriter : public ISrsHttpResponseWriter
|
||||
{
|
||||
private:
|
||||
SrsStSocket* skt;
|
||||
ISrsProtocolReadWriter* skt;
|
||||
SrsHttpHeader* hdr;
|
||||
// Before writing header, there is a chance to filter it,
|
||||
// such as remove some headers or inject new.
|
||||
ISrsHttpHeaderFilter* hf;
|
||||
private:
|
||||
char header_cache[SRS_HTTP_HEADER_CACHE_SIZE];
|
||||
iovec* iovss_cache;
|
||||
|
@ -222,7 +237,7 @@ private:
|
|||
// logically written.
|
||||
bool header_sent;
|
||||
public:
|
||||
SrsHttpResponseWriter(SrsStSocket* io);
|
||||
SrsHttpResponseWriter(ISrsProtocolReadWriter* io);
|
||||
virtual ~SrsHttpResponseWriter();
|
||||
public:
|
||||
virtual srs_error_t final_request();
|
||||
|
@ -248,11 +263,10 @@ private:
|
|||
// Already read total bytes.
|
||||
int64_t nb_total_read;
|
||||
public:
|
||||
SrsHttpResponseReader(SrsHttpMessage* msg, ISrsReader* reader);
|
||||
// Generally the reader is the under-layer io such as socket,
|
||||
// while buffer is a fast cache which may have cached some data from reader.
|
||||
SrsHttpResponseReader(SrsHttpMessage* msg, ISrsReader* reader, SrsFastStream* buffer);
|
||||
virtual ~SrsHttpResponseReader();
|
||||
public:
|
||||
// Initialize the response reader with buffer.
|
||||
virtual srs_error_t initialize(SrsFastStream* buffer);
|
||||
// Interface ISrsHttpResponseReader
|
||||
public:
|
||||
virtual bool eof();
|
||||
|
|
|
@ -35,8 +35,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
#include "gtest/gtest.h"
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
#include <srs_app_log.hpp>
|
||||
#include <srs_kernel_stream.hpp>
|
||||
|
||||
// we add an empty macro for upp to show the smart tips.
|
||||
#define VOID
|
||||
|
@ -61,6 +63,10 @@ extern srs_utime_t _srs_tmp_timeout;
|
|||
#define HELPER_ARRAY_INIT(buf, sz, val) \
|
||||
for (int i = 0; i < (int)sz; i++) (buf)[i]=val
|
||||
|
||||
// Dump simple stream to string.
|
||||
#define HELPER_BUFFER2STR(io) \
|
||||
string((const char*)(io)->bytes(), (size_t)(io)->length())
|
||||
|
||||
// the asserts of gtest:
|
||||
// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
|
||||
// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2
|
||||
|
|
1433
trunk/src/utest/srs_utest_http.cpp
Normal file
1433
trunk/src/utest/srs_utest_http.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -25,21 +25,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#define SRS_UTEST_PROTO_STACK_HPP
|
||||
|
||||
/*
|
||||
#include <srs_utest_protostack.hpp>
|
||||
#include <srs_utest_http.hpp>
|
||||
*/
|
||||
#include <srs_utest.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <srs_protocol_utility.hpp>
|
||||
|
||||
#include <srs_rtmp_stack.hpp>
|
||||
#include <srs_rtmp_handshake.hpp>
|
||||
#include <srs_protocol_stream.hpp>
|
||||
#include <srs_protocol_kbps.hpp>
|
||||
|
||||
using namespace _srs_internal;
|
||||
|
||||
#include <srs_protocol_io.hpp>
|
||||
#include <srs_utest_protocol.hpp>
|
||||
|
||||
#endif
|
||||
|
|
@ -2318,6 +2318,14 @@ VOID TEST(KernelUtility, StringUtils)
|
|||
EXPECT_TRUE(srs_string_contains("srs", "s", "sr"));
|
||||
EXPECT_TRUE(srs_string_contains("srs", "s", "sr", "srs"));
|
||||
}
|
||||
|
||||
if (true) {
|
||||
EXPECT_EQ(0, srs_string_count("srs", "y"));
|
||||
EXPECT_EQ(0, srs_string_count("srs", ""));
|
||||
EXPECT_EQ(1, srs_string_count("srs", "r"));
|
||||
EXPECT_EQ(2, srs_string_count("srs", "s"));
|
||||
EXPECT_EQ(3, srs_string_count("srs", "sr"));
|
||||
}
|
||||
|
||||
if (true) {
|
||||
vector<string> flags;
|
||||
|
@ -2633,9 +2641,9 @@ VOID TEST(KernelUtility, RTMPUtils2)
|
|||
VOID TEST(KernelErrorTest, CoverAll)
|
||||
{
|
||||
if (true) {
|
||||
EXPECT_TRUE(srs_is_system_control_error(ERROR_CONTROL_RTMP_CLOSE));
|
||||
EXPECT_TRUE(srs_is_system_control_error(ERROR_CONTROL_REPUBLISH));
|
||||
EXPECT_TRUE(srs_is_system_control_error(ERROR_CONTROL_REDIRECT));
|
||||
EXPECT_TRUE(srs_is_system_control_error(srs_error_new(ERROR_CONTROL_RTMP_CLOSE, "err")));
|
||||
EXPECT_TRUE(srs_is_system_control_error(srs_error_new(ERROR_CONTROL_REPUBLISH, "err")));
|
||||
EXPECT_TRUE(srs_is_system_control_error(srs_error_new(ERROR_CONTROL_REDIRECT, "err")));
|
||||
}
|
||||
|
||||
if (true) {
|
||||
|
@ -2645,9 +2653,9 @@ VOID TEST(KernelErrorTest, CoverAll)
|
|||
}
|
||||
|
||||
if (true) {
|
||||
EXPECT_TRUE(srs_is_client_gracefully_close(ERROR_SOCKET_READ));
|
||||
EXPECT_TRUE(srs_is_client_gracefully_close(ERROR_SOCKET_READ_FULLY));
|
||||
EXPECT_TRUE(srs_is_client_gracefully_close(ERROR_SOCKET_WRITE));
|
||||
EXPECT_TRUE(srs_is_client_gracefully_close(srs_error_new(ERROR_SOCKET_READ, "err")));
|
||||
EXPECT_TRUE(srs_is_client_gracefully_close(srs_error_new(ERROR_SOCKET_READ_FULLY, "err")));
|
||||
EXPECT_TRUE(srs_is_client_gracefully_close(srs_error_new(ERROR_SOCKET_WRITE, "err")));
|
||||
}
|
||||
|
||||
if (true) {
|
||||
|
|
|
@ -20,9 +20,7 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <srs_utest_protostack.hpp>
|
||||
|
||||
#include <srs_utest_protocol.hpp>
|
||||
#include <srs_utest_rtmp.hpp>
|
||||
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
|
@ -75,7 +73,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
VOID TEST(ProtoStackTest, PacketEncode)
|
||||
VOID TEST(ProtocolRTMPTest, PacketEncode)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -112,7 +110,7 @@ VOID TEST(ProtoStackTest, PacketEncode)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ManualFlush)
|
||||
VOID TEST(ProtocolRTMPTest, ManualFlush)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -222,7 +220,7 @@ VOID TEST(ProtoStackTest, ManualFlush)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, SendPacketsError)
|
||||
VOID TEST(ProtocolRTMPTest, SendPacketsError)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -303,7 +301,7 @@ VOID TEST(ProtoStackTest, SendPacketsError)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, SendHugePacket)
|
||||
VOID TEST(ProtocolRTMPTest, SendHugePacket)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -318,7 +316,7 @@ VOID TEST(ProtoStackTest, SendHugePacket)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, SendZeroMessages)
|
||||
VOID TEST(ProtocolRTMPTest, SendZeroMessages)
|
||||
{
|
||||
srs_error_t err;
|
||||
if (true) {
|
||||
|
@ -345,7 +343,7 @@ VOID TEST(ProtoStackTest, SendZeroMessages)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, HugeMessages)
|
||||
VOID TEST(ProtocolRTMPTest, HugeMessages)
|
||||
{
|
||||
srs_error_t err;
|
||||
if (true) {
|
||||
|
@ -409,7 +407,7 @@ VOID TEST(ProtoStackTest, HugeMessages)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, DecodeMessages)
|
||||
VOID TEST(ProtocolRTMPTest, DecodeMessages)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -428,7 +426,7 @@ VOID TEST(ProtoStackTest, DecodeMessages)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, OnDecodeMessages)
|
||||
VOID TEST(ProtocolRTMPTest, OnDecodeMessages)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -469,7 +467,7 @@ SrsCommonMessage* _create_amf0(char* bytes, int size, int stream_id)
|
|||
return msg;
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, OnDecodeMessages2)
|
||||
VOID TEST(ProtocolRTMPTest, OnDecodeMessages2)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -536,7 +534,7 @@ VOID TEST(ProtoStackTest, OnDecodeMessages2)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, OnDecodeMessages3)
|
||||
VOID TEST(ProtocolRTMPTest, OnDecodeMessages3)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -705,7 +703,7 @@ VOID TEST(ProtoStackTest, OnDecodeMessages3)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, OnDecodeMessages4)
|
||||
VOID TEST(ProtocolRTMPTest, OnDecodeMessages4)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -1070,7 +1068,7 @@ VOID TEST(ProtoStackTest, OnDecodeMessages4)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, RecvMessage)
|
||||
VOID TEST(ProtocolRTMPTest, RecvMessage)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -1120,7 +1118,7 @@ VOID TEST(ProtoStackTest, RecvMessage)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, RecvMessage2)
|
||||
VOID TEST(ProtocolRTMPTest, RecvMessage2)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -1179,7 +1177,7 @@ VOID TEST(ProtoStackTest, RecvMessage2)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, RecvMessage3)
|
||||
VOID TEST(ProtocolRTMPTest, RecvMessage3)
|
||||
{
|
||||
if (true) {
|
||||
SrsRequest req;
|
||||
|
@ -1239,7 +1237,7 @@ VOID TEST(ProtoStackTest, RecvMessage3)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, RecvMessage4)
|
||||
VOID TEST(ProtocolRTMPTest, RecvMessage4)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -1279,7 +1277,7 @@ VOID TEST(ProtoStackTest, RecvMessage4)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, HandshakeC0C1)
|
||||
VOID TEST(ProtocolRTMPTest, HandshakeC0C1)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -1379,7 +1377,7 @@ VOID TEST(ProtoStackTest, HandshakeC0C1)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, HandshakeS0S1S2)
|
||||
VOID TEST(ProtocolRTMPTest, HandshakeS0S1S2)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -1424,7 +1422,7 @@ VOID TEST(ProtoStackTest, HandshakeS0S1S2)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, HandshakeC2)
|
||||
VOID TEST(ProtocolRTMPTest, HandshakeC2)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -1469,7 +1467,7 @@ VOID TEST(ProtoStackTest, HandshakeC2)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ServerInfo)
|
||||
VOID TEST(ProtocolRTMPTest, ServerInfo)
|
||||
{
|
||||
SrsServerInfo si;
|
||||
EXPECT_EQ(0, si.pid);
|
||||
|
@ -1480,7 +1478,7 @@ VOID TEST(ProtoStackTest, ServerInfo)
|
|||
EXPECT_EQ(0, si.build);
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ClientCommandMessage)
|
||||
VOID TEST(ProtocolRTMPTest, ClientCommandMessage)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -1581,7 +1579,7 @@ VOID TEST(ProtoStackTest, ClientCommandMessage)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ServerCommandMessage)
|
||||
VOID TEST(ProtocolRTMPTest, ServerCommandMessage)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -1736,7 +1734,7 @@ VOID TEST(ProtoStackTest, ServerCommandMessage)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ServerRedirect)
|
||||
VOID TEST(ProtocolRTMPTest, ServerRedirect)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -1843,7 +1841,7 @@ VOID TEST(ProtoStackTest, ServerRedirect)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ServerIdentify)
|
||||
VOID TEST(ProtocolRTMPTest, ServerIdentify)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2023,7 +2021,7 @@ VOID TEST(ProtoStackTest, ServerIdentify)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ServerFMLEStart)
|
||||
VOID TEST(ProtocolRTMPTest, ServerFMLEStart)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2088,7 +2086,7 @@ VOID TEST(ProtoStackTest, ServerFMLEStart)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ServerHaivisionPublish)
|
||||
VOID TEST(ProtocolRTMPTest, ServerHaivisionPublish)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2127,7 +2125,7 @@ VOID TEST(ProtoStackTest, ServerHaivisionPublish)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ServerFMLEUnpublish)
|
||||
VOID TEST(ProtocolRTMPTest, ServerFMLEUnpublish)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2180,7 +2178,7 @@ VOID TEST(ProtoStackTest, ServerFMLEUnpublish)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ServerFlashPublish)
|
||||
VOID TEST(ProtocolRTMPTest, ServerFlashPublish)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2205,7 +2203,7 @@ VOID TEST(ProtoStackTest, ServerFlashPublish)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ServerRecursiveDepth)
|
||||
VOID TEST(ProtocolRTMPTest, ServerRecursiveDepth)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2260,7 +2258,7 @@ VOID TEST(ProtoStackTest, ServerRecursiveDepth)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ServerResponseCommands)
|
||||
VOID TEST(ProtocolRTMPTest, ServerResponseCommands)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2402,7 +2400,7 @@ VOID TEST(ProtoStackTest, ServerResponseCommands)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, CoverAll)
|
||||
VOID TEST(ProtocolRTMPTest, CoverAll)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2483,7 +2481,7 @@ VOID TEST(ProtoStackTest, CoverAll)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, CoverBandwidth)
|
||||
VOID TEST(ProtocolRTMPTest, CoverBandwidth)
|
||||
{
|
||||
if (true) {
|
||||
SrsBandwidthPacket p;
|
||||
|
@ -2555,7 +2553,7 @@ VOID TEST(ProtoStackTest, CoverBandwidth)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, CoverAllUnmarshal)
|
||||
VOID TEST(ProtocolRTMPTest, CoverAllUnmarshal)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2762,7 +2760,7 @@ VOID TEST(ProtoStackTest, CoverAllUnmarshal)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ComplexToSimpleHandshake)
|
||||
VOID TEST(ProtocolRTMPTest, ComplexToSimpleHandshake)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2785,7 +2783,7 @@ VOID TEST(ProtoStackTest, ComplexToSimpleHandshake)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, ConnectAppWithArgs)
|
||||
VOID TEST(ProtocolRTMPTest, ConnectAppWithArgs)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2848,7 +2846,7 @@ VOID TEST(ProtoStackTest, ConnectAppWithArgs)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, AgentMessageCodec)
|
||||
VOID TEST(ProtocolRTMPTest, AgentMessageCodec)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2950,7 +2948,7 @@ srs_error_t _mock_packet_to_shared_msg(SrsPacket* packet, int stream_id, SrsShar
|
|||
return err;
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, CheckStreamID)
|
||||
VOID TEST(ProtocolRTMPTest, CheckStreamID)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -2995,7 +2993,7 @@ VOID TEST(ProtoStackTest, CheckStreamID)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtoStackTest, AgentMessageTransform)
|
||||
VOID TEST(ProtocolRTMPTest, AgentMessageTransform)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
|
@ -3095,7 +3093,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
VOID TEST(ProtoStackTest, MergeReadHandler)
|
||||
VOID TEST(ProtocolRTMPTest, MergeReadHandler)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
35
trunk/src/utest/srs_utest_rtmp.hpp
Normal file
35
trunk/src/utest/srs_utest_rtmp.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2019 Winlin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SRS_UTEST_PROTO_STACK_HPP
|
||||
#define SRS_UTEST_PROTO_STACK_HPP
|
||||
|
||||
/*
|
||||
#include <srs_utest_rtmp.hpp>
|
||||
*/
|
||||
#include <srs_utest.hpp>
|
||||
|
||||
#include <srs_utest_protocol.hpp>
|
||||
|
||||
#endif
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue