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
2014-04-04 23:06:27 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
ef26e7756032f78acb7c3a9c9c5add339daa8be9
ef26e775
1 parent
00eda0d7
implements the http stream module.
隐藏空白字符变更
内嵌
并排对比
正在显示
1 个修改的文件
包含
303 行增加
和
335 行删除
trunk/src/app/srs_app_http_conn.cpp
trunk/src/app/srs_app_http_conn.cpp
100644 → 100755
查看文件 @
ef26e77
/*
The MIT License (MIT)
Copyright (c) 2013-2014 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <srs_app_http_conn.hpp>
#ifdef SRS_HTTP_SERVER
#include <sstream>
using
namespace
std
;
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <srs_kernel_log.hpp>
#include <srs_kernel_error.hpp>
#include <srs_app_socket.hpp>
#include <srs_app_http.hpp>
#include <srs_core_autofree.hpp>
#include <srs_app_json.hpp>
#include <srs_app_config.hpp>
SrsHttpRoot
::
SrsHttpRoot
()
{
// TODO: FIXME: support reload vhosts.
}
SrsHttpRoot
::~
SrsHttpRoot
()
{
}
int
SrsHttpRoot
::
initialize
()
{
int
ret
=
ERROR_SUCCESS
;
// add root
handlers
.
push_back
(
new
SrsHttpVhost
(
"__http__"
,
"/"
,
_srs_config
->
get_http_stream_dir
()));
// add other virtual path
SrsConfDirective
*
root
=
_srs_config
->
get_root
();
for
(
int
i
=
0
;
i
<
(
int
)
root
->
directives
.
size
();
i
++
)
{
SrsConfDirective
*
conf
=
root
->
at
(
i
);
if
(
!
conf
->
is_vhost
())
{
continue
;
}
std
::
string
vhost
=
conf
->
arg0
();
if
(
!
_srs_config
->
get_vhost_http_enabled
(
vhost
))
{
continue
;
}
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
));
}
return
ret
;
}
bool
SrsHttpRoot
::
can_handle
(
const
char
*
path
,
int
length
,
const
char
**
pchild
)
{
// reset the child path to path,
// for child to reparse the path.
*
pchild
=
path
;
// only compare the first char.
return
srs_path_equals
(
"/"
,
path
,
1
);
}
bool
SrsHttpRoot
::
is_handler_valid
(
SrsHttpMessage
*
req
,
int
&
status_code
,
std
::
string
&
reason_phrase
)
{
if
(
!
SrsHttpHandler
::
is_handler_valid
(
req
,
status_code
,
reason_phrase
))
{
return
false
;
}
if
(
req
->
match
()
->
matched_url
.
length
()
!=
1
)
{
status_code
=
HTTP_NotFound
;
reason_phrase
=
HTTP_NotFound_str
;
return
false
;
}
return
true
;
}
int
SrsHttpRoot
::
do_process_request
(
SrsSocket
*
skt
,
SrsHttpMessage
*
req
)
{
std
::
stringstream
ss
;
ss
<<
JOBJECT_START
<<
JFIELD_ERROR
(
ERROR_SUCCESS
)
<<
JFIELD_CONT
<<
JFIELD_ORG
(
"urls"
,
JOBJECT_START
);
vector
<
SrsHttpHandler
*>::
iterator
it
;
for
(
it
=
handlers
.
begin
();
it
!=
handlers
.
end
();
++
it
)
{
SrsHttpVhost
*
handler
=
dynamic_cast
<
SrsHttpVhost
*>
(
*
it
);
srs_assert
(
handler
);
ss
<<
JFIELD_ORG
(
handler
->
mount
(),
JOBJECT_START
)
<<
JFIELD_STR
(
"mount"
,
handler
->
mount
())
<<
JFIELD_CONT
<<
JFIELD_STR
(
"vhost"
,
handler
->
vhost
())
<<
JFIELD_CONT
<<
JFIELD_STR
(
"dir"
,
handler
->
dir
())
<<
JOBJECT_END
;
if
(
it
+
1
!=
handlers
.
end
())
{
ss
<<
JFIELD_CONT
;
}
}
ss
<<
JOBJECT_END
<<
JOBJECT_END
;
return
res_json
(
skt
,
req
,
ss
.
str
());
}
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*/
)
{
int
min_match
=
srs_min
(
length
,
(
int
)
_mount
.
length
());
return
srs_path_equals
(
_mount
.
c_str
(),
path
,
min_match
);
}
bool
SrsHttpVhost
::
is_handler_valid
(
SrsHttpMessage
*
req
,
int
&
status_code
,
std
::
string
&
reason_phrase
)
{
std
::
string
fullpath
=
_dir
+
"/"
+
req
->
match
()
->
unmatched_url
;
if
(
req
->
match
()
->
unmatched_url
.
empty
())
{
fullpath
+=
req
->
match
()
->
matched_url
;
}
if
(
::
access
(
fullpath
.
c_str
(),
F_OK
|
R_OK
)
<
0
)
{
srs_warn
(
"check file %s does not exists"
,
fullpath
.
c_str
());
status_code
=
HTTP_NotFound
;
reason_phrase
=
HTTP_NotFound_str
;
return
false
;
}
return
true
;
}
int
SrsHttpVhost
::
do_process_request
(
SrsSocket
*
skt
,
SrsHttpMessage
*
req
)
{
int
ret
=
ERROR_SUCCESS
;
std
::
string
fullpath
=
_dir
+
"/"
+
req
->
match
()
->
unmatched_url
;
if
(
req
->
match
()
->
unmatched_url
.
empty
())
{
fullpath
+=
req
->
match
()
->
matched_url
;
}
if
(
srs_string_ends_with
(
fullpath
,
"/"
))
{
fullpath
+=
"index.html"
;
}
int
fd
=
::
open
(
fullpath
.
c_str
(),
O_RDONLY
);
if
(
fd
<
0
)
{
ret
=
ERROR_HTTP_OPEN_FILE
;
srs_warn
(
"open file %s failed, ret=%d"
,
fullpath
.
c_str
(),
ret
);
return
ret
;
}
int64_t
length
=
(
int64_t
)
::
lseek
(
fd
,
0
,
SEEK_END
);
::
lseek
(
fd
,
0
,
SEEK_SET
);
char
*
buf
=
new
char
[
length
];
SrsAutoFree
(
char
,
buf
,
true
);
if
(
::
read
(
fd
,
buf
,
length
)
<
0
)
{
::
close
(
fd
);
ret
=
ERROR_HTTP_READ_FILE
;
srs_warn
(
"read file %s failed, ret=%d"
,
fullpath
.
c_str
(),
ret
);
return
ret
;
}
::
close
(
fd
);
std
::
string
str
;
str
.
append
(
buf
,
length
);
if
(
srs_string_ends_with
(
fullpath
,
".ts"
))
{
return
res_mpegts
(
skt
,
req
,
str
);
}
else
if
(
srs_string_ends_with
(
fullpath
,
".m3u8"
))
{
return
res_m3u8
(
skt
,
req
,
str
);
}
else
{
return
res_text
(
skt
,
req
,
str
);
}
return
ret
;
}
string
SrsHttpVhost
::
vhost
()
{
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
)
{
parser
=
new
SrsHttpParser
();
handler
=
_handler
;
requires_crossdomain
=
false
;
}
SrsHttpConn
::~
SrsHttpConn
()
{
srs_freep
(
parser
);
}
int
SrsHttpConn
::
do_cycle
()
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
get_peer_ip
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"get peer ip failed. ret=%d"
,
ret
);
return
ret
;
}
srs_trace
(
"http get peer ip success. ip=%s"
,
ip
);
// initialize parser
if
((
ret
=
parser
->
initialize
(
HTTP_REQUEST
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"http initialize http parser failed. ret=%d"
,
ret
);
return
ret
;
}
// underlayer socket
SrsSocket
skt
(
stfd
);
// process http messages.
for
(;;)
{
SrsHttpMessage
*
req
=
NULL
;
// get a http message
if
((
ret
=
parser
->
parse_message
(
&
skt
,
&
req
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// if SUCCESS, always NOT-NULL and completed message.
srs_assert
(
req
);
srs_assert
(
req
->
is_complete
());
// always free it in this scope.
SrsAutoFree
(
SrsHttpMessage
,
req
,
false
);
// ok, handle http request.
if
((
ret
=
process_request
(
&
skt
,
req
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
}
return
ret
;
}
int
SrsHttpConn
::
process_request
(
SrsSocket
*
skt
,
SrsHttpMessage
*
req
)
{
int
ret
=
ERROR_SUCCESS
;
// parse uri to schema/server:port/path?query
if
((
ret
=
req
->
parse_uri
())
!=
ERROR_SUCCESS
)
{
return
ret
;
}
srs_trace
(
"http request parsed, method=%d, url=%s, content-length=%"
PRId64
""
,
req
->
method
(),
req
->
url
().
c_str
(),
req
->
content_length
());
// TODO: maybe need to parse the url.
std
::
string
url
=
req
->
path
();
SrsHttpHandlerMatch
*
p
=
NULL
;
if
((
ret
=
handler
->
best_match
(
url
.
data
(),
url
.
length
(),
&
p
))
!=
ERROR_SUCCESS
)
{
srs_warn
(
"failed to find the best match handler for url. ret=%d"
,
ret
);
return
ret
;
}
// if success, p and pstart should be valid.
srs_assert
(
p
);
srs_assert
(
p
->
handler
);
srs_assert
(
p
->
matched_url
.
length
()
<=
url
.
length
());
srs_info
(
"best match handler, matched_url=%s"
,
p
->
matched_url
.
c_str
());
req
->
set_match
(
p
);
req
->
set_requires_crossdomain
(
requires_crossdomain
);
// use handler to process request.
if
((
ret
=
p
->
handler
->
process_request
(
skt
,
req
))
!=
ERROR_SUCCESS
)
{
srs_warn
(
"handler failed to process http request. ret=%d"
,
ret
);
return
ret
;
}
if
(
req
->
requires_crossdomain
())
{
requires_crossdomain
=
true
;
}
return
ret
;
}
#endif
/*
The MIT License (MIT)
Copyright (c) 2013-2014 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <srs_app_http_conn.hpp>
#ifdef SRS_HTTP_SERVER
#include <sstream>
using
namespace
std
;
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <srs_kernel_log.hpp>
#include <srs_kernel_error.hpp>
#include <srs_app_socket.hpp>
#include <srs_app_http.hpp>
#include <srs_core_autofree.hpp>
#include <srs_app_json.hpp>
#include <srs_app_config.hpp>
SrsHttpRoot
::
SrsHttpRoot
()
{
// TODO: FIXME: support reload vhosts.
}
SrsHttpRoot
::~
SrsHttpRoot
()
{
}
int
SrsHttpRoot
::
initialize
()
{
int
ret
=
ERROR_SUCCESS
;
// add root
handlers
.
push_back
(
new
SrsHttpVhost
(
"__http__"
,
"/"
,
_srs_config
->
get_http_stream_dir
()));
// add other virtual path
SrsConfDirective
*
root
=
_srs_config
->
get_root
();
for
(
int
i
=
0
;
i
<
(
int
)
root
->
directives
.
size
();
i
++
)
{
SrsConfDirective
*
conf
=
root
->
at
(
i
);
if
(
!
conf
->
is_vhost
())
{
continue
;
}
std
::
string
vhost
=
conf
->
arg0
();
if
(
!
_srs_config
->
get_vhost_http_enabled
(
vhost
))
{
continue
;
}
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
));
}
return
ret
;
}
bool
SrsHttpRoot
::
can_handle
(
const
char
*
path
,
int
length
,
const
char
**
pchild
)
{
// reset the child path to path,
// for child to reparse the path.
*
pchild
=
path
;
// never handle request for root.
return
false
;
}
bool
SrsHttpRoot
::
is_handler_valid
(
SrsHttpMessage
*
req
,
int
&
status_code
,
std
::
string
&
reason_phrase
)
{
status_code
=
HTTP_InternalServerError
;
reason_phrase
=
HTTP_InternalServerError_str
;
return
false
;
}
int
SrsHttpRoot
::
do_process_request
(
SrsSocket
*
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*/
)
{
int
min_match
=
srs_min
(
length
,
(
int
)
_mount
.
length
());
return
srs_path_equals
(
_mount
.
c_str
(),
path
,
min_match
);
}
bool
SrsHttpVhost
::
is_handler_valid
(
SrsHttpMessage
*
req
,
int
&
status_code
,
std
::
string
&
reason_phrase
)
{
std
::
string
fullpath
=
_dir
+
"/"
+
req
->
match
()
->
unmatched_url
;
if
(
req
->
match
()
->
unmatched_url
.
empty
())
{
fullpath
+=
req
->
match
()
->
matched_url
;
}
if
(
::
access
(
fullpath
.
c_str
(),
F_OK
|
R_OK
)
<
0
)
{
srs_warn
(
"check file %s does not exists"
,
fullpath
.
c_str
());
status_code
=
HTTP_NotFound
;
reason_phrase
=
HTTP_NotFound_str
;
return
false
;
}
return
true
;
}
int
SrsHttpVhost
::
do_process_request
(
SrsSocket
*
skt
,
SrsHttpMessage
*
req
)
{
int
ret
=
ERROR_SUCCESS
;
std
::
string
fullpath
=
_dir
+
"/"
+
req
->
match
()
->
unmatched_url
;
if
(
req
->
match
()
->
unmatched_url
.
empty
())
{
fullpath
+=
req
->
match
()
->
matched_url
;
}
if
(
srs_string_ends_with
(
fullpath
,
"/"
))
{
fullpath
+=
"index.html"
;
}
int
fd
=
::
open
(
fullpath
.
c_str
(),
O_RDONLY
);
if
(
fd
<
0
)
{
ret
=
ERROR_HTTP_OPEN_FILE
;
srs_warn
(
"open file %s failed, ret=%d"
,
fullpath
.
c_str
(),
ret
);
return
ret
;
}
int64_t
length
=
(
int64_t
)
::
lseek
(
fd
,
0
,
SEEK_END
);
::
lseek
(
fd
,
0
,
SEEK_SET
);
char
*
buf
=
new
char
[
length
];
SrsAutoFree
(
char
,
buf
,
true
);
if
(
::
read
(
fd
,
buf
,
length
)
<
0
)
{
::
close
(
fd
);
ret
=
ERROR_HTTP_READ_FILE
;
srs_warn
(
"read file %s failed, ret=%d"
,
fullpath
.
c_str
(),
ret
);
return
ret
;
}
::
close
(
fd
);
std
::
string
str
;
str
.
append
(
buf
,
length
);
if
(
srs_string_ends_with
(
fullpath
,
".ts"
))
{
return
res_mpegts
(
skt
,
req
,
str
);
}
else
if
(
srs_string_ends_with
(
fullpath
,
".m3u8"
))
{
return
res_m3u8
(
skt
,
req
,
str
);
}
else
{
return
res_text
(
skt
,
req
,
str
);
}
return
ret
;
}
string
SrsHttpVhost
::
vhost
()
{
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
)
{
parser
=
new
SrsHttpParser
();
handler
=
_handler
;
requires_crossdomain
=
false
;
}
SrsHttpConn
::~
SrsHttpConn
()
{
srs_freep
(
parser
);
}
int
SrsHttpConn
::
do_cycle
()
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
get_peer_ip
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"get peer ip failed. ret=%d"
,
ret
);
return
ret
;
}
srs_trace
(
"http get peer ip success. ip=%s"
,
ip
);
// initialize parser
if
((
ret
=
parser
->
initialize
(
HTTP_REQUEST
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"http initialize http parser failed. ret=%d"
,
ret
);
return
ret
;
}
// underlayer socket
SrsSocket
skt
(
stfd
);
// process http messages.
for
(;;)
{
SrsHttpMessage
*
req
=
NULL
;
// get a http message
if
((
ret
=
parser
->
parse_message
(
&
skt
,
&
req
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// if SUCCESS, always NOT-NULL and completed message.
srs_assert
(
req
);
srs_assert
(
req
->
is_complete
());
// always free it in this scope.
SrsAutoFree
(
SrsHttpMessage
,
req
,
false
);
// ok, handle http request.
if
((
ret
=
process_request
(
&
skt
,
req
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
}
return
ret
;
}
int
SrsHttpConn
::
process_request
(
SrsSocket
*
skt
,
SrsHttpMessage
*
req
)
{
int
ret
=
ERROR_SUCCESS
;
// parse uri to schema/server:port/path?query
if
((
ret
=
req
->
parse_uri
())
!=
ERROR_SUCCESS
)
{
return
ret
;
}
srs_trace
(
"http request parsed, method=%d, url=%s, content-length=%"
PRId64
""
,
req
->
method
(),
req
->
url
().
c_str
(),
req
->
content_length
());
// TODO: maybe need to parse the url.
std
::
string
url
=
req
->
path
();
SrsHttpHandlerMatch
*
p
=
NULL
;
if
((
ret
=
handler
->
best_match
(
url
.
data
(),
url
.
length
(),
&
p
))
!=
ERROR_SUCCESS
)
{
srs_warn
(
"failed to find the best match handler for url. ret=%d"
,
ret
);
return
ret
;
}
// if success, p and pstart should be valid.
srs_assert
(
p
);
srs_assert
(
p
->
handler
);
srs_assert
(
p
->
matched_url
.
length
()
<=
url
.
length
());
srs_info
(
"best match handler, matched_url=%s"
,
p
->
matched_url
.
c_str
());
req
->
set_match
(
p
);
req
->
set_requires_crossdomain
(
requires_crossdomain
);
// use handler to process request.
if
((
ret
=
p
->
handler
->
process_request
(
skt
,
req
))
!=
ERROR_SUCCESS
)
{
srs_warn
(
"handler failed to process http request. ret=%d"
,
ret
);
return
ret
;
}
if
(
req
->
requires_crossdomain
())
{
requires_crossdomain
=
true
;
}
return
ret
;
}
#endif
...
...
请
注册
或
登录
后发表评论