Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
胡斌
/
srs
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
winlin
2015-01-17 23:00:40 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
cbed2bbca460a5922f3ee462b90467e15b1e591b
cbed2bbc
1 parent
9bbbaad2
fix #277, refine http server refer to go http-framework. 2.0.98
显示空白字符变更
内嵌
并排对比
正在显示
9 个修改的文件
包含
144 行增加
和
1112 行删除
README.md
trunk/src/app/srs_app_http.cpp
trunk/src/app/srs_app_http.hpp
trunk/src/app/srs_app_http_api.cpp
trunk/src/app/srs_app_http_conn.cpp
trunk/src/app/srs_app_http_conn.hpp
trunk/src/app/srs_app_server.cpp
trunk/src/app/srs_app_server.hpp
trunk/src/core/srs_core.hpp
README.md
查看文件 @
cbed2bb
...
...
@@ -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
...
...
trunk/src/app/srs_app_http.cpp
查看文件 @
cbed2bb
...
...
@@ -37,6 +37,7 @@ using namespace std;
#include <srs_app_json.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_protocol_buffer.hpp>
#include <srs_kernel_file.hpp>
#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
<
SrsHttpHandler
*>::
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
<
SrsHttpHandler
*>::
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
);
...
...
trunk/src/app/srs_app_http.hpp
查看文件 @
cbed2bb
...
...
@@ -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
<
SrsHttpHandler
*>
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,
...
...
trunk/src/app/srs_app_http_api.cpp
查看文件 @
cbed2bb
...
...
@@ -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
);
...
...
trunk/src/app/srs_app_http_conn.cpp
查看文件 @
cbed2bb
...
...
@@ -40,20 +40,16 @@ using namespace std;
#include <srs_app_config.hpp>
#include <srs_kernel_flv.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_kernel_file.hpp>
#define SRS_HTTP_DEFAULT_PAGE "index.html"
SrsHttpRoot
::
SrsHttpRoot
()
SrsHttpServer
::
SrsHttpServer
()
{
// TODO: FIXME: support reload vhosts.
}
SrsHttp
Root
::~
SrsHttpRoot
()
SrsHttp
Server
::~
SrsHttpServer
()
{
}
int
SrsHttp
Root
::
initialize
()
int
SrsHttp
Server
::
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,403 +84,21 @@ 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
<
SrsHttpHandler
*>::
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
)
{
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
;
}
// 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
)
{
return
ret
;
}
}
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
());
// TODO: maybe need to parse the url.
std
::
string
url
=
req
->
path
();
r
->
method_str
().
c_str
(),
r
->
url
().
c_str
(),
r
->
content_length
());
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
);
return
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
);
}
// 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
;
}
...
...
trunk/src/app/srs_app_http_conn.hpp
查看文件 @
cbed2bb
...
...
@@ -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
:
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
;
SrsHttpServer
();
virtual
~
SrsHttpServer
();
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
();
virtual
int
initialize
();
};
class
SrsHttpConn
:
public
SrsConnection
{
private
:
SrsHttpParser
*
parser
;
SrsHttpHandler
*
handler
;
bool
requires_crossdomain
;
SrsHttpServer
*
mux
;
public
:
SrsHttpConn
(
SrsServer
*
s
rs_server
,
st_netfd_t
client_stfd
,
SrsHttpHandler
*
_handler
);
SrsHttpConn
(
SrsServer
*
s
vr
,
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
...
...
trunk/src/app/srs_app_server.cpp
查看文件 @
cbed2bb
...
...
@@ -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
...
...
trunk/src/app/srs_app_server.hpp
查看文件 @
cbed2bb
...
...
@@ -39,7 +39,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
class
SrsServer
;
class
SrsConnection
;
class
SrsGoHttpServeMux
;
class
SrsHttp
Handl
er
;
class
SrsHttp
Serv
er
;
class
SrsIngester
;
class
SrsHttpHeartbeat
;
class
SrsKbps
;
...
...
@@ -120,7 +120,7 @@ private:
SrsGoHttpServeMux
*
http_api_mux
;
#endif
#ifdef SRS_AUTO_HTTP_SERVER
SrsHttp
Handler
*
http_stream_handler
;
SrsHttp
Server
*
http_stream_mux
;
#endif
#ifdef SRS_AUTO_HTTP_PARSER
SrsHttpHeartbeat
*
http_heartbeat
;
...
...
trunk/src/core/srs_core.hpp
查看文件 @
cbed2bb
...
...
@@ -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 9
6
#define VERSION_REVISION 9
8
// server info.
#define RTMP_SIG_SRS_KEY "SRS"
...
...
请
注册
或
登录
后发表评论