winlin

refine http server pages. change to 0.9.51

@@ -217,6 +217,7 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw @@ -217,6 +217,7 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw
217 * nginx v1.5.0: 139524 lines <br/> 217 * nginx v1.5.0: 139524 lines <br/>
218 218
219 ## History 219 ## History
  220 +* v1.0, 2014-04-05, support [http api](https://github.com/winlinvip/simple-rtmp-server/wiki/HTTPApi) and [http server](https://github.com/winlinvip/simple-rtmp-server/wiki/HTTPServer).
220 * v1.0, 2014-04-03, implements http framework and api/v1/version. 221 * v1.0, 2014-04-03, implements http framework and api/v1/version.
221 * v1.0, 2014-03-30, fix bug for st detecting epoll failed, force st to use epoll. 222 * v1.0, 2014-03-30, fix bug for st detecting epoll failed, force st to use epoll.
222 * v1.0, 2014-03-29, add wiki [Performance for RaspberryPi](https://github.com/winlinvip/simple-rtmp-server/wiki/RaspberryPi). 223 * v1.0, 2014-03-29, add wiki [Performance for RaspberryPi](https://github.com/winlinvip/simple-rtmp-server/wiki/RaspberryPi).
@@ -31,6 +31,7 @@ echo "depends tools are ok" @@ -31,6 +31,7 @@ echo "depends tools are ok"
31 ##################################################################################### 31 #####################################################################################
32 # for Ubuntu, auto install tools by apt-get 32 # for Ubuntu, auto install tools by apt-get
33 ##################################################################################### 33 #####################################################################################
  34 +OS_IS_UBUNTU=NO
34 function Ubuntu_prepare() 35 function Ubuntu_prepare()
35 { 36 {
36 uname -v|grep Ubuntu >/dev/null 2>&1 37 uname -v|grep Ubuntu >/dev/null 2>&1
@@ -38,6 +39,7 @@ function Ubuntu_prepare() @@ -38,6 +39,7 @@ function Ubuntu_prepare()
38 return 0; 39 return 0;
39 fi 40 fi
40 41
  42 + OS_IS_UBUNTU=YES
41 echo "Ubuntu detected, install tools if needed" 43 echo "Ubuntu detected, install tools if needed"
42 44
43 gcc --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then 45 gcc --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
@@ -113,12 +115,14 @@ Ubuntu_prepare; ret=$?; if [[ 0 -ne $ret ]]; then echo "Ubuntu prepare failed, r @@ -113,12 +115,14 @@ Ubuntu_prepare; ret=$?; if [[ 0 -ne $ret ]]; then echo "Ubuntu prepare failed, r
113 ##################################################################################### 115 #####################################################################################
114 # for Centos, auto install tools by yum 116 # for Centos, auto install tools by yum
115 ##################################################################################### 117 #####################################################################################
  118 +OS_IS_CENTOS=NO
116 function Centos_prepare() 119 function Centos_prepare()
117 { 120 {
118 if [[ ! -f /etc/redhat-release ]]; then 121 if [[ ! -f /etc/redhat-release ]]; then
119 return 0; 122 return 0;
120 fi 123 fi
121 124
  125 + OS_IS_CENTOS=YES
122 echo "Centos detected, install tools if needed" 126 echo "Centos detected, install tools if needed"
123 127
124 gcc --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then 128 gcc --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
@@ -315,6 +319,9 @@ function write_nginx_html5() @@ -315,6 +319,9 @@ function write_nginx_html5()
315 </video> 319 </video>
316 END 320 END
317 } 321 }
  322 +# create the nginx dir, for http-server if not build nginx
  323 +mkdir -p ${SRS_OBJS}/nginx
  324 +# make nginx
318 __SRS_BUILD_NGINX=NO; if [ $SRS_ARM_UBUNTU12 = NO ]; then if [ $SRS_NGINX = YES ]; then __SRS_BUILD_NGINX=YES; fi fi 325 __SRS_BUILD_NGINX=NO; if [ $SRS_ARM_UBUNTU12 = NO ]; then if [ $SRS_NGINX = YES ]; then __SRS_BUILD_NGINX=YES; fi fi
319 if [ $__SRS_BUILD_NGINX = YES ]; then 326 if [ $__SRS_BUILD_NGINX = YES ]; then
320 if [[ -f ${SRS_OBJS}/nginx/sbin/nginx ]]; then 327 if [[ -f ${SRS_OBJS}/nginx/sbin/nginx ]]; then
@@ -337,29 +344,29 @@ if [ $__SRS_BUILD_NGINX = YES ]; then @@ -337,29 +344,29 @@ if [ $__SRS_BUILD_NGINX = YES ]; then
337 # nginx default use nobody, so cannot read the ts/m3u8 created by srs. 344 # nginx default use nobody, so cannot read the ts/m3u8 created by srs.
338 cp ${SRS_OBJS}/nginx/conf/nginx.conf ${SRS_OBJS}/nginx/conf/nginx.conf.bk 345 cp ${SRS_OBJS}/nginx/conf/nginx.conf ${SRS_OBJS}/nginx/conf/nginx.conf.bk
339 sed -i "s/^.user nobody;/user `whoami`;/g" ${SRS_OBJS}/nginx/conf/nginx.conf 346 sed -i "s/^.user nobody;/user `whoami`;/g" ${SRS_OBJS}/nginx/conf/nginx.conf
340 -  
341 - # create forward dir  
342 - mkdir -p ${SRS_OBJS}/nginx/html/live &&  
343 - mkdir -p ${SRS_OBJS}/nginx/html/forward/live  
344 -  
345 - # generate default html pages for android.  
346 - html_file=${SRS_OBJS}/nginx/html/live/livestream.html && hls_stream=livestream.m3u8 && write_nginx_html5  
347 - html_file=${SRS_OBJS}/nginx/html/live/livestream_ld.html && hls_stream=livestream_ld.m3u8 && write_nginx_html5  
348 - html_file=${SRS_OBJS}/nginx/html/live/livestream_sd.html && hls_stream=livestream_sd.m3u8 && write_nginx_html5  
349 - html_file=${SRS_OBJS}/nginx/html/forward/live/livestream.html && hls_stream=livestream.m3u8 && write_nginx_html5  
350 - html_file=${SRS_OBJS}/nginx/html/forward/live/livestream_ld.html && hls_stream=livestream_ld.m3u8 && write_nginx_html5  
351 - html_file=${SRS_OBJS}/nginx/html/forward/live/livestream_sd.html && hls_stream=livestream_sd.m3u8 && write_nginx_html5  
352 -  
353 - # copy players to nginx html dir.  
354 - rm -rf ${SRS_OBJS}/nginx/html/players &&  
355 - ln -sf `pwd`/research/players ${SRS_OBJS}/nginx/html/players &&  
356 - rm -f ${SRS_OBJS}/nginx/crossdomain.xml &&  
357 - ln -sf `pwd`/research/players/crossdomain.xml ${SRS_OBJS}/nginx/html/crossdomain.xml  
358 -  
359 - # nginx.html to detect whether nginx is alive  
360 - echo "nginx is ok" > ${SRS_OBJS}/nginx/html/nginx.html  
361 fi 347 fi
362 348
  349 +# create forward dir
  350 +mkdir -p ${SRS_OBJS}/nginx/html/live &&
  351 +mkdir -p ${SRS_OBJS}/nginx/html/forward/live
  352 +
  353 +# generate default html pages for android.
  354 +html_file=${SRS_OBJS}/nginx/html/live/livestream.html && hls_stream=livestream.m3u8 && write_nginx_html5
  355 +html_file=${SRS_OBJS}/nginx/html/live/livestream_ld.html && hls_stream=livestream_ld.m3u8 && write_nginx_html5
  356 +html_file=${SRS_OBJS}/nginx/html/live/livestream_sd.html && hls_stream=livestream_sd.m3u8 && write_nginx_html5
  357 +html_file=${SRS_OBJS}/nginx/html/forward/live/livestream.html && hls_stream=livestream.m3u8 && write_nginx_html5
  358 +html_file=${SRS_OBJS}/nginx/html/forward/live/livestream_ld.html && hls_stream=livestream_ld.m3u8 && write_nginx_html5
  359 +html_file=${SRS_OBJS}/nginx/html/forward/live/livestream_sd.html && hls_stream=livestream_sd.m3u8 && write_nginx_html5
  360 +
  361 +# copy players to nginx html dir.
  362 +rm -rf ${SRS_OBJS}/nginx/html/players &&
  363 +ln -sf `pwd`/research/players ${SRS_OBJS}/nginx/html/players &&
  364 +rm -f ${SRS_OBJS}/nginx/crossdomain.xml &&
  365 +ln -sf `pwd`/research/players/crossdomain.xml ${SRS_OBJS}/nginx/html/crossdomain.xml
  366 +
  367 +# nginx.html to detect whether nginx is alive
  368 +echo "nginx is ok" > ${SRS_OBJS}/nginx/html/nginx.html
  369 +
363 if [ $SRS_NGINX = YES ]; then 370 if [ $SRS_NGINX = YES ]; then
364 echo "#define SRS_NGINX" >> $SRS_AUTO_HEADERS_H 371 echo "#define SRS_NGINX" >> $SRS_AUTO_HEADERS_H
365 else 372 else
@@ -411,31 +418,23 @@ mkdir -p `pwd`/${SRS_OBJS}/nginx/html/forward && @@ -411,31 +418,23 @@ mkdir -p `pwd`/${SRS_OBJS}/nginx/html/forward &&
411 ln -sf `pwd`/${SRS_OBJS}/nginx/html/forward research/api-server/static-dir/forward 418 ln -sf `pwd`/${SRS_OBJS}/nginx/html/forward research/api-server/static-dir/forward
412 ret=$?; if [[ $ret -ne 0 ]]; then echo "link players to cherrypy static-dir failed, ret=$ret"; exit $ret; fi 419 ret=$?; if [[ $ret -ne 0 ]]; then echo "link players to cherrypy static-dir failed, ret=$ret"; exit $ret; fi
413 420
414 -# only when the nginx is ok,  
415 -# if api-server not enalbed, use nginx as demo. 421 +#####################################################################################
  422 +# generate demo index.html
  423 +#####################################################################################
  424 +# if nginx enalbed, generate nginx index file.
416 if [ $__SRS_BUILD_NGINX = YES ]; then 425 if [ $__SRS_BUILD_NGINX = YES ]; then
417 - if [ $SRS_HTTP_CALLBACK = YES ]; then  
418 - # override the default index.  
419 rm -f ${SRS_OBJS}/nginx/html/index.html && 426 rm -f ${SRS_OBJS}/nginx/html/index.html &&
420 ln -sf `pwd`/research/players/nginx_index.html ${SRS_OBJS}/nginx/html/index.html 427 ln -sf `pwd`/research/players/nginx_index.html ${SRS_OBJS}/nginx/html/index.html
421 - else 428 +fi
  429 +# if http-server enalbed, use srs embeded http-server
  430 +if [ $SRS_HTTP_SERVER = YES ]; then
422 rm -f ${SRS_OBJS}/nginx/html/index.html && 431 rm -f ${SRS_OBJS}/nginx/html/index.html &&
423 - cat<<END > ${SRS_OBJS}/nginx/html/index.html  
424 -<!DOCTYPE html>  
425 -<html>  
426 -<head>  
427 - <title>SRS</title>  
428 - <meta charset="utf-8">  
429 -</head>  
430 -<body>  
431 - <script type="text/javascript">  
432 - setTimeout(function(){  
433 - window.location.href = "players/index.html" + window.location.search;  
434 - }, 500);  
435 - </script>  
436 -</body>  
437 -END  
438 - fi 432 + ln -sf `pwd`/research/players/srs-http-server_index.html ${SRS_OBJS}/nginx/html/index.html
  433 +fi
  434 +# if api-server enabled, generate for api server.
  435 +if [ $SRS_HTTP_CALLBACK = YES ]; then
  436 + rm -f ${SRS_OBJS}/nginx/html/index.html &&
  437 + ln -sf `pwd`/research/players/api-server_index.html ${SRS_OBJS}/nginx/html/index.html
439 fi 438 fi
440 439
441 ##################################################################################### 440 #####################################################################################
@@ -603,7 +602,11 @@ echo "" >> $SRS_AUTO_HEADERS_H @@ -603,7 +602,11 @@ echo "" >> $SRS_AUTO_HEADERS_H
603 ##################################################################################### 602 #####################################################################################
604 # generated the contributors from AUTHORS.txt 603 # generated the contributors from AUTHORS.txt
605 ##################################################################################### 604 #####################################################################################
606 -SRS_CONSTRIBUTORS=`cat ../AUTHORS.txt|grep "*"|awk -F '\* ' '{print $2}'` 605 +if [ $OS_IS_CENTOS = YES ]; then
  606 + SRS_CONSTRIBUTORS=`cat ../AUTHORS.txt|grep "*"|awk -F '* ' '{print $2}'`
  607 +else
  608 + SRS_CONSTRIBUTORS=`cat ../AUTHORS.txt|grep "*"|awk -F '\* ' '{print $2}'`
  609 +fi
607 echo "#define SRS_CONSTRIBUTORS \"\\" >> $SRS_AUTO_HEADERS_H 610 echo "#define SRS_CONSTRIBUTORS \"\\" >> $SRS_AUTO_HEADERS_H
608 for CONTRIBUTOR in $SRS_CONSTRIBUTORS; do 611 for CONTRIBUTOR in $SRS_CONSTRIBUTORS; do
609 echo "${CONTRIBUTOR} \\" >> $SRS_AUTO_HEADERS_H 612 echo "${CONTRIBUTOR} \\" >> $SRS_AUTO_HEADERS_H
@@ -168,12 +168,12 @@ if [ $SRS_DEV = YES ]; then @@ -168,12 +168,12 @@ if [ $SRS_DEV = YES ]; then
168 SRS_NGINX=YES 168 SRS_NGINX=YES
169 SRS_SSL=YES 169 SRS_SSL=YES
170 SRS_FFMPEG=YES 170 SRS_FFMPEG=YES
171 - SRS_HTTP_CALLBACK=YES 171 + if [ $SRS_HTTP_CALLBACK = RESERVED ]; then SRS_HTTP_CALLBACK=YES; fi
172 SRS_HTTP_SERVER=YES 172 SRS_HTTP_SERVER=YES
173 SRS_HTTP_API=YES 173 SRS_HTTP_API=YES
174 SRS_LIBRTMP=YES 174 SRS_LIBRTMP=YES
175 - SRS_BWTC=YES  
176 - SRS_RESEARCH=YES 175 + if [ $SRS_BWTC = RESERVED ]; then SRS_BWTC=YES; fi
  176 + if [ $SRS_RESEARCH = RESERVED ]; then SRS_RESEARCH=YES; fi
177 SRS_UTEST=YES 177 SRS_UTEST=YES
178 if [ $SRS_GPERF = RESERVED ]; then SRS_GPERF=NO; fi 178 if [ $SRS_GPERF = RESERVED ]; then SRS_GPERF=NO; fi
179 if [ $SRS_GPERF_MC = RESERVED ]; then SRS_GPERF_MC=NO; fi 179 if [ $SRS_GPERF_MC = RESERVED ]; then SRS_GPERF_MC=NO; fi
  1 +<!DOCTYPE html>
  2 +<html>
  3 +<head>
  4 + <title>SRS</title>
  5 + <meta charset="utf-8">
  6 + <script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script>
  7 + <script type="text/javascript" src="players/js/srs.page.js"></script>
  8 + <script type="text/javascript" src="players/js/srs.utility.js"></script>
  9 +</head>
  10 +<body>
  11 + <script type="text/javascript">
  12 + setTimeout(function(){
  13 + window.location.href = "players/index.html" + window.location.search;
  14 + }, 500);
  15 + </script>
  16 +</body>
@@ -15,6 +15,8 @@ function srs_get_version_code() { return "1.19"; } @@ -15,6 +15,8 @@ function srs_get_version_code() { return "1.19"; }
15 function srs_get_player_vhost() { return "players"; } 15 function srs_get_player_vhost() { return "players"; }
16 // the api server port, for chat room. 16 // the api server port, for chat room.
17 function srs_get_api_server_port() { return 8085; } 17 function srs_get_api_server_port() { return 8085; }
  18 +// the srs http server port
  19 +function srs_get_srs_http_server_port() { return 8080; }
18 // get the stream published to vhost, 20 // get the stream published to vhost,
19 // generally we need to transcode the stream to support HLS and filters. 21 // generally we need to transcode the stream to support HLS and filters.
20 // for example, src_vhost is "players", we transcode stream to vhost "players_pub". 22 // for example, src_vhost is "players", we transcode stream to vhost "players_pub".
@@ -3,19 +3,11 @@ @@ -3,19 +3,11 @@
3 <head> 3 <head>
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 - <script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script>  
7 - <script type="text/javascript" src="players/js/srs.page.js"></script>  
8 - <script type="text/javascript" src="players/js/srs.utility.js"></script>  
9 </head> 6 </head>
10 <body> 7 <body>
11 <script type="text/javascript"> 8 <script type="text/javascript">
12 - var query = parse_query_string();  
13 - var url = window.location.protocol + "//" + query.hostname + ":" + srs_get_api_server_port() + "/index.html" + window.location.search;  
14 - document.write("请确认api-server已经开启,跳转到api-server的页面(解决IE跨域问题)<br/>");  
15 - document.write("正在跳转,若您的浏览器没有跳转,请点击: <a href='" + url + "'>" + url + "</a>");  
16 -  
17 setTimeout(function(){ 9 setTimeout(function(){
18 - window.location.href = url;  
19 - }, 3000); 10 + window.location.href = "players/index.html" + window.location.search;
  11 + }, 500);
20 </script> 12 </script>
21 </body> 13 </body>
  1 +<!DOCTYPE html>
  2 +<html>
  3 +<head>
  4 + <title>SRS</title>
  5 + <meta charset="utf-8">
  6 + <script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script>
  7 + <script type="text/javascript" src="players/js/srs.page.js"></script>
  8 + <script type="text/javascript" src="players/js/srs.utility.js"></script>
  9 +</head>
  10 +<body>
  11 + <script type="text/javascript">
  12 + setTimeout(function(){
  13 + window.location.href = "players/index.html" + window.location.search;
  14 + }, 500);
  15 + </script>
  16 +</body>
@@ -52,6 +52,13 @@ bool srs_path_equals(const char* expect, const char* path, int nb_path) @@ -52,6 +52,13 @@ bool srs_path_equals(const char* expect, const char* path, int nb_path)
52 return equals; 52 return equals;
53 } 53 }
54 54
  55 +bool srs_path_like(const char* expect, const char* path, int nb_path)
  56 +{
  57 + int size = strlen(expect);
  58 + bool equals = !strncmp(expect, path, srs_min(size, nb_path));
  59 + return equals;
  60 +}
  61 +
55 SrsHttpHandlerMatch::SrsHttpHandlerMatch() 62 SrsHttpHandlerMatch::SrsHttpHandlerMatch()
56 { 63 {
57 handler = NULL; 64 handler = NULL;
@@ -217,6 +224,34 @@ SrsHttpHandler* SrsHttpHandler::res_content_type(std::stringstream& ss) @@ -217,6 +224,34 @@ SrsHttpHandler* SrsHttpHandler::res_content_type(std::stringstream& ss)
217 return this; 224 return this;
218 } 225 }
219 226
  227 +SrsHttpHandler* SrsHttpHandler::res_content_type_xml(std::stringstream& ss)
  228 +{
  229 + ss << "Content-Type: text/xml;charset=utf-8" << __CRLF
  230 + << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF;
  231 + return this;
  232 +}
  233 +
  234 +SrsHttpHandler* SrsHttpHandler::res_content_type_javascript(std::stringstream& ss)
  235 +{
  236 + ss << "Content-Type: text/javascript;charset=utf-8" << __CRLF
  237 + << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF;
  238 + return this;
  239 +}
  240 +
  241 +SrsHttpHandler* SrsHttpHandler::res_content_type_swf(std::stringstream& ss)
  242 +{
  243 + ss << "Content-Type: application/x-shockwave-flash;charset=utf-8" << __CRLF
  244 + << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF;
  245 + return this;
  246 +}
  247 +
  248 +SrsHttpHandler* SrsHttpHandler::res_content_type_css(std::stringstream& ss)
  249 +{
  250 + ss << "Content-Type: text/css;charset=utf-8" << __CRLF
  251 + << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF;
  252 + return this;
  253 +}
  254 +
220 SrsHttpHandler* SrsHttpHandler::res_content_type_json(std::stringstream& ss) 255 SrsHttpHandler* SrsHttpHandler::res_content_type_json(std::stringstream& ss)
221 { 256 {
222 ss << "Content-Type: application/json;charset=utf-8" << __CRLF 257 ss << "Content-Type: application/json;charset=utf-8" << __CRLF
@@ -299,6 +334,74 @@ int SrsHttpHandler::res_text(SrsSocket* skt, SrsHttpMessage* req, std::string bo @@ -299,6 +334,74 @@ int SrsHttpHandler::res_text(SrsSocket* skt, SrsHttpMessage* req, std::string bo
299 return res_flush(skt, ss); 334 return res_flush(skt, ss);
300 } 335 }
301 336
  337 +int SrsHttpHandler::res_xml(SrsSocket* skt, SrsHttpMessage* req, std::string body)
  338 +{
  339 + std::stringstream ss;
  340 +
  341 + res_status_line(ss)->res_content_type_xml(ss)
  342 + ->res_content_length(ss, (int)body.length());
  343 +
  344 + if (req->requires_crossdomain()) {
  345 + res_enable_crossdomain(ss);
  346 + }
  347 +
  348 + res_header_eof(ss)
  349 + ->res_body(ss, body);
  350 +
  351 + return res_flush(skt, ss);
  352 +}
  353 +
  354 +int SrsHttpHandler::res_javascript(SrsSocket* skt, SrsHttpMessage* req, std::string body)
  355 +{
  356 + std::stringstream ss;
  357 +
  358 + res_status_line(ss)->res_content_type_javascript(ss)
  359 + ->res_content_length(ss, (int)body.length());
  360 +
  361 + if (req->requires_crossdomain()) {
  362 + res_enable_crossdomain(ss);
  363 + }
  364 +
  365 + res_header_eof(ss)
  366 + ->res_body(ss, body);
  367 +
  368 + return res_flush(skt, ss);
  369 +}
  370 +
  371 +int SrsHttpHandler::res_swf(SrsSocket* skt, SrsHttpMessage* req, std::string body)
  372 +{
  373 + std::stringstream ss;
  374 +
  375 + res_status_line(ss)->res_content_type_swf(ss)
  376 + ->res_content_length(ss, (int)body.length());
  377 +
  378 + if (req->requires_crossdomain()) {
  379 + res_enable_crossdomain(ss);
  380 + }
  381 +
  382 + res_header_eof(ss)
  383 + ->res_body(ss, body);
  384 +
  385 + return res_flush(skt, ss);
  386 +}
  387 +
  388 +int SrsHttpHandler::res_css(SrsSocket* skt, SrsHttpMessage* req, std::string body)
  389 +{
  390 + std::stringstream ss;
  391 +
  392 + res_status_line(ss)->res_content_type_css(ss)
  393 + ->res_content_length(ss, (int)body.length());
  394 +
  395 + if (req->requires_crossdomain()) {
  396 + res_enable_crossdomain(ss);
  397 + }
  398 +
  399 + res_header_eof(ss)
  400 + ->res_body(ss, body);
  401 +
  402 + return res_flush(skt, ss);
  403 +}
  404 +
302 int SrsHttpHandler::res_m3u8(SrsSocket* skt, SrsHttpMessage* req, std::string body) 405 int SrsHttpHandler::res_m3u8(SrsSocket* skt, SrsHttpMessage* req, std::string body)
303 { 406 {
304 std::stringstream ss; 407 std::stringstream ss;
@@ -152,7 +152,12 @@ class SrsHttpHandler; @@ -152,7 +152,12 @@ class SrsHttpHandler;
152 152
153 // compare the path. 153 // compare the path.
154 // full compare, extractly match. 154 // full compare, extractly match.
  155 +// used for api match.
155 extern bool srs_path_equals(const char* expect, const char* path, int nb_path); 156 extern bool srs_path_equals(const char* expect, const char* path, int nb_path);
  157 +// compare the path use like,
  158 +// used for http stream to match,
  159 +// if the path like the requires
  160 +extern bool srs_path_like(const char* expect, const char* path, int nb_path);
156 161
157 // state of message 162 // state of message
158 enum SrsHttpParseState { 163 enum SrsHttpParseState {
@@ -228,6 +233,10 @@ public: @@ -228,6 +233,10 @@ public:
228 virtual SrsHttpHandler* res_status_line(std::stringstream& ss); 233 virtual SrsHttpHandler* res_status_line(std::stringstream& ss);
229 virtual SrsHttpHandler* res_status_line_error(std::stringstream& ss, int code, std::string reason_phrase); 234 virtual SrsHttpHandler* res_status_line_error(std::stringstream& ss, int code, std::string reason_phrase);
230 virtual SrsHttpHandler* res_content_type(std::stringstream& ss); 235 virtual SrsHttpHandler* res_content_type(std::stringstream& ss);
  236 + virtual SrsHttpHandler* res_content_type_xml(std::stringstream& ss);
  237 + virtual SrsHttpHandler* res_content_type_javascript(std::stringstream& ss);
  238 + virtual SrsHttpHandler* res_content_type_swf(std::stringstream& ss);
  239 + virtual SrsHttpHandler* res_content_type_css(std::stringstream& ss);
231 virtual SrsHttpHandler* res_content_type_json(std::stringstream& ss); 240 virtual SrsHttpHandler* res_content_type_json(std::stringstream& ss);
232 virtual SrsHttpHandler* res_content_type_m3u8(std::stringstream& ss); 241 virtual SrsHttpHandler* res_content_type_m3u8(std::stringstream& ss);
233 virtual SrsHttpHandler* res_content_type_mpegts(std::stringstream& ss); 242 virtual SrsHttpHandler* res_content_type_mpegts(std::stringstream& ss);
@@ -239,6 +248,10 @@ public: @@ -239,6 +248,10 @@ public:
239 public: 248 public:
240 virtual int res_options(SrsSocket* skt); 249 virtual int res_options(SrsSocket* skt);
241 virtual int res_text(SrsSocket* skt, SrsHttpMessage* req, std::string body); 250 virtual int res_text(SrsSocket* skt, SrsHttpMessage* req, std::string body);
  251 + virtual int res_xml(SrsSocket* skt, SrsHttpMessage* req, std::string body);
  252 + virtual int res_javascript(SrsSocket* skt, SrsHttpMessage* req, std::string body);
  253 + virtual int res_swf(SrsSocket* skt, SrsHttpMessage* req, std::string body);
  254 + virtual int res_css(SrsSocket* skt, SrsHttpMessage* req, std::string body);
242 virtual int res_m3u8(SrsSocket* skt, SrsHttpMessage* req, std::string body); 255 virtual int res_m3u8(SrsSocket* skt, SrsHttpMessage* req, std::string body);
243 virtual int res_mpegts(SrsSocket* skt, SrsHttpMessage* req, std::string body); 256 virtual int res_mpegts(SrsSocket* skt, SrsHttpMessage* req, std::string body);
244 virtual int res_json(SrsSocket* skt, SrsHttpMessage* req, std::string json); 257 virtual int res_json(SrsSocket* skt, SrsHttpMessage* req, std::string json);
@@ -40,6 +40,8 @@ using namespace std; @@ -40,6 +40,8 @@ using namespace std;
40 #include <srs_app_json.hpp> 40 #include <srs_app_json.hpp>
41 #include <srs_app_config.hpp> 41 #include <srs_app_config.hpp>
42 42
  43 +#define SRS_HTTP_DEFAULT_PAGE "index.html"
  44 +
43 SrsHttpRoot::SrsHttpRoot() 45 SrsHttpRoot::SrsHttpRoot()
44 { 46 {
45 // TODO: FIXME: support reload vhosts. 47 // TODO: FIXME: support reload vhosts.
@@ -88,14 +90,26 @@ int SrsHttpRoot::initialize() @@ -88,14 +90,26 @@ int SrsHttpRoot::initialize()
88 return ret; 90 return ret;
89 } 91 }
90 92
91 -bool SrsHttpRoot::can_handle(const char* path, int length, const char** pchild) 93 +int SrsHttpRoot::best_match(const char* path, int length, SrsHttpHandlerMatch** ppmatch)
92 { 94 {
93 - // reset the child path to path,  
94 - // for child to reparse the path.  
95 - *pchild = path; 95 + int ret = ERROR_SUCCESS;
96 96
97 - // never handle request for root.  
98 - return true; 97 + // find the best matched child handler.
  98 + std::vector<SrsHttpHandler*>::iterator it;
  99 + for (it = handlers.begin(); it != handlers.end(); ++it) {
  100 + SrsHttpHandler* h = *it;
  101 +
  102 + // search all child handlers.
  103 + h->best_match(path, length, ppmatch);
  104 + }
  105 +
  106 + // if already matched by child, return.
  107 + if (*ppmatch) {
  108 + return ret;
  109 + }
  110 +
  111 + // not matched, error.
  112 + return ERROR_HTTP_HANDLER_MATCH_URL;
99 } 113 }
100 114
101 bool SrsHttpRoot::is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase) 115 bool SrsHttpRoot::is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase)
@@ -125,19 +139,12 @@ SrsHttpVhost::~SrsHttpVhost() @@ -125,19 +139,12 @@ SrsHttpVhost::~SrsHttpVhost()
125 139
126 bool SrsHttpVhost::can_handle(const char* path, int length, const char** /*pchild*/) 140 bool SrsHttpVhost::can_handle(const char* path, int length, const char** /*pchild*/)
127 { 141 {
128 - int min_match = srs_min(length, (int)_mount.length());  
129 - return srs_path_equals(_mount.c_str(), path, min_match); 142 + return srs_path_like(_mount.c_str(), path, length);
130 } 143 }
131 144
132 bool SrsHttpVhost::is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase) 145 bool SrsHttpVhost::is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase)
133 { 146 {
134 - std::string fullpath = _dir + "/" + req->match()->unmatched_url;  
135 - if (_mount == "/") {  
136 - fullpath = _dir + "/" + req->match()->matched_url;  
137 - if (!req->match()->unmatched_url.empty()) {  
138 - fullpath += "/" + req->match()->unmatched_url;  
139 - }  
140 - } 147 + std::string fullpath = get_request_file(req);
141 148
142 if (::access(fullpath.c_str(), F_OK | R_OK) < 0) { 149 if (::access(fullpath.c_str(), F_OK | R_OK) < 0) {
143 srs_warn("check file %s does not exists", fullpath.c_str()); 150 srs_warn("check file %s does not exists", fullpath.c_str());
@@ -154,17 +161,7 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req) @@ -154,17 +161,7 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req)
154 { 161 {
155 int ret = ERROR_SUCCESS; 162 int ret = ERROR_SUCCESS;
156 163
157 - std::string fullpath = _dir + "/" + req->match()->unmatched_url;  
158 - if (_mount == "/") {  
159 - fullpath = _dir + "/" + req->match()->matched_url;  
160 - if (!req->match()->unmatched_url.empty()) {  
161 - fullpath += "/" + req->match()->unmatched_url;  
162 - }  
163 - }  
164 -  
165 - if (srs_string_ends_with(fullpath, "/")) {  
166 - fullpath += "index.html";  
167 - } 164 + std::string fullpath = get_request_file(req);
168 165
169 int fd = ::open(fullpath.c_str(), O_RDONLY); 166 int fd = ::open(fullpath.c_str(), O_RDONLY);
170 if (fd < 0) { 167 if (fd < 0) {
@@ -194,6 +191,14 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req) @@ -194,6 +191,14 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req)
194 return res_mpegts(skt, req, str); 191 return res_mpegts(skt, req, str);
195 } else if (srs_string_ends_with(fullpath, ".m3u8")) { 192 } else if (srs_string_ends_with(fullpath, ".m3u8")) {
196 return res_m3u8(skt, req, str); 193 return res_m3u8(skt, req, str);
  194 + } else if (srs_string_ends_with(fullpath, ".xml")) {
  195 + return res_xml(skt, req, str);
  196 + } else if (srs_string_ends_with(fullpath, ".js")) {
  197 + return res_javascript(skt, req, str);
  198 + } else if (srs_string_ends_with(fullpath, ".swf")) {
  199 + return res_swf(skt, req, str);
  200 + } else if (srs_string_ends_with(fullpath, ".css")) {
  201 + return res_css(skt, req, str);
197 } else { 202 } else {
198 return res_text(skt, req, str); 203 return res_text(skt, req, str);
199 } 204 }
@@ -201,6 +206,31 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req) @@ -201,6 +206,31 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req)
201 return ret; 206 return ret;
202 } 207 }
203 208
  209 +string SrsHttpVhost::get_request_file(SrsHttpMessage* req)
  210 +{
  211 + std::string fullpath = _dir + "/";
  212 +
  213 + // if root, directly use the matched url.
  214 + if (_mount == "/") {
  215 + // add the dir
  216 + fullpath += req->match()->matched_url;
  217 + // if file speicified, add the file.
  218 + if (!req->match()->unmatched_url.empty()) {
  219 + fullpath += "/" + req->match()->unmatched_url;
  220 + }
  221 + } else {
  222 + // virtual path, ignore the virutal path.
  223 + fullpath += req->match()->unmatched_url;
  224 + }
  225 +
  226 + // add default pages.
  227 + if (srs_string_ends_with(fullpath, "/")) {
  228 + fullpath += SRS_HTTP_DEFAULT_PAGE;
  229 + }
  230 +
  231 + return fullpath;
  232 +}
  233 +
204 string SrsHttpVhost::vhost() 234 string SrsHttpVhost::vhost()
205 { 235 {
206 return _vhost; 236 return _vhost;
@@ -49,7 +49,7 @@ public: @@ -49,7 +49,7 @@ public:
49 virtual ~SrsHttpRoot(); 49 virtual ~SrsHttpRoot();
50 public: 50 public:
51 virtual int initialize(); 51 virtual int initialize();
52 - virtual bool can_handle(const char* path, int length, const char** pchild); 52 + virtual int best_match(const char* path, int length, SrsHttpHandlerMatch** ppmatch);
53 protected: 53 protected:
54 virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase); 54 virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase);
55 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); 55 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
@@ -69,6 +69,8 @@ public: @@ -69,6 +69,8 @@ public:
69 protected: 69 protected:
70 virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase); 70 virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase);
71 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); 71 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
  72 +private:
  73 + virtual std::string get_request_file(SrsHttpMessage* req);
