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-05-22 22:24:05 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
ce1bb6c60582e0cf26e500d4a35f3f272cfb8628
ce1bb6c6
1 parent
e2955da7
refine code, extrat the ISrsHttpMessage.
显示空白字符变更
内嵌
并排对比
正在显示
13 个修改的文件
包含
1266 行增加
和
1145 行删除
trunk/src/app/srs_app_heartbeat.cpp
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_api.hpp
trunk/src/app/srs_app_http_client.cpp
trunk/src/app/srs_app_http_client.hpp
trunk/src/app/srs_app_http_conn.cpp
trunk/src/app/srs_app_http_conn.hpp
trunk/src/app/srs_app_http_hooks.cpp
trunk/src/main/srs_main_ingest_hls.cpp
trunk/src/protocol/srs_http_stack.cpp
trunk/src/protocol/srs_http_stack.hpp
trunk/src/app/srs_app_heartbeat.cpp
查看文件 @
ce1bb6c
...
...
@@ -82,14 +82,14 @@ void SrsHttpHeartbeat::heartbeat()
return
;
}
SrsHttpMessage
*
msg
=
NULL
;
I
SrsHttpMessage
*
msg
=
NULL
;
if
((
ret
=
http
.
post
(
uri
.
get_path
(),
req
,
&
msg
))
!=
ERROR_SUCCESS
)
{
srs_info
(
"http post hartbeart uri failed. "
"url=%s, request=%s, response=%s, ret=%d"
,
url
.
c_str
(),
req
.
c_str
(),
res
.
c_str
(),
ret
);
return
;
}
SrsAutoFree
(
SrsHttpMessage
,
msg
);
SrsAutoFree
(
I
SrsHttpMessage
,
msg
);
std
::
string
res
;
if
((
ret
=
msg
->
body_read_all
(
res
))
!=
ERROR_SUCCESS
)
{
...
...
trunk/src/app/srs_app_http.cpp
查看文件 @
ce1bb6c
...
...
@@ -25,726 +25,17 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifdef SRS_AUTO_HTTP_PARSER
#include <stdlib.h>
#include <sys/stat.h>
#include <algorithm>
#include <sstream>
using
namespace
std
;
#include <srs_kernel_error.hpp>
#include <srs_kernel_log.hpp>
#include <srs_app_st_socket.hpp>
#include <srs_app_http_api.hpp>
#include <srs_app_http_conn.hpp>
#include <srs_app_json.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_rtmp_buffer.hpp>
#include <srs_kernel_file.hpp>
#include <srs_core_autofree.hpp>
#include <srs_rtmp_buffer.hpp>
#include <srs_rtmp_sdk.hpp>
#include <srs_rtmp_buffer.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_rtmp_utility.hpp>
#define SRS_DEFAULT_HTTP_PORT 80
// for http parser macros
#define SRS_CONSTS_HTTP_OPTIONS HTTP_OPTIONS
#define SRS_CONSTS_HTTP_GET HTTP_GET
#define SRS_CONSTS_HTTP_POST HTTP_POST
#define SRS_CONSTS_HTTP_PUT HTTP_PUT
#define SRS_CONSTS_HTTP_DELETE HTTP_DELETE
// for ead all of http body, read each time.
#define SRS_HTTP_READ_CACHE_BYTES 4096
#define SRS_HTTP_DEFAULT_PAGE "index.html"
int
srs_http_response_json
(
ISrsHttpResponseWriter
*
w
,
string
data
)
{
w
->
header
()
->
set_content_length
(
data
.
length
());
w
->
header
()
->
set_content_type
(
"application/json"
);
return
w
->
write
((
char
*
)
data
.
data
(),
(
int
)
data
.
length
());
}
// get the status text of code.
string
srs_generate_http_status_text
(
int
status
)
{
static
std
::
map
<
int
,
std
::
string
>
_status_map
;
if
(
_status_map
.
empty
())
{
_status_map
[
SRS_CONSTS_HTTP_Continue
]
=
SRS_CONSTS_HTTP_Continue_str
;
_status_map
[
SRS_CONSTS_HTTP_SwitchingProtocols
]
=
SRS_CONSTS_HTTP_SwitchingProtocols_str
;
_status_map
[
SRS_CONSTS_HTTP_OK
]
=
SRS_CONSTS_HTTP_OK_str
;
_status_map
[
SRS_CONSTS_HTTP_Created
]
=
SRS_CONSTS_HTTP_Created_str
;
_status_map
[
SRS_CONSTS_HTTP_Accepted
]
=
SRS_CONSTS_HTTP_Accepted_str
;
_status_map
[
SRS_CONSTS_HTTP_NonAuthoritativeInformation
]
=
SRS_CONSTS_HTTP_NonAuthoritativeInformation_str
;
_status_map
[
SRS_CONSTS_HTTP_NoContent
]
=
SRS_CONSTS_HTTP_NoContent_str
;
_status_map
[
SRS_CONSTS_HTTP_ResetContent
]
=
SRS_CONSTS_HTTP_ResetContent_str
;
_status_map
[
SRS_CONSTS_HTTP_PartialContent
]
=
SRS_CONSTS_HTTP_PartialContent_str
;
_status_map
[
SRS_CONSTS_HTTP_MultipleChoices
]
=
SRS_CONSTS_HTTP_MultipleChoices_str
;
_status_map
[
SRS_CONSTS_HTTP_MovedPermanently
]
=
SRS_CONSTS_HTTP_MovedPermanently_str
;
_status_map
[
SRS_CONSTS_HTTP_Found
]
=
SRS_CONSTS_HTTP_Found_str
;
_status_map
[
SRS_CONSTS_HTTP_SeeOther
]
=
SRS_CONSTS_HTTP_SeeOther_str
;
_status_map
[
SRS_CONSTS_HTTP_NotModified
]
=
SRS_CONSTS_HTTP_NotModified_str
;
_status_map
[
SRS_CONSTS_HTTP_UseProxy
]
=
SRS_CONSTS_HTTP_UseProxy_str
;
_status_map
[
SRS_CONSTS_HTTP_TemporaryRedirect
]
=
SRS_CONSTS_HTTP_TemporaryRedirect_str
;
_status_map
[
SRS_CONSTS_HTTP_BadRequest
]
=
SRS_CONSTS_HTTP_BadRequest_str
;
_status_map
[
SRS_CONSTS_HTTP_Unauthorized
]
=
SRS_CONSTS_HTTP_Unauthorized_str
;
_status_map
[
SRS_CONSTS_HTTP_PaymentRequired
]
=
SRS_CONSTS_HTTP_PaymentRequired_str
;
_status_map
[
SRS_CONSTS_HTTP_Forbidden
]
=
SRS_CONSTS_HTTP_Forbidden_str
;
_status_map
[
SRS_CONSTS_HTTP_NotFound
]
=
SRS_CONSTS_HTTP_NotFound_str
;
_status_map
[
SRS_CONSTS_HTTP_MethodNotAllowed
]
=
SRS_CONSTS_HTTP_MethodNotAllowed_str
;
_status_map
[
SRS_CONSTS_HTTP_NotAcceptable
]
=
SRS_CONSTS_HTTP_NotAcceptable_str
;
_status_map
[
SRS_CONSTS_HTTP_ProxyAuthenticationRequired
]
=
SRS_CONSTS_HTTP_ProxyAuthenticationRequired_str
;
_status_map
[
SRS_CONSTS_HTTP_RequestTimeout
]
=
SRS_CONSTS_HTTP_RequestTimeout_str
;
_status_map
[
SRS_CONSTS_HTTP_Conflict
]
=
SRS_CONSTS_HTTP_Conflict_str
;
_status_map
[
SRS_CONSTS_HTTP_Gone
]
=
SRS_CONSTS_HTTP_Gone_str
;
_status_map
[
SRS_CONSTS_HTTP_LengthRequired
]
=
SRS_CONSTS_HTTP_LengthRequired_str
;
_status_map
[
SRS_CONSTS_HTTP_PreconditionFailed
]
=
SRS_CONSTS_HTTP_PreconditionFailed_str
;
_status_map
[
SRS_CONSTS_HTTP_RequestEntityTooLarge
]
=
SRS_CONSTS_HTTP_RequestEntityTooLarge_str
;
_status_map
[
SRS_CONSTS_HTTP_RequestURITooLarge
]
=
SRS_CONSTS_HTTP_RequestURITooLarge_str
;
_status_map
[
SRS_CONSTS_HTTP_UnsupportedMediaType
]
=
SRS_CONSTS_HTTP_UnsupportedMediaType_str
;
_status_map
[
SRS_CONSTS_HTTP_RequestedRangeNotSatisfiable
]
=
SRS_CONSTS_HTTP_RequestedRangeNotSatisfiable_str
;
_status_map
[
SRS_CONSTS_HTTP_ExpectationFailed
]
=
SRS_CONSTS_HTTP_ExpectationFailed_str
;
_status_map
[
SRS_CONSTS_HTTP_InternalServerError
]
=
SRS_CONSTS_HTTP_InternalServerError_str
;
_status_map
[
SRS_CONSTS_HTTP_NotImplemented
]
=
SRS_CONSTS_HTTP_NotImplemented_str
;
_status_map
[
SRS_CONSTS_HTTP_BadGateway
]
=
SRS_CONSTS_HTTP_BadGateway_str
;
_status_map
[
SRS_CONSTS_HTTP_ServiceUnavailable
]
=
SRS_CONSTS_HTTP_ServiceUnavailable_str
;
_status_map
[
SRS_CONSTS_HTTP_GatewayTimeout
]
=
SRS_CONSTS_HTTP_GatewayTimeout_str
;
_status_map
[
SRS_CONSTS_HTTP_HTTPVersionNotSupported
]
=
SRS_CONSTS_HTTP_HTTPVersionNotSupported_str
;
}
std
::
string
status_text
;
if
(
_status_map
.
find
(
status
)
==
_status_map
.
end
())
{
status_text
=
"Status Unknown"
;
}
else
{
status_text
=
_status_map
[
status
];
}
return
status_text
;
}
// bodyAllowedForStatus reports whether a given response status code
// permits a body. See RFC2616, section 4.4.
bool
srs_go_http_body_allowd
(
int
status
)
{
if
(
status
>=
100
&&
status
<=
199
)
{
return
false
;
}
else
if
(
status
==
204
||
status
==
304
)
{
return
false
;
}
return
true
;
}
// DetectContentType implements the algorithm described
// at http://mimesniff.spec.whatwg.org/ to determine the
// Content-Type of the given data. It considers at most the
// first 512 bytes of data. DetectContentType always returns
// a valid MIME type: if it cannot determine a more specific one, it
// returns "application/octet-stream".
string
srs_go_http_detect
(
char
*
data
,
int
size
)
{
// detect only when data specified.
if
(
data
)
{
}
return
"application/octet-stream"
;
// fallback
}
// Error replies to the request with the specified error message and HTTP code.
// The error message should be plain text.
int
srs_go_http_error
(
ISrsHttpResponseWriter
*
w
,
int
code
,
string
error
)
{
int
ret
=
ERROR_SUCCESS
;
w
->
header
()
->
set_content_type
(
"text/plain; charset=utf-8"
);
w
->
header
()
->
set_content_length
(
error
.
length
());
w
->
write_header
(
code
);
w
->
write
((
char
*
)
error
.
data
(),
(
int
)
error
.
length
());
return
ret
;
}
SrsHttpHeader
::
SrsHttpHeader
()
{
}
SrsHttpHeader
::~
SrsHttpHeader
()
{
}
void
SrsHttpHeader
::
set
(
string
key
,
string
value
)
{
headers
[
key
]
=
value
;
}
string
SrsHttpHeader
::
get
(
string
key
)
{
std
::
string
v
;
if
(
headers
.
find
(
key
)
!=
headers
.
end
())
{
v
=
headers
[
key
];
}
return
v
;
}
int64_t
SrsHttpHeader
::
content_length
()
{
std
::
string
cl
=
get
(
"Content-Length"
);
if
(
cl
.
empty
())
{
return
-
1
;
}
return
(
int64_t
)
::
atof
(
cl
.
c_str
());
}
void
SrsHttpHeader
::
set_content_length
(
int64_t
size
)
{
char
buf
[
64
];
snprintf
(
buf
,
sizeof
(
buf
),
"%"
PRId64
,
size
);
set
(
"Content-Length"
,
buf
);
}
string
SrsHttpHeader
::
content_type
()
{
return
get
(
"Content-Type"
);
}
void
SrsHttpHeader
::
set_content_type
(
string
ct
)
{
set
(
"Content-Type"
,
ct
);
}
void
SrsHttpHeader
::
write
(
stringstream
&
ss
)
{
std
::
map
<
std
::
string
,
std
::
string
>::
iterator
it
;
for
(
it
=
headers
.
begin
();
it
!=
headers
.
end
();
++
it
)
{
ss
<<
it
->
first
<<
": "
<<
it
->
second
<<
SRS_HTTP_CRLF
;
}
}
ISrsHttpResponseWriter
::
ISrsHttpResponseWriter
()
{
}
ISrsHttpResponseWriter
::~
ISrsHttpResponseWriter
()
{
}
ISrsHttpResponseReader
::
ISrsHttpResponseReader
()
{
}
ISrsHttpResponseReader
::~
ISrsHttpResponseReader
()
{
}
ISrsHttpHandler
::
ISrsHttpHandler
()
{
entry
=
NULL
;
}
ISrsHttpHandler
::~
ISrsHttpHandler
()
{
}
SrsHttpRedirectHandler
::
SrsHttpRedirectHandler
(
string
u
,
int
c
)
{
url
=
u
;
code
=
c
;
}
SrsHttpRedirectHandler
::~
SrsHttpRedirectHandler
()
{
}
int
SrsHttpRedirectHandler
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
{
int
ret
=
ERROR_SUCCESS
;
// TODO: FIXME: implements it.
return
ret
;
}
SrsHttpNotFoundHandler
::
SrsHttpNotFoundHandler
()
{
}
SrsHttpNotFoundHandler
::~
SrsHttpNotFoundHandler
()
{
}
int
SrsHttpNotFoundHandler
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
{
return
srs_go_http_error
(
w
,
SRS_CONSTS_HTTP_NotFound
,
SRS_CONSTS_HTTP_NotFound_str
);
}
SrsHttpFileServer
::
SrsHttpFileServer
(
string
root_dir
)
{
dir
=
root_dir
;
}
SrsHttpFileServer
::~
SrsHttpFileServer
()
{
}
int
SrsHttpFileServer
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
{
string
upath
=
r
->
path
();
// add default pages.
if
(
srs_string_ends_with
(
upath
,
"/"
))
{
upath
+=
SRS_HTTP_DEFAULT_PAGE
;
}
string
fullpath
=
dir
+
"/"
;
// remove the virtual directory.
srs_assert
(
entry
);
size_t
pos
=
entry
->
pattern
.
find
(
"/"
);
if
(
upath
.
length
()
>
entry
->
pattern
.
length
()
&&
pos
!=
string
::
npos
)
{
fullpath
+=
upath
.
substr
(
entry
->
pattern
.
length
()
-
pos
);
}
else
{
fullpath
+=
upath
;
}
// stat current dir, if exists, return error.
if
(
!
srs_path_exists
(
fullpath
))
{
srs_warn
(
"http miss file=%s, pattern=%s, upath=%s"
,
fullpath
.
c_str
(),
entry
->
pattern
.
c_str
(),
upath
.
c_str
());
return
SrsHttpNotFoundHandler
().
serve_http
(
w
,
r
);
}
srs_trace
(
"http match file=%s, pattern=%s, upath=%s"
,
fullpath
.
c_str
(),
entry
->
pattern
.
c_str
(),
upath
.
c_str
());
// handle file according to its extension.
// use vod stream for .flv/.fhv
if
(
srs_string_ends_with
(
fullpath
,
".flv"
)
||
srs_string_ends_with
(
fullpath
,
".fhv"
))
{
return
serve_flv_file
(
w
,
r
,
fullpath
);
}
else
if
(
srs_string_ends_with
(
fullpath
,
".mp4"
))
{
return
serve_mp4_file
(
w
,
r
,
fullpath
);
}
// serve common static file.
return
serve_file
(
w
,
r
,
fullpath
);
}
int
SrsHttpFileServer
::
serve_file
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
string
fullpath
)
{
int
ret
=
ERROR_SUCCESS
;
// 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
();
// unset the content length to encode in chunked encoding.
w
->
header
()
->
set_content_length
(
length
);
static
std
::
map
<
std
::
string
,
std
::
string
>
_mime
;
if
(
_mime
.
empty
())
{
_mime
[
".ts"
]
=
"video/MP2T"
;
_mime
[
".flv"
]
=
"video/x-flv"
;
_mime
[
".m4v"
]
=
"video/x-m4v"
;
_mime
[
".3gpp"
]
=
"video/3gpp"
;
_mime
[
".3gp"
]
=
"video/3gpp"
;
_mime
[
".mp4"
]
=
"video/mp4"
;
_mime
[
".aac"
]
=
"audio/x-aac"
;
_mime
[
".mp3"
]
=
"audio/mpeg"
;
_mime
[
".m4a"
]
=
"audio/x-m4a"
;
_mime
[
".ogg"
]
=
"audio/ogg"
;
// @see hls-m3u8-draft-pantos-http-live-streaming-12.pdf, page 5.
_mime
[
".m3u8"
]
=
"application/vnd.apple.mpegurl"
;
// application/x-mpegURL
_mime
[
".rss"
]
=
"application/rss+xml"
;
_mime
[
".json"
]
=
"application/json"
;
_mime
[
".swf"
]
=
"application/x-shockwave-flash"
;
_mime
[
".doc"
]
=
"application/msword"
;
_mime
[
".zip"
]
=
"application/zip"
;
_mime
[
".rar"
]
=
"application/x-rar-compressed"
;
_mime
[
".xml"
]
=
"text/xml"
;
_mime
[
".html"
]
=
"text/html"
;
_mime
[
".js"
]
=
"text/javascript"
;
_mime
[
".css"
]
=
"text/css"
;
_mime
[
".ico"
]
=
"image/x-icon"
;
_mime
[
".png"
]
=
"image/png"
;
_mime
[
".jpeg"
]
=
"image/jpeg"
;
_mime
[
".jpg"
]
=
"image/jpeg"
;
_mime
[
".gif"
]
=
"image/gif"
;
}
if
(
true
)
{
size_t
pos
;
std
::
string
ext
=
fullpath
;
if
((
pos
=
ext
.
rfind
(
"."
))
!=
string
::
npos
)
{
ext
=
ext
.
substr
(
pos
);
}
if
(
_mime
.
find
(
ext
)
==
_mime
.
end
())
{
w
->
header
()
->
set_content_type
(
"application/octet-stream"
);
}
else
{
w
->
header
()
->
set_content_type
(
_mime
[
ext
]);
}
}
// write body.
int64_t
left
=
length
;
if
((
ret
=
copy
(
w
,
&
fs
,
r
,
(
int
)
left
))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"read file=%s size=%d failed, ret=%d"
,
fullpath
.
c_str
(),
left
,
ret
);
}
return
ret
;
}
return
w
->
final_request
();
}
int
SrsHttpFileServer
::
serve_flv_file
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
string
fullpath
)
{
std
::
string
start
=
r
->
query_get
(
"start"
);
if
(
start
.
empty
())
{
return
serve_file
(
w
,
r
,
fullpath
);
}
int
offset
=
::
atoi
(
start
.
c_str
());
if
(
offset
<=
0
)
{
return
serve_file
(
w
,
r
,
fullpath
);
}
return
serve_flv_stream
(
w
,
r
,
fullpath
,
offset
);
}
int
SrsHttpFileServer
::
serve_mp4_file
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
string
fullpath
)
{
// for flash to request mp4 range in query string.
// for example, http://digitalprimates.net/dash/DashTest.html?url=http://dashdemo.edgesuite.net/digitalprimates/nexus/oops-20120802-manifest.mpd
std
::
string
range
=
r
->
query_get
(
"range"
);
// or, use bytes to request range,
// for example, http://dashas.castlabs.com/demo/try.html
if
(
range
.
empty
())
{
range
=
r
->
query_get
(
"bytes"
);
}
// rollback to serve whole file.
size_t
pos
=
string
::
npos
;
if
(
range
.
empty
()
||
(
pos
=
range
.
find
(
"-"
))
==
string
::
npos
)
{
return
serve_file
(
w
,
r
,
fullpath
);
}
// parse the start in query string
int
start
=
0
;
if
(
pos
>
0
)
{
start
=
::
atoi
(
range
.
substr
(
0
,
pos
).
c_str
());
}
// parse end in query string.
int
end
=
-
1
;
if
(
pos
<
range
.
length
()
-
1
)
{
end
=
::
atoi
(
range
.
substr
(
pos
+
1
).
c_str
());
}
// invalid param, serve as whole mp4 file.
if
(
start
<
0
||
(
end
!=
-
1
&&
start
>
end
))
{
return
serve_file
(
w
,
r
,
fullpath
);
}
return
serve_mp4_stream
(
w
,
r
,
fullpath
,
start
,
end
);
}
int
SrsHttpFileServer
::
serve_flv_stream
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
string
fullpath
,
int
offset
)
{
return
serve_file
(
w
,
r
,
fullpath
);
}
int
SrsHttpFileServer
::
serve_mp4_stream
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
string
fullpath
,
int
start
,
int
end
)
{
return
serve_file
(
w
,
r
,
fullpath
);
}
int
SrsHttpFileServer
::
copy
(
ISrsHttpResponseWriter
*
w
,
SrsFileReader
*
fs
,
SrsHttpMessage
*
r
,
int
size
)
{
int
ret
=
ERROR_SUCCESS
;
int
left
=
size
;
char
*
buf
=
r
->
http_ts_send_buffer
();
while
(
left
>
0
)
{
ssize_t
nread
=
-
1
;
int
max_read
=
srs_min
(
left
,
SRS_HTTP_TS_SEND_BUFFER_SIZE
);
if
((
ret
=
fs
->
read
(
buf
,
max_read
,
&
nread
))
!=
ERROR_SUCCESS
)
{
break
;
}
left
-=
nread
;
if
((
ret
=
w
->
write
(
buf
,
(
int
)
nread
))
!=
ERROR_SUCCESS
)
{
break
;
}
}
return
ret
;
}
SrsHttpMuxEntry
::
SrsHttpMuxEntry
()
{
enabled
=
true
;
explicit_match
=
false
;
handler
=
NULL
;
}
SrsHttpMuxEntry
::~
SrsHttpMuxEntry
()
{
srs_freep
(
handler
);
}
ISrsHttpMatchHijacker
::
ISrsHttpMatchHijacker
()
{
}
ISrsHttpMatchHijacker
::~
ISrsHttpMatchHijacker
()
{
}
SrsHttpServeMux
::
SrsHttpServeMux
()
{
}
SrsHttpServeMux
::~
SrsHttpServeMux
()
{
std
::
map
<
std
::
string
,
SrsHttpMuxEntry
*>::
iterator
it
;
for
(
it
=
entries
.
begin
();
it
!=
entries
.
end
();
++
it
)
{
SrsHttpMuxEntry
*
entry
=
it
->
second
;
srs_freep
(
entry
);
}
entries
.
clear
();
vhosts
.
clear
();
hijackers
.
clear
();
}
int
SrsHttpServeMux
::
initialize
()
{
int
ret
=
ERROR_SUCCESS
;
// TODO: FIXME: implements it.
return
ret
;
}
void
SrsHttpServeMux
::
hijack
(
ISrsHttpMatchHijacker
*
h
)
{
std
::
vector
<
ISrsHttpMatchHijacker
*>::
iterator
it
=
::
find
(
hijackers
.
begin
(),
hijackers
.
end
(),
h
);
if
(
it
!=
hijackers
.
end
())
{
return
;
}
hijackers
.
push_back
(
h
);
}
void
SrsHttpServeMux
::
unhijack
(
ISrsHttpMatchHijacker
*
h
)
{
std
::
vector
<
ISrsHttpMatchHijacker
*>::
iterator
it
=
::
find
(
hijackers
.
begin
(),
hijackers
.
end
(),
h
);
if
(
it
==
hijackers
.
end
())
{
return
;
}
hijackers
.
erase
(
it
);
}
int
SrsHttpServeMux
::
handle
(
std
::
string
pattern
,
ISrsHttpHandler
*
handler
)
{
int
ret
=
ERROR_SUCCESS
;
srs_assert
(
handler
);
if
(
pattern
.
empty
())
{
ret
=
ERROR_HTTP_PATTERN_EMPTY
;
srs_error
(
"http: empty pattern. ret=%d"
,
ret
);
return
ret
;
}
if
(
entries
.
find
(
pattern
)
!=
entries
.
end
())
{
SrsHttpMuxEntry
*
exists
=
entries
[
pattern
];
if
(
exists
->
explicit_match
)
{
ret
=
ERROR_HTTP_PATTERN_DUPLICATED
;
srs_error
(
"http: multiple registrations for %s. ret=%d"
,
pattern
.
c_str
(),
ret
);
return
ret
;
}
}
std
::
string
vhost
=
pattern
;
if
(
pattern
.
at
(
0
)
!=
'/'
)
{
if
(
pattern
.
find
(
"/"
)
!=
string
::
npos
)
{
vhost
=
pattern
.
substr
(
0
,
pattern
.
find
(
"/"
));
}
vhosts
[
vhost
]
=
handler
;
}
if
(
true
)
{
SrsHttpMuxEntry
*
entry
=
new
SrsHttpMuxEntry
();
entry
->
explicit_match
=
true
;
entry
->
handler
=
handler
;
entry
->
pattern
=
pattern
;
entry
->
handler
->
entry
=
entry
;
if
(
entries
.
find
(
pattern
)
!=
entries
.
end
())
{
SrsHttpMuxEntry
*
exists
=
entries
[
pattern
];
srs_freep
(
exists
);
}
entries
[
pattern
]
=
entry
;
}
// Helpful behavior:
// If pattern is /tree/, insert an implicit permanent redirect for /tree.
// It can be overridden by an explicit registration.
if
(
pattern
!=
"/"
&&
!
pattern
.
empty
()
&&
pattern
.
at
(
pattern
.
length
()
-
1
)
==
'/'
)
{
std
::
string
rpattern
=
pattern
.
substr
(
0
,
pattern
.
length
()
-
1
);
SrsHttpMuxEntry
*
entry
=
NULL
;
// free the exists not explicit entry
if
(
entries
.
find
(
rpattern
)
!=
entries
.
end
())
{
SrsHttpMuxEntry
*
exists
=
entries
[
rpattern
];
if
(
!
exists
->
explicit_match
)
{
entry
=
exists
;
}
}
// create implicit redirect.
if
(
!
entry
||
entry
->
explicit_match
)
{
srs_freep
(
entry
);
entry
=
new
SrsHttpMuxEntry
();
entry
->
explicit_match
=
false
;
entry
->
handler
=
new
SrsHttpRedirectHandler
(
pattern
,
SRS_CONSTS_HTTP_MovedPermanently
);
entry
->
pattern
=
pattern
;
entry
->
handler
->
entry
=
entry
;
entries
[
rpattern
]
=
entry
;
}
}
return
ret
;
}
int
SrsHttpServeMux
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
{
int
ret
=
ERROR_SUCCESS
;
ISrsHttpHandler
*
h
=
NULL
;
if
((
ret
=
find_handler
(
r
,
&
h
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"find handler failed. ret=%d"
,
ret
);
return
ret
;
}
srs_assert
(
h
);
if
((
ret
=
h
->
serve_http
(
w
,
r
))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"handler serve http failed. ret=%d"
,
ret
);
}
return
ret
;
}
return
ret
;
}
int
SrsHttpServeMux
::
find_handler
(
SrsHttpMessage
*
r
,
ISrsHttpHandler
**
ph
)
{
int
ret
=
ERROR_SUCCESS
;
// TODO: FIXME: support the path . and ..
if
(
r
->
url
().
find
(
".."
)
!=
std
::
string
::
npos
)
{
ret
=
ERROR_HTTP_URL_NOT_CLEAN
;
srs_error
(
"htt url not canonical, url=%s. ret=%d"
,
r
->
url
().
c_str
(),
ret
);
return
ret
;
}
if
((
ret
=
match
(
r
,
ph
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"http match handler failed. ret=%d"
,
ret
);
return
ret
;
}
// always hijack.
if
(
!
hijackers
.
empty
())
{
// notice all hijacker the match failed.
std
::
vector
<
ISrsHttpMatchHijacker
*>::
iterator
it
;
for
(
it
=
hijackers
.
begin
();
it
!=
hijackers
.
end
();
++
it
)
{
ISrsHttpMatchHijacker
*
hijacker
=
*
it
;
if
((
ret
=
hijacker
->
hijack
(
r
,
ph
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hijacker match failed. ret=%d"
,
ret
);
return
ret
;
}
}
}
if
(
*
ph
==
NULL
)
{
// TODO: FIXME: memory leak.
*
ph
=
new
SrsHttpNotFoundHandler
();
}
return
ret
;
}
int
SrsHttpServeMux
::
match
(
SrsHttpMessage
*
r
,
ISrsHttpHandler
**
ph
)
{
int
ret
=
ERROR_SUCCESS
;
std
::
string
path
=
r
->
path
();
// Host-specific pattern takes precedence over generic ones
if
(
!
vhosts
.
empty
()
&&
vhosts
.
find
(
r
->
host
())
!=
vhosts
.
end
())
{
path
=
r
->
host
()
+
path
;
}
int
nb_matched
=
0
;
ISrsHttpHandler
*
h
=
NULL
;
std
::
map
<
std
::
string
,
SrsHttpMuxEntry
*>::
iterator
it
;
for
(
it
=
entries
.
begin
();
it
!=
entries
.
end
();
++
it
)
{
std
::
string
pattern
=
it
->
first
;
SrsHttpMuxEntry
*
entry
=
it
->
second
;
if
(
!
entry
->
enabled
)
{
continue
;
}
if
(
!
path_match
(
pattern
,
path
))
{
continue
;
}
if
(
!
h
||
(
int
)
pattern
.
length
()
>
nb_matched
)
{
nb_matched
=
(
int
)
pattern
.
length
();
h
=
entry
->
handler
;
}
}
*
ph
=
h
;
return
ret
;
}
bool
SrsHttpServeMux
::
path_match
(
string
pattern
,
string
path
)
{
if
(
pattern
.
empty
())
{
return
false
;
}
int
n
=
(
int
)
pattern
.
length
();
// not endswith '/', exactly match.
if
(
pattern
.
at
(
n
-
1
)
!=
'/'
)
{
return
pattern
==
path
;
}
// endswith '/', match any,
// for example, '/api/' match '/api/[N]'
if
((
int
)
path
.
length
()
>=
n
)
{
if
(
memcmp
(
pattern
.
data
(),
path
.
data
(),
n
)
==
0
)
{
return
true
;
}
}
return
false
;
}
#include <srs_core_autofree.hpp>
SrsHttpResponseWriter
::
SrsHttpResponseWriter
(
SrsStSocket
*
io
)
{
...
...
@@ -1078,7 +369,7 @@ int SrsHttpResponseReader::read_specified(char* data, int nb_data, int* nb_read)
return
ret
;
}
SrsHttpMessage
::
SrsHttpMessage
(
SrsStSocket
*
io
,
SrsConnection
*
c
)
SrsHttpMessage
::
SrsHttpMessage
(
SrsStSocket
*
io
,
SrsConnection
*
c
)
:
ISrsHttpMessage
()
{
conn
=
c
;
chunked
=
false
;
...
...
@@ -1165,11 +456,6 @@ int SrsHttpMessage::update(string url, http_parser* header, SrsFastBuffer* body,
return
ret
;
}
char
*
SrsHttpMessage
::
http_ts_send_buffer
()
{
return
_http_ts_send_buffer
;
}
SrsConnection
*
SrsHttpMessage
::
connection
()
{
return
conn
;
...
...
@@ -1409,7 +695,7 @@ int SrsHttpParser::initialize(enum http_parser_type type)
return
ret
;
}
int
SrsHttpParser
::
parse_message
(
SrsStSocket
*
skt
,
SrsConnection
*
conn
,
SrsHttpMessage
**
ppmsg
)
int
SrsHttpParser
::
parse_message
(
SrsStSocket
*
skt
,
SrsConnection
*
conn
,
I
SrsHttpMessage
**
ppmsg
)
{
*
ppmsg
=
NULL
;
...
...
trunk/src/app/srs_app_http.hpp
查看文件 @
ce1bb6c
...
...
@@ -34,366 +34,22 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <map>
#include <string>
#include <vector>
#include <sstream>
#include <http_parser.h>
#include <srs_app_st.hpp>
#include <srs_kernel_consts.hpp>
#include <srs_http_stack.hpp>
class
SrsRequest
;
class
SrsStSocket
;
class
SrsHttpUri
;
class
SrsHttpMessage
;
class
SrsFileReader
;
class
SrsSimpleBuffer
;
class
SrsHttpMuxEntry
;
class
ISrsHttpResponseWriter
;
class
SrsFastBuffer
;
class
SrsHttpUri
;
class
SrsConnection
;
// http specification
// CR = <US-ASCII CR, carriage return (13)>
#define SRS_HTTP_CR SRS_CONSTS_CR // 0x0D
// LF = <US-ASCII LF, linefeed (10)>
#define SRS_HTTP_LF SRS_CONSTS_LF // 0x0A
// SP = <US-ASCII SP, space (32)>
#define SRS_HTTP_SP ' ' // 0x20
// HT = <US-ASCII HT, horizontal-tab (9)>
#define SRS_HTTP_HT '\x09' // 0x09
// HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
// protocol elements except the entity-body (see appendix 19.3 for
// tolerant applications).
#define SRS_HTTP_CRLF "\r\n" // 0x0D0A
#define SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
// @see SrsHttpMessage._http_ts_send_buffer
#define SRS_HTTP_TS_SEND_BUFFER_SIZE 4096
// helper function: response in json format.
extern
int
srs_http_response_json
(
ISrsHttpResponseWriter
*
w
,
std
::
string
data
);
// state of message
enum
SrsHttpParseState
{
SrsHttpParseStateInit
=
0
,
SrsHttpParseStateStart
,
SrsHttpParseStateHeaderComplete
,
SrsHttpParseStateMessageComplete
};
// A Header represents the key-value pairs in an HTTP header.
class
SrsHttpHeader
{
private
:
std
::
map
<
std
::
string
,
std
::
string
>
headers
;
public
:
SrsHttpHeader
();
virtual
~
SrsHttpHeader
();
public
:
// Add adds the key, value pair to the header.
// It appends to any existing values associated with key.
virtual
void
set
(
std
::
string
key
,
std
::
string
value
);
// Get gets the first value associated with the given key.
// If there are no values associated with the key, Get returns "".
// To access multiple values of a key, access the map directly
// with CanonicalHeaderKey.
virtual
std
::
string
get
(
std
::
string
key
);
public
:
/**
* get the content length. -1 if not set.
*/
virtual
int64_t
content_length
();
/**
* set the content length by header "Content-Length"
*/
virtual
void
set_content_length
(
int64_t
size
);
public
:
/**
* get the content type. empty string if not set.
*/
virtual
std
::
string
content_type
();
/**
* set the content type by header "Content-Type"
*/
virtual
void
set_content_type
(
std
::
string
ct
);
public
:
/**
* write all headers to string stream.
*/
virtual
void
write
(
std
::
stringstream
&
ss
);
};
// A ResponseWriter interface is used by an HTTP handler to
// construct an HTTP response.
// Usage 1, response with specified length content:
// ISrsHttpResponseWriter* w; // create or get response.
// std::string msg = "Hello, HTTP!";
// w->header()->set_content_type("text/plain; charset=utf-8");
// w->header()->set_content_length(msg.length());
// w->write_header(SRS_CONSTS_HTTP_OK);
// w->write((char*)msg.data(), (int)msg.length());
// w->final_request(); // optional flush.
// Usage 2, response with HTTP code only, zero content length.
// ISrsHttpResponseWriter* w; // create or get response.
// w->header()->set_content_length(0);
// w->write_header(SRS_CONSTS_HTTP_OK);
// w->final_request();
// Usage 3, response in chunked encoding.
// ISrsHttpResponseWriter* w; // create or get response.
// std::string msg = "Hello, HTTP!";
// w->header()->set_content_type("application/octet-stream");
// w->write_header(SRS_CONSTS_HTTP_OK);
// w->write((char*)msg.data(), (int)msg.length());
// w->write((char*)msg.data(), (int)msg.length());
// w->write((char*)msg.data(), (int)msg.length());
// w->write((char*)msg.data(), (int)msg.length());
// w->final_request(); // required to end the chunked and flush.
class
ISrsHttpResponseWriter
{
public
:
ISrsHttpResponseWriter
();
virtual
~
ISrsHttpResponseWriter
();
public
:
// when chunked mode,
// final the request to complete the chunked encoding.
// for no-chunked mode,
// final to send request, for example, content-length is 0.
virtual
int
final_request
()
=
0
;
// Header returns the header map that will be sent by WriteHeader.
// Changing the header after a call to WriteHeader (or Write) has
// no effect.
virtual
SrsHttpHeader
*
header
()
=
0
;
// Write writes the data to the connection as part of an HTTP reply.
// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
// before writing the data. If the Header does not contain a
// Content-Type line, Write adds a Content-Type set to the result of passing
// the initial 512 bytes of written data to DetectContentType.
// @param data, the data to send. NULL to flush header only.
virtual
int
write
(
char
*
data
,
int
size
)
=
0
;
// WriteHeader sends an HTTP response header with status code.
// If WriteHeader is not called explicitly, the first call to Write
// will trigger an implicit WriteHeader(http.StatusOK).
// Thus explicit calls to WriteHeader are mainly used to
// send error codes.
// @remark, user must set header then write or write_header.
virtual
void
write_header
(
int
code
)
=
0
;
};
/**
* the reader interface for http response.
*/
class
ISrsHttpResponseReader
{
public
:
ISrsHttpResponseReader
();
virtual
~
ISrsHttpResponseReader
();
public
:
/**
* whether response read EOF.
* response writer use st socket
*/
virtual
bool
eof
()
=
0
;
/**
* read from the response body.
* @param data, the buffer to read data buffer to.
* @param nb_data, the max size of data buffer.
* @param nb_read, the actual read size of bytes. NULL to ignore.
* @remark when eof(), return error.
*/
virtual
int
read
(
char
*
data
,
int
nb_data
,
int
*
nb_read
)
=
0
;
};
// Objects implementing the Handler interface can be
// registered to serve a particular path or subtree
// in the HTTP server.
//
// ServeHTTP should write reply headers and data to the ResponseWriter
// and then return. Returning signals that the request is finished
// and that the HTTP server can move on to the next request on
// the connection.
class
ISrsHttpHandler
{
public
:
SrsHttpMuxEntry
*
entry
;
public
:
ISrsHttpHandler
();
virtual
~
ISrsHttpHandler
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
=
0
;
};
// Redirect to a fixed URL
class
SrsHttpRedirectHandler
:
public
ISrsHttpHandler
{
private
:
std
::
string
url
;
int
code
;
public
:
SrsHttpRedirectHandler
(
std
::
string
u
,
int
c
);
virtual
~
SrsHttpRedirectHandler
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
};
// NotFound replies to the request with an HTTP 404 not found error.
class
SrsHttpNotFoundHandler
:
public
ISrsHttpHandler
{
public
:
SrsHttpNotFoundHandler
();
virtual
~
SrsHttpNotFoundHandler
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
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("/", SrsHttpFileServer("/tmp"))
// http.Handle("/", SrsHttpFileServer("static-dir"))
class
SrsHttpFileServer
:
public
ISrsHttpHandler
{
protected
:
std
::
string
dir
;
public
:
SrsHttpFileServer
(
std
::
string
root_dir
);
virtual
~
SrsHttpFileServer
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
private
:
/**
* serve the file by specified path
*/
virtual
int
serve_file
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
std
::
string
fullpath
);
virtual
int
serve_flv_file
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
std
::
string
fullpath
);
virtual
int
serve_mp4_file
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
std
::
string
fullpath
);
protected
:
/**
* when access flv file with x.flv?start=xxx
*/
virtual
int
serve_flv_stream
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
std
::
string
fullpath
,
int
offset
);
/**
* when access mp4 file with x.mp4?range=start-end
* @param start the start offset in bytes.
* @param end the end offset in bytes. -1 to end of file.
* @remark response data in [start, end].
*/
virtual
int
serve_mp4_stream
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
std
::
string
fullpath
,
int
start
,
int
end
);
protected
:
/**
* copy the fs to response writer in size bytes.
*/
virtual
int
copy
(
ISrsHttpResponseWriter
*
w
,
SrsFileReader
*
fs
,
SrsHttpMessage
*
r
,
int
size
);
};
// the mux entry for server mux.
// the matcher info, for example, the pattern and handler.
class
SrsHttpMuxEntry
{
public
:
bool
explicit_match
;
ISrsHttpHandler
*
handler
;
std
::
string
pattern
;
bool
enabled
;
public
:
SrsHttpMuxEntry
();
virtual
~
SrsHttpMuxEntry
();
};
/**
* the hijacker for http pattern match.
*/
class
ISrsHttpMatchHijacker
{
public
:
ISrsHttpMatchHijacker
();
virtual
~
ISrsHttpMatchHijacker
();
public
:
/**
* when match the request failed, no handler to process request.
* @param request the http request message to match the handler.
* @param ph the already matched handler, hijack can rewrite it.
*/
virtual
int
hijack
(
SrsHttpMessage
*
request
,
ISrsHttpHandler
**
ph
)
=
0
;
};
// ServeMux is an HTTP request multiplexer.
// It matches the URL of each incoming request against a list of registered
// patterns and calls the handler for the pattern that
// most closely matches the URL.
//
// Patterns name fixed, rooted paths, like "/favicon.ico",
// or rooted subtrees, like "/images/" (note the trailing slash).
// Longer patterns take precedence over shorter ones, so that
// if there are handlers registered for both "/images/"
// and "/images/thumbnails/", the latter handler will be
// called for paths beginning "/images/thumbnails/" and the
// former will receive requests for any other paths in the
// "/images/" subtree.
//
// Note that since a pattern ending in a slash names a rooted subtree,
// the pattern "/" matches all paths not matched by other registered
// patterns, not just the URL with Path == "/".
//
// Patterns may optionally begin with a host name, restricting matches to
// URLs on that host only. Host-specific patterns take precedence over
// general patterns, so that a handler might register for the two patterns
// "/codesearch" and "codesearch.google.com/" without also taking over
// requests for "http://www.google.com/".
//
// ServeMux also takes care of sanitizing the URL request path,
// redirecting any request containing . or .. elements to an
// equivalent .- and ..-free URL.
class
SrsHttpServeMux
{
private
:
// the pattern handler, to handle the http request.
std
::
map
<
std
::
string
,
SrsHttpMuxEntry
*>
entries
;
// the vhost handler.
// when find the handler to process the request,
// append the matched vhost when pattern not starts with /,
// for example, for pattern /live/livestream.flv of vhost ossrs.net,
// the path will rewrite to ossrs.net/live/livestream.flv
std
::
map
<
std
::
string
,
ISrsHttpHandler
*>
vhosts
;
// all hijackers for http match.
// for example, the hstrs(http stream trigger rtmp source)
// can hijack and install handler when request incoming and no handler.
std
::
vector
<
ISrsHttpMatchHijacker
*>
hijackers
;
public
:
SrsHttpServeMux
();
virtual
~
SrsHttpServeMux
();
public
:
/**
* initialize the http serve mux.
*/
virtual
int
initialize
();
/**
* hijack the http match.
*/
virtual
void
hijack
(
ISrsHttpMatchHijacker
*
h
);
virtual
void
unhijack
(
ISrsHttpMatchHijacker
*
h
);
public
:
// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
virtual
int
handle
(
std
::
string
pattern
,
ISrsHttpHandler
*
handler
);
// interface ISrsHttpHandler
public:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
private
:
virtual
int
find_handler
(
SrsHttpMessage
*
r
,
ISrsHttpHandler
**
ph
);
virtual
int
match
(
SrsHttpMessage
*
r
,
ISrsHttpHandler
**
ph
);
virtual
bool
path_match
(
std
::
string
pattern
,
std
::
string
path
);
};
/**
* response writer use st socket
*/
class
SrsHttpResponseWriter
:
public
ISrsHttpResponseWriter
{
private
:
...
...
@@ -427,8 +83,8 @@ public:
};
/**
* response reader use st socket.
*/
* response reader use st socket.
*/
class
SrsHttpResponseReader
:
virtual
public
ISrsHttpResponseReader
{
private
:
...
...
@@ -450,7 +106,7 @@ public:
* initialize the response reader with buffer.
*/
virtual
int
initialize
(
SrsFastBuffer
*
buffer
);
// interface ISrsHttpResponseReader
// interface ISrsHttpResponseReader
public:
virtual
bool
eof
();
virtual
int
read
(
char
*
data
,
int
nb_data
,
int
*
nb_read
);
...
...
@@ -469,9 +125,9 @@ typedef std::pair<std::string, std::string> SrsHttpHeaderField;
// usage. In addition to the notes on the fields below, see the
// documentation for Request.Write and RoundTripper.
/**
* the http message, request or response.
*/
class
SrsHttpMessage
* the http message, request or response.
*/
class
SrsHttpMessage
:
public
ISrsHttpMessage
{
private
:
/**
...
...
@@ -525,8 +181,7 @@ public:
virtual
int
update
(
std
::
string
url
,
http_parser
*
header
,
SrsFastBuffer
*
body
,
std
::
vector
<
SrsHttpHeaderField
>&
headers
);
public
:
virtual
char
*
http_ts_send_buffer
();
private
:
virtual
SrsConnection
*
connection
();
public
:
virtual
u_int8_t
method
();
...
...
@@ -631,7 +286,7 @@ public:
* or error and *ppmsg must be NULL.
* @remark, if success, *ppmsg always NOT-NULL, *ppmsg always is_complete().
*/
virtual
int
parse_message
(
SrsStSocket
*
skt
,
SrsConnection
*
conn
,
SrsHttpMessage
**
ppmsg
);
virtual
int
parse_message
(
SrsStSocket
*
skt
,
SrsConnection
*
conn
,
I
SrsHttpMessage
**
ppmsg
);
private
:
/**
* parse the HTTP message to member field: msg.
...
...
trunk/src/app/srs_app_http_api.cpp
查看文件 @
ce1bb6c
...
...
@@ -48,7 +48,7 @@ SrsGoApiRoot::~SrsGoApiRoot()
{
}
int
SrsGoApiRoot
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsGoApiRoot
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
std
::
stringstream
ss
;
...
...
@@ -70,7 +70,7 @@ SrsGoApiApi::~SrsGoApiApi()
{
}
int
SrsGoApiApi
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsGoApiApi
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
std
::
stringstream
ss
;
...
...
@@ -92,7 +92,7 @@ SrsGoApiV1::~SrsGoApiV1()
{
}
int
SrsGoApiV1
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsGoApiV1
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
std
::
stringstream
ss
;
...
...
@@ -123,7 +123,7 @@ SrsGoApiVersion::~SrsGoApiVersion()
{
}
int
SrsGoApiVersion
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsGoApiVersion
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
std
::
stringstream
ss
;
...
...
@@ -148,7 +148,7 @@ SrsGoApiSummaries::~SrsGoApiSummaries()
{
}
int
SrsGoApiSummaries
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsGoApiSummaries
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
std
::
stringstream
ss
;
srs_api_dump_summaries
(
ss
);
...
...
@@ -163,7 +163,7 @@ SrsGoApiRusages::~SrsGoApiRusages()
{
}
int
SrsGoApiRusages
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
req
)
int
SrsGoApiRusages
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
req
)
{
std
::
stringstream
ss
;
...
...
@@ -204,7 +204,7 @@ SrsGoApiSelfProcStats::~SrsGoApiSelfProcStats()
{
}
int
SrsGoApiSelfProcStats
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsGoApiSelfProcStats
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
std
::
stringstream
ss
;
...
...
@@ -274,7 +274,7 @@ SrsGoApiSystemProcStats::~SrsGoApiSystemProcStats()
{
}
int
SrsGoApiSystemProcStats
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsGoApiSystemProcStats
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
std
::
stringstream
ss
;
...
...
@@ -309,7 +309,7 @@ SrsGoApiMemInfos::~SrsGoApiMemInfos()
{
}
int
SrsGoApiMemInfos
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsGoApiMemInfos
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
std
::
stringstream
ss
;
...
...
@@ -345,7 +345,7 @@ SrsGoApiAuthors::~SrsGoApiAuthors()
{
}
int
SrsGoApiAuthors
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsGoApiAuthors
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
std
::
stringstream
ss
;
...
...
@@ -370,9 +370,9 @@ SrsGoApiRequests::~SrsGoApiRequests()
{
}
int
SrsGoApiRequests
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsGoApiRequests
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
SrsHttpMessage
*
req
=
r
;
I
SrsHttpMessage
*
req
=
r
;
std
::
stringstream
ss
;
...
...
@@ -431,7 +431,7 @@ SrsGoApiVhosts::~SrsGoApiVhosts()
{
}
int
SrsGoApiVhosts
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsGoApiVhosts
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
std
::
stringstream
data
;
SrsStatistic
*
stat
=
SrsStatistic
::
instance
();
...
...
@@ -456,7 +456,7 @@ SrsGoApiStreams::~SrsGoApiStreams()
{
}
int
SrsGoApiStreams
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsGoApiStreams
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
std
::
stringstream
data
;
SrsStatistic
*
stat
=
SrsStatistic
::
instance
();
...
...
@@ -529,7 +529,7 @@ int SrsHttpApi::do_cycle()
// process http messages.
for
(;;)
{
SrsHttpMessage
*
req
=
NULL
;
I
SrsHttpMessage
*
req
=
NULL
;
// get a http message
if
((
ret
=
parser
->
parse_message
(
&
skt
,
this
,
&
req
))
!=
ERROR_SUCCESS
)
{
...
...
@@ -540,7 +540,7 @@ int SrsHttpApi::do_cycle()
srs_assert
(
req
);
// always free it in this scope.
SrsAutoFree
(
SrsHttpMessage
,
req
);
SrsAutoFree
(
I
SrsHttpMessage
,
req
);
// TODO: FIXME: use the post body.
std
::
string
res
;
...
...
@@ -566,7 +566,7 @@ int SrsHttpApi::do_cycle()
return
ret
;
}
int
SrsHttpApi
::
process_request
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsHttpApi
::
process_request
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
trunk/src/app/srs_app_http_api.hpp
查看文件 @
ce1bb6c
...
...
@@ -33,7 +33,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifdef SRS_AUTO_HTTP_API
class
SrsStSocket
;
class
SrsHttpMessage
;
class
I
SrsHttpMessage
;
class
SrsHttpParser
;
class
SrsHttpHandler
;
...
...
@@ -48,7 +48,7 @@ public:
SrsGoApiRoot
();
virtual
~
SrsGoApiRoot
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsGoApiApi
:
public
ISrsHttpHandler
...
...
@@ -57,7 +57,7 @@ public:
SrsGoApiApi
();
virtual
~
SrsGoApiApi
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsGoApiV1
:
public
ISrsHttpHandler
...
...
@@ -66,7 +66,7 @@ public:
SrsGoApiV1
();
virtual
~
SrsGoApiV1
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsGoApiVersion
:
public
ISrsHttpHandler
...
...
@@ -75,7 +75,7 @@ public:
SrsGoApiVersion
();
virtual
~
SrsGoApiVersion
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsGoApiSummaries
:
public
ISrsHttpHandler
...
...
@@ -84,7 +84,7 @@ public:
SrsGoApiSummaries
();
virtual
~
SrsGoApiSummaries
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsGoApiRusages
:
public
ISrsHttpHandler
...
...
@@ -93,7 +93,7 @@ public:
SrsGoApiRusages
();
virtual
~
SrsGoApiRusages
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsGoApiSelfProcStats
:
public
ISrsHttpHandler
...
...
@@ -102,7 +102,7 @@ public:
SrsGoApiSelfProcStats
();
virtual
~
SrsGoApiSelfProcStats
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsGoApiSystemProcStats
:
public
ISrsHttpHandler
...
...
@@ -111,7 +111,7 @@ public:
SrsGoApiSystemProcStats
();
virtual
~
SrsGoApiSystemProcStats
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsGoApiMemInfos
:
public
ISrsHttpHandler
...
...
@@ -120,7 +120,7 @@ public:
SrsGoApiMemInfos
();
virtual
~
SrsGoApiMemInfos
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsGoApiAuthors
:
public
ISrsHttpHandler
...
...
@@ -129,7 +129,7 @@ public:
SrsGoApiAuthors
();
virtual
~
SrsGoApiAuthors
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsGoApiRequests
:
public
ISrsHttpHandler
...
...
@@ -138,7 +138,7 @@ public:
SrsGoApiRequests
();
virtual
~
SrsGoApiRequests
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsGoApiVhosts
:
public
ISrsHttpHandler
...
...
@@ -147,7 +147,7 @@ public:
SrsGoApiVhosts
();
virtual
~
SrsGoApiVhosts
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsGoApiStreams
:
public
ISrsHttpHandler
...
...
@@ -156,7 +156,7 @@ public:
SrsGoApiStreams
();
virtual
~
SrsGoApiStreams
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsHttpApi
:
public
SrsConnection
...
...
@@ -177,7 +177,7 @@ public:
protected
:
virtual
int
do_cycle
();
private
:
virtual
int
process_request
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
process_request
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
#endif
...
...
trunk/src/app/srs_app_http_client.cpp
查看文件 @
ce1bb6c
...
...
@@ -71,7 +71,7 @@ int SrsHttpClient::initialize(string h, int p, int64_t t_us)
return
ret
;
}
int
SrsHttpClient
::
post
(
string
path
,
string
req
,
SrsHttpMessage
**
ppmsg
)
int
SrsHttpClient
::
post
(
string
path
,
string
req
,
I
SrsHttpMessage
**
ppmsg
)
{
*
ppmsg
=
NULL
;
...
...
@@ -104,7 +104,7 @@ int SrsHttpClient::post(string path, string req, SrsHttpMessage** ppmsg)
return
ret
;
}
SrsHttpMessage
*
msg
=
NULL
;
I
SrsHttpMessage
*
msg
=
NULL
;
if
((
ret
=
parser
->
parse_message
(
skt
,
NULL
,
&
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"parse http post response failed. ret=%d"
,
ret
);
return
ret
;
...
...
@@ -117,7 +117,7 @@ int SrsHttpClient::post(string path, string req, SrsHttpMessage** ppmsg)
return
ret
;
}
int
SrsHttpClient
::
get
(
string
path
,
std
::
string
req
,
SrsHttpMessage
**
ppmsg
)
int
SrsHttpClient
::
get
(
string
path
,
std
::
string
req
,
I
SrsHttpMessage
**
ppmsg
)
{
*
ppmsg
=
NULL
;
...
...
@@ -150,7 +150,7 @@ int SrsHttpClient::get(string path, std::string req, SrsHttpMessage** ppmsg)
return
ret
;
}
SrsHttpMessage
*
msg
=
NULL
;
I
SrsHttpMessage
*
msg
=
NULL
;
if
((
ret
=
parser
->
parse_message
(
skt
,
NULL
,
&
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"parse http post response failed. ret=%d"
,
ret
);
return
ret
;
...
...
trunk/src/app/srs_app_http_client.hpp
查看文件 @
ce1bb6c
...
...
@@ -37,7 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
class
SrsHttpUri
;
class
SrsHttpParser
;
class
SrsHttpMessage
;
class
I
SrsHttpMessage
;
class
SrsStSocket
;
// the default timeout for http client.
...
...
@@ -73,14 +73,14 @@ public:
* @param req the data post to uri. empty string to ignore.
* @param ppmsg output the http message to read the response.
*/
virtual
int
post
(
std
::
string
path
,
std
::
string
req
,
SrsHttpMessage
**
ppmsg
);
virtual
int
post
(
std
::
string
path
,
std
::
string
req
,
I
SrsHttpMessage
**
ppmsg
);
/**
* to get data from the uri.
* @param the path to request on.
* @param req the data post to uri. empty string to ignore.
* @param ppmsg output the http message to read the response.
*/
virtual
int
get
(
std
::
string
path
,
std
::
string
req
,
SrsHttpMessage
**
ppmsg
);
virtual
int
get
(
std
::
string
path
,
std
::
string
req
,
I
SrsHttpMessage
**
ppmsg
);
private
:
virtual
void
disconnect
();
virtual
int
connect
();
...
...
trunk/src/app/srs_app_http_conn.cpp
查看文件 @
ce1bb6c
...
...
@@ -60,7 +60,7 @@ SrsVodStream::~SrsVodStream()
{
}
int
SrsVodStream
::
serve_flv_stream
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
string
fullpath
,
int
offset
)
int
SrsVodStream
::
serve_flv_stream
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
,
string
fullpath
,
int
offset
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
@@ -144,7 +144,7 @@ int SrsVodStream::serve_flv_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r,
return
ret
;
}
int
SrsVodStream
::
serve_mp4_stream
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
string
fullpath
,
int
start
,
int
end
)
int
SrsVodStream
::
serve_mp4_stream
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
,
string
fullpath
,
int
start
,
int
end
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
@@ -567,7 +567,7 @@ SrsLiveStream::~SrsLiveStream()
srs_freep
(
req
);
}
int
SrsLiveStream
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsLiveStream
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
@@ -743,7 +743,7 @@ void SrsHlsM3u8Stream::set_m3u8(std::string v)
m3u8
=
v
;
}
int
SrsHlsM3u8Stream
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsHlsM3u8Stream
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
@@ -775,7 +775,7 @@ void SrsHlsTsStream::set_ts(std::string v)
ts
=
v
;
}
int
SrsHlsTsStream
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsHlsTsStream
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
@@ -1110,7 +1110,7 @@ int SrsHttpServer::on_reload_vhost_hls(string vhost)
return
ret
;
}
int
SrsHttpServer
::
hijack
(
SrsHttpMessage
*
request
,
ISrsHttpHandler
**
ph
)
int
SrsHttpServer
::
hijack
(
I
SrsHttpMessage
*
request
,
ISrsHttpHandler
**
ph
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
@@ -1169,8 +1169,12 @@ int SrsHttpServer::hijack(SrsHttpMessage* request, ISrsHttpHandler** ph)
}
}
// convert to concreate class.
SrsHttpMessage
*
hreq
=
dynamic_cast
<
SrsHttpMessage
*>
(
request
);
srs_assert
(
hreq
);
// hijack for entry.
SrsRequest
*
r
=
request
->
to_request
(
vhost
->
arg0
());
SrsRequest
*
r
=
hreq
->
to_request
(
vhost
->
arg0
());
SrsAutoFree
(
SrsRequest
,
r
);
SrsSource
*
s
=
SrsSource
::
fetch
(
r
);
if
(
!
s
)
{
...
...
@@ -1389,7 +1393,7 @@ int SrsHttpConn::do_cycle()
// process http messages.
for
(;;)
{
SrsHttpMessage
*
req
=
NULL
;
I
SrsHttpMessage
*
req
=
NULL
;
// get a http message
if
((
ret
=
parser
->
parse_message
(
&
skt
,
this
,
&
req
))
!=
ERROR_SUCCESS
)
{
...
...
@@ -1400,7 +1404,7 @@ int SrsHttpConn::do_cycle()
srs_assert
(
req
);
// always free it in this scope.
SrsAutoFree
(
SrsHttpMessage
,
req
);
SrsAutoFree
(
I
SrsHttpMessage
,
req
);
// may should discard the body.
if
((
ret
=
on_got_http_message
(
req
))
!=
ERROR_SUCCESS
)
{
...
...
@@ -1423,7 +1427,7 @@ int SrsHttpConn::do_cycle()
return
ret
;
}
int
SrsHttpConn
::
process_request
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
)
int
SrsHttpConn
::
process_request
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
@@ -1450,7 +1454,7 @@ SrsStaticHttpConn::~SrsStaticHttpConn()
{
}
int
SrsStaticHttpConn
::
on_got_http_message
(
SrsHttpMessage
*
msg
)
int
SrsStaticHttpConn
::
on_got_http_message
(
I
SrsHttpMessage
*
msg
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
trunk/src/app/srs_app_http_conn.hpp
查看文件 @
ce1bb6c
...
...
@@ -49,7 +49,7 @@ class SrsAacEncoder;
class
SrsMp3Encoder
;
class
SrsFlvEncoder
;
class
SrsHttpParser
;
class
SrsHttpMessage
;
class
I
SrsHttpMessage
;
class
SrsHttpHandler
;
class
SrsMessageQueue
;
class
SrsSharedPtrMessage
;
...
...
@@ -66,8 +66,8 @@ public:
SrsVodStream
(
std
::
string
root_dir
);
virtual
~
SrsVodStream
();
protected
:
virtual
int
serve_flv_stream
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
std
::
string
fullpath
,
int
offset
);
virtual
int
serve_mp4_stream
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
,
std
::
string
fullpath
,
int
start
,
int
end
);
virtual
int
serve_flv_stream
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
,
std
::
string
fullpath
,
int
offset
);
virtual
int
serve_mp4_stream
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
,
std
::
string
fullpath
,
int
start
,
int
end
);
};
/**
...
...
@@ -243,7 +243,7 @@ public:
SrsLiveStream
(
SrsSource
*
s
,
SrsRequest
*
r
,
SrsStreamCache
*
c
);
virtual
~
SrsLiveStream
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
private
:
virtual
int
streaming_send_messages
(
ISrsStreamEncoder
*
enc
,
SrsSharedPtrMessage
**
msgs
,
int
nb_msgs
);
};
...
...
@@ -289,7 +289,7 @@ public:
public
:
virtual
void
set_m3u8
(
std
::
string
v
);
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
/**
...
...
@@ -305,7 +305,7 @@ public:
public
:
virtual
void
set_ts
(
std
::
string
v
);
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
/**
...
...
@@ -365,7 +365,7 @@ public:
virtual
int
on_reload_vhost_hls
(
std
::
string
vhost
);
// interface ISrsHttpMatchHijacker
public:
virtual
int
hijack
(
SrsHttpMessage
*
request
,
ISrsHttpHandler
**
ph
);
virtual
int
hijack
(
I
SrsHttpMessage
*
request
,
ISrsHttpHandler
**
ph
);
private
:
virtual
int
initialize_static_file
();
virtual
int
initialize_flv_streaming
();
...
...
@@ -392,9 +392,9 @@ protected:
// when got http message,
// for the static service or api, discard any body.
// for the stream caster, for instance, http flv streaming, may discard the flv header or not.
virtual
int
on_got_http_message
(
SrsHttpMessage
*
msg
)
=
0
;
virtual
int
on_got_http_message
(
I
SrsHttpMessage
*
msg
)
=
0
;
private
:
virtual
int
process_request
(
ISrsHttpResponseWriter
*
w
,
SrsHttpMessage
*
r
);
virtual
int
process_request
(
ISrsHttpResponseWriter
*
w
,
I
SrsHttpMessage
*
r
);
};
class
SrsStaticHttpConn
:
public
SrsHttpConn
...
...
@@ -403,7 +403,7 @@ public:
SrsStaticHttpConn
(
IConnectionManager
*
cm
,
st_netfd_t
fd
,
SrsHttpServeMux
*
m
);
virtual
~
SrsStaticHttpConn
();
public
:
virtual
int
on_got_http_message
(
SrsHttpMessage
*
msg
);
virtual
int
on_got_http_message
(
I
SrsHttpMessage
*
msg
);
};
#endif
...
...
trunk/src/app/srs_app_http_hooks.cpp
查看文件 @
ce1bb6c
...
...
@@ -371,11 +371,11 @@ int SrsHttpHooks::on_hls_notify(std::string url, SrsRequest* req, std::string ts
}
srs_warn
(
"GET %s"
,
path
.
c_str
());
SrsHttpMessage
*
msg
=
NULL
;
I
SrsHttpMessage
*
msg
=
NULL
;
if
((
ret
=
http
.
get
(
path
.
c_str
(),
""
,
&
msg
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
SrsAutoFree
(
SrsHttpMessage
,
msg
);
SrsAutoFree
(
I
SrsHttpMessage
,
msg
);
int
nb_buf
=
srs_min
(
nb_notify
,
SRS_HTTP_READ_BUFFER
);
char
*
buf
=
new
char
[
nb_buf
];
...
...
@@ -416,11 +416,11 @@ int SrsHttpHooks::do_post(std::string url, std::string req, int& code, string& r
return
ret
;
}
SrsHttpMessage
*
msg
=
NULL
;
I
SrsHttpMessage
*
msg
=
NULL
;
if
((
ret
=
http
.
post
(
uri
.
get_path
(),
req
,
&
msg
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
SrsAutoFree
(
SrsHttpMessage
,
msg
);
SrsAutoFree
(
I
SrsHttpMessage
,
msg
);
code
=
msg
->
status_code
();
if
((
ret
=
msg
->
body_read_all
(
res
))
!=
ERROR_SUCCESS
)
{
...
...
trunk/src/main/srs_main_ingest_hls.cpp
查看文件 @
ce1bb6c
...
...
@@ -383,14 +383,14 @@ int SrsIngestSrsInput::parseM3u8(SrsHttpUri* url, double& td, double& duration)
return
ret
;
}
SrsHttpMessage
*
msg
=
NULL
;
I
SrsHttpMessage
*
msg
=
NULL
;
if
((
ret
=
client
.
get
(
url
->
get_path
(),
""
,
&
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"HTTP GET %s failed. ret=%d"
,
url
->
get_url
(),
ret
);
return
ret
;
}
srs_assert
(
msg
);
SrsAutoFree
(
SrsHttpMessage
,
msg
);
SrsAutoFree
(
I
SrsHttpMessage
,
msg
);
std
::
string
body
;
if
((
ret
=
msg
->
body_read_all
(
body
))
!=
ERROR_SUCCESS
)
{
...
...
@@ -605,14 +605,14 @@ int SrsIngestSrsInput::SrsTsPiece::fetch(string m3u8)
return
ret
;
}
SrsHttpMessage
*
msg
=
NULL
;
I
SrsHttpMessage
*
msg
=
NULL
;
if
((
ret
=
client
.
get
(
uri
.
get_path
(),
""
,
&
msg
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"HTTP GET %s failed. ret=%d"
,
uri
.
get_url
(),
ret
);
return
ret
;
}
srs_assert
(
msg
);
SrsAutoFree
(
SrsHttpMessage
,
msg
);
SrsAutoFree
(
I
SrsHttpMessage
,
msg
);
if
((
ret
=
msg
->
body_read_all
(
body
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"read ts failed. ret=%d"
,
ret
);
...
...
trunk/src/protocol/srs_http_stack.cpp
查看文件 @
ce1bb6c
...
...
@@ -22,3 +22,717 @@
*/
#include <srs_http_stack.hpp>
#include <sstream>
using
namespace
std
;
#include <srs_kernel_error.hpp>
#include <srs_kernel_log.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_kernel_file.hpp>
#define SRS_HTTP_DEFAULT_PAGE "index.html"
// get the status text of code.
string
srs_generate_http_status_text
(
int
status
)
{
static
std
::
map
<
int
,
std
::
string
>
_status_map
;
if
(
_status_map
.
empty
())
{
_status_map
[
SRS_CONSTS_HTTP_Continue
]
=
SRS_CONSTS_HTTP_Continue_str
;
_status_map
[
SRS_CONSTS_HTTP_SwitchingProtocols
]
=
SRS_CONSTS_HTTP_SwitchingProtocols_str
;
_status_map
[
SRS_CONSTS_HTTP_OK
]
=
SRS_CONSTS_HTTP_OK_str
;
_status_map
[
SRS_CONSTS_HTTP_Created
]
=
SRS_CONSTS_HTTP_Created_str
;
_status_map
[
SRS_CONSTS_HTTP_Accepted
]
=
SRS_CONSTS_HTTP_Accepted_str
;
_status_map
[
SRS_CONSTS_HTTP_NonAuthoritativeInformation
]
=
SRS_CONSTS_HTTP_NonAuthoritativeInformation_str
;
_status_map
[
SRS_CONSTS_HTTP_NoContent
]
=
SRS_CONSTS_HTTP_NoContent_str
;
_status_map
[
SRS_CONSTS_HTTP_ResetContent
]
=
SRS_CONSTS_HTTP_ResetContent_str
;
_status_map
[
SRS_CONSTS_HTTP_PartialContent
]
=
SRS_CONSTS_HTTP_PartialContent_str
;
_status_map
[
SRS_CONSTS_HTTP_MultipleChoices
]
=
SRS_CONSTS_HTTP_MultipleChoices_str
;
_status_map
[
SRS_CONSTS_HTTP_MovedPermanently
]
=
SRS_CONSTS_HTTP_MovedPermanently_str
;
_status_map
[
SRS_CONSTS_HTTP_Found
]
=
SRS_CONSTS_HTTP_Found_str
;
_status_map
[
SRS_CONSTS_HTTP_SeeOther
]
=
SRS_CONSTS_HTTP_SeeOther_str
;
_status_map
[
SRS_CONSTS_HTTP_NotModified
]
=
SRS_CONSTS_HTTP_NotModified_str
;
_status_map
[
SRS_CONSTS_HTTP_UseProxy
]
=
SRS_CONSTS_HTTP_UseProxy_str
;
_status_map
[
SRS_CONSTS_HTTP_TemporaryRedirect
]
=
SRS_CONSTS_HTTP_TemporaryRedirect_str
;
_status_map
[
SRS_CONSTS_HTTP_BadRequest
]
=
SRS_CONSTS_HTTP_BadRequest_str
;
_status_map
[
SRS_CONSTS_HTTP_Unauthorized
]
=
SRS_CONSTS_HTTP_Unauthorized_str
;
_status_map
[
SRS_CONSTS_HTTP_PaymentRequired
]
=
SRS_CONSTS_HTTP_PaymentRequired_str
;
_status_map
[
SRS_CONSTS_HTTP_Forbidden
]
=
SRS_CONSTS_HTTP_Forbidden_str
;
_status_map
[
SRS_CONSTS_HTTP_NotFound
]
=
SRS_CONSTS_HTTP_NotFound_str
;
_status_map
[
SRS_CONSTS_HTTP_MethodNotAllowed
]
=
SRS_CONSTS_HTTP_MethodNotAllowed_str
;
_status_map
[
SRS_CONSTS_HTTP_NotAcceptable
]
=
SRS_CONSTS_HTTP_NotAcceptable_str
;
_status_map
[
SRS_CONSTS_HTTP_ProxyAuthenticationRequired
]
=
SRS_CONSTS_HTTP_ProxyAuthenticationRequired_str
;
_status_map
[
SRS_CONSTS_HTTP_RequestTimeout
]
=
SRS_CONSTS_HTTP_RequestTimeout_str
;
_status_map
[
SRS_CONSTS_HTTP_Conflict
]
=
SRS_CONSTS_HTTP_Conflict_str
;
_status_map
[
SRS_CONSTS_HTTP_Gone
]
=
SRS_CONSTS_HTTP_Gone_str
;
_status_map
[
SRS_CONSTS_HTTP_LengthRequired
]
=
SRS_CONSTS_HTTP_LengthRequired_str
;
_status_map
[
SRS_CONSTS_HTTP_PreconditionFailed
]
=
SRS_CONSTS_HTTP_PreconditionFailed_str
;
_status_map
[
SRS_CONSTS_HTTP_RequestEntityTooLarge
]
=
SRS_CONSTS_HTTP_RequestEntityTooLarge_str
;
_status_map
[
SRS_CONSTS_HTTP_RequestURITooLarge
]
=
SRS_CONSTS_HTTP_RequestURITooLarge_str
;
_status_map
[
SRS_CONSTS_HTTP_UnsupportedMediaType
]
=
SRS_CONSTS_HTTP_UnsupportedMediaType_str
;
_status_map
[
SRS_CONSTS_HTTP_RequestedRangeNotSatisfiable
]
=
SRS_CONSTS_HTTP_RequestedRangeNotSatisfiable_str
;
_status_map
[
SRS_CONSTS_HTTP_ExpectationFailed
]
=
SRS_CONSTS_HTTP_ExpectationFailed_str
;
_status_map
[
SRS_CONSTS_HTTP_InternalServerError
]
=
SRS_CONSTS_HTTP_InternalServerError_str
;
_status_map
[
SRS_CONSTS_HTTP_NotImplemented
]
=
SRS_CONSTS_HTTP_NotImplemented_str
;
_status_map
[
SRS_CONSTS_HTTP_BadGateway
]
=
SRS_CONSTS_HTTP_BadGateway_str
;
_status_map
[
SRS_CONSTS_HTTP_ServiceUnavailable
]
=
SRS_CONSTS_HTTP_ServiceUnavailable_str
;
_status_map
[
SRS_CONSTS_HTTP_GatewayTimeout
]
=
SRS_CONSTS_HTTP_GatewayTimeout_str
;
_status_map
[
SRS_CONSTS_HTTP_HTTPVersionNotSupported
]
=
SRS_CONSTS_HTTP_HTTPVersionNotSupported_str
;
}
std
::
string
status_text
;
if
(
_status_map
.
find
(
status
)
==
_status_map
.
end
())
{
status_text
=
"Status Unknown"
;
}
else
{
status_text
=
_status_map
[
status
];
}
return
status_text
;
}
// bodyAllowedForStatus reports whether a given response status code
// permits a body. See RFC2616, section 4.4.
bool
srs_go_http_body_allowd
(
int
status
)
{
if
(
status
>=
100
&&
status
<=
199
)
{
return
false
;
}
else
if
(
status
==
204
||
status
==
304
)
{
return
false
;
}
return
true
;
}
// DetectContentType implements the algorithm described
// at http://mimesniff.spec.whatwg.org/ to determine the
// Content-Type of the given data. It considers at most the
// first 512 bytes of data. DetectContentType always returns
// a valid MIME type: if it cannot determine a more specific one, it
// returns "application/octet-stream".
string
srs_go_http_detect
(
char
*
data
,
int
size
)
{
// detect only when data specified.
if
(
data
)
{
}
return
"application/octet-stream"
;
// fallback
}
// Error replies to the request with the specified error message and HTTP code.
// The error message should be plain text.
int
srs_go_http_error
(
ISrsHttpResponseWriter
*
w
,
int
code
,
string
error
)
{
int
ret
=
ERROR_SUCCESS
;
w
->
header
()
->
set_content_type
(
"text/plain; charset=utf-8"
);
w
->
header
()
->
set_content_length
(
error
.
length
());
w
->
write_header
(
code
);
w
->
write
((
char
*
)
error
.
data
(),
(
int
)
error
.
length
());
return
ret
;
}
int
srs_http_response_json
(
ISrsHttpResponseWriter
*
w
,
string
data
)
{
SrsHttpHeader
*
h
=
w
->
header
();
h
->
set_content_length
(
data
.
length
());
h
->
set_content_type
(
"application/json"
);
return
w
->
write
((
char
*
)
data
.
data
(),
(
int
)
data
.
length
());
}
SrsHttpHeader
::
SrsHttpHeader
()
{
}
SrsHttpHeader
::~
SrsHttpHeader
()
{
}
void
SrsHttpHeader
::
set
(
string
key
,
string
value
)
{
headers
[
key
]
=
value
;
}
string
SrsHttpHeader
::
get
(
string
key
)
{
std
::
string
v
;
if
(
headers
.
find
(
key
)
!=
headers
.
end
())
{
v
=
headers
[
key
];
}
return
v
;
}
int64_t
SrsHttpHeader
::
content_length
()
{
std
::
string
cl
=
get
(
"Content-Length"
);
if
(
cl
.
empty
())
{
return
-
1
;
}
return
(
int64_t
)
::
atof
(
cl
.
c_str
());
}
void
SrsHttpHeader
::
set_content_length
(
int64_t
size
)
{
char
buf
[
64
];
snprintf
(
buf
,
sizeof
(
buf
),
"%"
PRId64
,
size
);
set
(
"Content-Length"
,
buf
);
}
string
SrsHttpHeader
::
content_type
()
{
return
get
(
"Content-Type"
);
}
void
SrsHttpHeader
::
set_content_type
(
string
ct
)
{
set
(
"Content-Type"
,
ct
);
}
void
SrsHttpHeader
::
write
(
stringstream
&
ss
)
{
std
::
map
<
std
::
string
,
std
::
string
>::
iterator
it
;
for
(
it
=
headers
.
begin
();
it
!=
headers
.
end
();
++
it
)
{
ss
<<
it
->
first
<<
": "
<<
it
->
second
<<
SRS_HTTP_CRLF
;
}
}
ISrsHttpResponseWriter
::
ISrsHttpResponseWriter
()
{
}
ISrsHttpResponseWriter
::~
ISrsHttpResponseWriter
()
{
}
ISrsHttpResponseReader
::
ISrsHttpResponseReader
()
{
}
ISrsHttpResponseReader
::~
ISrsHttpResponseReader
()
{
}
ISrsHttpHandler
::
ISrsHttpHandler
()
{
entry
=
NULL
;
}
ISrsHttpHandler
::~
ISrsHttpHandler
()
{
}
SrsHttpRedirectHandler
::
SrsHttpRedirectHandler
(
string
u
,
int
c
)
{
url
=
u
;
code
=
c
;
}
SrsHttpRedirectHandler
::~
SrsHttpRedirectHandler
()
{
}
int
SrsHttpRedirectHandler
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
)
{
int
ret
=
ERROR_SUCCESS
;
// TODO: FIXME: implements it.
return
ret
;
}
SrsHttpNotFoundHandler
::
SrsHttpNotFoundHandler
()
{
}
SrsHttpNotFoundHandler
::~
SrsHttpNotFoundHandler
()
{
}
int
SrsHttpNotFoundHandler
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
)
{
return
srs_go_http_error
(
w
,
SRS_CONSTS_HTTP_NotFound
,
SRS_CONSTS_HTTP_NotFound_str
);
}
SrsHttpFileServer
::
SrsHttpFileServer
(
string
root_dir
)
{
dir
=
root_dir
;
}
SrsHttpFileServer
::~
SrsHttpFileServer
()
{
}
int
SrsHttpFileServer
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
)
{
string
upath
=
r
->
path
();
// add default pages.
if
(
srs_string_ends_with
(
upath
,
"/"
))
{
upath
+=
SRS_HTTP_DEFAULT_PAGE
;
}
string
fullpath
=
dir
+
"/"
;
// remove the virtual directory.
srs_assert
(
entry
);
size_t
pos
=
entry
->
pattern
.
find
(
"/"
);
if
(
upath
.
length
()
>
entry
->
pattern
.
length
()
&&
pos
!=
string
::
npos
)
{
fullpath
+=
upath
.
substr
(
entry
->
pattern
.
length
()
-
pos
);
}
else
{
fullpath
+=
upath
;
}
// stat current dir, if exists, return error.
if
(
!
srs_path_exists
(
fullpath
))
{
srs_warn
(
"http miss file=%s, pattern=%s, upath=%s"
,
fullpath
.
c_str
(),
entry
->
pattern
.
c_str
(),
upath
.
c_str
());
return
SrsHttpNotFoundHandler
().
serve_http
(
w
,
r
);
}
srs_trace
(
"http match file=%s, pattern=%s, upath=%s"
,
fullpath
.
c_str
(),
entry
->
pattern
.
c_str
(),
upath
.
c_str
());
// handle file according to its extension.
// use vod stream for .flv/.fhv
if
(
srs_string_ends_with
(
fullpath
,
".flv"
)
||
srs_string_ends_with
(
fullpath
,
".fhv"
))
{
return
serve_flv_file
(
w
,
r
,
fullpath
);
}
else
if
(
srs_string_ends_with
(
fullpath
,
".mp4"
))
{
return
serve_mp4_file
(
w
,
r
,
fullpath
);
}
// serve common static file.
return
serve_file
(
w
,
r
,
fullpath
);
}
int
SrsHttpFileServer
::
serve_file
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
,
string
fullpath
)
{
int
ret
=
ERROR_SUCCESS
;
// 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
();
// unset the content length to encode in chunked encoding.
w
->
header
()
->
set_content_length
(
length
);
static
std
::
map
<
std
::
string
,
std
::
string
>
_mime
;
if
(
_mime
.
empty
())
{
_mime
[
".ts"
]
=
"video/MP2T"
;
_mime
[
".flv"
]
=
"video/x-flv"
;
_mime
[
".m4v"
]
=
"video/x-m4v"
;
_mime
[
".3gpp"
]
=
"video/3gpp"
;
_mime
[
".3gp"
]
=
"video/3gpp"
;
_mime
[
".mp4"
]
=
"video/mp4"
;
_mime
[
".aac"
]
=
"audio/x-aac"
;
_mime
[
".mp3"
]
=
"audio/mpeg"
;
_mime
[
".m4a"
]
=
"audio/x-m4a"
;
_mime
[
".ogg"
]
=
"audio/ogg"
;
// @see hls-m3u8-draft-pantos-http-live-streaming-12.pdf, page 5.
_mime
[
".m3u8"
]
=
"application/vnd.apple.mpegurl"
;
// application/x-mpegURL
_mime
[
".rss"
]
=
"application/rss+xml"
;
_mime
[
".json"
]
=
"application/json"
;
_mime
[
".swf"
]
=
"application/x-shockwave-flash"
;
_mime
[
".doc"
]
=
"application/msword"
;
_mime
[
".zip"
]
=
"application/zip"
;
_mime
[
".rar"
]
=
"application/x-rar-compressed"
;
_mime
[
".xml"
]
=
"text/xml"
;
_mime
[
".html"
]
=
"text/html"
;
_mime
[
".js"
]
=
"text/javascript"
;
_mime
[
".css"
]
=
"text/css"
;
_mime
[
".ico"
]
=
"image/x-icon"
;
_mime
[
".png"
]
=
"image/png"
;
_mime
[
".jpeg"
]
=
"image/jpeg"
;
_mime
[
".jpg"
]
=
"image/jpeg"
;
_mime
[
".gif"
]
=
"image/gif"
;
}
if
(
true
)
{
size_t
pos
;
std
::
string
ext
=
fullpath
;
if
((
pos
=
ext
.
rfind
(
"."
))
!=
string
::
npos
)
{
ext
=
ext
.
substr
(
pos
);
}
if
(
_mime
.
find
(
ext
)
==
_mime
.
end
())
{
w
->
header
()
->
set_content_type
(
"application/octet-stream"
);
}
else
{
w
->
header
()
->
set_content_type
(
_mime
[
ext
]);
}
}
// write body.
int64_t
left
=
length
;
if
((
ret
=
copy
(
w
,
&
fs
,
r
,
(
int
)
left
))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"read file=%s size=%d failed, ret=%d"
,
fullpath
.
c_str
(),
left
,
ret
);
}
return
ret
;
}
return
w
->
final_request
();
}
int
SrsHttpFileServer
::
serve_flv_file
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
,
string
fullpath
)
{
std
::
string
start
=
r
->
query_get
(
"start"
);
if
(
start
.
empty
())
{
return
serve_file
(
w
,
r
,
fullpath
);
}
int
offset
=
::
atoi
(
start
.
c_str
());
if
(
offset
<=
0
)
{
return
serve_file
(
w
,
r
,
fullpath
);
}
return
serve_flv_stream
(
w
,
r
,
fullpath
,
offset
);
}
int
SrsHttpFileServer
::
serve_mp4_file
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
,
string
fullpath
)
{
// for flash to request mp4 range in query string.
// for example, http://digitalprimates.net/dash/DashTest.html?url=http://dashdemo.edgesuite.net/digitalprimates/nexus/oops-20120802-manifest.mpd
std
::
string
range
=
r
->
query_get
(
"range"
);
// or, use bytes to request range,
// for example, http://dashas.castlabs.com/demo/try.html
if
(
range
.
empty
())
{
range
=
r
->
query_get
(
"bytes"
);
}
// rollback to serve whole file.
size_t
pos
=
string
::
npos
;
if
(
range
.
empty
()
||
(
pos
=
range
.
find
(
"-"
))
==
string
::
npos
)
{
return
serve_file
(
w
,
r
,
fullpath
);
}
// parse the start in query string
int
start
=
0
;
if
(
pos
>
0
)
{
start
=
::
atoi
(
range
.
substr
(
0
,
pos
).
c_str
());
}
// parse end in query string.
int
end
=
-
1
;
if
(
pos
<
range
.
length
()
-
1
)
{
end
=
::
atoi
(
range
.
substr
(
pos
+
1
).
c_str
());
}
// invalid param, serve as whole mp4 file.
if
(
start
<
0
||
(
end
!=
-
1
&&
start
>
end
))
{
return
serve_file
(
w
,
r
,
fullpath
);
}
return
serve_mp4_stream
(
w
,
r
,
fullpath
,
start
,
end
);
}
int
SrsHttpFileServer
::
serve_flv_stream
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
,
string
fullpath
,
int
offset
)
{
return
serve_file
(
w
,
r
,
fullpath
);
}
int
SrsHttpFileServer
::
serve_mp4_stream
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
,
string
fullpath
,
int
start
,
int
end
)
{
return
serve_file
(
w
,
r
,
fullpath
);
}
int
SrsHttpFileServer
::
copy
(
ISrsHttpResponseWriter
*
w
,
SrsFileReader
*
fs
,
ISrsHttpMessage
*
r
,
int
size
)
{
int
ret
=
ERROR_SUCCESS
;
int
left
=
size
;
char
*
buf
=
r
->
http_ts_send_buffer
();
while
(
left
>
0
)
{
ssize_t
nread
=
-
1
;
int
max_read
=
srs_min
(
left
,
SRS_HTTP_TS_SEND_BUFFER_SIZE
);
if
((
ret
=
fs
->
read
(
buf
,
max_read
,
&
nread
))
!=
ERROR_SUCCESS
)
{
break
;
}
left
-=
nread
;
if
((
ret
=
w
->
write
(
buf
,
(
int
)
nread
))
!=
ERROR_SUCCESS
)
{
break
;
}
}
return
ret
;
}
SrsHttpMuxEntry
::
SrsHttpMuxEntry
()
{
enabled
=
true
;
explicit_match
=
false
;
handler
=
NULL
;
}
SrsHttpMuxEntry
::~
SrsHttpMuxEntry
()
{
srs_freep
(
handler
);
}
ISrsHttpMatchHijacker
::
ISrsHttpMatchHijacker
()
{
}
ISrsHttpMatchHijacker
::~
ISrsHttpMatchHijacker
()
{
}
SrsHttpServeMux
::
SrsHttpServeMux
()
{
}
SrsHttpServeMux
::~
SrsHttpServeMux
()
{
std
::
map
<
std
::
string
,
SrsHttpMuxEntry
*>::
iterator
it
;
for
(
it
=
entries
.
begin
();
it
!=
entries
.
end
();
++
it
)
{
SrsHttpMuxEntry
*
entry
=
it
->
second
;
srs_freep
(
entry
);
}
entries
.
clear
();
vhosts
.
clear
();
hijackers
.
clear
();
}
int
SrsHttpServeMux
::
initialize
()
{
int
ret
=
ERROR_SUCCESS
;
// TODO: FIXME: implements it.
return
ret
;
}
void
SrsHttpServeMux
::
hijack
(
ISrsHttpMatchHijacker
*
h
)
{
std
::
vector
<
ISrsHttpMatchHijacker
*>::
iterator
it
=
::
find
(
hijackers
.
begin
(),
hijackers
.
end
(),
h
);
if
(
it
!=
hijackers
.
end
())
{
return
;
}
hijackers
.
push_back
(
h
);
}
void
SrsHttpServeMux
::
unhijack
(
ISrsHttpMatchHijacker
*
h
)
{
std
::
vector
<
ISrsHttpMatchHijacker
*>::
iterator
it
=
::
find
(
hijackers
.
begin
(),
hijackers
.
end
(),
h
);
if
(
it
==
hijackers
.
end
())
{
return
;
}
hijackers
.
erase
(
it
);
}
int
SrsHttpServeMux
::
handle
(
std
::
string
pattern
,
ISrsHttpHandler
*
handler
)
{
int
ret
=
ERROR_SUCCESS
;
srs_assert
(
handler
);
if
(
pattern
.
empty
())
{
ret
=
ERROR_HTTP_PATTERN_EMPTY
;
srs_error
(
"http: empty pattern. ret=%d"
,
ret
);
return
ret
;
}
if
(
entries
.
find
(
pattern
)
!=
entries
.
end
())
{
SrsHttpMuxEntry
*
exists
=
entries
[
pattern
];
if
(
exists
->
explicit_match
)
{
ret
=
ERROR_HTTP_PATTERN_DUPLICATED
;
srs_error
(
"http: multiple registrations for %s. ret=%d"
,
pattern
.
c_str
(),
ret
);
return
ret
;
}
}
std
::
string
vhost
=
pattern
;
if
(
pattern
.
at
(
0
)
!=
'/'
)
{
if
(
pattern
.
find
(
"/"
)
!=
string
::
npos
)
{
vhost
=
pattern
.
substr
(
0
,
pattern
.
find
(
"/"
));
}
vhosts
[
vhost
]
=
handler
;
}
if
(
true
)
{
SrsHttpMuxEntry
*
entry
=
new
SrsHttpMuxEntry
();
entry
->
explicit_match
=
true
;
entry
->
handler
=
handler
;
entry
->
pattern
=
pattern
;
entry
->
handler
->
entry
=
entry
;
if
(
entries
.
find
(
pattern
)
!=
entries
.
end
())
{
SrsHttpMuxEntry
*
exists
=
entries
[
pattern
];
srs_freep
(
exists
);
}
entries
[
pattern
]
=
entry
;
}
// Helpful behavior:
// If pattern is /tree/, insert an implicit permanent redirect for /tree.
// It can be overridden by an explicit registration.
if
(
pattern
!=
"/"
&&
!
pattern
.
empty
()
&&
pattern
.
at
(
pattern
.
length
()
-
1
)
==
'/'
)
{
std
::
string
rpattern
=
pattern
.
substr
(
0
,
pattern
.
length
()
-
1
);
SrsHttpMuxEntry
*
entry
=
NULL
;
// free the exists not explicit entry
if
(
entries
.
find
(
rpattern
)
!=
entries
.
end
())
{
SrsHttpMuxEntry
*
exists
=
entries
[
rpattern
];
if
(
!
exists
->
explicit_match
)
{
entry
=
exists
;
}
}
// create implicit redirect.
if
(
!
entry
||
entry
->
explicit_match
)
{
srs_freep
(
entry
);
entry
=
new
SrsHttpMuxEntry
();
entry
->
explicit_match
=
false
;
entry
->
handler
=
new
SrsHttpRedirectHandler
(
pattern
,
SRS_CONSTS_HTTP_MovedPermanently
);
entry
->
pattern
=
pattern
;
entry
->
handler
->
entry
=
entry
;
entries
[
rpattern
]
=
entry
;
}
}
return
ret
;
}
int
SrsHttpServeMux
::
serve_http
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
)
{
int
ret
=
ERROR_SUCCESS
;
ISrsHttpHandler
*
h
=
NULL
;
if
((
ret
=
find_handler
(
r
,
&
h
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"find handler failed. ret=%d"
,
ret
);
return
ret
;
}
srs_assert
(
h
);
if
((
ret
=
h
->
serve_http
(
w
,
r
))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"handler serve http failed. ret=%d"
,
ret
);
}
return
ret
;
}
return
ret
;
}
int
SrsHttpServeMux
::
find_handler
(
ISrsHttpMessage
*
r
,
ISrsHttpHandler
**
ph
)
{
int
ret
=
ERROR_SUCCESS
;
// TODO: FIXME: support the path . and ..
if
(
r
->
url
().
find
(
".."
)
!=
std
::
string
::
npos
)
{
ret
=
ERROR_HTTP_URL_NOT_CLEAN
;
srs_error
(
"htt url not canonical, url=%s. ret=%d"
,
r
->
url
().
c_str
(),
ret
);
return
ret
;
}
if
((
ret
=
match
(
r
,
ph
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"http match handler failed. ret=%d"
,
ret
);
return
ret
;
}
// always hijack.
if
(
!
hijackers
.
empty
())
{
// notice all hijacker the match failed.
std
::
vector
<
ISrsHttpMatchHijacker
*>::
iterator
it
;
for
(
it
=
hijackers
.
begin
();
it
!=
hijackers
.
end
();
++
it
)
{
ISrsHttpMatchHijacker
*
hijacker
=
*
it
;
if
((
ret
=
hijacker
->
hijack
(
r
,
ph
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hijacker match failed. ret=%d"
,
ret
);
return
ret
;
}
}
}
if
(
*
ph
==
NULL
)
{
// TODO: FIXME: memory leak.
*
ph
=
new
SrsHttpNotFoundHandler
();
}
return
ret
;
}
int
SrsHttpServeMux
::
match
(
ISrsHttpMessage
*
r
,
ISrsHttpHandler
**
ph
)
{
int
ret
=
ERROR_SUCCESS
;
std
::
string
path
=
r
->
path
();
// Host-specific pattern takes precedence over generic ones
if
(
!
vhosts
.
empty
()
&&
vhosts
.
find
(
r
->
host
())
!=
vhosts
.
end
())
{
path
=
r
->
host
()
+
path
;
}
int
nb_matched
=
0
;
ISrsHttpHandler
*
h
=
NULL
;
std
::
map
<
std
::
string
,
SrsHttpMuxEntry
*>::
iterator
it
;
for
(
it
=
entries
.
begin
();
it
!=
entries
.
end
();
++
it
)
{
std
::
string
pattern
=
it
->
first
;
SrsHttpMuxEntry
*
entry
=
it
->
second
;
if
(
!
entry
->
enabled
)
{
continue
;
}
if
(
!
path_match
(
pattern
,
path
))
{
continue
;
}
if
(
!
h
||
(
int
)
pattern
.
length
()
>
nb_matched
)
{
nb_matched
=
(
int
)
pattern
.
length
();
h
=
entry
->
handler
;
}
}
*
ph
=
h
;
return
ret
;
}
bool
SrsHttpServeMux
::
path_match
(
string
pattern
,
string
path
)
{
if
(
pattern
.
empty
())
{
return
false
;
}
int
n
=
(
int
)
pattern
.
length
();
// not endswith '/', exactly match.
if
(
pattern
.
at
(
n
-
1
)
!=
'/'
)
{
return
pattern
==
path
;
}
// endswith '/', match any,
// for example, '/api/' match '/api/[N]'
if
((
int
)
path
.
length
()
>=
n
)
{
if
(
memcmp
(
pattern
.
data
(),
path
.
data
(),
n
)
==
0
)
{
return
true
;
}
}
return
false
;
}
ISrsHttpMessage
::
ISrsHttpMessage
()
{
_http_ts_send_buffer
=
new
char
[
SRS_HTTP_TS_SEND_BUFFER_SIZE
];
}
ISrsHttpMessage
::~
ISrsHttpMessage
()
{
srs_freep
(
_http_ts_send_buffer
);
}
char
*
ISrsHttpMessage
::
http_ts_send_buffer
()
{
return
_http_ts_send_buffer
;
}
...
...
trunk/src/protocol/srs_http_stack.hpp
查看文件 @
ce1bb6c
...
...
@@ -29,4 +29,466 @@
*/
#include <srs_core.hpp>
#include <map>
#include <string>
#include <vector>
class
SrsFileReader
;
class
SrsHttpHeader
;
class
ISrsHttpMessage
;
class
SrsHttpMuxEntry
;
class
ISrsHttpResponseWriter
;
// http specification
// CR = <US-ASCII CR, carriage return (13)>
#define SRS_HTTP_CR SRS_CONSTS_CR // 0x0D
// LF = <US-ASCII LF, linefeed (10)>
#define SRS_HTTP_LF SRS_CONSTS_LF // 0x0A
// SP = <US-ASCII SP, space (32)>
#define SRS_HTTP_SP ' ' // 0x20
// HT = <US-ASCII HT, horizontal-tab (9)>
#define SRS_HTTP_HT '\x09' // 0x09
// HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
// protocol elements except the entity-body (see appendix 19.3 for
// tolerant applications).
#define SRS_HTTP_CRLF "\r\n" // 0x0D0A
#define SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
// @see ISrsHttpMessage._http_ts_send_buffer
#define SRS_HTTP_TS_SEND_BUFFER_SIZE 4096
// for ead all of http body, read each time.
#define SRS_HTTP_READ_CACHE_BYTES 4096
// default http listen port.
#define SRS_DEFAULT_HTTP_PORT 80
// for http parser macros
#define SRS_CONSTS_HTTP_OPTIONS HTTP_OPTIONS
#define SRS_CONSTS_HTTP_GET HTTP_GET
#define SRS_CONSTS_HTTP_POST HTTP_POST
#define SRS_CONSTS_HTTP_PUT HTTP_PUT
#define SRS_CONSTS_HTTP_DELETE HTTP_DELETE
// helper function: response in json format.
extern
int
srs_http_response_json
(
ISrsHttpResponseWriter
*
w
,
std
::
string
data
);
// get the status text of code.
extern
std
::
string
srs_generate_http_status_text
(
int
status
);
// bodyAllowedForStatus reports whether a given response status code
// permits a body. See RFC2616, section 4.4.
extern
bool
srs_go_http_body_allowd
(
int
status
);
// DetectContentType implements the algorithm described
// at http://mimesniff.spec.whatwg.org/ to determine the
// Content-Type of the given data. It considers at most the
// first 512 bytes of data. DetectContentType always returns
// a valid MIME type: if it cannot determine a more specific one, it
// returns "application/octet-stream".
extern
std
::
string
srs_go_http_detect
(
char
*
data
,
int
size
);
// state of message
enum
SrsHttpParseState
{
SrsHttpParseStateInit
=
0
,
SrsHttpParseStateStart
,
SrsHttpParseStateHeaderComplete
,
SrsHttpParseStateMessageComplete
};
// A Header represents the key-value pairs in an HTTP header.
class
SrsHttpHeader
{
private
:
std
::
map
<
std
::
string
,
std
::
string
>
headers
;
public
:
SrsHttpHeader
();
virtual
~
SrsHttpHeader
();
public
:
// Add adds the key, value pair to the header.
// It appends to any existing values associated with key.
virtual
void
set
(
std
::
string
key
,
std
::
string
value
);
// Get gets the first value associated with the given key.
// If there are no values associated with the key, Get returns "".
// To access multiple values of a key, access the map directly
// with CanonicalHeaderKey.
virtual
std
::
string
get
(
std
::
string
key
);
public
:
/**
* get the content length. -1 if not set.
*/
virtual
int64_t
content_length
();
/**
* set the content length by header "Content-Length"
*/
virtual
void
set_content_length
(
int64_t
size
);
public
:
/**
* get the content type. empty string if not set.
*/
virtual
std
::
string
content_type
();
/**
* set the content type by header "Content-Type"
*/
virtual
void
set_content_type
(
std
::
string
ct
);
public
:
/**
* write all headers to string stream.
*/
virtual
void
write
(
std
::
stringstream
&
ss
);
};
// A ResponseWriter interface is used by an HTTP handler to
// construct an HTTP response.
// Usage 1, response with specified length content:
// ISrsHttpResponseWriter* w; // create or get response.
// std::string msg = "Hello, HTTP!";
// w->header()->set_content_type("text/plain; charset=utf-8");
// w->header()->set_content_length(msg.length());
// w->write_header(SRS_CONSTS_HTTP_OK);
// w->write((char*)msg.data(), (int)msg.length());
// w->final_request(); // optional flush.
// Usage 2, response with HTTP code only, zero content length.
// ISrsHttpResponseWriter* w; // create or get response.
// w->header()->set_content_length(0);
// w->write_header(SRS_CONSTS_HTTP_OK);
// w->final_request();
// Usage 3, response in chunked encoding.
// ISrsHttpResponseWriter* w; // create or get response.
// std::string msg = "Hello, HTTP!";
// w->header()->set_content_type("application/octet-stream");
// w->write_header(SRS_CONSTS_HTTP_OK);
// w->write((char*)msg.data(), (int)msg.length());
// w->write((char*)msg.data(), (int)msg.length());
// w->write((char*)msg.data(), (int)msg.length());
// w->write((char*)msg.data(), (int)msg.length());
// w->final_request(); // required to end the chunked and flush.
class
ISrsHttpResponseWriter
{
public
:
ISrsHttpResponseWriter
();
virtual
~
ISrsHttpResponseWriter
();
public
:
// when chunked mode,
// final the request to complete the chunked encoding.
// for no-chunked mode,
// final to send request, for example, content-length is 0.
virtual
int
final_request
()
=
0
;
// Header returns the header map that will be sent by WriteHeader.
// Changing the header after a call to WriteHeader (or Write) has
// no effect.
virtual
SrsHttpHeader
*
header
()
=
0
;
// Write writes the data to the connection as part of an HTTP reply.
// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
// before writing the data. If the Header does not contain a
// Content-Type line, Write adds a Content-Type set to the result of passing
// the initial 512 bytes of written data to DetectContentType.
// @param data, the data to send. NULL to flush header only.
virtual
int
write
(
char
*
data
,
int
size
)
=
0
;
// WriteHeader sends an HTTP response header with status code.
// If WriteHeader is not called explicitly, the first call to Write
// will trigger an implicit WriteHeader(http.StatusOK).
// Thus explicit calls to WriteHeader are mainly used to
// send error codes.
// @remark, user must set header then write or write_header.
virtual
void
write_header
(
int
code
)
=
0
;
};
/**
* the reader interface for http response.
*/
class
ISrsHttpResponseReader
{
public
:
ISrsHttpResponseReader
();
virtual
~
ISrsHttpResponseReader
();
public
:
/**
* whether response read EOF.
*/
virtual
bool
eof
()
=
0
;
/**
* read from the response body.
* @param data, the buffer to read data buffer to.
* @param nb_data, the max size of data buffer.
* @param nb_read, the actual read size of bytes. NULL to ignore.
* @remark when eof(), return error.
*/
virtual
int
read
(
char
*
data
,
int
nb_data
,
int
*
nb_read
)
=
0
;
};
// Objects implementing the Handler interface can be
// registered to serve a particular path or subtree
// in the HTTP server.
//
// ServeHTTP should write reply headers and data to the ResponseWriter
// and then return. Returning signals that the request is finished
// and that the HTTP server can move on to the next request on
// the connection.
class
ISrsHttpHandler
{
public
:
SrsHttpMuxEntry
*
entry
;
public
:
ISrsHttpHandler
();
virtual
~
ISrsHttpHandler
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
)
=
0
;
};
// Redirect to a fixed URL
class
SrsHttpRedirectHandler
:
public
ISrsHttpHandler
{
private
:
std
::
string
url
;
int
code
;
public
:
SrsHttpRedirectHandler
(
std
::
string
u
,
int
c
);
virtual
~
SrsHttpRedirectHandler
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
);
};
// NotFound replies to the request with an HTTP 404 not found error.
class
SrsHttpNotFoundHandler
:
public
ISrsHttpHandler
{
public
:
SrsHttpNotFoundHandler
();
virtual
~
SrsHttpNotFoundHandler
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
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("/", SrsHttpFileServer("/tmp"))
// http.Handle("/", SrsHttpFileServer("static-dir"))
class
SrsHttpFileServer
:
public
ISrsHttpHandler
{
protected
:
std
::
string
dir
;
public
:
SrsHttpFileServer
(
std
::
string
root_dir
);
virtual
~
SrsHttpFileServer
();
public
:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
);
private
:
/**
* serve the file by specified path
*/
virtual
int
serve_file
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
,
std
::
string
fullpath
);
virtual
int
serve_flv_file
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
,
std
::
string
fullpath
);
virtual
int
serve_mp4_file
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
,
std
::
string
fullpath
);
protected
:
/**
* when access flv file with x.flv?start=xxx
*/
virtual
int
serve_flv_stream
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
,
std
::
string
fullpath
,
int
offset
);
/**
* when access mp4 file with x.mp4?range=start-end
* @param start the start offset in bytes.
* @param end the end offset in bytes. -1 to end of file.
* @remark response data in [start, end].
*/
virtual
int
serve_mp4_stream
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
,
std
::
string
fullpath
,
int
start
,
int
end
);
protected
:
/**
* copy the fs to response writer in size bytes.
*/
virtual
int
copy
(
ISrsHttpResponseWriter
*
w
,
SrsFileReader
*
fs
,
ISrsHttpMessage
*
r
,
int
size
);
};
// the mux entry for server mux.
// the matcher info, for example, the pattern and handler.
class
SrsHttpMuxEntry
{
public
:
bool
explicit_match
;
ISrsHttpHandler
*
handler
;
std
::
string
pattern
;
bool
enabled
;
public
:
SrsHttpMuxEntry
();
virtual
~
SrsHttpMuxEntry
();
};
/**
* the hijacker for http pattern match.
*/
class
ISrsHttpMatchHijacker
{
public
:
ISrsHttpMatchHijacker
();
virtual
~
ISrsHttpMatchHijacker
();
public
:
/**
* when match the request failed, no handler to process request.
* @param request the http request message to match the handler.
* @param ph the already matched handler, hijack can rewrite it.
*/
virtual
int
hijack
(
ISrsHttpMessage
*
request
,
ISrsHttpHandler
**
ph
)
=
0
;
};
// ServeMux is an HTTP request multiplexer.
// It matches the URL of each incoming request against a list of registered
// patterns and calls the handler for the pattern that
// most closely matches the URL.
//
// Patterns name fixed, rooted paths, like "/favicon.ico",
// or rooted subtrees, like "/images/" (note the trailing slash).
// Longer patterns take precedence over shorter ones, so that
// if there are handlers registered for both "/images/"
// and "/images/thumbnails/", the latter handler will be
// called for paths beginning "/images/thumbnails/" and the
// former will receive requests for any other paths in the
// "/images/" subtree.
//
// Note that since a pattern ending in a slash names a rooted subtree,
// the pattern "/" matches all paths not matched by other registered
// patterns, not just the URL with Path == "/".
//
// Patterns may optionally begin with a host name, restricting matches to
// URLs on that host only. Host-specific patterns take precedence over
// general patterns, so that a handler might register for the two patterns
// "/codesearch" and "codesearch.google.com/" without also taking over
// requests for "http://www.google.com/".
//
// ServeMux also takes care of sanitizing the URL request path,
// redirecting any request containing . or .. elements to an
// equivalent .- and ..-free URL.
class
SrsHttpServeMux
{
private
:
// the pattern handler, to handle the http request.
std
::
map
<
std
::
string
,
SrsHttpMuxEntry
*>
entries
;
// the vhost handler.
// when find the handler to process the request,
// append the matched vhost when pattern not starts with /,
// for example, for pattern /live/livestream.flv of vhost ossrs.net,
// the path will rewrite to ossrs.net/live/livestream.flv
std
::
map
<
std
::
string
,
ISrsHttpHandler
*>
vhosts
;
// all hijackers for http match.
// for example, the hstrs(http stream trigger rtmp source)
// can hijack and install handler when request incoming and no handler.
std
::
vector
<
ISrsHttpMatchHijacker
*>
hijackers
;
public
:
SrsHttpServeMux
();
virtual
~
SrsHttpServeMux
();
public
:
/**
* initialize the http serve mux.
*/
virtual
int
initialize
();
/**
* hijack the http match.
*/
virtual
void
hijack
(
ISrsHttpMatchHijacker
*
h
);
virtual
void
unhijack
(
ISrsHttpMatchHijacker
*
h
);
public
:
// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
virtual
int
handle
(
std
::
string
pattern
,
ISrsHttpHandler
*
handler
);
// interface ISrsHttpHandler
public:
virtual
int
serve_http
(
ISrsHttpResponseWriter
*
w
,
ISrsHttpMessage
*
r
);
private
:
virtual
int
find_handler
(
ISrsHttpMessage
*
r
,
ISrsHttpHandler
**
ph
);
virtual
int
match
(
ISrsHttpMessage
*
r
,
ISrsHttpHandler
**
ph
);
virtual
bool
path_match
(
std
::
string
pattern
,
std
::
string
path
);
};
// for http header.
typedef
std
::
pair
<
std
::
string
,
std
::
string
>
SrsHttpHeaderField
;
// A Request represents an HTTP request received by a server
// or to be sent by a client.
//
// The field semantics differ slightly between client and server
// usage. In addition to the notes on the fields below, see the
// documentation for Request.Write and RoundTripper.
/**
* the http message, request or response.
*/
class
ISrsHttpMessage
{
private
:
/**
* use a buffer to read and send ts file.
*/
// TODO: FIXME: remove it.
char
*
_http_ts_send_buffer
;
public
:
ISrsHttpMessage
();
virtual
~
ISrsHttpMessage
();
public
:
/**
* the http request level cache.
*/
virtual
char
*
http_ts_send_buffer
();
public
:
virtual
u_int8_t
method
()
=
0
;
virtual
u_int16_t
status_code
()
=
0
;
/**
* method helpers.
*/
virtual
std
::
string
method_str
()
=
0
;
virtual
bool
is_http_get
()
=
0
;
virtual
bool
is_http_put
()
=
0
;
virtual
bool
is_http_post
()
=
0
;
virtual
bool
is_http_delete
()
=
0
;
virtual
bool
is_http_options
()
=
0
;
public
:
/**
* whether should keep the connection alive.
*/
virtual
bool
is_keep_alive
()
=
0
;
/**
* the uri contains the host and path.
*/
virtual
std
::
string
uri
()
=
0
;
/**
* the url maybe the path.
*/
virtual
std
::
string
url
()
=
0
;
virtual
std
::
string
host
()
=
0
;
virtual
std
::
string
path
()
=
0
;
virtual
std
::
string
ext
()
=
0
;
public
:
/**
* read body to string.
* @remark for small http body.
*/
virtual
int
body_read_all
(
std
::
string
&
body
)
=
0
;
/**
* get the body reader, to read one by one.
* @remark when body is very large, or chunked, use this.
*/
virtual
ISrsHttpResponseReader
*
body_reader
()
=
0
;
/**
* the content length, -1 for chunked or not set.
*/
virtual
int64_t
content_length
()
=
0
;
public
:
/**
* get the param in query string,
* for instance, query is "start=100&end=200",
* then query_get("start") is "100", and query_get("end") is "200"
*/
virtual
std
::
string
query_get
(
std
::
string
key
)
=
0
;
/**
* get the headers.
*/
virtual
int
request_header_count
()
=
0
;
virtual
std
::
string
request_header_key_at
(
int
index
)
=
0
;
virtual
std
::
string
request_header_value_at
(
int
index
)
=
0
;
};
#endif
...
...
请
注册
或
登录
后发表评论