mirror of
https://github.com/ossrs/srs.git
synced 2025-02-13 03:41:55 +00:00
implements the http stream module.
This commit is contained in:
parent
d34051d7b9
commit
00eda0d7b2
11 changed files with 195 additions and 38 deletions
|
@ -76,6 +76,9 @@ http_stream {
|
|||
# @remark, if use lower port, for instance 80, user must start srs by root.
|
||||
# default: 8080
|
||||
listen 8080;
|
||||
# the default dir for http root.
|
||||
# default: ./objs/nginx/html
|
||||
dir ./objs/nginx/html;
|
||||
}
|
||||
|
||||
#############################################################################################
|
||||
|
|
|
@ -1746,15 +1746,16 @@ int SrsConfig::get_http_api_listen()
|
|||
{
|
||||
SrsConfDirective* conf = get_http_api();
|
||||
|
||||
if (conf) {
|
||||
conf = conf->get("listen");
|
||||
|
||||
if (conf && !conf->arg0().empty()) {
|
||||
return ::atoi(conf->arg0().c_str());
|
||||
}
|
||||
if (!conf) {
|
||||
return SRS_CONF_DEFAULT_HTTP_API_PORT;
|
||||
}
|
||||
|
||||
return 1985;
|
||||
conf = conf->get("listen");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return SRS_CONF_DEFAULT_HTTP_API_PORT;
|
||||
}
|
||||
|
||||
return ::atoi(conf->arg0().c_str());
|
||||
}
|
||||
|
||||
SrsConfDirective* SrsConfig::get_http_stream()
|
||||
|
@ -1765,13 +1766,11 @@ SrsConfDirective* SrsConfig::get_http_stream()
|
|||
bool SrsConfig::get_http_stream_enabled()
|
||||
{
|
||||
SrsConfDirective* conf = get_http_stream();
|
||||
|
||||
if (!conf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
conf = conf->get("enabled");
|
||||
|
||||
if (conf && conf->arg0() == "on") {
|
||||
return true;
|
||||
}
|
||||
|
@ -1783,15 +1782,35 @@ int SrsConfig::get_http_stream_listen()
|
|||
{
|
||||
SrsConfDirective* conf = get_http_stream();
|
||||
|
||||
if (conf) {
|
||||
conf = conf->get("listen");
|
||||
|
||||
if (conf && !conf->arg0().empty()) {
|
||||
return ::atoi(conf->arg0().c_str());
|
||||
}
|
||||
if (!conf) {
|
||||
return SRS_CONF_DEFAULT_HTTP_STREAM_PORT;
|
||||
}
|
||||
|
||||
return 8080;
|
||||
conf = conf->get("listen");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return SRS_CONF_DEFAULT_HTTP_STREAM_PORT;
|
||||
}
|
||||
|
||||
return ::atoi(conf->arg0().c_str());
|
||||
}
|
||||
|
||||
string SrsConfig::get_http_stream_dir()
|
||||
{
|
||||
SrsConfDirective* conf = get_http_stream();
|
||||
if (!conf) {
|
||||
return SRS_CONF_DEFAULT_HTTP_DIR;
|
||||
}
|
||||
|
||||
conf = conf->get("dir");
|
||||
if (!conf) {
|
||||
return SRS_CONF_DEFAULT_HTTP_DIR;
|
||||
}
|
||||
|
||||
if (conf->arg0().empty()) {
|
||||
return SRS_CONF_DEFAULT_HTTP_DIR;
|
||||
}
|
||||
|
||||
return conf->arg0();
|
||||
}
|
||||
|
||||
bool SrsConfig::get_vhost_http_enabled(string vhost)
|
||||
|
|
|
@ -59,6 +59,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#define SRS_CONF_DEFAULT_HTTP_MOUNT "/"
|
||||
#define SRS_CONF_DEFAULT_HTTP_DIR SRS_CONF_DEFAULT_HLS_PATH
|
||||
|
||||
#define SRS_CONF_DEFAULT_HTTP_STREAM_PORT 8080
|
||||
#define SRS_CONF_DEFAULT_HTTP_API_PORT 1985
|
||||
|
||||
#define SRS_STAGE_PLAY_USER_INTERVAL_MS 1300
|
||||
#define SRS_STAGE_PUBLISH_USER_INTERVAL_MS 1100
|
||||
#define SRS_STAGE_FORWARDER_INTERVAL_MS 2000
|
||||
|
@ -207,6 +210,7 @@ private:
|
|||
public:
|
||||
virtual bool get_http_stream_enabled();
|
||||
virtual int get_http_stream_listen();
|
||||
virtual std::string get_http_stream_dir();
|
||||
public:
|
||||
virtual bool get_vhost_http_enabled(std::string vhost);
|
||||
virtual std::string get_vhost_http_mount(std::string vhost);
|
||||
|
|
|
@ -48,7 +48,8 @@ bool srs_path_equals(const char* expect, const char* path, int nb_path)
|
|||
return false;
|
||||
}
|
||||
|
||||
return !memcmp(expect, path, size);
|
||||
bool equals = !memcmp(expect, path, size);
|
||||
return equals;
|
||||
}
|
||||
|
||||
SrsHttpHandlerMatch::SrsHttpHandlerMatch()
|
||||
|
@ -223,6 +224,20 @@ SrsHttpHandler* SrsHttpHandler::res_content_type_json(std::stringstream& ss)
|
|||
return this;
|
||||
}
|
||||
|
||||
SrsHttpHandler* SrsHttpHandler::res_content_type_m3u8(std::stringstream& ss)
|
||||
{
|
||||
ss << "Content-Type: application/x-mpegURL;charset=utf-8" << __CRLF
|
||||
<< "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF;
|
||||
return this;
|
||||
}
|
||||
|
||||
SrsHttpHandler* SrsHttpHandler::res_content_type_mpegts(std::stringstream& ss)
|
||||
{
|
||||
ss << "Content-Type: video/MP2T;charset=utf-8" << __CRLF
|
||||
<< "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF;
|
||||
return this;
|
||||
}
|
||||
|
||||
SrsHttpHandler* SrsHttpHandler::res_content_length(std::stringstream& ss, int64_t length)
|
||||
{
|
||||
ss << "Content-Length: "<< length << __CRLF;
|
||||
|
@ -284,6 +299,40 @@ int SrsHttpHandler::res_text(SrsSocket* skt, SrsHttpMessage* req, std::string bo
|
|||
return res_flush(skt, ss);
|
||||
}
|
||||
|
||||
int SrsHttpHandler::res_m3u8(SrsSocket* skt, SrsHttpMessage* req, std::string body)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
res_status_line(ss)->res_content_type_m3u8(ss)
|
||||
->res_content_length(ss, (int)body.length());
|
||||
|
||||
if (req->requires_crossdomain()) {
|
||||
res_enable_crossdomain(ss);
|
||||
}
|
||||
|
||||
res_header_eof(ss)
|
||||
->res_body(ss, body);
|
||||
|
||||
return res_flush(skt, ss);
|
||||
}
|
||||
|
||||
int SrsHttpHandler::res_mpegts(SrsSocket* skt, SrsHttpMessage* req, std::string body)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
res_status_line(ss)->res_content_type_mpegts(ss)
|
||||
->res_content_length(ss, (int)body.length());
|
||||
|
||||
if (req->requires_crossdomain()) {
|
||||
res_enable_crossdomain(ss);
|
||||
}
|
||||
|
||||
res_header_eof(ss)
|
||||
->res_body(ss, body);
|
||||
|
||||
return res_flush(skt, ss);
|
||||
}
|
||||
|
||||
int SrsHttpHandler::res_json(SrsSocket* skt, SrsHttpMessage* req, std::string json)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
|
|
@ -229,6 +229,8 @@ public:
|
|||
virtual SrsHttpHandler* res_status_line_error(std::stringstream& ss, int code, std::string reason_phrase);
|
||||
virtual SrsHttpHandler* res_content_type(std::stringstream& ss);
|
||||
virtual SrsHttpHandler* res_content_type_json(std::stringstream& ss);
|
||||
virtual SrsHttpHandler* res_content_type_m3u8(std::stringstream& ss);
|
||||
virtual SrsHttpHandler* res_content_type_mpegts(std::stringstream& ss);
|
||||
virtual SrsHttpHandler* res_content_length(std::stringstream& ss, int64_t length);
|
||||
virtual SrsHttpHandler* res_enable_crossdomain(std::stringstream& ss);
|
||||
virtual SrsHttpHandler* res_header_eof(std::stringstream& ss);
|
||||
|
@ -237,6 +239,8 @@ public:
|
|||
public:
|
||||
virtual int res_options(SrsSocket* skt);
|
||||
virtual int res_text(SrsSocket* skt, SrsHttpMessage* req, std::string body);
|
||||
virtual int res_m3u8(SrsSocket* skt, SrsHttpMessage* req, std::string body);
|
||||
virtual int res_mpegts(SrsSocket* skt, SrsHttpMessage* req, std::string body);
|
||||
virtual int res_json(SrsSocket* skt, SrsHttpMessage* req, std::string json);
|
||||
virtual int res_error(SrsSocket* skt, SrsHttpMessage* req, int code, std::string reason_phrase, std::string body);
|
||||
// object creator
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
virtual ~SrsApiRoot();
|
||||
public:
|
||||
virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase);
|
||||
protected:
|
||||
virtual bool can_handle(const char* path, int length, const char** pchild);
|
||||
virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
|
||||
};
|
||||
|
@ -60,6 +61,7 @@ public:
|
|||
virtual ~SrsApiApi();
|
||||
public:
|
||||
virtual bool can_handle(const char* path, int length, const char** pchild);
|
||||
protected:
|
||||
virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
|
||||
};
|
||||
|
||||
|
@ -70,6 +72,7 @@ public:
|
|||
virtual ~SrsApiV1();
|
||||
public:
|
||||
virtual bool can_handle(const char* path, int length, const char** pchild);
|
||||
protected:
|
||||
virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
|
||||
};
|
||||
|
||||
|
@ -80,6 +83,7 @@ public:
|
|||
virtual ~SrsApiVersion();
|
||||
public:
|
||||
virtual bool can_handle(const char* path, int length, const char** pchild);
|
||||
protected:
|
||||
virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
|
||||
};
|
||||
|
||||
|
@ -90,6 +94,7 @@ public:
|
|||
virtual ~SrsApiAuthors();
|
||||
public:
|
||||
virtual bool can_handle(const char* path, int length, const char** pchild);
|
||||
protected:
|
||||
virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
|
||||
};
|
||||
|
||||
|
|
|
@ -28,6 +28,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <srs_kernel_log.hpp>
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_app_socket.hpp>
|
||||
|
@ -48,7 +52,11 @@ SrsHttpRoot::~SrsHttpRoot()
|
|||
int SrsHttpRoot::initialize()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// add root
|
||||
handlers.push_back(new SrsHttpVhost("__http__", "/", _srs_config->get_http_stream_dir()));
|
||||
|
||||
// add other virtual path
|
||||
SrsConfDirective* root = _srs_config->get_root();
|
||||
for (int i = 0; i < (int)root->directives.size(); i++) {
|
||||
SrsConfDirective* conf = root->at(i);
|
||||
|
@ -71,6 +79,16 @@ int SrsHttpRoot::initialize()
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool SrsHttpRoot::can_handle(const char* path, int length, const char** pchild)
|
||||
{
|
||||
// reset the child path to path,
|
||||
// for child to reparse the path.
|
||||
*pchild = path;
|
||||
|
||||
// only compare the first char.
|
||||
return srs_path_equals("/", path, 1);
|
||||
}
|
||||
|
||||
bool SrsHttpRoot::is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase)
|
||||
{
|
||||
if (!SrsHttpHandler::is_handler_valid(req, status_code, reason_phrase)) {
|
||||
|
@ -86,16 +104,6 @@ bool SrsHttpRoot::is_handler_valid(SrsHttpMessage* req, int& status_code, std::s
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SrsHttpRoot::can_handle(const char* path, int length, const char** pchild)
|
||||
{
|
||||
// reset the child path to path,
|
||||
// for child to reparse the path.
|
||||
*pchild = path;
|
||||
|
||||
// only compare the first char.
|
||||
return srs_path_equals("/", path, 1);
|
||||
}
|
||||
|
||||
int SrsHttpRoot::do_process_request(SrsSocket* skt, SrsHttpMessage* req)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
@ -139,21 +147,74 @@ SrsHttpVhost::~SrsHttpVhost()
|
|||
|
||||
bool SrsHttpVhost::can_handle(const char* path, int length, const char** /*pchild*/)
|
||||
{
|
||||
return srs_path_equals("/api", path, length);
|
||||
int min_match = srs_min(length, (int)_mount.length());
|
||||
return srs_path_equals(_mount.c_str(), path, min_match);
|
||||
}
|
||||
|
||||
bool SrsHttpVhost::is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase)
|
||||
{
|
||||
std::string fullpath = _dir + "/" + req->match()->unmatched_url;
|
||||
if (req->match()->unmatched_url.empty()) {
|
||||
fullpath += req->match()->matched_url;
|
||||
}
|
||||
|
||||
if (::access(fullpath.c_str(), F_OK | R_OK) < 0) {
|
||||
srs_warn("check file %s does not exists", fullpath.c_str());
|
||||
|
||||
status_code = HTTP_NotFound;
|
||||
reason_phrase = HTTP_NotFound_str;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req)
|
||||
{
|
||||
std::stringstream ss;
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
ss << JOBJECT_START
|
||||
<< JFIELD_ERROR(ERROR_SUCCESS) << JFIELD_CONT
|
||||
<< JFIELD_ORG("urls", JOBJECT_START)
|
||||
<< JFIELD_STR("v1", "the api version 1.0")
|
||||
<< JOBJECT_END
|
||||
<< JOBJECT_END;
|
||||
std::string fullpath = _dir + "/" + req->match()->unmatched_url;
|
||||
if (req->match()->unmatched_url.empty()) {
|
||||
fullpath += req->match()->matched_url;
|
||||
}
|
||||
|
||||
return res_json(skt, req, ss.str());
|
||||
if (srs_string_ends_with(fullpath, "/")) {
|
||||
fullpath += "index.html";
|
||||
}
|
||||
|
||||
int fd = ::open(fullpath.c_str(), O_RDONLY);
|
||||
if (fd < 0) {
|
||||
ret = ERROR_HTTP_OPEN_FILE;
|
||||
srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t length = (int64_t)::lseek(fd, 0, SEEK_END);
|
||||
::lseek(fd, 0, SEEK_SET);
|
||||
|
||||
char* buf = new char[length];
|
||||
SrsAutoFree(char, buf, true);
|
||||
|
||||
if (::read(fd, buf, length) < 0) {
|
||||
::close(fd);
|
||||
ret = ERROR_HTTP_READ_FILE;
|
||||
srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
::close(fd);
|
||||
|
||||
std::string str;
|
||||
str.append(buf, length);
|
||||
|
||||
if (srs_string_ends_with(fullpath, ".ts")) {
|
||||
return res_mpegts(skt, req, str);
|
||||
} else if (srs_string_ends_with(fullpath, ".m3u8")) {
|
||||
return res_m3u8(skt, req, str);
|
||||
} else {
|
||||
return res_text(skt, req, str);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
string SrsHttpVhost::vhost()
|
||||
|
|
|
@ -49,8 +49,9 @@ public:
|
|||
virtual ~SrsHttpRoot();
|
||||
public:
|
||||
virtual int initialize();
|
||||
virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase);
|
||||
virtual bool can_handle(const char* path, int length, const char** pchild);
|
||||
protected:
|
||||
virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase);
|
||||
virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
|
||||
};
|
||||
|
||||
|
@ -65,6 +66,8 @@ public:
|
|||
virtual ~SrsHttpVhost();
|
||||
public:
|
||||
virtual bool can_handle(const char* path, int length, const char** pchild);
|
||||
protected:
|
||||
virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase);
|
||||
virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
|
||||
public:
|
||||
virtual std::string vhost();
|
||||
|
|
|
@ -85,6 +85,11 @@ string srs_string_remove(string str, string remove_chars)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool srs_string_ends_with(string str, string flag)
|
||||
{
|
||||
return str.rfind(flag) == str.length() - flag.length();
|
||||
}
|
||||
|
||||
string srs_dns_resolve(string host)
|
||||
{
|
||||
if (inet_addr(host.c_str()) != INADDR_NONE) {
|
||||
|
|
|
@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
// current release version
|
||||
#define VERSION_MAJOR "0"
|
||||
#define VERSION_MINOR "9"
|
||||
#define VERSION_REVISION "48"
|
||||
#define VERSION_REVISION "49"
|
||||
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
|
||||
// server info.
|
||||
#define RTMP_SIG_SRS_KEY "srs"
|
||||
|
@ -97,6 +97,8 @@ extern std::string srs_string_replace(std::string str, std::string old_str, std:
|
|||
extern std::string srs_string_trim_end(std::string str, std::string trim_chars);
|
||||
// remove char in remove_chars of str
|
||||
extern std::string srs_string_remove(std::string str, std::string remove_chars);
|
||||
// whether string end with
|
||||
extern bool srs_string_ends_with(std::string str, std::string flag);
|
||||
|
||||
// dns resolve utility, return the resolved ip address.
|
||||
extern std::string srs_dns_resolve(std::string host);
|
||||
|
|
|
@ -159,6 +159,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#define ERROR_HTTP_PARSE_HEADER 802
|
||||
#define ERROR_HTTP_HANDLER_MATCH_URL 803
|
||||
#define ERROR_HTTP_HANDLER_INVALID 804
|
||||
#define ERROR_HTTP_OPEN_FILE 805
|
||||
#define ERROR_HTTP_READ_FILE 806
|
||||
|
||||
// system control message,
|
||||
// not an error, but special control logic.
|
||||
|
|
Loading…
Reference in a new issue