72 public: 74 public:
73 virtual std::string vhost(); 75 virtual std::string vhost();
74 virtual std::string mount(); 76 virtual std::string mount();
@@ -239,6 +239,7 @@ int SrsRtmpConn::stream_service_cycle() @@ -239,6 +239,7 @@ int SrsRtmpConn::stream_service_cycle()
239 srs_error("identify client failed. ret=%d", ret); 239 srs_error("identify client failed. ret=%d", ret);
240 return ret; 240 return ret;
241 } 241 }
  242 + req->strip();
242 srs_trace("identify client success. type=%s, stream_name=%s", 243 srs_trace("identify client success. type=%s, stream_name=%s",
243 srs_client_type_string(type).c_str(), req->stream.c_str()); 244 srs_client_type_string(type).c_str(), req->stream.c_str());
244 245
@@ -63,6 +63,24 @@ string srs_string_trim_end(string str, string trim_chars) @@ -63,6 +63,24 @@ string srs_string_trim_end(string str, string trim_chars)
63 return ret; 63 return ret;
64 } 64 }
65 65
  66 +string srs_string_trim_start(string str, string trim_chars)
  67 +{
  68 + std::string ret = str;
  69 +
  70 + for (int i = 0; i < (int)trim_chars.length(); i++) {
  71 + char ch = trim_chars.at(i);
  72 +
  73 + while (!ret.empty() && ret.at(0) == ch) {
  74 + ret.erase(ret.begin());
  75 +
  76 + // ok, matched, should reset the search
  77 + i = 0;
  78 + }
  79 + }
  80 +
  81 + return ret;
  82 +}
  83 +
