winlin

implements the http stream module.

@@ -76,6 +76,9 @@ http_stream { @@ -76,6 +76,9 @@ http_stream {
76 # @remark, if use lower port, for instance 80, user must start srs by root. 76 # @remark, if use lower port, for instance 80, user must start srs by root.
77 # default: 8080 77 # default: 8080
78 listen 8080; 78 listen 8080;
  79 + # the default dir for http root.
  80 + # default: ./objs/nginx/html
  81 + dir ./objs/nginx/html;
79 } 82 }
80 83
81 ############################################################################################# 84 #############################################################################################
@@ -1746,15 +1746,16 @@ int SrsConfig::get_http_api_listen() @@ -1746,15 +1746,16 @@ int SrsConfig::get_http_api_listen()
1746 { 1746 {
1747 SrsConfDirective* conf = get_http_api(); 1747 SrsConfDirective* conf = get_http_api();
1748 1748
1749 - if (conf) {  
1750 - conf = conf->get("listen");  
1751 -  
1752 - if (conf && !conf->arg0().empty()) {  
1753 - return ::atoi(conf->arg0().c_str());  
1754 - } 1749 + if (!conf) {
  1750 + return SRS_CONF_DEFAULT_HTTP_API_PORT;
1755 } 1751 }
1756 1752
1757 - return 1985; 1753 + conf = conf->get("listen");
  1754 + if (!conf || conf->arg0().empty()) {
  1755 + return SRS_CONF_DEFAULT_HTTP_API_PORT;
  1756 + }
  1757 +
  1758 + return ::atoi(conf->arg0().c_str());
1758 } 1759 }
1759 1760
1760 SrsConfDirective* SrsConfig::get_http_stream() 1761 SrsConfDirective* SrsConfig::get_http_stream()
@@ -1765,13 +1766,11 @@ SrsConfDirective* SrsConfig::get_http_stream() @@ -1765,13 +1766,11 @@ SrsConfDirective* SrsConfig::get_http_stream()
1765 bool SrsConfig::get_http_stream_enabled() 1766 bool SrsConfig::get_http_stream_enabled()
1766 { 1767 {
1767 SrsConfDirective* conf = get_http_stream(); 1768 SrsConfDirective* conf = get_http_stream();
1768 -  
1769 if (!conf) { 1769 if (!conf) {
1770 return false; 1770 return false;
1771 } 1771 }
1772 1772
1773 conf = conf->get("enabled"); 1773 conf = conf->get("enabled");
1774 -  
1775 if (conf && conf->arg0() == "on") { 1774 if (conf && conf->arg0() == "on") {
1776 return true; 1775 return true;
1777 } 1776 }
@@ -1783,15 +1782,35 @@ int SrsConfig::get_http_stream_listen() @@ -1783,15 +1782,35 @@ int SrsConfig::get_http_stream_listen()
1783 { 1782 {
1784 SrsConfDirective* conf = get_http_stream(); 1783 SrsConfDirective* conf = get_http_stream();
1785 1784
1786 - if (conf) {  
1787 - conf = conf->get("listen");  
1788 -  
1789 - if (conf && !conf->arg0().empty()) {  
1790 - return ::atoi(conf->arg0().c_str());  
1791 - } 1785 + if (!conf) {
  1786 + return SRS_CONF_DEFAULT_HTTP_STREAM_PORT;
  1787 + }
  1788 +
  1789 + conf = conf->get("listen");
  1790 + if (!conf || conf->arg0().empty()) {
  1791 + return SRS_CONF_DEFAULT_HTTP_STREAM_PORT;
1792 } 1792 }
1793 1793
1794 - return 8080; 1794 + return ::atoi(conf->arg0().c_str());
  1795 +}
  1796 +
  1797 +string SrsConfig::get_http_stream_dir()
  1798 +{
  1799 + SrsConfDirective* conf = get_http_stream();
  1800 + if (!conf) {
  1801 + return SRS_CONF_DEFAULT_HTTP_DIR;
  1802 + }
  1803 +
  1804 + conf = conf->get("dir");
  1805 + if (!conf) {
  1806 + return SRS_CONF_DEFAULT_HTTP_DIR;
  1807 + }
  1808 +
  1809 + if (conf->arg0().empty()) {
  1810 + return SRS_CONF_DEFAULT_HTTP_DIR;
  1811 + }
  1812 +
  1813 + return conf->arg0();
1795 } 1814 }
1796 1815
1797 bool SrsConfig::get_vhost_http_enabled(string vhost) 1816 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. @@ -59,6 +59,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
59 #define SRS_CONF_DEFAULT_HTTP_MOUNT "/" 59 #define SRS_CONF_DEFAULT_HTTP_MOUNT "/"
60 #define SRS_CONF_DEFAULT_HTTP_DIR SRS_CONF_DEFAULT_HLS_PATH 60 #define SRS_CONF_DEFAULT_HTTP_DIR SRS_CONF_DEFAULT_HLS_PATH
61 61
  62 +#define SRS_CONF_DEFAULT_HTTP_STREAM_PORT 8080
  63 +#define SRS_CONF_DEFAULT_HTTP_API_PORT 1985
  64 +
62 #define SRS_STAGE_PLAY_USER_INTERVAL_MS 1300 65 #define SRS_STAGE_PLAY_USER_INTERVAL_MS 1300
63 #define SRS_STAGE_PUBLISH_USER_INTERVAL_MS 1100 66 #define SRS_STAGE_PUBLISH_USER_INTERVAL_MS 1100
64 #define SRS_STAGE_FORWARDER_INTERVAL_MS 2000 67 #define SRS_STAGE_FORWARDER_INTERVAL_MS 2000
@@ -207,6 +210,7 @@ private: @@ -207,6 +210,7 @@ private:
207 public: 210 public:
208 virtual bool get_http_stream_enabled(); 211 virtual bool get_http_stream_enabled();
209 virtual int get_http_stream_listen(); 212 virtual int get_http_stream_listen();
  213 + virtual std::string get_http_stream_dir();
210 public: 214 public:
211 virtual bool get_vhost_http_enabled(std::string vhost); 215 virtual bool get_vhost_http_enabled(std::string vhost);
212 virtual std::string get_vhost_http_mount(std::string vhost); 216 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) @@ -48,7 +48,8 @@ bool srs_path_equals(const char* expect, const char* path, int nb_path)
48 return false; 48 return false;
49 } 49 }
50 50
51 - return !memcmp(expect, path, size); 51 + bool equals = !memcmp(expect, path, size);
  52 + return equals;
