1
0
Fork 0
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:
winlin 2014-04-04 23:04:38 +08:00
parent d34051d7b9
commit 00eda0d7b2
11 changed files with 195 additions and 38 deletions

View file

@ -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;
}
#############################################################################################

View file

@ -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)

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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);
};

View file

@ -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()

View file

@ -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();

View file

@ -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) {

View file

@ -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);

View file

@ -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.