66 string srs_string_remove(string str, string remove_chars) 84 string srs_string_remove(string str, string remove_chars)
67 { 85 {
68 std::string ret = str; 86 std::string ret = str;
@@ -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 "50" 34 +#define VERSION_REVISION "51"
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"
@@ -101,6 +101,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -101,6 +101,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
101 extern std::string srs_string_replace(std::string str, std::string old_str, std::string new_str); 101 extern std::string srs_string_replace(std::string str, std::string old_str, std::string new_str);
102 // trim char in trim_chars of str 102 // trim char in trim_chars of str
103 extern std::string srs_string_trim_end(std::string str, std::string trim_chars); 103 extern std::string srs_string_trim_end(std::string str, std::string trim_chars);
  104 +// trim char in trim_chars of str
  105 +extern std::string srs_string_trim_start(std::string str, std::string trim_chars);
104 // remove char in remove_chars of str 106 // remove char in remove_chars of str
105 extern std::string srs_string_remove(std::string str, std::string remove_chars); 107 extern std::string srs_string_remove(std::string str, std::string remove_chars);
106 // whether string end with 108 // whether string end with
@@ -128,14 +128,7 @@ int SrsRequest::discovery_app() @@ -128,14 +128,7 @@ int SrsRequest::discovery_app()
128 vhost = host; 128 vhost = host;
129 srs_vhost_resolve(vhost, app); 129 srs_vhost_resolve(vhost, app);
130 130
131 - // remove the unsupported chars in names.  
132 - vhost = srs_string_remove(vhost, "/ \n\r\t");  
133 - app = srs_string_remove(app, " \n\r\t");  
134 - stream = srs_string_remove(stream, " \n\r\t");  
135 -  
136 - // remove end slash of app  
137 - app = srs_string_trim_end(app, "/");  
138 - stream = srs_string_trim_end(stream, "/"); 131 + strip();
139 132
140 return ret; 133 return ret;
141 } 134 }
@@ -153,6 +146,22 @@ string SrsRequest::get_stream_url() @@ -153,6 +146,22 @@ string SrsRequest::get_stream_url()
153 return url; 146 return url;
154 } 147 }
155 148
  149 +void SrsRequest::strip()
  150 +{
  151 + // remove the unsupported chars in names.
  152 + vhost = srs_string_remove(vhost, "/ \n\r\t");
  153 + app = srs_string_remove(app, " \n\r\t");
  154 + stream = srs_string_remove(stream, " \n\r\t");
  155 +
  156 + // remove end slash of app/stream
  157 + app = srs_string_trim_end(app, "/");
  158 + stream = srs_string_trim_end(stream, "/");
  159 +
  160 + // remove start slash of app/stream
  161 + app = srs_string_trim_start(app, "/");
  162 + stream = srs_string_trim_start(stream, "/");
  163 +}
  164 +
156 SrsResponse::SrsResponse() 165 SrsResponse::SrsResponse()
157 { 166 {
158 stream_id = SRS_DEFAULT_SID; 167 stream_id = SRS_DEFAULT_SID;
@@ -82,6 +82,9 @@ public: @@ -82,6 +82,9 @@ public:
82 */ 82 */
83 virtual int discovery_app(); 83 virtual int discovery_app();
84 virtual std::string get_stream_url(); 84 virtual std::string get_stream_url();
  85 +
  86 + // strip url, user must strip when update the url.
  87 + virtual void strip();
85 }; 88 };
86 89
87 /** 90 /**