52 } 53 }
53 54
54 SrsHttpHandlerMatch::SrsHttpHandlerMatch() 55 SrsHttpHandlerMatch::SrsHttpHandlerMatch()
@@ -223,6 +224,20 @@ SrsHttpHandler* SrsHttpHandler::res_content_type_json(std::stringstream& ss) @@ -223,6 +224,20 @@ SrsHttpHandler* SrsHttpHandler::res_content_type_json(std::stringstream& ss)
223 return this; 224 return this;
224 } 225 }
225 226
  227 +SrsHttpHandler* SrsHttpHandler::res_content_type_m3u8(std::stringstream& ss)
  228 +{
  229 + ss << "Content-Type: application/x-mpegURL;charset=utf-8" << __CRLF
  230 + << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF;
  231 + return this;
  232 +}
  233 +
  234 +SrsHttpHandler* SrsHttpHandler::res_content_type_mpegts(std::stringstream& ss)
  235 +{
  236 + ss << "Content-Type: video/MP2T;charset=utf-8" << __CRLF
  237 + << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF;
  238 + return this;
  239 +}
  240 +
226 SrsHttpHandler* SrsHttpHandler::res_content_length(std::stringstream& ss, int64_t length) 241 SrsHttpHandler* SrsHttpHandler::res_content_length(std::stringstream& ss, int64_t length)
227 { 242 {
228 ss << "Content-Length: "<< length << __CRLF; 243 ss << "Content-Length: "<< length << __CRLF;
@@ -284,6 +299,40 @@ int SrsHttpHandler::res_text(SrsSocket* skt, SrsHttpMessage* req, std::string bo @@ -284,6 +299,40 @@ int SrsHttpHandler::res_text(SrsSocket* skt, SrsHttpMessage* req, std::string bo
284 return res_flush(skt, ss); 299 return res_flush(skt, ss);
285 } 300 }
286 301
  302 +int SrsHttpHandler::res_m3u8(SrsSocket* skt, SrsHttpMessage* req, std::string body)
  303 +{
  304 + std::stringstream ss;
  305 +
  306 + res_status_line(ss)->res_content_type_m3u8(ss)
  307 + ->res_content_length(ss, (int)body.length());
  308 +
  309 + if (req->requires_crossdomain()) {
  310 + res_enable_crossdomain(ss);
  311 + }
  312 +
  313 + res_header_eof(ss)
  314 + ->res_body(ss, body);
  315 +
  316 + return res_flush(skt, ss);
  317 +}
  318 +
  319 +int SrsHttpHandler::res_mpegts(SrsSocket* skt, SrsHttpMessage* req, std::string body)
  320 +{
  321 + std::stringstream ss;
  322 +
  323 + res_status_line(ss)->res_content_type_mpegts(ss)
  324 + ->res_content_length(ss, (int)body.length());
  325 +
  326 + if (req->requires_crossdomain()) {
  327 + res_enable_crossdomain(ss);
  328 + }
  329 +
  330 + res_header_eof(ss)
  331 + ->res_body(ss, body);
  332 +
  333 + return res_flush(skt, ss);
  334 +}
  335 +
287 int SrsHttpHandler::res_json(SrsSocket* skt, SrsHttpMessage* req, std::string json) 336 int SrsHttpHandler::res_json(SrsSocket* skt, SrsHttpMessage* req, std::string json)
288 { 337 {
289 std::stringstream ss; 338 std::stringstream ss;
@@ -229,6 +229,8 @@ public: @@ -229,6 +229,8 @@ public:
229 virtual SrsHttpHandler* res_status_line_error(std::stringstream& ss, int code, std::string reason_phrase); 229 virtual SrsHttpHandler* res_status_line_error(std::stringstream& ss, int code, std::string reason_phrase);
230 virtual SrsHttpHandler* res_content_type(std::stringstream& ss); 230 virtual SrsHttpHandler* res_content_type(std::stringstream& ss);
231 virtual SrsHttpHandler* res_content_type_json(std::stringstream& ss); 231 virtual SrsHttpHandler* res_content_type_json(std::stringstream& ss);
  232 + virtual SrsHttpHandler* res_content_type_m3u8(std::stringstream& ss);
  233 + virtual SrsHttpHandler* res_content_type_mpegts(std::stringstream& ss);
232 virtual SrsHttpHandler* res_content_length(std::stringstream& ss, int64_t length); 234 virtual SrsHttpHandler* res_content_length(std::stringstream& ss, int64_t length);
233 virtual SrsHttpHandler* res_enable_crossdomain(std::stringstream& ss); 235 virtual SrsHttpHandler* res_enable_crossdomain(std::stringstream& ss);
234 virtual SrsHttpHandler* res_header_eof(std::stringstream& ss); 236 virtual SrsHttpHandler* res_header_eof(std::stringstream& ss);
@@ -237,6 +239,8 @@ public: @@ -237,6 +239,8 @@ public:
237 public: 239 public:
238 virtual int res_options(SrsSocket* skt); 240 virtual int res_options(SrsSocket* skt);
239 virtual int res_text(SrsSocket* skt, SrsHttpMessage* req, std::string body); 241 virtual int res_text(SrsSocket* skt, SrsHttpMessage* req, std::string body);
  242 + virtual int res_m3u8(SrsSocket* skt, SrsHttpMessage* req, std::string body);
  243 + virtual int res_mpegts(SrsSocket* skt, SrsHttpMessage* req, std::string body);
240 virtual int res_json(SrsSocket* skt, SrsHttpMessage* req, std::string json); 244 virtual int res_json(SrsSocket* skt, SrsHttpMessage* req, std::string json);
241 virtual int res_error(SrsSocket* skt, SrsHttpMessage* req, int code, std::string reason_phrase, std::string body); 245 virtual int res_error(SrsSocket* skt, SrsHttpMessage* req, int code, std::string reason_phrase, std::string body);
242 // object creator 246 // object creator
@@ -49,6 +49,7 @@ public: @@ -49,6 +49,7 @@ public:
49 virtual ~SrsApiRoot(); 49 virtual ~SrsApiRoot();
50 public: 50 public:
51 virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase); 51 virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase);
  52 +protected:
52 virtual bool can_handle(const char* path, int length, const char** pchild); 53 virtual bool can_handle(const char* path, int length, const char** pchild);
53 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); 54 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
54 }; 55 };
@@ -60,6 +61,7 @@ public: @@ -60,6 +61,7 @@ public:
60 virtual ~SrsApiApi(); 61 virtual ~SrsApiApi();
61 public: 62 public:
62 virtual bool can_handle(const char* path, int length, const char** pchild); 63 virtual bool can_handle(const char* path, int length, const char** pchild);
  64 +protected:
