diff --git a/README.md b/README.md index 240bc861f..b37eb110a 100755 --- a/README.md +++ b/README.md @@ -510,6 +510,7 @@ Supported operating systems and hardware: ## History +* v2.0, 2015-01-17, fix [#277](https://github.com/winlinvip/simple-rtmp-server/issues/277), refine http server refer to go http-framework. 2.0.98 * v2.0, 2015-01-17, for [#277](https://github.com/winlinvip/simple-rtmp-server/issues/277), refine http api refer to go http-framework. 2.0.97 * v2.0, 2015-01-17, hotfix [#290](https://github.com/winlinvip/simple-rtmp-server/issues/290), use iformat only for rtmp input. 2.0.95 * v2.0, 2015-01-08, hotfix [#281](https://github.com/winlinvip/simple-rtmp-server/issues/281), fix hls bug ignore type-9 send aud. 2.0.93 diff --git a/trunk/src/app/srs_app_http.cpp b/trunk/src/app/srs_app_http.cpp index 838c30b41..df559a3c0 100644 --- a/trunk/src/app/srs_app_http.cpp +++ b/trunk/src/app/srs_app_http.cpp @@ -37,6 +37,7 @@ using namespace std; #include #include #include +#include #define SRS_DEFAULT_HTTP_PORT 80 @@ -49,24 +50,7 @@ using namespace std; #define SRS_CONSTS_HTTP_PUT HTTP_PUT #define SRS_CONSTS_HTTP_DELETE HTTP_DELETE -bool srs_path_equals(const char* expect, const char* path, int nb_path) -{ - int size = strlen(expect); - - if (size != nb_path) { - return false; - } - - bool equals = !memcmp(expect, path, size); - return equals; -} - -bool srs_path_like(const char* expect, const char* path, int nb_path) -{ - int size = strlen(expect); - bool equals = !strncmp(expect, path, srs_min(size, nb_path)); - return equals; -} +#define SRS_HTTP_DEFAULT_PAGE "index.html" int srs_go_http_response_json(ISrsGoHttpResponseWriter* w, string data) { @@ -278,6 +262,82 @@ int SrsGoHttpNotFoundHandler::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMes SRS_CONSTS_HTTP_NotFound, SRS_CONSTS_HTTP_NotFound_str); } +SrsGoHttpFileServer::SrsGoHttpFileServer(string root_dir) +{ + dir = root_dir; +} + +SrsGoHttpFileServer::~SrsGoHttpFileServer() +{ +} + +int SrsGoHttpFileServer::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) +{ + int ret = ERROR_SUCCESS; + + string upath = r->path(); + + // add default pages. + if (srs_string_ends_with(upath, "/")) { + upath += SRS_HTTP_DEFAULT_PAGE; + } + + string fullpath = dir + "/" + upath; + + // open the target file. + SrsFileReader fs; + + if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) { + srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret); + return ret; + } + + int64_t length = fs.filesize(); + + w->header()->set_content_length(length); + + if (srs_string_ends_with(fullpath, ".ts")) { + w->header()->set_content_type("video/MP2T"); + } else if (srs_string_ends_with(fullpath, ".m3u8")) { + w->header()->set_content_type("application/x-mpegURL;charset=utf-8"); + } else if (srs_string_ends_with(fullpath, ".flv")) { + w->header()->set_content_type("video/x-flv"); + } else if (srs_string_ends_with(fullpath, ".xml")) { + w->header()->set_content_type("text/xml;charset=utf-8"); + } else if (srs_string_ends_with(fullpath, ".js")) { + w->header()->set_content_type("text/javascript"); + } else if (srs_string_ends_with(fullpath, ".json")) { + w->header()->set_content_type("application/json;charset=utf-8"); + } else if (srs_string_ends_with(fullpath, ".swf")) { + w->header()->set_content_type("application/x-shockwave-flash"); + } else if (srs_string_ends_with(fullpath, ".css")) { + w->header()->set_content_type("text/css;charset=utf-8"); + } else if (srs_string_ends_with(fullpath, ".ico")) { + w->header()->set_content_type("image/x-icon"); + } else { + w->header()->set_content_type("text/html;charset=utf-8"); + } + + // write body. + int64_t left = length; + char* buf = r->http_ts_send_buffer(); + + while (left > 0) { + ssize_t nread = -1; + if ((ret = fs.read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) { + srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret); + break; + } + + left -= nread; + if ((ret = w->write(buf, nread)) != ERROR_SUCCESS) { + break; + } + } + + return ret; +} + SrsGoHttpMuxEntry::SrsGoHttpMuxEntry() { explicit_match = false; @@ -565,473 +625,11 @@ int SrsGoHttpResponseWriter::send_header(char* data, int size) return skt->write((void*)buf.c_str(), buf.length(), NULL); } -SrsHttpHandlerMatch::SrsHttpHandlerMatch() -{ - handler = NULL; -} - -SrsHttpHandler::SrsHttpHandler() -{ -} - -SrsHttpHandler::~SrsHttpHandler() -{ - std::vector::iterator it; - for (it = handlers.begin(); it != handlers.end(); ++it) { - SrsHttpHandler* handler = *it; - srs_freep(handler); - } - handlers.clear(); -} - -int SrsHttpHandler::initialize() -{ - int ret = ERROR_SUCCESS; - return ret; -} - -bool SrsHttpHandler::can_handle(const char* /*path*/, int /*length*/, const char** /*pchild*/) -{ - return false; -} - -int SrsHttpHandler::process_request(SrsStSocket* skt, SrsHttpMessage* req) -{ - if (req->method() == SRS_CONSTS_HTTP_OPTIONS) { - req->set_requires_crossdomain(true); - return res_options(skt); - } - - int status_code; - std::string reason_phrase; - if (!is_handler_valid(req, status_code, reason_phrase)) { - std::stringstream ss; - - ss << __SRS_JOBJECT_START - << __SRS_JFIELD_ERROR(ERROR_HTTP_HANDLER_INVALID) << __SRS_JFIELD_CONT - << __SRS_JFIELD_ORG("data", __SRS_JOBJECT_START) - << __SRS_JFIELD_ORG("status_code", status_code) << __SRS_JFIELD_CONT - << __SRS_JFIELD_STR("reason_phrase", reason_phrase) << __SRS_JFIELD_CONT - << __SRS_JFIELD_STR("url", req->url()) - << __SRS_JOBJECT_END - << __SRS_JOBJECT_END; - - return res_error(skt, req, status_code, reason_phrase, ss.str()); - } - - return do_process_request(skt, req); -} - -bool SrsHttpHandler::is_handler_valid(SrsHttpMessage* req, int& status_code, string& reason_phrase) -{ - if (!req->match()->unmatched_url.empty()) { - status_code = SRS_CONSTS_HTTP_NotFound; - reason_phrase = SRS_CONSTS_HTTP_NotFound_str; - - return false; - } - - return true; -} - -int SrsHttpHandler::do_process_request(SrsStSocket* /*skt*/, SrsHttpMessage* /*req*/) -{ - int ret = ERROR_SUCCESS; - return ret; -} - -int SrsHttpHandler::response_error(SrsStSocket* skt, SrsHttpMessage* req, int code, string desc) -{ - std::stringstream ss; - ss << __SRS_JOBJECT_START - << __SRS_JFIELD_ERROR(code) << __SRS_JFIELD_CONT - << __SRS_JFIELD_STR("desc", desc) - << __SRS_JOBJECT_END; - - return res_json(skt, req, ss.str()); -} - -int SrsHttpHandler::best_match(const char* path, int length, SrsHttpHandlerMatch** ppmatch) -{ - int ret = ERROR_SUCCESS; - - SrsHttpHandler* handler = NULL; - const char* match_start = NULL; - int match_length = 0; - - for (;;) { - // ensure cur is not NULL. - // ensure p not NULL and has bytes to parse. - if (!path || length <= 0) { - break; - } - - const char* p = NULL; - for (p = path + 1; p - path < length && *p != SRS_CONSTS_HTTP_PATH_SEP; p++) { - } - - // whether the handler can handler the node. - const char* pchild = p; - if (!can_handle(path, p - path, &pchild)) { - break; - } - - // save current handler, it's ok for current handler atleast. - handler = this; - match_start = path; - match_length = p - path; - - // find the best matched child handler. - std::vector::iterator it; - for (it = handlers.begin(); it != handlers.end(); ++it) { - SrsHttpHandler* h = *it; - - // matched, donot search more. - if (h->best_match(pchild, length - (pchild - path), ppmatch) == ERROR_SUCCESS) { - break; - } - } - - // whatever, donot loop. - break; - } - - // if already matched by child, return. - if (*ppmatch) { - return ret; - } - - // not matched, error. - if (handler == NULL) { - ret = ERROR_HTTP_HANDLER_MATCH_URL; - return ret; - } - - // matched by this handler. - *ppmatch = new SrsHttpHandlerMatch(); - (*ppmatch)->handler = handler; - (*ppmatch)->matched_url.append(match_start, match_length); - - int unmatch_length = length - match_length; - if (unmatch_length > 0) { - (*ppmatch)->unmatched_url.append(match_start + match_length, unmatch_length); - } - - return ret; -} - -SrsHttpHandler* SrsHttpHandler::res_status_line(stringstream& ss) -{ - ss << "HTTP/1.1 200 OK " << __SRS_CRLF - << "Server: "RTMP_SIG_SRS_KEY"/"RTMP_SIG_SRS_VERSION"" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_status_line_error(stringstream& ss, int code, string reason_phrase) -{ - ss << "HTTP/1.1 " << code << " " << reason_phrase << __SRS_CRLF - << "Server: SRS/"RTMP_SIG_SRS_VERSION"" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_content_type(stringstream& ss) -{ - ss << "Content-Type: text/html;charset=utf-8" << __SRS_CRLF - << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_content_type_xml(stringstream& ss) -{ - ss << "Content-Type: text/xml;charset=utf-8" << __SRS_CRLF - << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_content_type_javascript(stringstream& ss) -{ - ss << "Content-Type: text/javascript" << __SRS_CRLF - << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_content_type_swf(stringstream& ss) -{ - ss << "Content-Type: application/x-shockwave-flash" << __SRS_CRLF - << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_content_type_css(stringstream& ss) -{ - ss << "Content-Type: text/css;charset=utf-8" << __SRS_CRLF - << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_content_type_ico(stringstream& ss) -{ - ss << "Content-Type: image/x-icon" << __SRS_CRLF - << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_content_type_json(stringstream& ss) -{ - ss << "Content-Type: application/json;charset=utf-8" << __SRS_CRLF - << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_content_type_m3u8(stringstream& ss) -{ - ss << "Content-Type: application/x-mpegURL;charset=utf-8" << __SRS_CRLF - << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_content_type_mpegts(stringstream& ss) -{ - ss << "Content-Type: video/MP2T" << __SRS_CRLF - << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_content_type_flv(stringstream& ss) -{ - ss << "Content-Type: video/x-flv" << __SRS_CRLF - << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_content_length(stringstream& ss, int64_t length) -{ - ss << "Content-Length: "<< length << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_enable_crossdomain(stringstream& ss) -{ - ss << "Access-Control-Allow-Origin: *" << __SRS_CRLF - << "Access-Control-Allow-Methods: " - << "GET, POST, HEAD, PUT, DELETE" << __SRS_CRLF - << "Access-Control-Allow-Headers: " - << "Cache-Control,X-Proxy-Authorization,X-Requested-With,Content-Type" << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_header_eof(stringstream& ss) -{ - ss << __SRS_CRLF; - return this; -} - -SrsHttpHandler* SrsHttpHandler::res_body(stringstream& ss, string body) -{ - ss << body; - return this; -} - -int SrsHttpHandler::res_flush(SrsStSocket* skt, stringstream& ss) -{ - return skt->write((void*)ss.str().c_str(), ss.str().length(), NULL); -} - -int SrsHttpHandler::res_options(SrsStSocket* skt) -{ - std::stringstream ss; - - res_status_line(ss)->res_content_type(ss) - ->res_content_length(ss, 0)->res_enable_crossdomain(ss) - ->res_header_eof(ss); - - return res_flush(skt, ss); -} - -int SrsHttpHandler::res_text(SrsStSocket* skt, SrsHttpMessage* req, string body) -{ - std::stringstream ss; - - res_status_line(ss)->res_content_type(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_xml(SrsStSocket* skt, SrsHttpMessage* req, string body) -{ - std::stringstream ss; - - res_status_line(ss)->res_content_type_xml(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_javascript(SrsStSocket* skt, SrsHttpMessage* req, string body) -{ - std::stringstream ss; - - res_status_line(ss)->res_content_type_javascript(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_swf(SrsStSocket* skt, SrsHttpMessage* req, string body) -{ - std::stringstream ss; - - res_status_line(ss)->res_content_type_swf(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_css(SrsStSocket* skt, SrsHttpMessage* req, string body) -{ - std::stringstream ss; - - res_status_line(ss)->res_content_type_css(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_ico(SrsStSocket* skt, SrsHttpMessage* req, string body) -{ - std::stringstream ss; - - res_status_line(ss)->res_content_type_ico(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_m3u8(SrsStSocket* skt, SrsHttpMessage* req, 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(SrsStSocket* skt, SrsHttpMessage* req, 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(SrsStSocket* skt, SrsHttpMessage* req, string json) -{ - std::stringstream ss; - - res_status_line(ss)->res_content_type_json(ss) - ->res_content_length(ss, (int)json.length()); - - if (req->requires_crossdomain()) { - res_enable_crossdomain(ss); - } - - res_header_eof(ss) - ->res_body(ss, json); - - return res_flush(skt, ss); -} - -int SrsHttpHandler::res_error(SrsStSocket* skt, SrsHttpMessage* req, int code, string reason_phrase, string body) -{ - std::stringstream ss; - - res_status_line_error(ss, code, reason_phrase)->res_content_type_json(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); -} - -#ifdef SRS_AUTO_HTTP_SERVER -SrsHttpHandler* SrsHttpHandler::create_http_stream() -{ - return new SrsHttpRoot(); -} -#endif - SrsHttpMessage::SrsHttpMessage() { _body = new SrsSimpleBuffer(); _state = SrsHttpParseStateInit; _uri = new SrsHttpUri(); - _match = NULL; - _requires_crossdomain = false; _http_ts_send_buffer = new char[__SRS_HTTP_TS_SEND_BUFFER_SIZE]; } @@ -1039,7 +637,6 @@ SrsHttpMessage::~SrsHttpMessage() { srs_freep(_body); srs_freep(_uri); - srs_freep(_match); srs_freep(_http_ts_send_buffer); } @@ -1204,16 +801,6 @@ int64_t SrsHttpMessage::content_length() return _header.content_length; } -SrsHttpHandlerMatch* SrsHttpMessage::match() -{ - return _match; -} - -bool SrsHttpMessage::requires_crossdomain() -{ - return _requires_crossdomain; -} - void SrsHttpMessage::set_url(string url) { _url = url; @@ -1229,17 +816,6 @@ void SrsHttpMessage::set_header(http_parser* header) memcpy(&_header, header, sizeof(http_parser)); } -void SrsHttpMessage::set_match(SrsHttpHandlerMatch* match) -{ - srs_freep(_match); - _match = match; -} - -void SrsHttpMessage::set_requires_crossdomain(bool requires_crossdomain) -{ - _requires_crossdomain = requires_crossdomain; -} - void SrsHttpMessage::append_body(const char* body, int length) { _body->append(body, length); diff --git a/trunk/src/app/srs_app_http.hpp b/trunk/src/app/srs_app_http.hpp index 0113f7fb5..a004c6e61 100644 --- a/trunk/src/app/srs_app_http.hpp +++ b/trunk/src/app/srs_app_http.hpp @@ -70,15 +70,6 @@ class ISrsGoHttpResponseWriter; // helper function: response in json format. extern int srs_go_http_response_json(ISrsGoHttpResponseWriter* w, std::string data); -// compare the path. -// full compare, extractly match. -// used for api match. -extern bool srs_path_equals(const char* expect, const char* path, int nb_path); -// compare the path use like, -// used for http stream to match, -// if the path like the requires -extern bool srs_path_like(const char* expect, const char* path, int nb_path); - // state of message enum SrsHttpParseState { SrsHttpParseStateInit = 0, @@ -196,6 +187,25 @@ public: virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r); }; +// FileServer returns a handler that serves HTTP requests +// with the contents of the file system rooted at root. +// +// To use the operating system's file system implementation, +// use http.Dir: +// +// http.Handle("/", SrsGoHttpFileServer("/tmp")) +// http.Handle("/", SrsGoHttpFileServer("static-dir")) +class SrsGoHttpFileServer : public ISrsGoHttpHandler +{ +private: + std::string dir; +public: + SrsGoHttpFileServer(std::string root_dir); + virtual ~SrsGoHttpFileServer(); +public: + virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r); +}; + // the mux entry for server mux. class SrsGoHttpMuxEntry { @@ -294,115 +304,6 @@ public: virtual int send_header(char* data, int size); }; -/** -* the matched handler info. -*/ -class SrsHttpHandlerMatch -{ -public: - SrsHttpHandler* handler; - std::string matched_url; - std::string unmatched_url; -public: - SrsHttpHandlerMatch(); -}; - -/** -* resource handler for HTTP RESTful api. -*/ -class SrsHttpHandler -{ -protected: - /** - * we use handler chain to process request. - */ - std::vector handlers; -public: - SrsHttpHandler(); - virtual ~SrsHttpHandler(); -public: - /** - * initialize the handler. - */ - virtual int initialize(); - /** - * whether current handler can handle the specified path. - * @pchild set the next child path, if needed. - * for example, the root handler will reset pchild to path, - * to reparse the path use child handlers. - */ - virtual bool can_handle(const char* path, int length, const char** pchild); - /** - * use the handler to process the request. - * @remark sub classes should override the do_process_request. - */ - virtual int process_request(SrsStSocket* skt, SrsHttpMessage* req); -public: - /** - * find the best matched handler - */ - virtual int best_match(const char* path, int length, SrsHttpHandlerMatch** ppmatch); -// factory methods -protected: - /** - * check whether the handler is valid. - * for example, user access /apis, actually it's not found, - * we will find the root handler to process it. - * @remark user can override this method, and should invoke it first. - * @see SrsApiRoot::is_handler_valid - */ - virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase); - /** - * do the actual process of request., format as, for example: - * {"code":0, "data":{}} - */ - virtual int do_process_request(SrsStSocket* skt, SrsHttpMessage* req); - /** - * response error, format as, for example: - * {"code":100, "desc":"description"} - */ - virtual int response_error(SrsStSocket* skt, SrsHttpMessage* req, int code, std::string desc); -// response writer -public: - virtual SrsHttpHandler* res_status_line(std::stringstream& ss); - 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_xml(std::stringstream& ss); - virtual SrsHttpHandler* res_content_type_javascript(std::stringstream& ss); - virtual SrsHttpHandler* res_content_type_swf(std::stringstream& ss); - virtual SrsHttpHandler* res_content_type_css(std::stringstream& ss); - virtual SrsHttpHandler* res_content_type_ico(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_type_flv(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); - virtual SrsHttpHandler* res_body(std::stringstream& ss, std::string body); - virtual int res_flush(SrsStSocket* skt, std::stringstream& ss); -public: - virtual int res_options(SrsStSocket* skt); - virtual int res_text(SrsStSocket* skt, SrsHttpMessage* req, std::string body); - virtual int res_xml(SrsStSocket* skt, SrsHttpMessage* req, std::string body); - virtual int res_javascript(SrsStSocket* skt, SrsHttpMessage* req, std::string body); - virtual int res_swf(SrsStSocket* skt, SrsHttpMessage* req, std::string body); - virtual int res_css(SrsStSocket* skt, SrsHttpMessage* req, std::string body); - virtual int res_ico(SrsStSocket* skt, SrsHttpMessage* req, std::string body); - virtual int res_m3u8(SrsStSocket* skt, SrsHttpMessage* req, std::string body); - virtual int res_mpegts(SrsStSocket* skt, SrsHttpMessage* req, std::string body); - virtual int res_json(SrsStSocket* skt, SrsHttpMessage* req, std::string json); - virtual int res_error(SrsStSocket* skt, SrsHttpMessage* req, int code, std::string reason_phrase, std::string body); -// object creator -public: - /** - * create http stream resource handler. - */ -#ifdef SRS_AUTO_HTTP_SERVER - static SrsHttpHandler* create_http_stream(); -#endif -}; - // A Request represents an HTTP request received by a server // or to be sent by a client. // @@ -438,14 +339,6 @@ private: */ SrsHttpUri* _uri; /** - * best matched handler. - */ - SrsHttpHandlerMatch* _match; - /** - * whether the message requires crossdomain. - */ - bool _requires_crossdomain; - /** * use a buffer to read and send ts file. */ char* _http_ts_send_buffer; @@ -481,13 +374,9 @@ public: virtual char* body_raw(); virtual int64_t body_size(); virtual int64_t content_length(); - virtual SrsHttpHandlerMatch* match(); - virtual bool requires_crossdomain(); virtual void set_url(std::string url); virtual void set_state(SrsHttpParseState state); virtual void set_header(http_parser* header); - virtual void set_match(SrsHttpHandlerMatch* match); - virtual void set_requires_crossdomain(bool requires_crossdomain); virtual void append_body(const char* body, int length); /** * get the param in query string, diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 3edeafa72..083e9f9b3 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -431,8 +431,6 @@ SrsGoApiVhosts::~SrsGoApiVhosts() int SrsGoApiVhosts::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) { - SrsHttpMessage* req = r; - std::stringstream data; SrsStatistic* stat = SrsStatistic::instance(); int ret = stat->dumps_vhosts(data); diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index a3ccef6e7..06ec9cef8 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -40,20 +40,16 @@ using namespace std; #include #include #include -#include -#define SRS_HTTP_DEFAULT_PAGE "index.html" - -SrsHttpRoot::SrsHttpRoot() -{ - // TODO: FIXME: support reload vhosts. -} - -SrsHttpRoot::~SrsHttpRoot() +SrsHttpServer::SrsHttpServer() { } -int SrsHttpRoot::initialize() +SrsHttpServer::~SrsHttpServer() +{ +} + +int SrsHttpServer::initialize() { int ret = ERROR_SUCCESS; @@ -76,7 +72,10 @@ int SrsHttpRoot::initialize() std::string mount = _srs_config->get_vhost_http_mount(vhost); std::string dir = _srs_config->get_vhost_http_dir(vhost); - handlers.push_back(new SrsHttpVhost(vhost, mount, dir)); + if ((ret = mux.handle(mount, new SrsGoHttpFileServer(dir))) != ERROR_SUCCESS) { + srs_error("http: mount dir=%s for vhost=%s failed. ret=%d", dir.c_str(), vhost.c_str(), ret); + return ret; + } if (mount == "/") { default_root_exists = true; @@ -85,299 +84,9 @@ int SrsHttpRoot::initialize() if (!default_root_exists) { // add root - handlers.push_back(new SrsHttpVhost( - "__http__", "/", _srs_config->get_http_stream_dir())); - } - - return ret; -} - -int SrsHttpRoot::best_match(const char* path, int length, SrsHttpHandlerMatch** ppmatch) -{ - int ret = ERROR_SUCCESS; - - // find the best matched child handler. - std::vector::iterator it; - for (it = handlers.begin(); it != handlers.end(); ++it) { - SrsHttpHandler* h = *it; - - // search all child handlers. - h->best_match(path, length, ppmatch); - } - - // if already matched by child, return. - if (*ppmatch) { - return ret; - } - - // not matched, error. - return ERROR_HTTP_HANDLER_MATCH_URL; -} - -bool SrsHttpRoot::is_handler_valid(SrsHttpMessage* /*req*/, int& status_code, std::string& reason_phrase) -{ - status_code = SRS_CONSTS_HTTP_InternalServerError; - reason_phrase = SRS_CONSTS_HTTP_InternalServerError_str; - - return false; -} - -int SrsHttpRoot::do_process_request(SrsStSocket* /*skt*/, SrsHttpMessage* /*req*/) -{ - int ret = ERROR_SUCCESS; - return ret; -} - -SrsHttpVhost::SrsHttpVhost(std::string vhost, std::string mount, std::string dir) -{ - _vhost = vhost; - _mount = mount; - _dir = dir; -} - -SrsHttpVhost::~SrsHttpVhost() -{ -} - -bool SrsHttpVhost::can_handle(const char* path, int length, const char** /*pchild*/) -{ - return srs_path_like(_mount.c_str(), path, length); -} - -bool SrsHttpVhost::is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase) -{ - std::string fullpath = get_request_file(req); - - if (::access(fullpath.c_str(), F_OK | R_OK) < 0) { - srs_warn("check file %s does not exists", fullpath.c_str()); - - status_code = SRS_CONSTS_HTTP_NotFound; - reason_phrase = SRS_CONSTS_HTTP_NotFound_str; - return false; - } - - return true; -} - -int SrsHttpVhost::do_process_request(SrsStSocket* skt, SrsHttpMessage* req) -{ - std::string fullpath = get_request_file(req); - - // TODO: FIXME: support mp4, @see https://github.com/winlinvip/simple-rtmp-server/issues/174 - if (srs_string_ends_with(fullpath, ".ts")) { - return response_ts_file(skt, req, fullpath); - } else if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) { - std::string start = req->query_get("start"); - if (start.empty()) { - return response_flv_file(skt, req, fullpath); - } - - int offset = ::atoi(start.c_str()); - if (offset <= 0) { - return response_flv_file(skt, req, fullpath); - } - - return response_flv_file2(skt, req, fullpath, offset); - } - - return response_regular_file(skt, req, fullpath); -} - -int SrsHttpVhost::response_regular_file(SrsStSocket* skt, SrsHttpMessage* req, string fullpath) -{ - int ret = ERROR_SUCCESS; - - SrsFileReader fs; - - if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) { - srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret); - return ret; - } - - int64_t length = fs.filesize(); - - char* buf = new char[length]; - SrsAutoFree(char, buf); - - if ((ret = fs.read(buf, length, NULL)) != ERROR_SUCCESS) { - srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret); - return ret; - } - - 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 if (srs_string_ends_with(fullpath, ".xml")) { - return res_xml(skt, req, str); - } else if (srs_string_ends_with(fullpath, ".js")) { - return res_javascript(skt, req, str); - } else if (srs_string_ends_with(fullpath, ".json")) { - return res_json(skt, req, str); - } else if (srs_string_ends_with(fullpath, ".swf")) { - return res_swf(skt, req, str); - } else if (srs_string_ends_with(fullpath, ".css")) { - return res_css(skt, req, str); - } else if (srs_string_ends_with(fullpath, ".ico")) { - return res_ico(skt, req, str); - } else { - return res_text(skt, req, str); - } - - return ret; -} - -int SrsHttpVhost::response_flv_file(SrsStSocket* skt, SrsHttpMessage* req, string fullpath) -{ - int ret = ERROR_SUCCESS; - - SrsFileReader fs; - - // TODO: FIXME: use more advance cache. - if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) { - srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret); - return ret; - } - - int64_t length = fs.filesize(); - - // write http header for ts. - std::stringstream ss; - - res_status_line(ss)->res_content_type_flv(ss) - ->res_content_length(ss, (int)length); - - if (req->requires_crossdomain()) { - res_enable_crossdomain(ss); - } - - res_header_eof(ss); - - // flush http header to peer - if ((ret = res_flush(skt, ss)) != ERROR_SUCCESS) { - return ret; - } - - // write body. - int64_t left = length; - char* buf = req->http_ts_send_buffer(); - - while (left > 0) { - ssize_t nread = -1; - if ((ret = fs.read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) { - srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret); - break; - } - - left -= nread; - if ((ret = skt->write(buf, nread, NULL)) != ERROR_SUCCESS) { - break; - } - } - - return ret; -} - -int SrsHttpVhost::response_flv_file2(SrsStSocket* skt, SrsHttpMessage* req, string fullpath, int offset) -{ - int ret = ERROR_SUCCESS; - - SrsFileReader fs; - - // open flv file - if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) { - return ret; - } - - if (offset > fs.filesize()) { - ret = ERROR_HTTP_FLV_OFFSET_OVERFLOW; - srs_warn("http flv streaming %s overflow. size=%"PRId64", offset=%d, ret=%d", - fullpath.c_str(), fs.filesize(), offset, ret); - return ret; - } - - SrsFlvVodStreamDecoder ffd; - - // open fast decoder - if ((ret = ffd.initialize(&fs)) != ERROR_SUCCESS) { - return ret; - } - - // save header, send later. - char flv_header[13]; - - // send flv header - if ((ret = ffd.read_header_ext(flv_header)) != ERROR_SUCCESS) { - return ret; - } - - // save sequence header, send later - char* sh_data = NULL; - int sh_size = 0; - - if (true) { - // send sequence header - int64_t start = 0; - if ((ret = ffd.read_sequence_header_summary(&start, &sh_size)) != ERROR_SUCCESS) { - return ret; - } - if (sh_size <= 0) { - ret = ERROR_HTTP_FLV_SEQUENCE_HEADER; - srs_warn("http flv streaming no sequence header. size=%d, ret=%d", sh_size, ret); - return ret; - } - } - sh_data = new char[sh_size]; - SrsAutoFree(char, sh_data); - if ((ret = fs.read(sh_data, sh_size, NULL)) != ERROR_SUCCESS) { - return ret; - } - - // seek to data offset - int64_t left = fs.filesize() - offset; - - // write http header for ts. - std::stringstream ss; - - res_status_line(ss)->res_content_type_flv(ss) - ->res_content_length(ss, (int)(sizeof(flv_header) + sh_size + left)); - - if (req->requires_crossdomain()) { - res_enable_crossdomain(ss); - } - - res_header_eof(ss); - - // flush http header to peer - if ((ret = res_flush(skt, ss)) != ERROR_SUCCESS) { - return ret; - } - - if ((ret = skt->write(flv_header, sizeof(flv_header), NULL)) != ERROR_SUCCESS) { - return ret; - } - if (sh_size > 0 && (ret = skt->write(sh_data, sh_size, NULL)) != ERROR_SUCCESS) { - return ret; - } - - // write body. - char* buf = req->http_ts_send_buffer(); - if ((ret = ffd.lseek(offset)) != ERROR_SUCCESS) { - return ret; - } - - // send data - while (left > 0) { - ssize_t nread = -1; - if ((ret = fs.read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) { - return ret; - } - - left -= nread; - if ((ret = skt->write(buf, nread, NULL)) != ERROR_SUCCESS) { + std::string dir = _srs_config->get_http_stream_dir(); + if ((ret = mux.handle("/", new SrsGoHttpFileServer(dir))) != ERROR_SUCCESS) { + srs_error("http: mount root dir=%s failed. ret=%d", dir.c_str(), ret); return ret; } } @@ -385,103 +94,11 @@ int SrsHttpVhost::response_flv_file2(SrsStSocket* skt, SrsHttpMessage* req, stri return ret; } -int SrsHttpVhost::response_ts_file(SrsStSocket* skt, SrsHttpMessage* req, string fullpath) -{ - int ret = ERROR_SUCCESS; - - SrsFileReader fs; - - // TODO: FIXME: use more advance cache. - if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) { - srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret); - return ret; - } - - int64_t length = fs.filesize(); - - // write http header for ts. - std::stringstream ss; - - res_status_line(ss)->res_content_type_mpegts(ss) - ->res_content_length(ss, (int)length); - - if (req->requires_crossdomain()) { - res_enable_crossdomain(ss); - } - - res_header_eof(ss); - - // flush http header to peer - if ((ret = res_flush(skt, ss)) != ERROR_SUCCESS) { - return ret; - } - - // write body. - int64_t left = length; - char* buf = req->http_ts_send_buffer(); - - while (left > 0) { - ssize_t nread = -1; - if ((ret = fs.read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) { - srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret); - break; - } - - left -= nread; - if ((ret = skt->write(buf, nread, NULL)) != ERROR_SUCCESS) { - break; - } - } - - return ret; -} - -string SrsHttpVhost::get_request_file(SrsHttpMessage* req) -{ - std::string fullpath = _dir + "/"; - - // if root, directly use the matched url. - if (_mount == "/") { - // add the dir - fullpath += req->match()->matched_url; - // if file speicified, add the file. - if (!req->match()->unmatched_url.empty()) { - fullpath += "/" + req->match()->unmatched_url; - } - } else { - // virtual path, ignore the virutal path. - fullpath += req->match()->unmatched_url; - } - - // add default pages. - if (srs_string_ends_with(fullpath, "/")) { - fullpath += SRS_HTTP_DEFAULT_PAGE; - } - - return fullpath; -} - -string SrsHttpVhost::vhost() -{ - return _vhost; -} - -string SrsHttpVhost::mount() -{ - return _mount; -} - -string SrsHttpVhost::dir() -{ - return _dir; -} - -SrsHttpConn::SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd, SrsHttpHandler* _handler) - : SrsConnection(srs_server, client_stfd) +SrsHttpConn::SrsHttpConn(SrsServer* svr, st_netfd_t fd, SrsHttpServer* m) + : SrsConnection(svr, fd) { parser = new SrsHttpParser(); - handler = _handler; - requires_crossdomain = false; + mux = m; } SrsHttpConn::~SrsHttpConn() @@ -538,7 +155,8 @@ int SrsHttpConn::do_cycle() SrsAutoFree(SrsHttpMessage, req); // ok, handle http request. - if ((ret = process_request(&skt, req)) != ERROR_SUCCESS) { + SrsGoHttpResponseWriter writer(&skt); + if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) { return ret; } } @@ -546,41 +164,21 @@ int SrsHttpConn::do_cycle() return ret; } -int SrsHttpConn::process_request(SrsStSocket* skt, SrsHttpMessage* req) +int SrsHttpConn::process_request(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) { int ret = ERROR_SUCCESS; srs_trace("HTTP %s %s, content-length=%"PRId64"", - req->method_str().c_str(), req->url().c_str(), req->content_length()); + r->method_str().c_str(), r->url().c_str(), r->content_length()); - // TODO: maybe need to parse the url. - std::string url = req->path(); - - SrsHttpHandlerMatch* p = NULL; - if ((ret = handler->best_match(url.data(), url.length(), &p)) != ERROR_SUCCESS) { - srs_warn("failed to find the best match handler for url. ret=%d", ret); + // use default server mux to serve http request. + if ((ret = mux->mux.serve_http(w, r)) != ERROR_SUCCESS) { + if (!srs_is_client_gracefully_close(ret)) { + srs_error("serve http msg failed. ret=%d", ret); + } return ret; } - // if success, p and pstart should be valid. - srs_assert(p); - srs_assert(p->handler); - srs_assert(p->matched_url.length() <= url.length()); - srs_info("best match handler, matched_url=%s", p->matched_url.c_str()); - - req->set_match(p); - req->set_requires_crossdomain(requires_crossdomain); - - // use handler to process request. - if ((ret = p->handler->process_request(skt, req)) != ERROR_SUCCESS) { - srs_warn("handler failed to process http request. ret=%d", ret); - return ret; - } - - if (req->requires_crossdomain()) { - requires_crossdomain = true; - } - return ret; } diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index d222f7760..e258fea85 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -41,54 +41,25 @@ class SrsHttpParser; class SrsHttpMessage; class SrsHttpHandler; -// for http root. -class SrsHttpRoot : public SrsHttpHandler +// for http server. +class SrsHttpServer { public: - SrsHttpRoot(); - virtual ~SrsHttpRoot(); + SrsGoHttpServeMux mux; +public: + SrsHttpServer(); + virtual ~SrsHttpServer(); public: virtual int initialize(); - virtual int best_match(const char* path, int length, SrsHttpHandlerMatch** ppmatch); -protected: - virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase); - virtual int do_process_request(SrsStSocket* skt, SrsHttpMessage* req); -}; - -class SrsHttpVhost : public SrsHttpHandler -{ -private: - std::string _vhost; - std::string _mount; - std::string _dir; -public: - SrsHttpVhost(std::string vhost, std::string mount, std::string dir); - 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(SrsStSocket* skt, SrsHttpMessage* req); -private: - virtual int response_regular_file(SrsStSocket* skt, SrsHttpMessage* req, std::string fullpath); - virtual int response_flv_file(SrsStSocket* skt, SrsHttpMessage* req, std::string fullpath); - virtual int response_flv_file2(SrsStSocket* skt, SrsHttpMessage* req, std::string fullpath, int offset); - virtual int response_ts_file(SrsStSocket* skt, SrsHttpMessage* req, std::string fullpath); - virtual std::string get_request_file(SrsHttpMessage* req); -public: - virtual std::string vhost(); - virtual std::string mount(); - virtual std::string dir(); }; class SrsHttpConn : public SrsConnection { private: SrsHttpParser* parser; - SrsHttpHandler* handler; - bool requires_crossdomain; + SrsHttpServer* mux; public: - SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd, SrsHttpHandler* _handler); + SrsHttpConn(SrsServer* svr, st_netfd_t fd, SrsHttpServer* m); virtual ~SrsHttpConn(); public: virtual void kbps_resample(); @@ -99,7 +70,7 @@ public: protected: virtual int do_cycle(); private: - virtual int process_request(SrsStSocket* skt, SrsHttpMessage* req); + virtual int process_request(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r); }; #endif diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index ca96062bc..c754fc47f 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -333,7 +333,7 @@ SrsServer::SrsServer() http_api_mux = new SrsGoHttpServeMux(); #endif #ifdef SRS_AUTO_HTTP_SERVER - http_stream_handler = NULL; + http_stream_mux = new SrsHttpServer(); #endif #ifdef SRS_AUTO_HTTP_PARSER http_heartbeat = NULL; @@ -367,7 +367,7 @@ void SrsServer::destroy() #endif #ifdef SRS_AUTO_HTTP_SERVER - srs_freep(http_stream_handler); + srs_freep(http_stream_mux); #endif #ifdef SRS_AUTO_HTTP_PARSER @@ -462,25 +462,24 @@ int SrsServer::initialize() return ret; } #endif + #ifdef SRS_AUTO_HTTP_SERVER - srs_assert(!http_stream_handler); - http_stream_handler = SrsHttpHandler::create_http_stream(); + srs_assert(http_stream_mux); + if ((ret = http_stream_mux->initialize()) != ERROR_SUCCESS) { + return ret; + } #endif + #ifdef SRS_AUTO_HTTP_PARSER srs_assert(!http_heartbeat); http_heartbeat = new SrsHttpHeartbeat(); #endif + #ifdef SRS_AUTO_INGEST srs_assert(!ingester); ingester = new SrsIngester(); #endif -#ifdef SRS_AUTO_HTTP_SERVER - if ((ret = http_stream_handler->initialize()) != ERROR_SUCCESS) { - return ret; - } -#endif - return ret; } @@ -942,7 +941,7 @@ int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd) #endif } else if (type == SrsListenerHttpStream) { #ifdef SRS_AUTO_HTTP_SERVER - conn = new SrsHttpConn(this, client_stfd, http_stream_handler); + conn = new SrsHttpConn(this, client_stfd, http_stream_mux); #else srs_warn("close http client for server not support http-server"); srs_close_stfd(client_stfd); @@ -1019,10 +1018,10 @@ int SrsServer::on_reload_vhost_http_updated() int ret = ERROR_SUCCESS; #ifdef SRS_AUTO_HTTP_SERVER - srs_freep(http_stream_handler); - http_stream_handler = SrsHttpHandler::create_http_stream(); + srs_freep(http_stream_mux); + http_stream_mux = new SrsHttpServer(); - if ((ret = http_stream_handler->initialize()) != ERROR_SUCCESS) { + if ((ret = http_stream_mux->initialize()) != ERROR_SUCCESS) { return ret; } #endif diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 69e57885d..1380d9a97 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -39,7 +39,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class SrsServer; class SrsConnection; class SrsGoHttpServeMux; -class SrsHttpHandler; +class SrsHttpServer; class SrsIngester; class SrsHttpHeartbeat; class SrsKbps; @@ -120,7 +120,7 @@ private: SrsGoHttpServeMux* http_api_mux; #endif #ifdef SRS_AUTO_HTTP_SERVER - SrsHttpHandler* http_stream_handler; + SrsHttpServer* http_stream_mux; #endif #ifdef SRS_AUTO_HTTP_PARSER SrsHttpHeartbeat* http_heartbeat; diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 945f2232d..aabdfb6f7 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR 2 #define VERSION_MINOR 0 -#define VERSION_REVISION 96 +#define VERSION_REVISION 98 // server info. #define RTMP_SIG_SRS_KEY "SRS"