63 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); 65 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
64 }; 66 };
65 67
@@ -70,6 +72,7 @@ public: @@ -70,6 +72,7 @@ public:
70 virtual ~SrsApiV1(); 72 virtual ~SrsApiV1();
71 public: 73 public:
72 virtual bool can_handle(const char* path, int length, const char** pchild); 74 virtual bool can_handle(const char* path, int length, const char** pchild);
  75 +protected:
73 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); 76 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
74 }; 77 };
75 78
@@ -80,6 +83,7 @@ public: @@ -80,6 +83,7 @@ public:
80 virtual ~SrsApiVersion(); 83 virtual ~SrsApiVersion();
81 public: 84 public:
82 virtual bool can_handle(const char* path, int length, const char** pchild); 85 virtual bool can_handle(const char* path, int length, const char** pchild);
  86 +protected:
83 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); 87 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
84 }; 88 };
85 89
@@ -90,6 +94,7 @@ public: @@ -90,6 +94,7 @@ public:
90 virtual ~SrsApiAuthors(); 94 virtual ~SrsApiAuthors();
91 public: 95 public:
92 virtual bool can_handle(const char* path, int length, const char** pchild); 96 virtual bool can_handle(const char* path, int length, const char** pchild);
  97 +protected:
93 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); 98 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
94 }; 99 };
95 100
@@ -28,6 +28,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -28,6 +28,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include <sstream> 28 #include <sstream>
29 using namespace std; 29 using namespace std;
30 30
  31 +#include <sys/types.h>
  32 +#include <sys/stat.h>
  33 +#include <fcntl.h>
  34 +
31 #include <srs_kernel_log.hpp> 35 #include <srs_kernel_log.hpp>
32 #include <srs_kernel_error.hpp> 36 #include <srs_kernel_error.hpp>
33 #include <srs_app_socket.hpp> 37 #include <srs_app_socket.hpp>
@@ -48,7 +52,11 @@ SrsHttpRoot::~SrsHttpRoot() @@ -48,7 +52,11 @@ SrsHttpRoot::~SrsHttpRoot()
48 int SrsHttpRoot::initialize() 52 int SrsHttpRoot::initialize()
49 { 53 {
50 int ret = ERROR_SUCCESS; 54 int ret = ERROR_SUCCESS;
  55 +
  56 + // add root
  57 + handlers.push_back(new SrsHttpVhost("__http__", "/", _srs_config->get_http_stream_dir()));
51 58
  59 + // add other virtual path
52 SrsConfDirective* root = _srs_config->get_root(); 60 SrsConfDirective* root = _srs_config->get_root();
53 for (int i = 0; i < (int)root->directives.size(); i++) { 61 for (int i = 0; i < (int)root->directives.size(); i++) {
54 SrsConfDirective* conf = root->at(i); 62 SrsConfDirective* conf = root->at(i);
@@ -71,6 +79,16 @@ int SrsHttpRoot::initialize() @@ -71,6 +79,16 @@ int SrsHttpRoot::initialize()
71 return ret; 79 return ret;
72 } 80 }
73 81
  82 +bool SrsHttpRoot::can_handle(const char* path, int length, const char** pchild)
  83 +{
  84 + // reset the child path to path,
  85 + // for child to reparse the path.
  86 + *pchild = path;
  87 +
  88 + // only compare the first char.
  89 + return srs_path_equals("/", path, 1);
  90 +}
  91 +
74 bool SrsHttpRoot::is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase) 92 bool SrsHttpRoot::is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase)
75 { 93 {
76 if (!SrsHttpHandler::is_handler_valid(req, status_code, reason_phrase)) { 94 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 @@ -86,16 +104,6 @@ bool SrsHttpRoot::is_handler_valid(SrsHttpMessage* req, int& status_code, std::s
86 return true; 104 return true;
87 } 105 }
88 106
89 -bool SrsHttpRoot::can_handle(const char* path, int length, const char** pchild)  
90 -{  
91 - // reset the child path to path,  
92 - // for child to reparse the path.  
93 - *pchild = path;  
94 -  
95 - // only compare the first char.  
96 - return srs_path_equals("/", path, 1);  
97 -}  
98 -  
99 int SrsHttpRoot::do_process_request(SrsSocket* skt, SrsHttpMessage* req) 107 int SrsHttpRoot::do_process_request(SrsSocket* skt, SrsHttpMessage* req)
100 { 108 {
101 std::stringstream ss; 109 std::stringstream ss;
@@ -139,21 +147,74 @@ SrsHttpVhost::~SrsHttpVhost() @@ -139,21 +147,74 @@ SrsHttpVhost::~SrsHttpVhost()
139 147
140 bool SrsHttpVhost::can_handle(const char* path, int length, const char** /*pchild*/) 148 bool SrsHttpVhost::can_handle(const char* path, int length, const char** /*pchild*/)
141 { 149 {
142 - return srs_path_equals("/api", path, length); 150 + int min_match = srs_min(length, (int)_mount.length());
  151 + return srs_path_equals(_mount.c_str(), path, min_match);
  152 +}
  153 +
  154 +bool SrsHttpVhost::is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase)
  155 +{
  156 + std::string fullpath = _dir + "/" + req->match()->unmatched_url;
  157 + if (req->match()->unmatched_url.empty()) {
  158 + fullpath += req->match()->matched_url;
  159 + }
  160 +
  161 + if (::access(fullpath.c_str(), F_OK | R_OK) < 0) {
  162 + srs_warn("check file %s does not exists", fullpath.c_str());
  163 +
  164 + status_code = HTTP_NotFound;
  165 + reason_phrase = HTTP_NotFound_str;
  166 + return false;
  167 + }
  168 +
  169 + return true;
143 } 170 }
144 171
145 int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req) 172 int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req)
146 { 173 {
147 - std::stringstream ss; 174 + int ret = ERROR_SUCCESS;
148 175
149 - ss << JOBJECT_START  
150 - << JFIELD_ERROR(ERROR_SUCCESS) << JFIELD_CONT  
151 - << JFIELD_ORG("urls", JOBJECT_START)  
152 - << JFIELD_STR("v1", "the api version 1.0")  
153 - << JOBJECT_END  
154 - << JOBJECT_END; 176 + std::string fullpath = _dir + "/" + req->match()->unmatched_url;
  177 + if (req->match()->unmatched_url.empty()) {
  178 + fullpath += req->match()->matched_url;
  179 + }
155 180
156 - return res_json(skt, req, ss.str()); 181 + if (srs_string_ends_with(fullpath, "/")) {
  182 + fullpath += "index.html";
  183 + }
  184 +
  185 + int fd = ::open(fullpath.c_str(), O_RDONLY);
  186 + if (fd < 0) {
  187 + ret = ERROR_HTTP_OPEN_FILE;
  188 + srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret);
  189 + return ret;
  190 + }
  191 +
  192 + int64_t length = (int64_t)::lseek(fd, 0, SEEK_END);
  193 + ::lseek(fd, 0, SEEK_SET);
  194 +
  195 + char* buf = new char[length];
  196 + SrsAutoFree(char, buf, true);
  197 +
  198 + if (::read(fd, buf, length) < 0) {
  199 + ::close(fd);
  200 + ret = ERROR_HTTP_READ_FILE;
  201 + srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret);
  202 + return ret;
  203 + }
  204 + ::close(fd);
  205 +
  206 + std::string str;
  207 + str.append(buf, length);
  208 +
  209 + if (srs_string_ends_with(fullpath, ".ts")) {
  210 + return res_mpegts(skt, req, str);
  211 + } else if (srs_string_ends_with(fullpath, ".m3u8")) {
  212 + return res_m3u8(skt, req, str);
  213 + } else {
  214 + return res_text(skt, req, str);
  215 + }
  216 +
  217 + return ret;
157 } 218 }
158 219
159 string SrsHttpVhost::vhost() 220 string SrsHttpVhost::vhost()
@@ -49,8 +49,9 @@ public: @@ -49,8 +49,9 @@ public:
49 virtual ~SrsHttpRoot(); 49 virtual ~SrsHttpRoot();
50 public: 50 public:
51 virtual int initialize(); 51 virtual int initialize();
52 - virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase);  
53 virtual bool can_handle(const char* path, int length, const char** pchild); 52 virtual bool can_handle(const char* path, int length, const char** pchild);
  53 +protected:
  54 + virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase);
54 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); 55 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
55 }; 56 };
56 57
@@ -65,6 +66,8 @@ public: @@ -65,6 +66,8 @@ public:
65 virtual ~SrsHttpVhost(); 66 virtual ~SrsHttpVhost();
66 public: 67 public:
67 virtual bool can_handle(const char* path, int length, const char** pchild); 68 virtual bool can_handle(const char* path, int length, const char** pchild);
  69 +protected:
  70 + virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase);
68 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); 71 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
69 public: 72 public:
70 virtual std::string vhost(); 73 virtual std::string vhost();
@@ -85,6 +85,11 @@ string srs_string_remove(string str, string remove_chars) @@ -85,6 +85,11 @@ string srs_string_remove(string str, string remove_chars)
85 return ret; 85 return ret;
86 } 86 }
87 87
  88 +bool srs_string_ends_with(string str, string flag)
  89 +{
  90 + return str.rfind(flag) == str.length() - flag.length();
  91 +}
  92 +
88 string srs_dns_resolve(string host) 93 string srs_dns_resolve(string host)
89 { 94 {
90 if (inet_addr(host.c_str()) != INADDR_NONE) { 95 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. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR "0" 32 #define VERSION_MAJOR "0"
33 #define VERSION_MINOR "9" 33 #define VERSION_MINOR "9"
34 -#define VERSION_REVISION "48" 34 +#define VERSION_REVISION "49"
35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION 35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "srs" 37 #define RTMP_SIG_SRS_KEY "srs"
@@ -97,6 +97,8 @@ extern std::string srs_string_replace(std::string str, std::string old_str, std: @@ -97,6 +97,8 @@ extern std::string srs_string_replace(std::string str, std::string old_str, std:
97 extern std::string srs_string_trim_end(std::string str, std::string trim_chars); 97 extern std::string srs_string_trim_end(std::string str, std::string trim_chars);
98 // remove char in remove_chars of str 98 // remove char in remove_chars of str
99 extern std::string srs_string_remove(std::string str, std::string remove_chars); 99 extern std::string srs_string_remove(std::string str, std::string remove_chars);
  100 +// whether string end with
  101 +extern bool srs_string_ends_with(std::string str, std::string flag);
100 102
101 // dns resolve utility, return the resolved ip address. 103 // dns resolve utility, return the resolved ip address.
102 extern std::string srs_dns_resolve(std::string host); 104 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. @@ -159,6 +159,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
159 #define ERROR_HTTP_PARSE_HEADER 802 159 #define ERROR_HTTP_PARSE_HEADER 802
160 #define ERROR_HTTP_HANDLER_MATCH_URL 803 160 #define ERROR_HTTP_HANDLER_MATCH_URL 803
161 #define ERROR_HTTP_HANDLER_INVALID 804 161 #define ERROR_HTTP_HANDLER_INVALID 804
  162 +#define ERROR_HTTP_OPEN_FILE 805
  163 +#define ERROR_HTTP_READ_FILE 806
162 164
163 // system control message, 165 // system control message,
164 // not an error, but special control logic. 166 // not an error, but special control logic.