Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Z
ZLMediaKit
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
张翔宇
ZLMediaKit
Commits
d432888a
Unverified
Commit
d432888a
authored
Feb 11, 2022
by
夏楚
Committed by
GitHub
Feb 11, 2022
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1419 from ZLMediaKit/feature/mmap
通过共享mmap方式提高http文件/hls服务器性能
parents
72caa43c
a2b63448
隐藏空白字符变更
内嵌
并排
正在显示
19 个修改的文件
包含
588 行增加
和
445 行删除
+588
-445
src/Http/HlsPlayer.cpp
+16
-10
src/Http/HttpBody.cpp
+161
-106
src/Http/HttpBody.h
+18
-18
src/Http/HttpCookie.cpp
+67
-22
src/Http/HttpCookieManager.cpp
+75
-71
src/Http/HttpCookieManager.h
+54
-35
src/Http/HttpFileManager.cpp
+94
-103
src/Http/HttpFileManager.h
+1
-1
src/Http/HttpSession.cpp
+22
-21
src/Http/TsPlayer.cpp
+5
-1
src/Http/TsPlayer.h
+2
-1
src/Http/TsplayerImp.cpp
+6
-2
src/Record/HlsMaker.cpp
+1
-1
src/Record/HlsMaker.h
+1
-3
src/Record/HlsMakerImp.cpp
+3
-3
src/Record/HlsMakerImp.h
+1
-1
src/Record/HlsMediaSource.cpp
+17
-11
src/Record/HlsMediaSource.h
+43
-34
src/Record/HlsRecorder.h
+1
-1
没有找到文件。
src/Http/HlsPlayer.cpp
查看文件 @
d432888a
...
@@ -76,15 +76,17 @@ void HlsPlayer::fetchSegment() {
...
@@ -76,15 +76,17 @@ void HlsPlayer::fetchSegment() {
}
}
return
Socket
::
createSocket
(
poller
,
true
);
return
Socket
::
createSocket
(
poller
,
true
);
});
});
auto
benchmark_mode
=
(
*
this
)[
Client
::
kBenchmarkMode
].
as
<
int
>
();
_http_ts_player
->
setOnPacket
([
weak_self
](
const
char
*
data
,
size_t
len
)
{
if
(
!
benchmark_mode
)
{
auto
strong_self
=
weak_self
.
lock
();
_http_ts_player
->
setOnPacket
([
weak_self
](
const
char
*
data
,
size_t
len
)
{
if
(
!
strong_self
)
{
auto
strong_self
=
weak_self
.
lock
();
return
;
if
(
!
strong_self
)
{
}
return
;
//收到ts包
}
strong_self
->
onPacket_l
(
data
,
len
);
//收到ts包
});
strong_self
->
onPacket_l
(
data
,
len
);
});
}
if
(
!
(
*
this
)[
Client
::
kNetAdapter
].
empty
())
{
if
(
!
(
*
this
)[
Client
::
kNetAdapter
].
empty
())
{
_http_ts_player
->
setNetAdapter
((
*
this
)[
Client
::
kNetAdapter
]);
_http_ts_player
->
setNetAdapter
((
*
this
)[
Client
::
kNetAdapter
]);
...
@@ -349,7 +351,8 @@ void HlsPlayerImp::addTrackCompleted() {
...
@@ -349,7 +351,8 @@ void HlsPlayerImp::addTrackCompleted() {
}
}
void
HlsPlayerImp
::
onPlayResult
(
const
SockException
&
ex
)
{
void
HlsPlayerImp
::
onPlayResult
(
const
SockException
&
ex
)
{
if
(
ex
)
{
auto
benchmark_mode
=
(
*
this
)[
Client
::
kBenchmarkMode
].
as
<
int
>
();
if
(
ex
||
benchmark_mode
)
{
PlayerImp
<
HlsPlayer
,
PlayerBase
>::
onPlayResult
(
ex
);
PlayerImp
<
HlsPlayer
,
PlayerBase
>::
onPlayResult
(
ex
);
}
else
{
}
else
{
auto
demuxer
=
std
::
make_shared
<
HlsDemuxer
>
();
auto
demuxer
=
std
::
make_shared
<
HlsDemuxer
>
();
...
@@ -364,6 +367,9 @@ void HlsPlayerImp::onShutdown(const SockException &ex) {
...
@@ -364,6 +367,9 @@ void HlsPlayerImp::onShutdown(const SockException &ex) {
}
}
vector
<
Track
::
Ptr
>
HlsPlayerImp
::
getTracks
(
bool
ready
)
const
{
vector
<
Track
::
Ptr
>
HlsPlayerImp
::
getTracks
(
bool
ready
)
const
{
if
(
!
_demuxer
)
{
return
vector
<
Track
::
Ptr
>
();
}
return
static_pointer_cast
<
HlsDemuxer
>
(
_demuxer
)
->
getTracks
(
ready
);
return
static_pointer_cast
<
HlsDemuxer
>
(
_demuxer
)
->
getTracks
(
ready
);
}
}
...
...
src/Http/HttpBody.cpp
查看文件 @
d432888a
...
@@ -9,16 +9,24 @@
...
@@ -9,16 +9,24 @@
*/
*/
#include <csignal>
#include <csignal>
#include "HttpBody.h"
#include <tuple>
#include "Util/util.h"
#ifndef _WIN32
#include <sys/mman.h>
#endif
#if defined(__linux__) || defined(__linux)
#include <sys/sendfile.h>
#endif
#include "Util/File.h"
#include "Util/File.h"
#include "Util/uv_errno.h"
#include "Util/logger.h"
#include "Util/logger.h"
#include "Util/onceToken.h"
#include "Util/onceToken.h"
#include "Util/util.h"
#include "Util/uv_errno.h"
#include "HttpBody.h"
#include "HttpClient.h"
#include "HttpClient.h"
#ifndef _WIN32
#include "Common/macros.h"
#include <sys/mman.h>
#endif
#ifndef _WIN32
#ifndef _WIN32
#define ENABLE_MMAP
#define ENABLE_MMAP
...
@@ -29,94 +37,146 @@ using namespace toolkit;
...
@@ -29,94 +37,146 @@ using namespace toolkit;
namespace
mediakit
{
namespace
mediakit
{
HttpStringBody
::
HttpStringBody
(
string
str
){
HttpStringBody
::
HttpStringBody
(
string
str
)
{
_str
=
std
::
move
(
str
);
_str
=
std
::
move
(
str
);
}
}
ssize
_t
HttpStringBody
::
remainSize
()
{
int64
_t
HttpStringBody
::
remainSize
()
{
return
_str
.
size
()
-
_offset
;
return
_str
.
size
()
-
_offset
;
}
}
Buffer
::
Ptr
HttpStringBody
::
readData
(
size_t
size
)
{
Buffer
::
Ptr
HttpStringBody
::
readData
(
size_t
size
)
{
size
=
MIN
((
size_t
)
remainSize
(),
size
);
size
=
MIN
((
size_t
)
remainSize
(),
size
);
if
(
!
size
)
{
if
(
!
size
)
{
//没有剩余字节了
//没有剩余字节了
return
nullptr
;
return
nullptr
;
}
}
auto
ret
=
std
::
make_shared
<
BufferString
>
(
_str
,
_offset
,
size
);
auto
ret
=
std
::
make_shared
<
BufferString
>
(
_str
,
_offset
,
size
);
_offset
+=
size
;
_offset
+=
size
;
return
ret
;
return
ret
;
}
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
HttpFileBody
::
HttpFileBody
(
const
string
&
filePath
,
bool
use_mmap
)
{
#ifdef ENABLE_MMAP
std
::
shared_ptr
<
FILE
>
fp
(
fopen
(
filePath
.
data
(),
"rb"
),
[](
FILE
*
fp
)
{
static
mutex
s_mtx
;
static
unordered_map
<
string
/*file_path*/
,
std
::
tuple
<
char
*/
*
ptr
*/
,
int64_t
/*size*/
,
weak_ptr
<
char
>
/*mmap*/
>
>
s_shared_mmap
;
//删除mmap记录
static
void
delSharedMmap
(
const
string
&
file_path
,
char
*
ptr
)
{
lock_guard
<
mutex
>
lck
(
s_mtx
);
auto
it
=
s_shared_mmap
.
find
(
file_path
);
if
(
it
!=
s_shared_mmap
.
end
()
&&
std
::
get
<
0
>
(
it
->
second
)
==
ptr
)
{
s_shared_mmap
.
erase
(
it
);
}
}
static
std
::
shared_ptr
<
char
>
getSharedMmap
(
const
string
&
file_path
,
int64_t
&
file_size
)
{
{
lock_guard
<
mutex
>
lck
(
s_mtx
);
auto
it
=
s_shared_mmap
.
find
(
file_path
);
if
(
it
!=
s_shared_mmap
.
end
())
{
auto
ret
=
std
::
get
<
2
>
(
it
->
second
).
lock
();
if
(
ret
)
{
//命中mmap缓存
file_size
=
std
::
get
<
1
>
(
it
->
second
);
return
ret
;
}
}
}
//打开文件
std
::
shared_ptr
<
FILE
>
fp
(
fopen
(
file_path
.
data
(),
"rb"
),
[](
FILE
*
fp
)
{
if
(
fp
)
{
if
(
fp
)
{
fclose
(
fp
);
fclose
(
fp
);
}
}
});
});
if
(
!
fp
)
{
if
(
!
fp
)
{
init
(
fp
,
0
,
0
,
use_mmap
);
//文件不存在
}
else
{
file_size
=
-
1
;
init
(
fp
,
0
,
File
::
fileSize
(
fp
.
get
()),
use_mmap
)
;
return
nullptr
;
}
}
}
//获取文件大小
file_size
=
File
::
fileSize
(
fp
.
get
());
HttpFileBody
::
HttpFileBody
(
const
std
::
shared_ptr
<
FILE
>
&
fp
,
size_t
offset
,
size_t
max_size
,
bool
use_mmap
)
{
int
fd
=
fileno
(
fp
.
get
());
init
(
fp
,
offset
,
max_size
,
use_mmap
);
if
(
fd
<
0
)
{
WarnL
<<
"fileno failed:"
<<
get_uv_errmsg
(
false
);
return
nullptr
;
}
auto
ptr
=
(
char
*
)
mmap
(
NULL
,
file_size
,
PROT_READ
,
MAP_SHARED
,
fd
,
0
);
if
(
ptr
==
MAP_FAILED
)
{
WarnL
<<
"mmap "
<<
file_path
<<
" failed:"
<<
get_uv_errmsg
(
false
);
return
nullptr
;
}
std
::
shared_ptr
<
char
>
ret
(
ptr
,
[
file_size
,
fp
,
file_path
](
char
*
ptr
)
{
munmap
(
ptr
,
file_size
);
delSharedMmap
(
file_path
,
ptr
);
});
#if 0
if (file_size < 10 * 1024 * 1024 && file_path.rfind(".ts") != string::npos) {
//如果是小ts文件,那么尝试先加载到内存
auto buf = BufferRaw::create();
buf->assign(ret.get(), file_size);
ret.reset(buf->data(), [buf, file_path](char *ptr) {
delSharedMmap(file_path, ptr);
});
}
#endif
{
lock_guard
<
mutex
>
lck
(
s_mtx
);
s_shared_mmap
[
file_path
]
=
std
::
make_tuple
(
ret
.
get
(),
file_size
,
ret
);
}
return
ret
;
}
}
#endif
#if defined(__linux__) || defined(__linux)
HttpFileBody
::
HttpFileBody
(
const
string
&
file_path
,
bool
use_mmap
)
{
#include <sys/sendfile.h>
#ifdef ENABLE_MMAP
if
(
use_mmap
)
{
_map_addr
=
getSharedMmap
(
file_path
,
_read_to
);
}
#endif
#endif
if
(
!
_map_addr
&&
_read_to
!=
-
1
)
{
_fp
.
reset
(
fopen
(
file_path
.
data
(),
"rb"
),
[](
FILE
*
fp
)
{
if
(
fp
)
{
fclose
(
fp
);
}
});
if
(
!
_fp
)
{
//文件不存在
_read_to
=
-
1
;
return
;
}
_read_to
=
File
::
fileSize
(
_fp
.
get
());
}
}
void
HttpFileBody
::
setRange
(
uint64_t
offset
,
uint64_t
max_size
)
{
CHECK
((
int64_t
)
offset
<=
_read_to
&&
(
int64_t
)(
max_size
+
offset
)
<=
_read_to
);
_read_to
=
max_size
+
offset
;
_file_offset
=
offset
;
if
(
_fp
&&
!
_map_addr
)
{
fseek64
(
_fp
.
get
(),
_file_offset
,
SEEK_SET
);
}
}
int
HttpFileBody
::
sendFile
(
int
fd
)
{
int
HttpFileBody
::
sendFile
(
int
fd
)
{
#if defined(__linux__) || defined(__linux)
#if defined(__linux__) || defined(__linux)
static
onceToken
s_token
([]()
{
if
(
!
_fp
)
{
signal
(
SIGPIPE
,
SIG_IGN
);
return
-
1
;
});
}
static
onceToken
s_token
([]()
{
signal
(
SIGPIPE
,
SIG_IGN
);
});
off_t
off
=
_file_offset
;
off_t
off
=
_file_offset
;
return
sendfile
(
fd
,
fileno
(
_fp
.
get
()),
&
off
,
_
max_size
);
return
sendfile
(
fd
,
fileno
(
_fp
.
get
()),
&
off
,
_
read_to
-
_file_offset
);
#else
#else
return
-
1
;
return
-
1
;
#endif
#endif
}
}
void
HttpFileBody
::
init
(
const
std
::
shared_ptr
<
FILE
>
&
fp
,
size_t
offset
,
size_t
max_size
,
bool
use_mmap
)
{
class
BufferMmap
:
public
Buffer
{
_fp
=
fp
;
_max_size
=
max_size
;
_file_offset
=
offset
;
#ifdef ENABLE_MMAP
if
(
use_mmap
)
{
do
{
if
(
!
_fp
)
{
//文件不存在
break
;
}
int
fd
=
fileno
(
fp
.
get
());
if
(
fd
<
0
)
{
WarnL
<<
"fileno failed:"
<<
get_uv_errmsg
(
false
);
break
;
}
auto
ptr
=
(
char
*
)
mmap
(
NULL
,
max_size
,
PROT_READ
,
MAP_SHARED
,
fd
,
offset
);
if
(
ptr
==
MAP_FAILED
)
{
WarnL
<<
"mmap failed:"
<<
get_uv_errmsg
(
false
);
break
;
}
_map_addr
.
reset
(
ptr
,
[
max_size
,
fp
](
char
*
ptr
)
{
munmap
(
ptr
,
max_size
);
});
}
while
(
false
);
}
#endif
if
(
!
_map_addr
&&
offset
&&
fp
.
get
())
{
//未映射,那么fseek设置偏移量
fseek64
(
fp
.
get
(),
offset
,
SEEK_SET
);
}
}
class
BufferMmap
:
public
Buffer
{
public
:
public
:
typedef
std
::
shared_ptr
<
BufferMmap
>
Ptr
;
typedef
std
::
shared_ptr
<
BufferMmap
>
Ptr
;
BufferMmap
(
const
std
::
shared_ptr
<
char
>
&
map_addr
,
size_t
offset
,
size_t
size
)
{
BufferMmap
(
const
std
::
shared_ptr
<
char
>
&
map_addr
,
size_t
offset
,
size_t
size
)
{
...
@@ -124,103 +184,96 @@ public:
...
@@ -124,103 +184,96 @@ public:
_data
=
map_addr
.
get
()
+
offset
;
_data
=
map_addr
.
get
()
+
offset
;
_size
=
size
;
_size
=
size
;
}
}
~
BufferMmap
()
override
{};
~
BufferMmap
()
override
{};
//返回数据长度
//返回数据长度
char
*
data
()
const
override
{
char
*
data
()
const
override
{
return
_data
;
}
return
_data
;
size_t
size
()
const
override
{
return
_size
;
}
}
size_t
size
()
const
override
{
return
_size
;
}
private
:
private
:
std
::
shared_ptr
<
char
>
_map_addr
;
char
*
_data
;
char
*
_data
;
size_t
_size
;
size_t
_size
;
std
::
shared_ptr
<
char
>
_map_addr
;
};
};
ssize
_t
HttpFileBody
::
remainSize
()
{
int64
_t
HttpFileBody
::
remainSize
()
{
return
_
max_size
-
_offset
;
return
_
read_to
-
_file
_offset
;
}
}
Buffer
::
Ptr
HttpFileBody
::
readData
(
size_t
size
)
{
Buffer
::
Ptr
HttpFileBody
::
readData
(
size_t
size
)
{
size
=
MIN
((
size_t
)
remainSize
(),
size
);
size
=
MIN
((
size_t
)
remainSize
(),
size
);
if
(
!
size
)
{
if
(
!
size
)
{
//没有剩余字节了
//没有剩余字节了
return
nullptr
;
return
nullptr
;
}
}
if
(
!
_map_addr
)
{
if
(
!
_map_addr
)
{
//fread模式
//
fread模式
ssize_t
iRead
;
ssize_t
iRead
;
auto
ret
=
_pool
.
obtain2
();
auto
ret
=
_pool
.
obtain2
();
ret
->
setCapacity
(
size
+
1
);
ret
->
setCapacity
(
size
+
1
);
do
{
do
{
iRead
=
fread
(
ret
->
data
(),
1
,
size
,
_fp
.
get
());
iRead
=
fread
(
ret
->
data
(),
1
,
size
,
_fp
.
get
());
}
while
(
-
1
==
iRead
&&
UV_EINTR
==
get_uv_error
(
false
));
}
while
(
-
1
==
iRead
&&
UV_EINTR
==
get_uv_error
(
false
));
if
(
iRead
>
0
)
{
if
(
iRead
>
0
)
{
//读到数据了
//读到数据了
ret
->
setSize
(
iRead
);
ret
->
setSize
(
iRead
);
_offset
+=
iRead
;
_
file_
offset
+=
iRead
;
return
std
::
move
(
ret
);
return
std
::
move
(
ret
);
}
}
//读取文件异常,文件真实长度小于声明长度
//读取文件异常,文件真实长度小于声明长度
_
offset
=
_max_size
;
_
file_offset
=
_read_to
;
WarnL
<<
"read file err:"
<<
get_uv_errmsg
();
WarnL
<<
"read file err:"
<<
get_uv_errmsg
();
return
nullptr
;
return
nullptr
;
}
}
//mmap模式
//
mmap模式
auto
ret
=
std
::
make_shared
<
BufferMmap
>
(
_map_addr
,
_offset
,
size
);
auto
ret
=
std
::
make_shared
<
BufferMmap
>
(
_map_addr
,
_file_offset
,
size
);
_offset
+=
size
;
_
file_
offset
+=
size
;
return
ret
;
return
ret
;
}
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
HttpMultiFormBody
::
HttpMultiFormBody
(
const
HttpArgs
&
args
,
const
string
&
filePath
,
const
string
&
boundary
){
std
::
shared_ptr
<
FILE
>
fp
(
fopen
(
filePath
.
data
(),
"rb"
),
[](
FILE
*
fp
)
{
HttpMultiFormBody
::
HttpMultiFormBody
(
const
HttpArgs
&
args
,
const
string
&
filePath
,
const
string
&
boundary
)
{
if
(
fp
){
_fileBody
=
std
::
make_shared
<
HttpFileBody
>
(
filePath
);
fclose
(
fp
);
if
(
_fileBody
->
remainSize
()
<
0
)
{
}
});
if
(
!
fp
){
throw
std
::
invalid_argument
(
StrPrinter
<<
"open file failed:"
<<
filePath
<<
" "
<<
get_uv_errmsg
());
throw
std
::
invalid_argument
(
StrPrinter
<<
"open file failed:"
<<
filePath
<<
" "
<<
get_uv_errmsg
());
}
}
_fileBody
=
std
::
make_shared
<
HttpFileBody
>
(
fp
,
0
,
File
::
fileSize
(
fp
.
get
()));
auto
fileName
=
filePath
;
auto
fileName
=
filePath
;
auto
pos
=
filePath
.
rfind
(
'/'
);
auto
pos
=
filePath
.
rfind
(
'/'
);
if
(
pos
!=
string
::
npos
)
{
if
(
pos
!=
string
::
npos
)
{
fileName
=
filePath
.
substr
(
pos
+
1
);
fileName
=
filePath
.
substr
(
pos
+
1
);
}
}
_bodyPrefix
=
multiFormBodyPrefix
(
args
,
boundary
,
fileName
);
_bodyPrefix
=
multiFormBodyPrefix
(
args
,
boundary
,
fileName
);
_bodySuffix
=
multiFormBodySuffix
(
boundary
);
_bodySuffix
=
multiFormBodySuffix
(
boundary
);
_totalSize
=
_bodyPrefix
.
size
()
+
_bodySuffix
.
size
()
+
_fileBody
->
remainSize
();
_totalSize
=
_bodyPrefix
.
size
()
+
_bodySuffix
.
size
()
+
_fileBody
->
remainSize
();
}
}
ssize
_t
HttpMultiFormBody
::
remainSize
()
{
int64
_t
HttpMultiFormBody
::
remainSize
()
{
return
_totalSize
-
_offset
;
return
_totalSize
-
_offset
;
}
}
Buffer
::
Ptr
HttpMultiFormBody
::
readData
(
size_t
size
){
Buffer
::
Ptr
HttpMultiFormBody
::
readData
(
size_t
size
)
{
if
(
_bodyPrefix
.
size
())
{
if
(
_bodyPrefix
.
size
())
{
auto
ret
=
std
::
make_shared
<
BufferString
>
(
_bodyPrefix
);
auto
ret
=
std
::
make_shared
<
BufferString
>
(
_bodyPrefix
);
_offset
+=
_bodyPrefix
.
size
();
_offset
+=
_bodyPrefix
.
size
();
_bodyPrefix
.
clear
();
_bodyPrefix
.
clear
();
return
ret
;
return
ret
;
}
}
if
(
_fileBody
->
remainSize
())
{
if
(
_fileBody
->
remainSize
())
{
auto
ret
=
_fileBody
->
readData
(
size
);
auto
ret
=
_fileBody
->
readData
(
size
);
if
(
!
ret
)
{
if
(
!
ret
)
{
//读取文件出现异常,提前中断
//读取文件出现异常,提前中断
_offset
=
_totalSize
;
_offset
=
_totalSize
;
}
else
{
}
else
{
_offset
+=
ret
->
size
();
_offset
+=
ret
->
size
();
}
}
return
ret
;
return
ret
;
}
}
if
(
_bodySuffix
.
size
())
{
if
(
_bodySuffix
.
size
())
{
auto
ret
=
std
::
make_shared
<
BufferString
>
(
_bodySuffix
);
auto
ret
=
std
::
make_shared
<
BufferString
>
(
_bodySuffix
);
_offset
=
_totalSize
;
_offset
=
_totalSize
;
_bodySuffix
.
clear
();
_bodySuffix
.
clear
();
...
@@ -230,7 +283,7 @@ Buffer::Ptr HttpMultiFormBody::readData(size_t size){
...
@@ -230,7 +283,7 @@ Buffer::Ptr HttpMultiFormBody::readData(size_t size){
return
nullptr
;
return
nullptr
;
}
}
string
HttpMultiFormBody
::
multiFormBodySuffix
(
const
string
&
boundary
){
string
HttpMultiFormBody
::
multiFormBodySuffix
(
const
string
&
boundary
)
{
string
MPboundary
=
string
(
"--"
)
+
boundary
;
string
MPboundary
=
string
(
"--"
)
+
boundary
;
string
endMPboundary
=
MPboundary
+
"--"
;
string
endMPboundary
=
MPboundary
+
"--"
;
_StrPrinter
body
;
_StrPrinter
body
;
...
@@ -238,21 +291,23 @@ string HttpMultiFormBody::multiFormBodySuffix(const string &boundary){
...
@@ -238,21 +291,23 @@ string HttpMultiFormBody::multiFormBodySuffix(const string &boundary){
return
std
::
move
(
body
);
return
std
::
move
(
body
);
}
}
string
HttpMultiFormBody
::
multiFormContentType
(
const
string
&
boundary
){
string
HttpMultiFormBody
::
multiFormContentType
(
const
string
&
boundary
)
{
return
StrPrinter
<<
"multipart/form-data; boundary="
<<
boundary
;
return
StrPrinter
<<
"multipart/form-data; boundary="
<<
boundary
;
}
}
string
HttpMultiFormBody
::
multiFormBodyPrefix
(
const
HttpArgs
&
args
,
const
string
&
boundary
,
const
string
&
fileName
)
{
string
HttpMultiFormBody
::
multiFormBodyPrefix
(
const
HttpArgs
&
args
,
const
string
&
boundary
,
const
string
&
fileName
)
{
string
MPboundary
=
string
(
"--"
)
+
boundary
;
string
MPboundary
=
string
(
"--"
)
+
boundary
;
_StrPrinter
body
;
_StrPrinter
body
;
for
(
auto
&
pr
:
args
)
{
for
(
auto
&
pr
:
args
)
{
body
<<
MPboundary
<<
"
\r\n
"
;
body
<<
MPboundary
<<
"
\r\n
"
;
body
<<
"Content-Disposition: form-data; name=
\"
"
<<
pr
.
first
<<
"
\"\r\n\r\n
"
;
body
<<
"Content-Disposition: form-data; name=
\"
"
<<
pr
.
first
<<
"
\"\r\n\r\n
"
;
body
<<
pr
.
second
<<
"
\r\n
"
;
body
<<
pr
.
second
<<
"
\r\n
"
;
}
}
body
<<
MPboundary
<<
"
\r\n
"
;
body
<<
MPboundary
<<
"
\r\n
"
;
body
<<
"Content-Disposition: form-data; name=
\"
"
<<
"file"
<<
"
\"
;filename=
\"
"
<<
fileName
<<
"
\"\r\n
"
;
body
<<
"Content-Disposition: form-data; name=
\"
"
body
<<
"Content-Type: application/octet-stream
\r\n\r\n
"
;
<<
"file"
<<
"
\"
;filename=
\"
"
<<
fileName
<<
"
\"\r\n
"
;
body
<<
"Content-Type: application/octet-stream
\r\n\r\n
"
;
return
std
::
move
(
body
);
return
std
::
move
(
body
);
}
}
...
@@ -260,7 +315,7 @@ HttpBufferBody::HttpBufferBody(Buffer::Ptr buffer) {
...
@@ -260,7 +315,7 @@ HttpBufferBody::HttpBufferBody(Buffer::Ptr buffer) {
_buffer
=
std
::
move
(
buffer
);
_buffer
=
std
::
move
(
buffer
);
}
}
ssize
_t
HttpBufferBody
::
remainSize
()
{
int64
_t
HttpBufferBody
::
remainSize
()
{
return
_buffer
?
_buffer
->
size
()
:
0
;
return
_buffer
?
_buffer
->
size
()
:
0
;
}
}
...
@@ -268,4 +323,4 @@ Buffer::Ptr HttpBufferBody::readData(size_t size) {
...
@@ -268,4 +323,4 @@ Buffer::Ptr HttpBufferBody::readData(size_t size) {
return
Buffer
::
Ptr
(
std
::
move
(
_buffer
));
return
Buffer
::
Ptr
(
std
::
move
(
_buffer
));
}
}
}
//
namespace mediakit
}
//
namespace mediakit
src/Http/HttpBody.h
查看文件 @
d432888a
...
@@ -37,7 +37,7 @@ public:
...
@@ -37,7 +37,7 @@ public:
/**
/**
* 剩余数据大小,如果返回-1, 那么就不设置content-length
* 剩余数据大小,如果返回-1, 那么就不设置content-length
*/
*/
virtual
ssize
_t
remainSize
()
{
return
0
;};
virtual
int64
_t
remainSize
()
{
return
0
;};
/**
/**
* 读取一定字节数,返回大小可能小于size
* 读取一定字节数,返回大小可能小于size
...
@@ -77,7 +77,7 @@ public:
...
@@ -77,7 +77,7 @@ public:
HttpStringBody
(
std
::
string
str
);
HttpStringBody
(
std
::
string
str
);
~
HttpStringBody
()
override
=
default
;
~
HttpStringBody
()
override
=
default
;
ssize
_t
remainSize
()
override
;
int64
_t
remainSize
()
override
;
toolkit
::
Buffer
::
Ptr
readData
(
size_t
size
)
override
;
toolkit
::
Buffer
::
Ptr
readData
(
size_t
size
)
override
;
private
:
private
:
...
@@ -94,7 +94,7 @@ public:
...
@@ -94,7 +94,7 @@ public:
HttpBufferBody
(
toolkit
::
Buffer
::
Ptr
buffer
);
HttpBufferBody
(
toolkit
::
Buffer
::
Ptr
buffer
);
~
HttpBufferBody
()
override
=
default
;
~
HttpBufferBody
()
override
=
default
;
ssize
_t
remainSize
()
override
;
int64
_t
remainSize
()
override
;
toolkit
::
Buffer
::
Ptr
readData
(
size_t
size
)
override
;
toolkit
::
Buffer
::
Ptr
readData
(
size_t
size
)
override
;
private
:
private
:
...
@@ -104,32 +104,32 @@ private:
...
@@ -104,32 +104,32 @@ private:
/**
/**
* 文件类型的content
* 文件类型的content
*/
*/
class
HttpFileBody
:
public
HttpBody
{
class
HttpFileBody
:
public
HttpBody
{
public
:
public
:
typedef
std
::
shared_ptr
<
HttpFileBody
>
Ptr
;
typedef
std
::
shared_ptr
<
HttpFileBody
>
Ptr
;
/**
/**
* 构造函数
* 构造函数
* @param fp 文件句柄,文件的偏移量必须为0
* @param file_path 文件路径
* @param offset 相对文件头的偏移量
* @param max_size 最大读取字节数,未判断是否大于文件真实大小
* @param use_mmap 是否使用mmap方式访问文件
* @param use_mmap 是否使用mmap方式访问文件
*/
*/
HttpFileBody
(
const
std
::
shared_ptr
<
FILE
>
&
fp
,
size_t
offset
,
size_t
max_size
,
bool
use_mmap
=
true
);
HttpFileBody
(
const
std
::
string
&
file_path
,
bool
use_mmap
=
true
);
HttpFileBody
(
const
std
::
string
&
file_path
,
bool
use_mmap
=
true
);
~
HttpFileBody
()
override
=
default
;
~
HttpFileBody
()
override
=
default
;
ssize_t
remainSize
()
override
;
/**
* 设置读取范围
* @param offset 相对文件头的偏移量
* @param max_size 最大读取字节数
*/
void
setRange
(
uint64_t
offset
,
uint64_t
max_size
);
int64_t
remainSize
()
override
;
toolkit
::
Buffer
::
Ptr
readData
(
size_t
size
)
override
;
toolkit
::
Buffer
::
Ptr
readData
(
size_t
size
)
override
;
int
sendFile
(
int
fd
)
override
;
int
sendFile
(
int
fd
)
override
;
private
:
private
:
void
init
(
const
std
::
shared_ptr
<
FILE
>
&
fp
,
size_t
offset
,
size_t
max_size
,
bool
use_mmap
);
int64_t
_read_to
=
0
;
uint64_t
_file_offset
=
0
;
private
:
size_t
_max_size
;
size_t
_offset
=
0
;
size_t
_file_offset
=
0
;
std
::
shared_ptr
<
FILE
>
_fp
;
std
::
shared_ptr
<
FILE
>
_fp
;
std
::
shared_ptr
<
char
>
_map_addr
;
std
::
shared_ptr
<
char
>
_map_addr
;
toolkit
::
ResourcePool
<
toolkit
::
BufferRaw
>
_pool
;
toolkit
::
ResourcePool
<
toolkit
::
BufferRaw
>
_pool
;
...
@@ -152,7 +152,7 @@ public:
...
@@ -152,7 +152,7 @@ public:
*/
*/
HttpMultiFormBody
(
const
HttpArgs
&
args
,
const
std
::
string
&
filePath
,
const
std
::
string
&
boundary
=
"0xKhTmLbOuNdArY"
);
HttpMultiFormBody
(
const
HttpArgs
&
args
,
const
std
::
string
&
filePath
,
const
std
::
string
&
boundary
=
"0xKhTmLbOuNdArY"
);
virtual
~
HttpMultiFormBody
(){}
virtual
~
HttpMultiFormBody
(){}
ssize
_t
remainSize
()
override
;
int64
_t
remainSize
()
override
;
toolkit
::
Buffer
::
Ptr
readData
(
size_t
size
)
override
;
toolkit
::
Buffer
::
Ptr
readData
(
size_t
size
)
override
;
public
:
public
:
...
@@ -161,8 +161,8 @@ public:
...
@@ -161,8 +161,8 @@ public:
static
std
::
string
multiFormContentType
(
const
std
::
string
&
boundary
);
static
std
::
string
multiFormContentType
(
const
std
::
string
&
boundary
);
private
:
private
:
size
_t
_offset
=
0
;
uint64
_t
_offset
=
0
;
size
_t
_totalSize
;
int64
_t
_totalSize
;
std
::
string
_bodyPrefix
;
std
::
string
_bodyPrefix
;
std
::
string
_bodySuffix
;
std
::
string
_bodySuffix
;
HttpFileBody
::
Ptr
_fileBody
;
HttpFileBody
::
Ptr
_fileBody
;
...
...
src/Http/HttpCookie.cpp
查看文件 @
d432888a
...
@@ -10,7 +10,7 @@
...
@@ -10,7 +10,7 @@
#include "HttpCookie.h"
#include "HttpCookie.h"
#include "Util/util.h"
#include "Util/util.h"
#include "Util/
logger
.h"
#include "Util/
onceToken
.h"
#if defined(_WIN32)
#if defined(_WIN32)
#include "Util/strptime_win.h"
#include "Util/strptime_win.h"
...
@@ -21,28 +21,75 @@ using namespace std;
...
@@ -21,28 +21,75 @@ using namespace std;
namespace
mediakit
{
namespace
mediakit
{
void
HttpCookie
::
setPath
(
const
string
&
path
){
void
HttpCookie
::
setPath
(
const
string
&
path
)
{
_path
=
path
;
_path
=
path
;
}
}
void
HttpCookie
::
setHost
(
const
string
&
host
){
void
HttpCookie
::
setHost
(
const
string
&
host
)
{
_host
=
host
;
_host
=
host
;
}
}
static
time_t
timeStrToInt
(
const
string
&
date
){
static
long
s_gmtoff
=
0
;
//时间差
static
onceToken
s_token
([]()
{
#ifdef _WIN32
TIME_ZONE_INFORMATION
tzinfo
;
DWORD
dwStandardDaylight
;
long
bias
;
dwStandardDaylight
=
GetTimeZoneInformation
(
&
tzinfo
);
bias
=
tzinfo
.
Bias
;
if
(
dwStandardDaylight
==
TIME_ZONE_ID_STANDARD
)
{
bias
+=
tzinfo
.
StandardBias
;
}
if
(
dwStandardDaylight
==
TIME_ZONE_ID_DAYLIGHT
)
{
bias
+=
tzinfo
.
DaylightBias
;
}
s_gmtoff
=
-
bias
*
60
;
//时间差(分钟)
#else
s_gmtoff
=
getLocalTime
(
time
(
nullptr
)).
tm_gmtoff
;
#endif // _WIN32
});
// from https://gmbabar.wordpress.com/2010/12/01/mktime-slow-use-custom-function/#comment-58
static
time_t
time_to_epoch
(
const
struct
tm
*
ltm
,
int
utcdiff
)
{
const
int
mon_days
[]
=
{
31
,
28
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
};
long
tyears
,
tdays
,
leaps
,
utc_hrs
;
int
i
;
tyears
=
ltm
->
tm_year
-
70
;
// tm->tm_year is from 1900.
leaps
=
(
tyears
+
2
)
/
4
;
// no of next two lines until year 2100.
// i = (ltm->tm_year – 100) / 100;
// leaps -= ( (i/4)*3 + i%4 );
tdays
=
0
;
for
(
i
=
0
;
i
<
ltm
->
tm_mon
;
i
++
)
tdays
+=
mon_days
[
i
];
tdays
+=
ltm
->
tm_mday
-
1
;
// days of month passed.
tdays
=
tdays
+
(
tyears
*
365
)
+
leaps
;
utc_hrs
=
ltm
->
tm_hour
+
utcdiff
;
// for your time zone.
return
(
tdays
*
86400
)
+
(
utc_hrs
*
3600
)
+
(
ltm
->
tm_min
*
60
)
+
ltm
->
tm_sec
;
}
static
time_t
timeStrToInt
(
const
string
&
date
)
{
struct
tm
tt
;
struct
tm
tt
;
strptime
(
date
.
data
(),
"%a, %b %d %Y %H:%M:%S %Z"
,
&
tt
);
strptime
(
date
.
data
(),
"%a, %b %d %Y %H:%M:%S %Z"
,
&
tt
);
return
mktime
(
&
tt
);
// mktime内部有使用互斥锁,非常影响性能
return
time_to_epoch
(
&
tt
,
s_gmtoff
/
3600
);
// mktime(&tt);
}
}
void
HttpCookie
::
setExpires
(
const
string
&
expires
,
const
string
&
server_date
){
void
HttpCookie
::
setExpires
(
const
string
&
expires
,
const
string
&
server_date
)
{
_expire
=
timeStrToInt
(
expires
);
_expire
=
timeStrToInt
(
expires
);
if
(
!
server_date
.
empty
())
{
if
(
!
server_date
.
empty
())
{
_expire
=
time
(
NULL
)
+
(
_expire
-
timeStrToInt
(
server_date
));
_expire
=
time
(
NULL
)
+
(
_expire
-
timeStrToInt
(
server_date
));
}
}
}
}
void
HttpCookie
::
setKeyVal
(
const
string
&
key
,
const
string
&
val
){
void
HttpCookie
::
setKeyVal
(
const
string
&
key
,
const
string
&
val
)
{
_key
=
key
;
_key
=
key
;
_val
=
val
;
_val
=
val
;
}
}
HttpCookie
::
operator
bool
(){
HttpCookie
::
operator
bool
()
{
return
!
_host
.
empty
()
&&
!
_key
.
empty
()
&&
!
_val
.
empty
()
&&
(
_expire
>
time
(
NULL
));
return
!
_host
.
empty
()
&&
!
_key
.
empty
()
&&
!
_val
.
empty
()
&&
(
_expire
>
time
(
NULL
));
}
}
...
@@ -50,19 +97,18 @@ const string &HttpCookie::getVal() const {
...
@@ -50,19 +97,18 @@ const string &HttpCookie::getVal() const {
return
_val
;
return
_val
;
}
}
const
string
&
HttpCookie
::
getKey
()
const
{
const
string
&
HttpCookie
::
getKey
()
const
{
return
_key
;
return
_key
;
}
}
HttpCookieStorage
&
HttpCookieStorage
::
Instance
()
{
HttpCookieStorage
&
HttpCookieStorage
::
Instance
(){
static
HttpCookieStorage
instance
;
static
HttpCookieStorage
instance
;
return
instance
;
return
instance
;
}
}
void
HttpCookieStorage
::
set
(
const
HttpCookie
::
Ptr
&
cookie
)
{
void
HttpCookieStorage
::
set
(
const
HttpCookie
::
Ptr
&
cookie
)
{
lock_guard
<
mutex
>
lck
(
_mtx_cookie
);
lock_guard
<
mutex
>
lck
(
_mtx_cookie
);
if
(
!
cookie
||
!
(
*
cookie
))
{
if
(
!
cookie
||
!
(
*
cookie
))
{
return
;
return
;
}
}
_all_cookie
[
cookie
->
_host
][
cookie
->
_path
][
cookie
->
_key
]
=
cookie
;
_all_cookie
[
cookie
->
_host
][
cookie
->
_path
][
cookie
->
_key
]
=
cookie
;
...
@@ -71,20 +117,20 @@ void HttpCookieStorage::set(const HttpCookie::Ptr &cookie) {
...
@@ -71,20 +117,20 @@ void HttpCookieStorage::set(const HttpCookie::Ptr &cookie) {
vector
<
HttpCookie
::
Ptr
>
HttpCookieStorage
::
get
(
const
string
&
host
,
const
string
&
path
)
{
vector
<
HttpCookie
::
Ptr
>
HttpCookieStorage
::
get
(
const
string
&
host
,
const
string
&
path
)
{
vector
<
HttpCookie
::
Ptr
>
ret
(
0
);
vector
<
HttpCookie
::
Ptr
>
ret
(
0
);
lock_guard
<
mutex
>
lck
(
_mtx_cookie
);
lock_guard
<
mutex
>
lck
(
_mtx_cookie
);
auto
it
=
_all_cookie
.
find
(
host
);
auto
it
=
_all_cookie
.
find
(
host
);
if
(
it
==
_all_cookie
.
end
())
{
if
(
it
==
_all_cookie
.
end
())
{
//未找到该host相关记录
//未找到该host相关记录
return
ret
;
return
ret
;
}
}
//遍历该host下所有path
//遍历该host下所有path
for
(
auto
&
pr
:
it
->
second
)
{
for
(
auto
&
pr
:
it
->
second
)
{
if
(
path
.
find
(
pr
.
first
)
!=
0
)
{
if
(
path
.
find
(
pr
.
first
)
!=
0
)
{
//这个path不匹配
//这个path不匹配
continue
;
continue
;
}
}
//遍历该path下的各个cookie
//遍历该path下的各个cookie
for
(
auto
it_cookie
=
pr
.
second
.
begin
()
;
it_cookie
!=
pr
.
second
.
end
()
;
)
{
for
(
auto
it_cookie
=
pr
.
second
.
begin
();
it_cookie
!=
pr
.
second
.
end
();)
{
if
(
!*
(
it_cookie
->
second
))
{
if
(
!*
(
it_cookie
->
second
))
{
//该cookie已经过期,移除之
//该cookie已经过期,移除之
it_cookie
=
pr
.
second
.
erase
(
it_cookie
);
it_cookie
=
pr
.
second
.
erase
(
it_cookie
);
continue
;
continue
;
...
@@ -97,5 +143,4 @@ vector<HttpCookie::Ptr> HttpCookieStorage::get(const string &host, const string
...
@@ -97,5 +143,4 @@ vector<HttpCookie::Ptr> HttpCookieStorage::get(const string &host, const string
return
ret
;
return
ret
;
}
}
}
/* namespace mediakit */
}
/* namespace mediakit */
src/Http/HttpCookieManager.cpp
查看文件 @
d432888a
...
@@ -8,10 +8,10 @@
...
@@ -8,10 +8,10 @@
* may be found in the AUTHORS file in the root of the source tree.
* may be found in the AUTHORS file in the root of the source tree.
*/
*/
#include "Util/util.h"
#include "Util/MD5.h"
#include "Common/config.h"
#include "HttpCookieManager.h"
#include "HttpCookieManager.h"
#include "Common/config.h"
#include "Util/MD5.h"
#include "Util/util.h"
using
namespace
std
;
using
namespace
std
;
using
namespace
toolkit
;
using
namespace
toolkit
;
...
@@ -19,27 +19,25 @@ using namespace toolkit;
...
@@ -19,27 +19,25 @@ using namespace toolkit;
namespace
mediakit
{
namespace
mediakit
{
//////////////////////////////HttpServerCookie////////////////////////////////////
//////////////////////////////HttpServerCookie////////////////////////////////////
HttpServerCookie
::
HttpServerCookie
(
const
std
::
shared_ptr
<
HttpCookieManager
>
&
manager
,
HttpServerCookie
::
HttpServerCookie
(
const
string
&
cookie_name
,
const
std
::
shared_ptr
<
HttpCookieManager
>
&
manager
,
const
string
&
cookie_name
,
const
string
&
uid
,
const
string
&
uid
,
const
string
&
cookie
,
uint64_t
max_elapsed
)
{
const
string
&
cookie
,
uint64_t
max_elapsed
){
_uid
=
uid
;
_uid
=
uid
;
_max_elapsed
=
max_elapsed
;
_max_elapsed
=
max_elapsed
;
_cookie_uuid
=
cookie
;
_cookie_uuid
=
cookie
;
_cookie_name
=
cookie_name
;
_cookie_name
=
cookie_name
;
_manager
=
manager
;
_manager
=
manager
;
manager
->
onAddCookie
(
_cookie_name
,
_uid
,
_cookie_uuid
);
manager
->
onAddCookie
(
_cookie_name
,
_uid
,
_cookie_uuid
);
}
}
HttpServerCookie
::~
HttpServerCookie
()
{
HttpServerCookie
::~
HttpServerCookie
()
{
auto
strongManager
=
_manager
.
lock
();
auto
strongManager
=
_manager
.
lock
();
if
(
strongManager
)
{
if
(
strongManager
)
{
strongManager
->
onDelCookie
(
_cookie_name
,
_uid
,
_cookie_uuid
);
strongManager
->
onDelCookie
(
_cookie_name
,
_uid
,
_cookie_uuid
);
}
}
}
}
const
string
&
HttpServerCookie
::
getUid
()
const
{
const
string
&
HttpServerCookie
::
getUid
()
const
{
return
_uid
;
return
_uid
;
}
}
...
@@ -47,11 +45,11 @@ string HttpServerCookie::getCookie(const string &path) const {
...
@@ -47,11 +45,11 @@ string HttpServerCookie::getCookie(const string &path) const {
return
(
StrPrinter
<<
_cookie_name
<<
"="
<<
_cookie_uuid
<<
";expires="
<<
cookieExpireTime
()
<<
";path="
<<
path
);
return
(
StrPrinter
<<
_cookie_name
<<
"="
<<
_cookie_uuid
<<
";expires="
<<
cookieExpireTime
()
<<
";path="
<<
path
);
}
}
const
string
&
HttpServerCookie
::
getCookie
()
const
{
const
string
&
HttpServerCookie
::
getCookie
()
const
{
return
_cookie_uuid
;
return
_cookie_uuid
;
}
}
const
string
&
HttpServerCookie
::
getCookieName
()
const
{
const
string
&
HttpServerCookie
::
getCookieName
()
const
{
return
_cookie_name
;
return
_cookie_name
;
}
}
...
@@ -63,11 +61,11 @@ bool HttpServerCookie::isExpired() {
...
@@ -63,11 +61,11 @@ bool HttpServerCookie::isExpired() {
return
_ticker
.
elapsedTime
()
>
_max_elapsed
*
1000
;
return
_ticker
.
elapsedTime
()
>
_max_elapsed
*
1000
;
}
}
std
::
shared_ptr
<
lock_guard
<
recursive_mutex
>
>
HttpServerCookie
::
getLock
()
{
void
HttpServerCookie
::
setAttach
(
std
::
shared_ptr
<
void
>
attach
)
{
return
std
::
make_shared
<
lock_guard
<
recursive_mutex
>
>
(
_mtx
);
_attach
=
std
::
move
(
attach
);
}
}
string
HttpServerCookie
::
cookieExpireTime
()
const
{
string
HttpServerCookie
::
cookieExpireTime
()
const
{
char
buf
[
64
];
char
buf
[
64
];
time_t
tt
=
time
(
NULL
)
+
_max_elapsed
;
time_t
tt
=
time
(
NULL
)
+
_max_elapsed
;
strftime
(
buf
,
sizeof
buf
,
"%a, %b %d %Y %H:%M:%S GMT"
,
gmtime
(
&
tt
));
strftime
(
buf
,
sizeof
buf
,
"%a, %b %d %Y %H:%M:%S GMT"
,
gmtime
(
&
tt
));
...
@@ -78,10 +76,13 @@ INSTANCE_IMP(HttpCookieManager);
...
@@ -78,10 +76,13 @@ INSTANCE_IMP(HttpCookieManager);
HttpCookieManager
::
HttpCookieManager
()
{
HttpCookieManager
::
HttpCookieManager
()
{
//定时删除过期的cookie,防止内存膨胀
//定时删除过期的cookie,防止内存膨胀
_timer
=
std
::
make_shared
<
Timer
>
(
10.0
f
,[
this
](){
_timer
=
std
::
make_shared
<
Timer
>
(
onManager
();
10.0
f
,
return
true
;
[
this
]()
{
},
nullptr
);
onManager
();
return
true
;
},
nullptr
);
}
}
HttpCookieManager
::~
HttpCookieManager
()
{
HttpCookieManager
::~
HttpCookieManager
()
{
...
@@ -91,11 +92,11 @@ HttpCookieManager::~HttpCookieManager() {
...
@@ -91,11 +92,11 @@ HttpCookieManager::~HttpCookieManager() {
void
HttpCookieManager
::
onManager
()
{
void
HttpCookieManager
::
onManager
()
{
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
//先遍历所有类型
//先遍历所有类型
for
(
auto
it_name
=
_map_cookie
.
begin
()
;
it_name
!=
_map_cookie
.
end
()
;)
{
for
(
auto
it_name
=
_map_cookie
.
begin
();
it_name
!=
_map_cookie
.
end
();)
{
//再遍历该类型下的所有cookie
//再遍历该类型下的所有cookie
for
(
auto
it_cookie
=
it_name
->
second
.
begin
()
;
it_cookie
!=
it_name
->
second
.
end
()
;
)
{
for
(
auto
it_cookie
=
it_name
->
second
.
begin
()
;
it_cookie
!=
it_name
->
second
.
end
();)
{
if
(
it_cookie
->
second
->
isExpired
())
{
if
(
it_cookie
->
second
->
isExpired
())
{
//cookie过期,移除记录
//
cookie过期,移除记录
DebugL
<<
it_cookie
->
second
->
getUid
()
<<
" cookie过期:"
<<
it_cookie
->
second
->
getCookie
();
DebugL
<<
it_cookie
->
second
->
getUid
()
<<
" cookie过期:"
<<
it_cookie
->
second
->
getCookie
();
it_cookie
=
it_name
->
second
.
erase
(
it_cookie
);
it_cookie
=
it_name
->
second
.
erase
(
it_cookie
);
continue
;
continue
;
...
@@ -103,7 +104,7 @@ void HttpCookieManager::onManager() {
...
@@ -103,7 +104,7 @@ void HttpCookieManager::onManager() {
++
it_cookie
;
++
it_cookie
;
}
}
if
(
it_name
->
second
.
empty
())
{
if
(
it_name
->
second
.
empty
())
{
//该类型下没有任何cooki记录,移除之
//该类型下没有任何cooki记录,移除之
DebugL
<<
"该path下没有任何cooki记录:"
<<
it_name
->
first
;
DebugL
<<
"该path下没有任何cooki记录:"
<<
it_name
->
first
;
it_name
=
_map_cookie
.
erase
(
it_name
);
it_name
=
_map_cookie
.
erase
(
it_name
);
...
@@ -113,36 +114,38 @@ void HttpCookieManager::onManager() {
...
@@ -113,36 +114,38 @@ void HttpCookieManager::onManager() {
}
}
}
}
HttpServerCookie
::
Ptr
HttpCookieManager
::
addCookie
(
const
string
&
cookie_name
,
const
string
&
uidIn
,
uint64_t
max_elapsed
,
int
max_client
)
{
HttpServerCookie
::
Ptr
HttpCookieManager
::
addCookie
(
const
string
&
cookie_name
,
const
string
&
uid_in
,
uint64_t
max_elapsed
,
std
::
shared_ptr
<
void
>
attach
,
int
max_client
)
{
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
auto
cookie
=
_geneator
.
obtain
();
auto
cookie
=
_geneator
.
obtain
();
auto
uid
=
uid
In
.
empty
()
?
cookie
:
uidI
n
;
auto
uid
=
uid
_in
.
empty
()
?
cookie
:
uid_i
n
;
auto
oldCookie
=
getOldestCookie
(
cookie_name
,
uid
,
max_client
);
auto
oldCookie
=
getOldestCookie
(
cookie_name
,
uid
,
max_client
);
if
(
!
oldCookie
.
empty
())
{
if
(
!
oldCookie
.
empty
())
{
//假如该账号已经登录了,那么删除老的cookie。
//假如该账号已经登录了,那么删除老的cookie。
//目的是实现单账号多地登录时挤占登录
//目的是实现单账号多地登录时挤占登录
delCookie
(
cookie_name
,
oldCookie
);
delCookie
(
cookie_name
,
oldCookie
);
}
}
HttpServerCookie
::
Ptr
data
(
new
HttpServerCookie
(
shared_from_this
(),
cookie_name
,
uid
,
cookie
,
max_elapsed
));
HttpServerCookie
::
Ptr
data
(
new
HttpServerCookie
(
shared_from_this
(),
cookie_name
,
uid
,
cookie
,
max_elapsed
));
data
->
setAttach
(
std
::
move
(
attach
));
//保存该账号下的新cookie
//保存该账号下的新cookie
_map_cookie
[
cookie_name
][
cookie
]
=
data
;
_map_cookie
[
cookie_name
][
cookie
]
=
data
;
return
data
;
return
data
;
}
}
HttpServerCookie
::
Ptr
HttpCookieManager
::
getCookie
(
const
string
&
cookie_name
,
const
string
&
cookie
)
{
HttpServerCookie
::
Ptr
HttpCookieManager
::
getCookie
(
const
string
&
cookie_name
,
const
string
&
cookie
)
{
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
auto
it_name
=
_map_cookie
.
find
(
cookie_name
);
auto
it_name
=
_map_cookie
.
find
(
cookie_name
);
if
(
it_name
==
_map_cookie
.
end
())
{
if
(
it_name
==
_map_cookie
.
end
())
{
//不存在该类型的cookie
//不存在该类型的cookie
return
nullptr
;
return
nullptr
;
}
}
auto
it_cookie
=
it_name
->
second
.
find
(
cookie
);
auto
it_cookie
=
it_name
->
second
.
find
(
cookie
);
if
(
it_cookie
==
it_name
->
second
.
end
())
{
if
(
it_cookie
==
it_name
->
second
.
end
())
{
//该类型下没有对应的cookie
//该类型下没有对应的cookie
return
nullptr
;
return
nullptr
;
}
}
if
(
it_cookie
->
second
->
isExpired
())
{
if
(
it_cookie
->
second
->
isExpired
())
{
//cookie过期
//
cookie过期
DebugL
<<
"cookie过期:"
<<
it_cookie
->
second
->
getCookie
();
DebugL
<<
"cookie过期:"
<<
it_cookie
->
second
->
getCookie
();
it_name
->
second
.
erase
(
it_cookie
);
it_name
->
second
.
erase
(
it_cookie
);
return
nullptr
;
return
nullptr
;
...
@@ -150,7 +153,7 @@ HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name,con
...
@@ -150,7 +153,7 @@ HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name,con
return
it_cookie
->
second
;
return
it_cookie
->
second
;
}
}
HttpServerCookie
::
Ptr
HttpCookieManager
::
getCookie
(
const
string
&
cookie_name
,
const
StrCaseMap
&
http_header
)
{
HttpServerCookie
::
Ptr
HttpCookieManager
::
getCookie
(
const
string
&
cookie_name
,
const
StrCaseMap
&
http_header
)
{
auto
it
=
http_header
.
find
(
"Cookie"
);
auto
it
=
http_header
.
find
(
"Cookie"
);
if
(
it
==
http_header
.
end
())
{
if
(
it
==
http_header
.
end
())
{
return
nullptr
;
return
nullptr
;
...
@@ -159,100 +162,100 @@ HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name,con
...
@@ -159,100 +162,100 @@ HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name,con
if
(
!
cookie
.
size
())
{
if
(
!
cookie
.
size
())
{
cookie
=
FindField
(
it
->
second
.
data
(),
(
cookie_name
+
"="
).
data
(),
nullptr
);
cookie
=
FindField
(
it
->
second
.
data
(),
(
cookie_name
+
"="
).
data
(),
nullptr
);
}
}
if
(
cookie
.
empty
())
{
if
(
cookie
.
empty
())
{
return
nullptr
;
return
nullptr
;
}
}
return
HttpCookieManager
::
Instance
().
getCookie
(
cookie_name
,
cookie
);
return
HttpCookieManager
::
Instance
().
getCookie
(
cookie_name
,
cookie
);
}
}
HttpServerCookie
::
Ptr
HttpCookieManager
::
getCookieByUid
(
const
string
&
cookie_name
,
const
string
&
uid
)
{
HttpServerCookie
::
Ptr
HttpCookieManager
::
getCookieByUid
(
const
string
&
cookie_name
,
const
string
&
uid
)
{
if
(
cookie_name
.
empty
()
||
uid
.
empty
())
{
if
(
cookie_name
.
empty
()
||
uid
.
empty
())
{
return
nullptr
;
return
nullptr
;
}
}
auto
cookie
=
getOldestCookie
(
cookie_name
,
uid
);
auto
cookie
=
getOldestCookie
(
cookie_name
,
uid
);
if
(
cookie
.
empty
())
{
if
(
cookie
.
empty
())
{
return
nullptr
;
return
nullptr
;
}
}
return
getCookie
(
cookie_name
,
cookie
);
return
getCookie
(
cookie_name
,
cookie
);
}
}
bool
HttpCookieManager
::
delCookie
(
const
HttpServerCookie
::
Ptr
&
cookie
)
{
bool
HttpCookieManager
::
delCookie
(
const
HttpServerCookie
::
Ptr
&
cookie
)
{
if
(
!
cookie
)
{
if
(
!
cookie
)
{
return
false
;
return
false
;
}
}
return
delCookie
(
cookie
->
getCookieName
(),
cookie
->
getCookie
());
return
delCookie
(
cookie
->
getCookieName
(),
cookie
->
getCookie
());
}
}
bool
HttpCookieManager
::
delCookie
(
const
string
&
cookie_name
,
const
string
&
cookie
)
{
bool
HttpCookieManager
::
delCookie
(
const
string
&
cookie_name
,
const
string
&
cookie
)
{
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
auto
it_name
=
_map_cookie
.
find
(
cookie_name
);
auto
it_name
=
_map_cookie
.
find
(
cookie_name
);
if
(
it_name
==
_map_cookie
.
end
())
{
if
(
it_name
==
_map_cookie
.
end
())
{
return
false
;
return
false
;
}
}
return
it_name
->
second
.
erase
(
cookie
);
return
it_name
->
second
.
erase
(
cookie
);
}
}
void
HttpCookieManager
::
onAddCookie
(
const
string
&
cookie_name
,
const
string
&
uid
,
const
string
&
cookie
)
{
void
HttpCookieManager
::
onAddCookie
(
const
string
&
cookie_name
,
const
string
&
uid
,
const
string
&
cookie
)
{
//添加新的cookie,我们记录下这个uid下有哪些cookie,目的是实现单账号多地登录时挤占登录
//添加新的cookie,我们记录下这个uid下有哪些cookie,目的是实现单账号多地登录时挤占登录
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
//相同用户下可以存在多个cookie(意味多地登录),这些cookie根据登录时间的早晚依次排序
//相同用户下可以存在多个cookie(意味多地登录),这些cookie根据登录时间的早晚依次排序
_map_uid_to_cookie
[
cookie_name
][
uid
][
getCurrentMillisecond
()]
=
cookie
;
_map_uid_to_cookie
[
cookie_name
][
uid
][
getCurrentMillisecond
()]
=
cookie
;
}
}
void
HttpCookieManager
::
onDelCookie
(
const
string
&
cookie_name
,
const
string
&
uid
,
const
string
&
cookie
){
void
HttpCookieManager
::
onDelCookie
(
const
string
&
cookie_name
,
const
string
&
uid
,
const
string
&
cookie
)
{
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
//回收随机字符串
//回收随机字符串
_geneator
.
release
(
cookie
);
_geneator
.
release
(
cookie
);
auto
it_name
=
_map_uid_to_cookie
.
find
(
cookie_name
);
auto
it_name
=
_map_uid_to_cookie
.
find
(
cookie_name
);
if
(
it_name
==
_map_uid_to_cookie
.
end
())
{
if
(
it_name
==
_map_uid_to_cookie
.
end
())
{
//该类型下未有任意用户登录
//该类型下未有任意用户登录
return
;
return
;
}
}
auto
it_uid
=
it_name
->
second
.
find
(
uid
);
auto
it_uid
=
it_name
->
second
.
find
(
uid
);
if
(
it_uid
==
it_name
->
second
.
end
())
{
if
(
it_uid
==
it_name
->
second
.
end
())
{
//该用户尚未登录
//该用户尚未登录
return
;
return
;
}
}
//遍历同一名用户下的所有客户端,移除命中的客户端
//遍历同一名用户下的所有客户端,移除命中的客户端
for
(
auto
it_cookie
=
it_uid
->
second
.
begin
()
;
it_cookie
!=
it_uid
->
second
.
end
()
;
++
it_cookie
)
{
for
(
auto
it_cookie
=
it_uid
->
second
.
begin
();
it_cookie
!=
it_uid
->
second
.
end
();
++
it_cookie
)
{
if
(
it_cookie
->
second
!=
cookie
)
{
if
(
it_cookie
->
second
!=
cookie
)
{
//不是该cookie
//不是该cookie
continue
;
continue
;
}
}
//移除该用户名下的某个cookie,这个设备cookie将失效
//移除该用户名下的某个cookie,这个设备cookie将失效
it_uid
->
second
.
erase
(
it_cookie
);
it_uid
->
second
.
erase
(
it_cookie
);
if
(
it_uid
->
second
.
size
()
!=
0
)
{
if
(
it_uid
->
second
.
size
()
!=
0
)
{
break
;
break
;
}
}
//该用户名下没有任何设备在线,移除之
//该用户名下没有任何设备在线,移除之
it_name
->
second
.
erase
(
it_uid
);
it_name
->
second
.
erase
(
it_uid
);
if
(
it_name
->
second
.
size
()
!=
0
)
{
if
(
it_name
->
second
.
size
()
!=
0
)
{
break
;
break
;
}
}
//该类型下未有任何用户在线,移除之
//该类型下未有任何用户在线,移除之
_map_uid_to_cookie
.
erase
(
it_name
);
_map_uid_to_cookie
.
erase
(
it_name
);
break
;
break
;
}
}
}
}
string
HttpCookieManager
::
getOldestCookie
(
const
string
&
cookie_name
,
const
string
&
uid
,
int
max_client
)
{
string
HttpCookieManager
::
getOldestCookie
(
const
string
&
cookie_name
,
const
string
&
uid
,
int
max_client
)
{
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
lock_guard
<
recursive_mutex
>
lck
(
_mtx_cookie
);
auto
it_name
=
_map_uid_to_cookie
.
find
(
cookie_name
);
auto
it_name
=
_map_uid_to_cookie
.
find
(
cookie_name
);
if
(
it_name
==
_map_uid_to_cookie
.
end
())
{
if
(
it_name
==
_map_uid_to_cookie
.
end
())
{
//不存在该类型的cookie
//不存在该类型的cookie
return
""
;
return
""
;
}
}
auto
it_uid
=
it_name
->
second
.
find
(
uid
);
auto
it_uid
=
it_name
->
second
.
find
(
uid
);
if
(
it_uid
==
it_name
->
second
.
end
())
{
if
(
it_uid
==
it_name
->
second
.
end
())
{
//该用户从未登录过
//该用户从未登录过
return
""
;
return
""
;
}
}
if
(
it_uid
->
second
.
size
()
<
MAX
(
1
,
max_client
))
{
if
(
it_uid
->
second
.
size
()
<
MAX
(
1
,
max_client
))
{
//同一名用户下,客户端个数还没达到限制个数
//同一名用户下,客户端个数还没达到限制个数
return
""
;
return
""
;
}
}
...
@@ -261,28 +264,29 @@ string HttpCookieManager::getOldestCookie(const string &cookie_name,const string
...
@@ -261,28 +264,29 @@ string HttpCookieManager::getOldestCookie(const string &cookie_name,const string
}
}
/////////////////////////////////RandStrGeneator////////////////////////////////////
/////////////////////////////////RandStrGeneator////////////////////////////////////
string
RandStrGeneator
::
obtain
(){
string
RandStrGeneator
::
obtain
()
{
//获取唯一的防膨胀的随机字符串
//获取唯一的防膨胀的随机字符串
while
(
true
){
while
(
true
)
{
auto
str
=
obtain_l
();
auto
str
=
obtain_l
();
if
(
_obtained
.
find
(
str
)
==
_obtained
.
end
())
{
if
(
_obtained
.
find
(
str
)
==
_obtained
.
end
())
{
//没有重复
//没有重复
_obtained
.
emplace
(
str
);
_obtained
.
emplace
(
str
);
return
str
;
return
str
;
}
}
}
}
}
}
void
RandStrGeneator
::
release
(
const
string
&
str
){
void
RandStrGeneator
::
release
(
const
string
&
str
)
{
//从防膨胀库中移除
//从防膨胀库中移除
_obtained
.
erase
(
str
);
_obtained
.
erase
(
str
);
}
}
string
RandStrGeneator
::
obtain_l
(){
string
RandStrGeneator
::
obtain_l
()
{
//12个伪随机字节 + 4个递增的整形字节,然后md5即为随机字符串
//
12个伪随机字节 + 4个递增的整形字节,然后md5即为随机字符串
auto
str
=
makeRandStr
(
12
,
false
);
auto
str
=
makeRandStr
(
12
,
false
);
str
.
append
((
char
*
)
&
_index
,
sizeof
(
_index
));
str
.
append
((
char
*
)
&
_index
,
sizeof
(
_index
));
++
_index
;
++
_index
;
return
MD5
(
str
).
hexdigest
();
return
MD5
(
str
).
hexdigest
();
}
}
}
//
namespace
mediakit
}
//
namespace
mediakit
\ No newline at end of file
\ No newline at end of file
src/Http/HttpCookieManager.h
查看文件 @
d432888a
...
@@ -11,13 +11,13 @@
...
@@ -11,13 +11,13 @@
#ifndef SRC_HTTP_COOKIEMANAGER_H
#ifndef SRC_HTTP_COOKIEMANAGER_H
#define SRC_HTTP_COOKIEMANAGER_H
#define SRC_HTTP_COOKIEMANAGER_H
#include <memory>
#include "Common/Parser.h"
#include <unordered_map>
#include "Network/Socket.h"
#include "Util/TimeTicker.h"
#include "Util/mini.h"
#include "Util/mini.h"
#include "Util/util.h"
#include "Util/util.h"
#include "Util/TimeTicker.h"
#include <memory>
#include "Network/Socket.h"
#include <unordered_map>
#include "Common/Parser.h"
#define COOKIE_DEFAULT_LIFE (7 * 24 * 60 * 60)
#define COOKIE_DEFAULT_LIFE (7 * 24 * 60 * 60)
...
@@ -28,9 +28,9 @@ class HttpCookieManager;
...
@@ -28,9 +28,9 @@ class HttpCookieManager;
/**
/**
* cookie对象,用于保存cookie的一些相关属性
* cookie对象,用于保存cookie的一些相关属性
*/
*/
class
HttpServerCookie
:
public
toolkit
::
AnyStorage
,
public
toolkit
::
noncopyable
{
class
HttpServerCookie
:
public
toolkit
::
noncopyable
{
public
:
public
:
typedef
std
::
shared_ptr
<
HttpServerCookie
>
Ptr
;
using
Ptr
=
std
::
shared_ptr
<
HttpServerCookie
>
;
/**
/**
* 构建cookie
* 构建cookie
* @param manager cookie管理者对象
* @param manager cookie管理者对象
...
@@ -40,12 +40,10 @@ public:
...
@@ -40,12 +40,10 @@ public:
* @param max_elapsed 最大过期时间,单位秒
* @param max_elapsed 最大过期时间,单位秒
*/
*/
HttpServerCookie
(
const
std
::
shared_ptr
<
HttpCookieManager
>
&
manager
,
HttpServerCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
shared_ptr
<
HttpCookieManager
>
&
manager
,
const
std
::
string
&
cookie_name
,
const
std
::
string
&
uid
,
const
std
::
string
&
uid
,
const
std
::
string
&
cookie
,
uint64_t
max_elapsed
);
const
std
::
string
&
cookie
,
~
HttpServerCookie
();
uint64_t
max_elapsed
);
~
HttpServerCookie
()
;
/**
/**
* 获取uid
* 获取uid
...
@@ -65,13 +63,13 @@ public:
...
@@ -65,13 +63,13 @@ public:
* 获取cookie随机字符串
* 获取cookie随机字符串
* @return cookie随机字符串
* @return cookie随机字符串
*/
*/
const
std
::
string
&
getCookie
()
const
;
const
std
::
string
&
getCookie
()
const
;
/**
/**
* 获取该cookie名
* 获取该cookie名
* @return
* @return
*/
*/
const
std
::
string
&
getCookieName
()
const
;
const
std
::
string
&
getCookieName
()
const
;
/**
/**
* 更新该cookie的过期时间,可以让此cookie不失效
* 更新该cookie的过期时间,可以让此cookie不失效
...
@@ -85,26 +83,35 @@ public:
...
@@ -85,26 +83,35 @@ public:
bool
isExpired
();
bool
isExpired
();
/**
/**
* 获取区域锁
* 设置附加数据
* @return
*/
*/
std
::
shared_ptr
<
std
::
lock_guard
<
std
::
recursive_mutex
>
>
getLock
();
void
setAttach
(
std
::
shared_ptr
<
void
>
attach
);
/*
* 获取附加数据
*/
template
<
class
T
>
const
T
&
getAttach
()
const
{
return
*
static_cast
<
const
T
*>
(
_attach
.
get
());
}
private
:
private
:
std
::
string
cookieExpireTime
()
const
;
std
::
string
cookieExpireTime
()
const
;
private
:
private
:
std
::
string
_uid
;
std
::
string
_uid
;
std
::
string
_cookie_name
;
std
::
string
_cookie_name
;
std
::
string
_cookie_uuid
;
std
::
string
_cookie_uuid
;
uint64_t
_max_elapsed
;
uint64_t
_max_elapsed
;
toolkit
::
Ticker
_ticker
;
toolkit
::
Ticker
_ticker
;
std
::
recursive_mutex
_mtx
;
std
::
shared_ptr
<
void
>
_attach
;
std
::
weak_ptr
<
HttpCookieManager
>
_manager
;
std
::
weak_ptr
<
HttpCookieManager
>
_manager
;
};
};
/**
/**
* cookie随机字符串生成器
* cookie随机字符串生成器
*/
*/
class
RandStrGeneator
{
class
RandStrGeneator
{
public
:
public
:
RandStrGeneator
()
=
default
;
RandStrGeneator
()
=
default
;
~
RandStrGeneator
()
=
default
;
~
RandStrGeneator
()
=
default
;
...
@@ -120,8 +127,10 @@ public:
...
@@ -120,8 +127,10 @@ public:
* @param str 随机字符串
* @param str 随机字符串
*/
*/
void
release
(
const
std
::
string
&
str
);
void
release
(
const
std
::
string
&
str
);
private
:
private
:
std
::
string
obtain_l
();
std
::
string
obtain_l
();
private
:
private
:
//碰撞库
//碰撞库
std
::
unordered_set
<
std
::
string
>
_obtained
;
std
::
unordered_set
<
std
::
string
>
_obtained
;
...
@@ -135,8 +144,8 @@ private:
...
@@ -135,8 +144,8 @@ private:
*/
*/
class
HttpCookieManager
:
public
std
::
enable_shared_from_this
<
HttpCookieManager
>
{
class
HttpCookieManager
:
public
std
::
enable_shared_from_this
<
HttpCookieManager
>
{
public
:
public
:
typedef
std
::
shared_ptr
<
HttpCookieManager
>
Ptr
;
friend
class
HttpServerCookie
;
friend
class
HttpServerCookie
;
using
Ptr
=
std
::
shared_ptr
<
HttpCookieManager
>
;
~
HttpCookieManager
();
~
HttpCookieManager
();
/**
/**
...
@@ -152,7 +161,10 @@ public:
...
@@ -152,7 +161,10 @@ public:
* @param max_elapsed 该cookie过期时间,单位秒
* @param max_elapsed 该cookie过期时间,单位秒
* @return cookie对象
* @return cookie对象
*/
*/
HttpServerCookie
::
Ptr
addCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
uid
,
uint64_t
max_elapsed
=
COOKIE_DEFAULT_LIFE
,
int
max_client
=
1
);
HttpServerCookie
::
Ptr
addCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
uid
,
uint64_t
max_elapsed
=
COOKIE_DEFAULT_LIFE
,
std
::
shared_ptr
<
void
>
attach
=
nullptr
,
int
max_client
=
1
);
/**
/**
* 根据cookie随机字符串查找cookie对象
* 根据cookie随机字符串查找cookie对象
...
@@ -160,7 +172,7 @@ public:
...
@@ -160,7 +172,7 @@ public:
* @param cookie cookie随机字符串
* @param cookie cookie随机字符串
* @return cookie对象,可以为nullptr
* @return cookie对象,可以为nullptr
*/
*/
HttpServerCookie
::
Ptr
getCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
cookie
);
HttpServerCookie
::
Ptr
getCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
cookie
);
/**
/**
* 从http头中获取cookie对象
* 从http头中获取cookie对象
...
@@ -168,7 +180,7 @@ public:
...
@@ -168,7 +180,7 @@ public:
* @param http_header http头
* @param http_header http头
* @return cookie对象
* @return cookie对象
*/
*/
HttpServerCookie
::
Ptr
getCookie
(
const
std
::
string
&
cookie_name
,
const
StrCaseMap
&
http_header
);
HttpServerCookie
::
Ptr
getCookie
(
const
std
::
string
&
cookie_name
,
const
StrCaseMap
&
http_header
);
/**
/**
* 根据uid获取cookie
* 根据uid获取cookie
...
@@ -176,7 +188,7 @@ public:
...
@@ -176,7 +188,7 @@ public:
* @param uid 用户id
* @param uid 用户id
* @return cookie对象
* @return cookie对象
*/
*/
HttpServerCookie
::
Ptr
getCookieByUid
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
uid
);
HttpServerCookie
::
Ptr
getCookieByUid
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
uid
);
/**
/**
* 删除cookie,用户登出时使用
* 删除cookie,用户登出时使用
...
@@ -184,8 +196,10 @@ public:
...
@@ -184,8 +196,10 @@ public:
* @return
* @return
*/
*/
bool
delCookie
(
const
HttpServerCookie
::
Ptr
&
cookie
);
bool
delCookie
(
const
HttpServerCookie
::
Ptr
&
cookie
);
private
:
private
:
HttpCookieManager
();
HttpCookieManager
();
void
onManager
();
void
onManager
();
/**
/**
* 构造cookie对象时触发,目的是记录某账号下多个cookie
* 构造cookie对象时触发,目的是记录某账号下多个cookie
...
@@ -193,7 +207,7 @@ private:
...
@@ -193,7 +207,7 @@ private:
* @param uid 用户id
* @param uid 用户id
* @param cookie cookie随机字符串
* @param cookie cookie随机字符串
*/
*/
void
onAddCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
uid
,
const
std
::
string
&
cookie
);
void
onAddCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
uid
,
const
std
::
string
&
cookie
);
/**
/**
* 析构cookie对象时触发
* 析构cookie对象时触发
...
@@ -201,7 +215,7 @@ private:
...
@@ -201,7 +215,7 @@ private:
* @param uid 用户id
* @param uid 用户id
* @param cookie cookie随机字符串
* @param cookie cookie随机字符串
*/
*/
void
onDelCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
uid
,
const
std
::
string
&
cookie
);
void
onDelCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
uid
,
const
std
::
string
&
cookie
);
/**
/**
* 获取某用户名下最先登录时的cookie,目的是实现某用户下最多登录若干个设备
* 获取某用户名下最先登录时的cookie,目的是实现某用户下最多登录若干个设备
...
@@ -210,7 +224,7 @@ private:
...
@@ -210,7 +224,7 @@ private:
* @param max_client 最多登录的设备个数
* @param max_client 最多登录的设备个数
* @return 最早的cookie随机字符串
* @return 最早的cookie随机字符串
*/
*/
std
::
string
getOldestCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
uid
,
int
max_client
=
1
);
std
::
string
getOldestCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
uid
,
int
max_client
=
1
);
/**
/**
* 删除cookie
* 删除cookie
...
@@ -218,16 +232,21 @@ private:
...
@@ -218,16 +232,21 @@ private:
* @param cookie cookie随机字符串
* @param cookie cookie随机字符串
* @return 成功true
* @return 成功true
*/
*/
bool
delCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
cookie
);
bool
delCookie
(
const
std
::
string
&
cookie_name
,
const
std
::
string
&
cookie
);
private
:
private
:
std
::
unordered_map
<
std
::
string
/*cookie_name*/
,
std
::
unordered_map
<
std
::
string
/*cookie*/
,
HttpServerCookie
::
Ptr
/*cookie_data*/
>
>
_map_cookie
;
std
::
unordered_map
<
std
::
unordered_map
<
std
::
string
/*cookie_name*/
,
std
::
unordered_map
<
std
::
string
/*uid*/
,
std
::
map
<
uint64_t
/*cookie time stamp*/
,
std
::
string
/*cookie*/
>
>
>
_map_uid_to_cookie
;
std
::
string
/*cookie_name*/
,
std
::
unordered_map
<
std
::
string
/*cookie*/
,
HttpServerCookie
::
Ptr
/*cookie_data*/
>>
_map_cookie
;
std
::
unordered_map
<
std
::
string
/*cookie_name*/
,
std
::
unordered_map
<
std
::
string
/*uid*/
,
std
::
map
<
uint64_t
/*cookie time stamp*/
,
std
::
string
/*cookie*/
>>>
_map_uid_to_cookie
;
std
::
recursive_mutex
_mtx_cookie
;
std
::
recursive_mutex
_mtx_cookie
;
toolkit
::
Timer
::
Ptr
_timer
;
toolkit
::
Timer
::
Ptr
_timer
;
RandStrGeneator
_geneator
;
RandStrGeneator
_geneator
;
};
};
}
//namespace mediakit
}
// namespace mediakit
#endif //SRC_HTTP_COOKIEMANAGER_H
#endif //
SRC_HTTP_COOKIEMANAGER_H
src/Http/HttpFileManager.cpp
查看文件 @
d432888a
...
@@ -34,9 +34,6 @@ static const string kHlsSuffix = "/hls.m3u8";
...
@@ -34,9 +34,6 @@ static const string kHlsSuffix = "/hls.m3u8";
class
HttpCookieAttachment
{
class
HttpCookieAttachment
{
public
:
public
:
HttpCookieAttachment
()
{};
~
HttpCookieAttachment
()
{};
public
:
//cookie生效作用域,本cookie只对该目录下的文件生效
//cookie生效作用域,本cookie只对该目录下的文件生效
string
_path
;
string
_path
;
//上次鉴权失败信息,为空则上次鉴权成功
//上次鉴权失败信息,为空则上次鉴权成功
...
@@ -192,13 +189,13 @@ static bool makeFolderMenu(const string &httpPath, const string &strFullPath, st
...
@@ -192,13 +189,13 @@ static bool makeFolderMenu(const string &httpPath, const string &strFullPath, st
}
}
//拦截hls的播放请求
//拦截hls的播放请求
static
bool
emitHlsPlayed
(
const
Parser
&
parser
,
const
MediaInfo
&
media
I
nfo
,
const
HttpSession
::
HttpAccessPathInvoker
&
invoker
,
TcpSession
&
sender
){
static
bool
emitHlsPlayed
(
const
Parser
&
parser
,
const
MediaInfo
&
media
_i
nfo
,
const
HttpSession
::
HttpAccessPathInvoker
&
invoker
,
TcpSession
&
sender
){
//访问的hls.m3u8结尾,我们转换成kBroadcastMediaPlayed事件
//访问的hls.m3u8结尾,我们转换成kBroadcastMediaPlayed事件
Broadcast
::
AuthInvoker
auth_invoker
=
[
invoker
](
const
string
&
err
)
{
Broadcast
::
AuthInvoker
auth_invoker
=
[
invoker
](
const
string
&
err
)
{
//cookie有效期为kHlsCookieSecond
//cookie有效期为kHlsCookieSecond
invoker
(
err
,
""
,
kHlsCookieSecond
);
invoker
(
err
,
""
,
kHlsCookieSecond
);
};
};
bool
flag
=
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastMediaPlayed
,
media
I
nfo
,
auth_invoker
,
static_cast
<
SockInfo
&>
(
sender
));
bool
flag
=
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastMediaPlayed
,
media
_i
nfo
,
auth_invoker
,
static_cast
<
SockInfo
&>
(
sender
));
if
(
!
flag
)
{
if
(
!
flag
)
{
//未开启鉴权,那么允许播放
//未开启鉴权,那么允许播放
auth_invoker
(
""
);
auth_invoker
(
""
);
...
@@ -247,7 +244,7 @@ public:
...
@@ -247,7 +244,7 @@ public:
* 4、cookie中记录的url参数是否跟本次url参数一致,如果一致直接返回客户端错误码
* 4、cookie中记录的url参数是否跟本次url参数一致,如果一致直接返回客户端错误码
* 5、触发kBroadcastHttpAccess事件
* 5、触发kBroadcastHttpAccess事件
*/
*/
static
void
canAccessPath
(
TcpSession
&
sender
,
const
Parser
&
parser
,
const
MediaInfo
&
media
I
nfo
,
bool
is_dir
,
static
void
canAccessPath
(
TcpSession
&
sender
,
const
Parser
&
parser
,
const
MediaInfo
&
media
_i
nfo
,
bool
is_dir
,
const
function
<
void
(
const
string
&
errMsg
,
const
HttpServerCookie
::
Ptr
&
cookie
)
>
&
callback
)
{
const
function
<
void
(
const
string
&
errMsg
,
const
HttpServerCookie
::
Ptr
&
cookie
)
>
&
callback
)
{
//获取用户唯一id
//获取用户唯一id
auto
uid
=
parser
.
Params
();
auto
uid
=
parser
.
Params
();
...
@@ -265,13 +262,12 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
...
@@ -265,13 +262,12 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
if
(
cookie
)
{
if
(
cookie
)
{
//找到了cookie,对cookie上锁先
//找到了cookie,对cookie上锁先
auto
lck
=
cookie
->
getLock
();
auto
&
attach
=
cookie
->
getAttach
<
HttpCookieAttachment
>
();
auto
attachment
=
(
*
cookie
)[
kCookieName
].
get
<
HttpCookieAttachment
>
();
if
(
path
.
find
(
attach
.
_path
)
==
0
)
{
if
(
path
.
find
(
attachment
.
_path
)
==
0
)
{
//上次cookie是限定本目录
//上次cookie是限定本目录
if
(
attach
ment
.
_err_msg
.
empty
())
{
if
(
attach
.
_err_msg
.
empty
())
{
//上次鉴权成功
//上次鉴权成功
if
(
attach
ment
.
_is_hls
)
{
if
(
attach
.
_is_hls
)
{
//如果播放的是hls,那么刷新hls的cookie(获取ts文件也会刷新)
//如果播放的是hls,那么刷新hls的cookie(获取ts文件也会刷新)
cookie
->
updateTime
();
cookie
->
updateTime
();
cookie_from_header
=
false
;
cookie_from_header
=
false
;
...
@@ -282,7 +278,7 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
...
@@ -282,7 +278,7 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
//上次鉴权失败,但是如果url参数发生变更,那么也重新鉴权下
//上次鉴权失败,但是如果url参数发生变更,那么也重新鉴权下
if
(
parser
.
Params
().
empty
()
||
parser
.
Params
()
==
cookie
->
getUid
())
{
if
(
parser
.
Params
().
empty
()
||
parser
.
Params
()
==
cookie
->
getUid
())
{
//url参数未变,或者本来就没有url参数,那么判断本次请求为重复请求,无访问权限
//url参数未变,或者本来就没有url参数,那么判断本次请求为重复请求,无访问权限
callback
(
attach
ment
.
_err_msg
,
cookie_from_header
?
nullptr
:
cookie
);
callback
(
attach
.
_err_msg
,
cookie_from_header
?
nullptr
:
cookie
);
return
;
return
;
}
}
}
}
...
@@ -290,7 +286,7 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
...
@@ -290,7 +286,7 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
HttpCookieManager
::
Instance
().
delCookie
(
cookie
);
HttpCookieManager
::
Instance
().
delCookie
(
cookie
);
}
}
bool
is_hls
=
media
I
nfo
.
_schema
==
HLS_SCHEMA
;
bool
is_hls
=
media
_i
nfo
.
_schema
==
HLS_SCHEMA
;
SockInfoImp
::
Ptr
info
=
std
::
make_shared
<
SockInfoImp
>
();
SockInfoImp
::
Ptr
info
=
std
::
make_shared
<
SockInfoImp
>
();
info
->
_identifier
=
sender
.
getIdentifier
();
info
->
_identifier
=
sender
.
getIdentifier
();
...
@@ -300,10 +296,10 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
...
@@ -300,10 +296,10 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
info
->
_local_port
=
sender
.
get_local_port
();
info
->
_local_port
=
sender
.
get_local_port
();
//该用户从来未获取过cookie,这个时候我们广播是否允许该用户访问该http目录
//该用户从来未获取过cookie,这个时候我们广播是否允许该用户访问该http目录
HttpSession
::
HttpAccessPathInvoker
accessPathInvoker
=
[
callback
,
uid
,
path
,
is_dir
,
is_hls
,
media
I
nfo
,
info
]
HttpSession
::
HttpAccessPathInvoker
accessPathInvoker
=
[
callback
,
uid
,
path
,
is_dir
,
is_hls
,
media
_i
nfo
,
info
]
(
const
string
&
err
Msg
,
const
string
&
cookie_path_in
,
int
cookieLifeS
econd
)
{
(
const
string
&
err
_msg
,
const
string
&
cookie_path_in
,
int
life_s
econd
)
{
HttpServerCookie
::
Ptr
cookie
;
HttpServerCookie
::
Ptr
cookie
;
if
(
cookieLifeS
econd
)
{
if
(
life_s
econd
)
{
//本次鉴权设置了有效期,我们把鉴权结果缓存在cookie中
//本次鉴权设置了有效期,我们把鉴权结果缓存在cookie中
string
cookie_path
=
cookie_path_in
;
string
cookie_path
=
cookie_path_in
;
if
(
cookie_path
.
empty
())
{
if
(
cookie_path
.
empty
())
{
...
@@ -311,32 +307,28 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
...
@@ -311,32 +307,28 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
cookie_path
=
is_dir
?
path
:
path
.
substr
(
0
,
path
.
rfind
(
"/"
)
+
1
);
cookie_path
=
is_dir
?
path
:
path
.
substr
(
0
,
path
.
rfind
(
"/"
)
+
1
);
}
}
cookie
=
HttpCookieManager
::
Instance
().
addCookie
(
kCookieName
,
uid
,
cookieLifeSecond
);
auto
attach
=
std
::
make_shared
<
HttpCookieAttachment
>
();
//对cookie上锁
auto
lck
=
cookie
->
getLock
();
HttpCookieAttachment
attachment
;
//记录用户能访问的路径
//记录用户能访问的路径
attach
ment
.
_path
=
cookie_path
;
attach
->
_path
=
cookie_path
;
//记录能否访问
//记录能否访问
attach
ment
.
_err_msg
=
errM
sg
;
attach
->
_err_msg
=
err_m
sg
;
//记录访问的是否为hls
//记录访问的是否为hls
attach
ment
.
_is_hls
=
is_hls
;
attach
->
_is_hls
=
is_hls
;
if
(
is_hls
)
{
if
(
is_hls
)
{
//hls相关信息
//
hls相关信息
attach
ment
.
_hls_data
=
std
::
make_shared
<
HlsCookieData
>
(
mediaI
nfo
,
info
);
attach
->
_hls_data
=
std
::
make_shared
<
HlsCookieData
>
(
media_i
nfo
,
info
);
//hls未查找MediaSource
//
hls未查找MediaSource
attach
ment
.
_have_find_media_source
=
false
;
attach
->
_have_find_media_source
=
false
;
}
}
(
*
cookie
)[
kCookieName
].
set
<
HttpCookieAttachment
>
(
std
::
move
(
attachment
));
callback
(
err_msg
,
HttpCookieManager
::
Instance
().
addCookie
(
kCookieName
,
uid
,
life_second
,
attach
));
callback
(
errMsg
,
cookie
);
}
else
{
}
else
{
callback
(
err
M
sg
,
nullptr
);
callback
(
err
_m
sg
,
nullptr
);
}
}
};
};
if
(
is_hls
)
{
if
(
is_hls
)
{
//是hls的播放鉴权,拦截之
//是hls的播放鉴权,拦截之
emitHlsPlayed
(
parser
,
media
I
nfo
,
accessPathInvoker
,
sender
);
emitHlsPlayed
(
parser
,
media
_i
nfo
,
accessPathInvoker
,
sender
);
return
;
return
;
}
}
...
@@ -370,13 +362,13 @@ static string pathCat(const string &a, const string &b){
...
@@ -370,13 +362,13 @@ static string pathCat(const string &a, const string &b){
* 访问文件
* 访问文件
* @param sender 事件触发者
* @param sender 事件触发者
* @param parser http请求
* @param parser http请求
* @param media
I
nfo http url信息
* @param media
_i
nfo http url信息
* @param
strFile
文件绝对路径
* @param
file_path
文件绝对路径
* @param cb 回调对象
* @param cb 回调对象
*/
*/
static
void
accessFile
(
TcpSession
&
sender
,
const
Parser
&
parser
,
const
MediaInfo
&
media
Info
,
const
string
&
strFile
,
const
HttpFileManager
::
invoker
&
cb
)
{
static
void
accessFile
(
TcpSession
&
sender
,
const
Parser
&
parser
,
const
MediaInfo
&
media
_info
,
const
string
&
file_path
,
const
HttpFileManager
::
invoker
&
cb
)
{
bool
is_hls
=
end_with
(
strFile
,
kHlsSuffix
);
bool
is_hls
=
end_with
(
file_path
,
kHlsSuffix
);
bool
file_exist
=
File
::
is_file
(
strFile
.
data
());
bool
file_exist
=
File
::
is_file
(
file_path
.
data
());
if
(
!
is_hls
&&
!
file_exist
)
{
if
(
!
is_hls
&&
!
file_exist
)
{
//文件不存在且不是hls,那么直接返回404
//文件不存在且不是hls,那么直接返回404
sendNotFound
(
cb
);
sendNotFound
(
cb
);
...
@@ -385,13 +377,13 @@ static void accessFile(TcpSession &sender, const Parser &parser, const MediaInfo
...
@@ -385,13 +377,13 @@ static void accessFile(TcpSession &sender, const Parser &parser, const MediaInfo
if
(
is_hls
)
{
if
(
is_hls
)
{
//hls,那么移除掉后缀获取真实的stream_id并且修改协议为HLS
//hls,那么移除掉后缀获取真实的stream_id并且修改协议为HLS
const_cast
<
string
&>
(
media
I
nfo
.
_schema
)
=
HLS_SCHEMA
;
const_cast
<
string
&>
(
media
_i
nfo
.
_schema
)
=
HLS_SCHEMA
;
replace
(
const_cast
<
string
&>
(
media
I
nfo
.
_streamid
),
kHlsSuffix
,
""
);
replace
(
const_cast
<
string
&>
(
media
_i
nfo
.
_streamid
),
kHlsSuffix
,
""
);
}
}
weak_ptr
<
TcpSession
>
weakSession
=
sender
.
shared_from_this
();
weak_ptr
<
TcpSession
>
weakSession
=
sender
.
shared_from_this
();
//判断是否有权限访问该文件
//判断是否有权限访问该文件
canAccessPath
(
sender
,
parser
,
media
Info
,
false
,
[
cb
,
strFile
,
parser
,
is_hls
,
mediaI
nfo
,
weakSession
,
file_exist
](
const
string
&
errMsg
,
const
HttpServerCookie
::
Ptr
&
cookie
)
{
canAccessPath
(
sender
,
parser
,
media
_info
,
false
,
[
cb
,
file_path
,
parser
,
is_hls
,
media_i
nfo
,
weakSession
,
file_exist
](
const
string
&
errMsg
,
const
HttpServerCookie
::
Ptr
&
cookie
)
{
auto
strongSession
=
weakSession
.
lock
();
auto
strongSession
=
weakSession
.
lock
();
if
(
!
strongSession
)
{
if
(
!
strongSession
)
{
//http客户端已经断开,不需要回复
//http客户端已经断开,不需要回复
...
@@ -401,80 +393,82 @@ static void accessFile(TcpSession &sender, const Parser &parser, const MediaInfo
...
@@ -401,80 +393,82 @@ static void accessFile(TcpSession &sender, const Parser &parser, const MediaInfo
//文件鉴权失败
//文件鉴权失败
StrCaseMap
headerOut
;
StrCaseMap
headerOut
;
if
(
cookie
)
{
if
(
cookie
)
{
auto
lck
=
cookie
->
getLock
();
headerOut
[
"Set-Cookie"
]
=
cookie
->
getCookie
(
cookie
->
getAttach
<
HttpCookieAttachment
>
().
_path
);
headerOut
[
"Set-Cookie"
]
=
cookie
->
getCookie
((
*
cookie
)[
kCookieName
].
get
<
HttpCookieAttachment
>
().
_path
);
}
}
cb
(
401
,
"text/html"
,
headerOut
,
std
::
make_shared
<
HttpStringBody
>
(
errMsg
));
cb
(
401
,
"text/html"
,
headerOut
,
std
::
make_shared
<
HttpStringBody
>
(
errMsg
));
return
;
return
;
}
}
auto
response_file
=
[
file_exist
,
is_hls
](
const
HttpServerCookie
::
Ptr
&
cookie
,
const
HttpFileManager
::
invoker
&
cb
,
const
string
&
strFile
,
const
Parser
&
parser
)
{
auto
response_file
=
[
file_exist
,
is_hls
](
const
HttpServerCookie
::
Ptr
&
cookie
,
const
HttpFileManager
::
invoker
&
cb
,
const
string
&
file_path
,
const
Parser
&
parser
,
const
string
&
file_content
=
""
)
{
StrCaseMap
httpHeader
;
StrCaseMap
httpHeader
;
if
(
cookie
)
{
if
(
cookie
)
{
auto
lck
=
cookie
->
getLock
();
httpHeader
[
"Set-Cookie"
]
=
cookie
->
getCookie
(
cookie
->
getAttach
<
HttpCookieAttachment
>
().
_path
);
httpHeader
[
"Set-Cookie"
]
=
cookie
->
getCookie
((
*
cookie
)[
kCookieName
].
get
<
HttpCookieAttachment
>
().
_path
);
}
}
HttpSession
::
HttpResponseInvoker
invoker
=
[
&
](
int
code
,
const
StrCaseMap
&
headerOut
,
const
HttpBody
::
Ptr
&
body
)
{
HttpSession
::
HttpResponseInvoker
invoker
=
[
&
](
int
code
,
const
StrCaseMap
&
headerOut
,
const
HttpBody
::
Ptr
&
body
)
{
if
(
cookie
&&
file_exist
)
{
if
(
cookie
&&
file_exist
)
{
auto
lck
=
cookie
->
getLock
();
auto
&
attach
=
cookie
->
getAttach
<
HttpCookieAttachment
>
();
auto
is_hls
=
(
*
cookie
)[
kCookieName
].
get
<
HttpCookieAttachment
>
().
_is_hls
;
if
(
attach
.
_is_hls
)
{
if
(
is_hls
)
{
attach
.
_hls_data
->
addByteUsage
(
body
->
remainSize
());
(
*
cookie
)[
kCookieName
].
get
<
HttpCookieAttachment
>
().
_hls_data
->
addByteUsage
(
body
->
remainSize
());
}
}
}
}
cb
(
code
,
HttpFileManager
::
getContentType
(
strFile
.
data
()),
headerOut
,
body
);
cb
(
code
,
HttpFileManager
::
getContentType
(
file_path
.
data
()),
headerOut
,
body
);
};
};
invoker
.
responseFile
(
parser
.
getHeader
(),
httpHeader
,
strFile
,
!
is_hls
);
invoker
.
responseFile
(
parser
.
getHeader
(),
httpHeader
,
file_content
.
empty
()
?
file_path
:
file_content
,
!
is_hls
,
file_content
.
empty
()
);
};
};
if
(
!
is_hls
)
{
if
(
!
is_hls
)
{
//不是hls,直接回复文件或404
//不是hls,直接回复文件或404
response_file
(
cookie
,
cb
,
strFile
,
parser
);
response_file
(
cookie
,
cb
,
file_path
,
parser
);
return
;
return
;
}
}
//是hls直播,判断HLS直播流是否已经注册
//是hls直播,判断HLS直播流是否已经注册
bool
have_find_media_src
=
false
;
bool
have_find_media_src
=
false
;
if
(
cookie
)
{
if
(
cookie
)
{
auto
lck
=
cookie
->
getLock
();
auto
&
attach
=
cookie
->
getAttach
<
HttpCookieAttachment
>
();
have_find_media_src
=
(
*
cookie
)[
kCookieName
].
get
<
HttpCookieAttachment
>
()
.
_have_find_media_source
;
have_find_media_src
=
attach
.
_have_find_media_source
;
if
(
!
have_find_media_src
)
{
if
(
!
have_find_media_src
)
{
(
*
cookie
)[
kCookieName
].
get
<
HttpCookieAttachment
>
().
_have_find_media_source
=
true
;
const_cast
<
HttpCookieAttachment
&>
(
attach
).
_have_find_media_source
=
true
;
}
else
{
auto
src
=
attach
.
_hls_data
->
getMediaSource
();
if
(
src
)
{
//直接从内存获取m3u8索引文件(而不是从文件系统)
response_file
(
cookie
,
cb
,
file_path
,
parser
,
src
->
getIndexFile
());
return
;
}
}
}
}
}
if
(
have_find_media_src
)
{
if
(
have_find_media_src
)
{
//之前该cookie已经通过MediaSource::findAsync查找过了,所以现在只以文件系统查找结果为准
//之前该cookie已经通过MediaSource::findAsync查找过了,所以现在只以文件系统查找结果为准
response_file
(
cookie
,
cb
,
strFile
,
parser
);
response_file
(
cookie
,
cb
,
file_path
,
parser
);
return
;
return
;
}
}
//hls文件不存在,我们等待其生成并延后回复
//hls文件不存在,我们等待其生成并延后回复
MediaSource
::
findAsync
(
media
Info
,
strongSession
,
[
response_file
,
cookie
,
cb
,
strFile
,
parser
](
const
MediaSource
::
Ptr
&
src
)
{
MediaSource
::
findAsync
(
media
_info
,
strongSession
,
[
response_file
,
cookie
,
cb
,
file_path
,
parser
](
const
MediaSource
::
Ptr
&
src
)
{
if
(
cookie
)
{
if
(
cookie
)
{
auto
lck
=
cookie
->
getLock
();
//尝试添加HlsMediaSource的观看人数(HLS是按需生成的,这样可以触发HLS文件的生成)
//尝试添加HlsMediaSource的观看人数(HLS是按需生成的,这样可以触发HLS文件的生成)
(
*
cookie
)[
kCookieName
].
get
<
HttpCookieAttachment
>
().
_hls_data
->
addByteUsage
(
0
);
auto
&
attach
=
cookie
->
getAttach
<
HttpCookieAttachment
>
();
}
attach
.
_hls_data
->
addByteUsage
(
0
);
if
(
src
&&
File
::
is_file
(
strFile
.
data
()))
{
attach
.
_hls_data
->
setMediaSource
(
dynamic_pointer_cast
<
HlsMediaSource
>
(
src
));
//流和m3u8文件都存在,那么直接返回文件
response_file
(
cookie
,
cb
,
strFile
,
parser
);
return
;
}
}
auto
hls
=
dynamic_pointer_cast
<
HlsMediaSource
>
(
src
);
auto
hls
=
dynamic_pointer_cast
<
HlsMediaSource
>
(
src
);
if
(
!
hls
)
{
if
(
!
hls
)
{
//流不存在,那么直接返回文件(相当于纯粹的HLS文件服务器,但是会挂起播放器15秒左右(用于等待HLS流的注册))
//流不存在,那么直接返回文件(相当于纯粹的HLS文件服务器,但是会挂起播放器15秒左右(用于等待HLS流的注册))
response_file
(
cookie
,
cb
,
strFile
,
parser
);
response_file
(
cookie
,
cb
,
file_path
,
parser
);
return
;
return
;
}
}
//
流存在,但是m3u8文件不存在,那么等待生成m3u8文件(HLS源注册后,并不会立即生成HLS文件,有人观看才会按需生成HLS文件)
//
可能异步获取m3u8索引文件
hls
->
waitForFile
([
response_file
,
cookie
,
cb
,
strFile
,
parser
](
)
{
hls
->
getIndexFile
([
response_file
,
file_path
,
cookie
,
cb
,
parser
](
const
string
&
file
)
{
response_file
(
cookie
,
cb
,
strFile
,
parser
);
response_file
(
cookie
,
cb
,
file_path
,
parser
,
file
);
});
});
});
});
});
});
}
}
static
string
getFilePath
(
const
Parser
&
parser
,
const
MediaInfo
&
media
I
nfo
,
TcpSession
&
sender
){
static
string
getFilePath
(
const
Parser
&
parser
,
const
MediaInfo
&
media
_i
nfo
,
TcpSession
&
sender
){
GET_CONFIG
(
bool
,
enableVhost
,
General
::
kEnableVhost
);
GET_CONFIG
(
bool
,
enableVhost
,
General
::
kEnableVhost
);
GET_CONFIG
(
string
,
rootPath
,
Http
::
kRootPath
);
GET_CONFIG
(
string
,
rootPath
,
Http
::
kRootPath
);
GET_CONFIG_FUNC
(
StrCaseMap
,
virtualPathMap
,
Http
::
kVirtualPath
,
[](
const
string
&
str
)
{
GET_CONFIG_FUNC
(
StrCaseMap
,
virtualPathMap
,
Http
::
kVirtualPath
,
[](
const
string
&
str
)
{
...
@@ -482,17 +476,17 @@ static string getFilePath(const Parser &parser,const MediaInfo &mediaInfo, TcpSe
...
@@ -482,17 +476,17 @@ static string getFilePath(const Parser &parser,const MediaInfo &mediaInfo, TcpSe
});
});
string
url
,
path
;
string
url
,
path
;
auto
it
=
virtualPathMap
.
find
(
media
I
nfo
.
_app
);
auto
it
=
virtualPathMap
.
find
(
media
_i
nfo
.
_app
);
if
(
it
!=
virtualPathMap
.
end
())
{
if
(
it
!=
virtualPathMap
.
end
())
{
//访问的是virtualPath
//访问的是virtualPath
path
=
it
->
second
;
path
=
it
->
second
;
url
=
parser
.
Url
().
substr
(
1
+
media
I
nfo
.
_app
.
size
());
url
=
parser
.
Url
().
substr
(
1
+
media
_i
nfo
.
_app
.
size
());
}
else
{
}
else
{
//访问的是rootPath
//访问的是rootPath
path
=
rootPath
;
path
=
rootPath
;
url
=
parser
.
Url
();
url
=
parser
.
Url
();
}
}
auto
ret
=
File
::
absolutePath
(
enableVhost
?
media
I
nfo
.
_vhost
+
url
:
url
,
path
);
auto
ret
=
File
::
absolutePath
(
enableVhost
?
media
_i
nfo
.
_vhost
+
url
:
url
,
path
);
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastHttpBeforeAccess
,
parser
,
ret
,
static_cast
<
SockInfo
&>
(
sender
));
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastHttpBeforeAccess
,
parser
,
ret
,
static_cast
<
SockInfo
&>
(
sender
));
return
ret
;
return
ret
;
}
}
...
@@ -505,33 +499,33 @@ static string getFilePath(const Parser &parser,const MediaInfo &mediaInfo, TcpSe
...
@@ -505,33 +499,33 @@ static string getFilePath(const Parser &parser,const MediaInfo &mediaInfo, TcpSe
*/
*/
void
HttpFileManager
::
onAccessPath
(
TcpSession
&
sender
,
Parser
&
parser
,
const
HttpFileManager
::
invoker
&
cb
)
{
void
HttpFileManager
::
onAccessPath
(
TcpSession
&
sender
,
Parser
&
parser
,
const
HttpFileManager
::
invoker
&
cb
)
{
auto
fullUrl
=
string
(
HTTP_SCHEMA
)
+
"://"
+
parser
[
"Host"
]
+
parser
.
FullUrl
();
auto
fullUrl
=
string
(
HTTP_SCHEMA
)
+
"://"
+
parser
[
"Host"
]
+
parser
.
FullUrl
();
MediaInfo
media
I
nfo
(
fullUrl
);
MediaInfo
media
_i
nfo
(
fullUrl
);
auto
strFile
=
getFilePath
(
parser
,
mediaI
nfo
,
sender
);
auto
file_path
=
getFilePath
(
parser
,
media_i
nfo
,
sender
);
//访问的是文件夹
//访问的是文件夹
if
(
File
::
is_dir
(
strFile
.
data
()))
{
if
(
File
::
is_dir
(
file_path
.
data
()))
{
auto
indexFile
=
searchIndexFile
(
strFile
);
auto
indexFile
=
searchIndexFile
(
file_path
);
if
(
!
indexFile
.
empty
())
{
if
(
!
indexFile
.
empty
())
{
//发现该文件夹下有index文件
//发现该文件夹下有index文件
strFile
=
pathCat
(
strFile
,
indexFile
);
file_path
=
pathCat
(
file_path
,
indexFile
);
parser
.
setUrl
(
pathCat
(
parser
.
Url
(),
indexFile
));
parser
.
setUrl
(
pathCat
(
parser
.
Url
(),
indexFile
));
accessFile
(
sender
,
parser
,
media
Info
,
strFile
,
cb
);
accessFile
(
sender
,
parser
,
media
_info
,
file_path
,
cb
);
return
;
return
;
}
}
string
strMenu
;
string
strMenu
;
//生成文件夹菜单索引
//生成文件夹菜单索引
if
(
!
makeFolderMenu
(
parser
.
Url
(),
strFile
,
strMenu
))
{
if
(
!
makeFolderMenu
(
parser
.
Url
(),
file_path
,
strMenu
))
{
//文件夹不存在
//文件夹不存在
sendNotFound
(
cb
);
sendNotFound
(
cb
);
return
;
return
;
}
}
//判断是否有权限访问该目录
//判断是否有权限访问该目录
canAccessPath
(
sender
,
parser
,
media
I
nfo
,
true
,
[
strMenu
,
cb
](
const
string
&
errMsg
,
const
HttpServerCookie
::
Ptr
&
cookie
)
mutable
{
canAccessPath
(
sender
,
parser
,
media
_i
nfo
,
true
,
[
strMenu
,
cb
](
const
string
&
errMsg
,
const
HttpServerCookie
::
Ptr
&
cookie
)
mutable
{
if
(
!
errMsg
.
empty
())
{
if
(
!
errMsg
.
empty
())
{
strMenu
=
errMsg
;
strMenu
=
errMsg
;
}
}
StrCaseMap
headerOut
;
StrCaseMap
headerOut
;
if
(
cookie
)
{
if
(
cookie
)
{
headerOut
[
"Set-Cookie"
]
=
cookie
->
getCookie
(
(
*
cookie
)[
kCookieName
].
get
<
HttpCookieAttachment
>
().
_path
);
headerOut
[
"Set-Cookie"
]
=
cookie
->
getCookie
(
cookie
->
getAttach
<
HttpCookieAttachment
>
().
_path
);
}
}
cb
(
errMsg
.
empty
()
?
200
:
401
,
"text/html"
,
headerOut
,
std
::
make_shared
<
HttpStringBody
>
(
strMenu
));
cb
(
errMsg
.
empty
()
?
200
:
401
,
"text/html"
,
headerOut
,
std
::
make_shared
<
HttpStringBody
>
(
strMenu
));
});
});
...
@@ -539,7 +533,7 @@ void HttpFileManager::onAccessPath(TcpSession &sender, Parser &parser, const Htt
...
@@ -539,7 +533,7 @@ void HttpFileManager::onAccessPath(TcpSession &sender, Parser &parser, const Htt
}
}
//访问的是文件
//访问的是文件
accessFile
(
sender
,
parser
,
media
Info
,
strFile
,
cb
);
accessFile
(
sender
,
parser
,
media
_info
,
file_path
,
cb
);
};
};
...
@@ -579,16 +573,19 @@ HttpResponseInvokerImp::HttpResponseInvokerImp(const HttpResponseInvokerImp::Htt
...
@@ -579,16 +573,19 @@ HttpResponseInvokerImp::HttpResponseInvokerImp(const HttpResponseInvokerImp::Htt
void
HttpResponseInvokerImp
::
responseFile
(
const
StrCaseMap
&
requestHeader
,
void
HttpResponseInvokerImp
::
responseFile
(
const
StrCaseMap
&
requestHeader
,
const
StrCaseMap
&
responseHeader
,
const
StrCaseMap
&
responseHeader
,
const
string
&
file
Path
,
const
string
&
file
,
bool
use_mmap
)
const
{
bool
use_mmap
,
StrCaseMap
&
httpHeader
=
const_cast
<
StrCaseMap
&>
(
responseHeader
);
bool
is_path
)
const
{
std
::
shared_ptr
<
FILE
>
fp
(
fopen
(
filePath
.
data
(),
"rb"
),
[](
FILE
*
fp
)
{
if
(
!
is_path
)
{
if
(
fp
)
{
//file是文件内容
fclose
(
fp
);
(
*
this
)(
200
,
responseHeader
,
std
::
make_shared
<
HttpStringBody
>
(
file
)
);
}
return
;
}
);
}
if
(
!
fp
)
{
//file是文件路径
StrCaseMap
&
httpHeader
=
const_cast
<
StrCaseMap
&>
(
responseHeader
);
auto
fileBody
=
std
::
make_shared
<
HttpFileBody
>
(
file
,
use_mmap
);
if
(
fileBody
->
remainSize
()
<
0
)
{
//打开文件失败
//打开文件失败
GET_CONFIG
(
string
,
notFound
,
Http
::
kNotFound
);
GET_CONFIG
(
string
,
notFound
,
Http
::
kNotFound
);
GET_CONFIG
(
string
,
charSet
,
Http
::
kCharSet
);
GET_CONFIG
(
string
,
charSet
,
Http
::
kCharSet
);
...
@@ -600,29 +597,23 @@ void HttpResponseInvokerImp::responseFile(const StrCaseMap &requestHeader,
...
@@ -600,29 +597,23 @@ void HttpResponseInvokerImp::responseFile(const StrCaseMap &requestHeader,
}
}
auto
&
strRange
=
const_cast
<
StrCaseMap
&>
(
requestHeader
)[
"Range"
];
auto
&
strRange
=
const_cast
<
StrCaseMap
&>
(
requestHeader
)[
"Range"
];
size_t
iRangeStart
=
0
;
int
code
=
200
;
size_t
iRangeEnd
=
0
;
if
(
!
strRange
.
empty
())
{
size_t
fileSize
=
File
::
fileSize
(
fp
.
get
());
int
code
;
if
(
strRange
.
size
()
==
0
)
{
//全部下载
code
=
200
;
iRangeEnd
=
fileSize
-
1
;
}
else
{
//分节下载
//分节下载
code
=
206
;
code
=
206
;
iRangeStart
=
atoll
(
FindField
(
strRange
.
data
(),
"bytes="
,
"-"
).
data
());
auto
iRangeStart
=
atoll
(
FindField
(
strRange
.
data
(),
"bytes="
,
"-"
).
data
());
iRangeEnd
=
atoll
(
FindField
(
strRange
.
data
(),
"-"
,
nullptr
).
data
());
auto
iRangeEnd
=
atoll
(
FindField
(
strRange
.
data
(),
"-"
,
nullptr
).
data
());
auto
fileSize
=
fileBody
->
remainSize
();
if
(
iRangeEnd
==
0
)
{
if
(
iRangeEnd
==
0
)
{
iRangeEnd
=
fileSize
-
1
;
iRangeEnd
=
fileSize
-
1
;
}
}
//设置文件范围
fileBody
->
setRange
(
iRangeStart
,
iRangeEnd
-
iRangeStart
+
1
);
//分节下载返回Content-Range头
//分节下载返回Content-Range头
httpHeader
.
emplace
(
"Content-Range"
,
StrPrinter
<<
"bytes "
<<
iRangeStart
<<
"-"
<<
iRangeEnd
<<
"/"
<<
fileSize
<<
endl
);
httpHeader
.
emplace
(
"Content-Range"
,
StrPrinter
<<
"bytes "
<<
iRangeStart
<<
"-"
<<
iRangeEnd
<<
"/"
<<
fileSize
<<
endl
);
}
}
//回复文件
//回复文件
HttpBody
::
Ptr
fileBody
=
std
::
make_shared
<
HttpFileBody
>
(
fp
,
iRangeStart
,
iRangeEnd
-
iRangeStart
+
1
,
use_mmap
);
(
*
this
)(
code
,
httpHeader
,
fileBody
);
(
*
this
)(
code
,
httpHeader
,
fileBody
);
}
}
...
...
src/Http/HttpFileManager.h
查看文件 @
d432888a
...
@@ -35,7 +35,7 @@ public:
...
@@ -35,7 +35,7 @@ public:
void
operator
()(
int
code
,
const
StrCaseMap
&
headerOut
,
const
HttpBody
::
Ptr
&
body
)
const
;
void
operator
()(
int
code
,
const
StrCaseMap
&
headerOut
,
const
HttpBody
::
Ptr
&
body
)
const
;
void
operator
()(
int
code
,
const
StrCaseMap
&
headerOut
,
const
std
::
string
&
body
)
const
;
void
operator
()(
int
code
,
const
StrCaseMap
&
headerOut
,
const
std
::
string
&
body
)
const
;
void
responseFile
(
const
StrCaseMap
&
requestHeader
,
const
StrCaseMap
&
responseHeader
,
const
std
::
string
&
file
Path
,
bool
use_mmap
=
true
)
const
;
void
responseFile
(
const
StrCaseMap
&
requestHeader
,
const
StrCaseMap
&
responseHeader
,
const
std
::
string
&
file
,
bool
use_mmap
=
true
,
bool
is_path
=
true
)
const
;
operator
bool
();
operator
bool
();
private
:
private
:
HttpResponseInvokerLambda0
_lambad
;
HttpResponseInvokerLambda0
_lambad
;
...
...
src/Http/HttpSession.cpp
查看文件 @
d432888a
...
@@ -519,16 +519,16 @@ void HttpSession::sendResponse(int code,
...
@@ -519,16 +519,16 @@ void HttpSession::sendResponse(int code,
GET_CONFIG
(
uint32_t
,
keepAliveSec
,
Http
::
kKeepAliveSecond
);
GET_CONFIG
(
uint32_t
,
keepAliveSec
,
Http
::
kKeepAliveSecond
);
//body默认为空
//body默认为空
ssize
_t
size
=
0
;
int64
_t
size
=
0
;
if
(
body
&&
body
->
remainSize
())
{
if
(
body
&&
body
->
remainSize
())
{
//有body,获取body大小
//有body,获取body大小
size
=
body
->
remainSize
();
size
=
body
->
remainSize
();
}
}
if
(
no_content_length
)
{
if
(
no_content_length
)
{
//http-flv直播是Keep-Alive类型
//
http-flv直播是Keep-Alive类型
bClose
=
false
;
bClose
=
false
;
}
else
if
((
size_t
)
size
>=
SIZE_MAX
||
size
<
0
)
{
}
else
if
((
size_t
)
size
>=
SIZE_MAX
||
size
<
0
)
{
//不固定长度的body,那么发送完body后应该关闭socket,以便浏览器做下载完毕的判断
//不固定长度的body,那么发送完body后应该关闭socket,以便浏览器做下载完毕的判断
bClose
=
true
;
bClose
=
true
;
}
}
...
@@ -537,47 +537,47 @@ void HttpSession::sendResponse(int code,
...
@@ -537,47 +537,47 @@ void HttpSession::sendResponse(int code,
headerOut
.
emplace
(
kDate
,
dateStr
());
headerOut
.
emplace
(
kDate
,
dateStr
());
headerOut
.
emplace
(
kServer
,
kServerName
);
headerOut
.
emplace
(
kServer
,
kServerName
);
headerOut
.
emplace
(
kConnection
,
bClose
?
"close"
:
"keep-alive"
);
headerOut
.
emplace
(
kConnection
,
bClose
?
"close"
:
"keep-alive"
);
if
(
!
bClose
)
{
if
(
!
bClose
)
{
string
keepAliveString
=
"timeout="
;
string
keepAliveString
=
"timeout="
;
keepAliveString
+=
to_string
(
keepAliveSec
);
keepAliveString
+=
to_string
(
keepAliveSec
);
keepAliveString
+=
", max=100"
;
keepAliveString
+=
", max=100"
;
headerOut
.
emplace
(
kKeepAlive
,
std
::
move
(
keepAliveString
));
headerOut
.
emplace
(
kKeepAlive
,
std
::
move
(
keepAliveString
));
}
}
if
(
!
_origin
.
empty
())
{
if
(
!
_origin
.
empty
())
{
//设置跨域
//设置跨域
headerOut
.
emplace
(
kAccessControlAllowOrigin
,
_origin
);
headerOut
.
emplace
(
kAccessControlAllowOrigin
,
_origin
);
headerOut
.
emplace
(
kAccessControlAllowCredentials
,
"true"
);
headerOut
.
emplace
(
kAccessControlAllowCredentials
,
"true"
);
}
}
if
(
!
no_content_length
&&
size
>=
0
&&
(
size_t
)
size
<
SIZE_MAX
)
{
if
(
!
no_content_length
&&
size
>=
0
&&
(
size_t
)
size
<
SIZE_MAX
)
{
//文件长度为固定值,且不是http-flv强制设置Content-Length
//文件长度为固定值,且不是http-flv强制设置Content-Length
headerOut
[
kContentLength
]
=
to_string
(
size
);
headerOut
[
kContentLength
]
=
to_string
(
size
);
}
}
if
(
size
&&
!
pcContentType
)
{
if
(
size
&&
!
pcContentType
)
{
//有body时,设置缺省类型
//有body时,设置缺省类型
pcContentType
=
"text/plain"
;
pcContentType
=
"text/plain"
;
}
}
if
((
size
||
no_content_length
)
&&
pcContentType
)
{
if
((
size
||
no_content_length
)
&&
pcContentType
)
{
//有body时,设置文件类型
//有body时,设置文件类型
string
strContentType
=
pcContentType
;
string
strContentType
=
pcContentType
;
strContentType
+=
"; charset="
;
strContentType
+=
"; charset="
;
strContentType
+=
charSet
;
strContentType
+=
charSet
;
headerOut
.
emplace
(
kContentType
,
std
::
move
(
strContentType
));
headerOut
.
emplace
(
kContentType
,
std
::
move
(
strContentType
));
}
}
//发送http头
//发送http头
string
str
;
string
str
;
str
.
reserve
(
256
);
str
.
reserve
(
256
);
str
+=
"HTTP/1.1 "
;
str
+=
"HTTP/1.1 "
;
str
+=
to_string
(
code
);
str
+=
to_string
(
code
);
str
+=
' '
;
str
+=
' '
;
str
+=
getHttpStatusMessage
(
code
)
;
str
+=
getHttpStatusMessage
(
code
);
str
+=
"
\r\n
"
;
str
+=
"
\r\n
"
;
for
(
auto
&
pr
:
header
)
{
for
(
auto
&
pr
:
header
)
{
str
+=
pr
.
first
;
str
+=
pr
.
first
;
str
+=
": "
;
str
+=
": "
;
str
+=
pr
.
second
;
str
+=
pr
.
second
;
str
+=
"
\r\n
"
;
str
+=
"
\r\n
"
;
...
@@ -586,18 +586,21 @@ void HttpSession::sendResponse(int code,
...
@@ -586,18 +586,21 @@ void HttpSession::sendResponse(int code,
SockSender
::
send
(
std
::
move
(
str
));
SockSender
::
send
(
std
::
move
(
str
));
_ticker
.
resetTime
();
_ticker
.
resetTime
();
if
(
!
size
)
{
if
(
!
size
)
{
//没有body
//没有body
if
(
bClose
)
{
if
(
bClose
)
{
shutdown
(
SockException
(
Err_shutdown
,
StrPrinter
<<
"close connection after send http header completed with status code:"
<<
code
));
shutdown
(
SockException
(
Err_shutdown
,
StrPrinter
<<
"close connection after send http header completed with status code:"
<<
code
));
}
}
return
;
return
;
}
}
#if 0
//sendfile跟共享mmap相比并没有性能上的优势,相反,sendfile还有功能上的缺陷,先屏蔽
if (typeid(*this) == typeid(HttpSession) && !body->sendFile(getSock()->rawFD())) {
if (typeid(*this) == typeid(HttpSession) && !body->sendFile(getSock()->rawFD())) {
//http支持sendfile优化
//
http支持sendfile优化
return;
return;
}
}
#endif
GET_CONFIG
(
uint32_t
,
sendBufSize
,
Http
::
kSendBufSize
);
GET_CONFIG
(
uint32_t
,
sendBufSize
,
Http
::
kSendBufSize
);
if
(
body
->
remainSize
()
>
sendBufSize
)
{
if
(
body
->
remainSize
()
>
sendBufSize
)
{
...
@@ -607,9 +610,7 @@ void HttpSession::sendResponse(int code,
...
@@ -607,9 +610,7 @@ void HttpSession::sendResponse(int code,
//发送http body
//发送http body
AsyncSenderData
::
Ptr
data
=
std
::
make_shared
<
AsyncSenderData
>
(
shared_from_this
(),
body
,
bClose
);
AsyncSenderData
::
Ptr
data
=
std
::
make_shared
<
AsyncSenderData
>
(
shared_from_this
(),
body
,
bClose
);
getSock
()
->
setOnFlush
([
data
]()
{
getSock
()
->
setOnFlush
([
data
]()
{
return
AsyncSender
::
onSocketFlushed
(
data
);
});
return
AsyncSender
::
onSocketFlushed
(
data
);
});
AsyncSender
::
onSocketFlushed
(
data
);
AsyncSender
::
onSocketFlushed
(
data
);
}
}
...
...
src/Http/TsPlayer.cpp
查看文件 @
d432888a
...
@@ -20,6 +20,7 @@ TsPlayer::TsPlayer(const EventPoller::Ptr &poller) : HttpTSPlayer(poller, true)
...
@@ -20,6 +20,7 @@ TsPlayer::TsPlayer(const EventPoller::Ptr &poller) : HttpTSPlayer(poller, true)
void
TsPlayer
::
play
(
const
string
&
url
)
{
void
TsPlayer
::
play
(
const
string
&
url
)
{
TraceL
<<
"play http-ts: "
<<
url
;
TraceL
<<
"play http-ts: "
<<
url
;
_play_result
=
false
;
_play_result
=
false
;
_benchmark_mode
=
(
*
this
)[
Client
::
kBenchmarkMode
].
as
<
int
>
();
setHeaderTimeout
((
*
this
)[
Client
::
kTimeoutMS
].
as
<
int
>
());
setHeaderTimeout
((
*
this
)[
Client
::
kTimeoutMS
].
as
<
int
>
());
setBodyTimeout
((
*
this
)[
Client
::
kMediaTimeoutMS
].
as
<
int
>
());
setBodyTimeout
((
*
this
)[
Client
::
kMediaTimeoutMS
].
as
<
int
>
());
setMethod
(
"GET"
);
setMethod
(
"GET"
);
...
@@ -45,7 +46,9 @@ void TsPlayer::onResponseBody(const char *buf, size_t size) {
...
@@ -45,7 +46,9 @@ void TsPlayer::onResponseBody(const char *buf, size_t size) {
_play_result
=
true
;
_play_result
=
true
;
onPlayResult
(
SockException
(
Err_success
,
"play http-ts success"
));
onPlayResult
(
SockException
(
Err_success
,
"play http-ts success"
));
}
}
HttpTSPlayer
::
onResponseBody
(
buf
,
size
);
if
(
!
_benchmark_mode
)
{
HttpTSPlayer
::
onResponseBody
(
buf
,
size
);
}
}
}
}
//
namespace
mediakit
}
//
namespace
mediakit
\ No newline at end of file
src/Http/TsPlayer.h
查看文件 @
d432888a
...
@@ -16,7 +16,7 @@
...
@@ -16,7 +16,7 @@
namespace
mediakit
{
namespace
mediakit
{
class
TsPlayer
:
public
HttpTSPlayer
,
public
PlayerBase
{
class
TsPlayer
:
public
HttpTSPlayer
,
public
PlayerBase
{
public
:
public
:
TsPlayer
(
const
toolkit
::
EventPoller
::
Ptr
&
poller
);
TsPlayer
(
const
toolkit
::
EventPoller
::
Ptr
&
poller
);
~
TsPlayer
()
override
=
default
;
~
TsPlayer
()
override
=
default
;
...
@@ -37,6 +37,7 @@ protected:
...
@@ -37,6 +37,7 @@ protected:
private
:
private
:
bool
_play_result
=
true
;
bool
_play_result
=
true
;
bool
_benchmark_mode
=
false
;
};
};
}
// namespace mediakit
}
// namespace mediakit
...
...
src/Http/TsplayerImp.cpp
查看文件 @
d432888a
...
@@ -33,7 +33,8 @@ void TsPlayerImp::addTrackCompleted() {
...
@@ -33,7 +33,8 @@ void TsPlayerImp::addTrackCompleted() {
}
}
void
TsPlayerImp
::
onPlayResult
(
const
SockException
&
ex
)
{
void
TsPlayerImp
::
onPlayResult
(
const
SockException
&
ex
)
{
if
(
ex
)
{
auto
benchmark_mode
=
(
*
this
)[
Client
::
kBenchmarkMode
].
as
<
int
>
();
if
(
ex
||
benchmark_mode
)
{
PlayerImp
<
TsPlayer
,
PlayerBase
>::
onPlayResult
(
ex
);
PlayerImp
<
TsPlayer
,
PlayerBase
>::
onPlayResult
(
ex
);
}
else
{
}
else
{
auto
demuxer
=
std
::
make_shared
<
HlsDemuxer
>
();
auto
demuxer
=
std
::
make_shared
<
HlsDemuxer
>
();
...
@@ -47,7 +48,10 @@ void TsPlayerImp::onShutdown(const SockException &ex) {
...
@@ -47,7 +48,10 @@ void TsPlayerImp::onShutdown(const SockException &ex) {
_demuxer
=
nullptr
;
_demuxer
=
nullptr
;
}
}
vector
<
Track
::
Ptr
>
TsPlayerImp
::
getTracks
(
bool
ready
)
const
{
vector
<
Track
::
Ptr
>
TsPlayerImp
::
getTracks
(
bool
ready
)
const
{
if
(
!
_demuxer
)
{
return
vector
<
Track
::
Ptr
>
();
}
return
static_pointer_cast
<
HlsDemuxer
>
(
_demuxer
)
->
getTracks
(
ready
);
return
static_pointer_cast
<
HlsDemuxer
>
(
_demuxer
)
->
getTracks
(
ready
);
}
}
...
...
src/Record/HlsMaker.cpp
查看文件 @
d432888a
...
@@ -70,7 +70,7 @@ void HlsMaker::makeIndexFile(bool eof) {
...
@@ -70,7 +70,7 @@ void HlsMaker::makeIndexFile(bool eof) {
snprintf
(
file_content
,
sizeof
(
file_content
),
"#EXT-X-ENDLIST
\n
"
);
snprintf
(
file_content
,
sizeof
(
file_content
),
"#EXT-X-ENDLIST
\n
"
);
m3u8
.
append
(
file_content
);
m3u8
.
append
(
file_content
);
}
}
onWriteHls
(
m3u8
.
data
(),
m3u8
.
size
()
);
onWriteHls
(
m3u8
);
}
}
...
...
src/Record/HlsMaker.h
查看文件 @
d432888a
...
@@ -72,10 +72,8 @@ protected:
...
@@ -72,10 +72,8 @@ protected:
/**
/**
* 写m3u8文件回调
* 写m3u8文件回调
* @param data
* @param len
*/
*/
virtual
void
onWriteHls
(
const
char
*
data
,
size_t
len
)
=
0
;
virtual
void
onWriteHls
(
const
std
::
string
&
data
)
=
0
;
/**
/**
* 上一个 ts 切片写入完成, 可在这里进行通知处理
* 上一个 ts 切片写入完成, 可在这里进行通知处理
...
...
src/Record/HlsMakerImp.cpp
查看文件 @
d432888a
...
@@ -111,13 +111,13 @@ void HlsMakerImp::onWriteSegment(const char *data, size_t len) {
...
@@ -111,13 +111,13 @@ void HlsMakerImp::onWriteSegment(const char *data, size_t len) {
}
}
}
}
void
HlsMakerImp
::
onWriteHls
(
const
char
*
data
,
size_t
len
)
{
void
HlsMakerImp
::
onWriteHls
(
const
std
::
string
&
data
)
{
auto
hls
=
makeFile
(
_path_hls
);
auto
hls
=
makeFile
(
_path_hls
);
if
(
hls
)
{
if
(
hls
)
{
fwrite
(
data
,
len
,
1
,
hls
.
get
());
fwrite
(
data
.
data
(),
data
.
size
()
,
1
,
hls
.
get
());
hls
.
reset
();
hls
.
reset
();
if
(
_media_src
)
{
if
(
_media_src
)
{
_media_src
->
registHls
(
true
);
_media_src
->
registHls
(
data
);
}
}
}
else
{
}
else
{
WarnL
<<
"create hls file failed,"
<<
_path_hls
<<
" "
<<
get_uv_errmsg
();
WarnL
<<
"create hls file failed,"
<<
_path_hls
<<
" "
<<
get_uv_errmsg
();
...
...
src/Record/HlsMakerImp.h
查看文件 @
d432888a
...
@@ -53,7 +53,7 @@ protected:
...
@@ -53,7 +53,7 @@ protected:
std
::
string
onOpenSegment
(
uint64_t
index
)
override
;
std
::
string
onOpenSegment
(
uint64_t
index
)
override
;
void
onDelSegment
(
uint64_t
index
)
override
;
void
onDelSegment
(
uint64_t
index
)
override
;
void
onWriteSegment
(
const
char
*
data
,
size_t
len
)
override
;
void
onWriteSegment
(
const
char
*
data
,
size_t
len
)
override
;
void
onWriteHls
(
const
char
*
data
,
size_t
len
)
override
;
void
onWriteHls
(
const
std
::
string
&
data
)
override
;
void
onFlushLastSegment
(
uint32_t
duration_ms
)
override
;
void
onFlushLastSegment
(
uint32_t
duration_ms
)
override
;
private
:
private
:
...
...
src/Record/HlsMediaSource.cpp
查看文件 @
d432888a
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
using
namespace
toolkit
;
using
namespace
toolkit
;
namespace
mediakit
{
namespace
mediakit
{
HlsCookieData
::
HlsCookieData
(
const
MediaInfo
&
info
,
const
std
::
shared_ptr
<
SockInfo
>
&
sock_info
)
{
HlsCookieData
::
HlsCookieData
(
const
MediaInfo
&
info
,
const
std
::
shared_ptr
<
SockInfo
>
&
sock_info
)
{
_info
=
info
;
_info
=
info
;
...
@@ -21,15 +21,15 @@ HlsCookieData::HlsCookieData(const MediaInfo &info, const std::shared_ptr<SockIn
...
@@ -21,15 +21,15 @@ HlsCookieData::HlsCookieData(const MediaInfo &info, const std::shared_ptr<SockIn
addReaderCount
();
addReaderCount
();
}
}
void
HlsCookieData
::
addReaderCount
(){
void
HlsCookieData
::
addReaderCount
()
{
if
(
!*
_added
)
{
if
(
!*
_added
)
{
auto
src
=
std
::
dynamic_pointer_cast
<
HlsMediaSource
>
(
MediaSource
::
find
(
HLS_SCHEMA
,
_info
.
_vhost
,
_info
.
_app
,
_info
.
_streamid
));
auto
src
=
std
::
dynamic_pointer_cast
<
HlsMediaSource
>
(
MediaSource
::
find
(
HLS_SCHEMA
,
_info
.
_vhost
,
_info
.
_app
,
_info
.
_streamid
));
if
(
src
)
{
if
(
src
)
{
*
_added
=
true
;
*
_added
=
true
;
_ring_reader
=
src
->
getRing
()
->
attach
(
EventPollerPool
::
Instance
().
getPoller
());
_ring_reader
=
src
->
getRing
()
->
attach
(
EventPollerPool
::
Instance
().
getPoller
());
auto
added
=
_added
;
auto
added
=
_added
;
_ring_reader
->
setDetachCB
([
added
](){
_ring_reader
->
setDetachCB
([
added
]()
{
//HlsMediaSource已经销毁
//
HlsMediaSource已经销毁
*
added
=
false
;
*
added
=
false
;
});
});
}
}
...
@@ -39,14 +39,14 @@ void HlsCookieData::addReaderCount(){
...
@@ -39,14 +39,14 @@ void HlsCookieData::addReaderCount(){
HlsCookieData
::~
HlsCookieData
()
{
HlsCookieData
::~
HlsCookieData
()
{
if
(
*
_added
)
{
if
(
*
_added
)
{
uint64_t
duration
=
(
_ticker
.
createdTime
()
-
_ticker
.
elapsedTime
())
/
1000
;
uint64_t
duration
=
(
_ticker
.
createdTime
()
-
_ticker
.
elapsedTime
())
/
1000
;
WarnL
<<
_sock_info
->
getIdentifier
()
<<
"("
<<
_sock_info
->
get_peer_ip
()
<<
":"
<<
_sock_info
->
get_peer_port
()
<<
") "
WarnL
<<
_sock_info
->
getIdentifier
()
<<
"("
<<
_sock_info
->
get_peer_ip
()
<<
":"
<<
_sock_info
->
get_peer_port
()
<<
"HLS播放器("
<<
_info
.
_vhost
<<
"/"
<<
_info
.
_app
<<
"/"
<<
_info
.
_streamid
<<
"
) "
<<
"
HLS播放器("
<<
_info
.
_vhost
<<
"/"
<<
_info
.
_app
<<
"/"
<<
_info
.
_streamid
<<
")断开,耗时(s):"
<<
duration
;
<<
")断开,耗时(s):"
<<
duration
;
GET_CONFIG
(
uint32_t
,
iFlowThreshold
,
General
::
kFlowThreshold
);
GET_CONFIG
(
uint32_t
,
iFlowThreshold
,
General
::
kFlowThreshold
);
uint64_t
bytes
=
_bytes
.
load
();
uint64_t
bytes
=
_bytes
.
load
();
if
(
bytes
>=
iFlowThreshold
*
1024
)
{
if
(
bytes
>=
iFlowThreshold
*
1024
)
{
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastFlowReport
,
_info
,
bytes
,
duration
,
true
,
static_cast
<
SockInfo
&>
(
*
_sock_info
));
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastFlowReport
,
_info
,
bytes
,
duration
,
true
,
static_cast
<
SockInfo
&>
(
*
_sock_info
));
}
}
}
}
}
}
...
@@ -57,6 +57,12 @@ void HlsCookieData::addByteUsage(size_t bytes) {
...
@@ -57,6 +57,12 @@ void HlsCookieData::addByteUsage(size_t bytes) {
_ticker
.
resetTime
();
_ticker
.
resetTime
();
}
}
void
HlsCookieData
::
setMediaSource
(
const
HlsMediaSource
::
Ptr
&
src
)
{
_src
=
src
;
}
}
//namespace mediakit
HlsMediaSource
::
Ptr
HlsCookieData
::
getMediaSource
()
const
{
return
_src
.
lock
();
}
}
// namespace mediakit
src/Record/HlsMediaSource.h
查看文件 @
d432888a
...
@@ -11,11 +11,11 @@
...
@@ -11,11 +11,11 @@
#ifndef ZLMEDIAKIT_HLSMEDIASOURCE_H
#ifndef ZLMEDIAKIT_HLSMEDIASOURCE_H
#define ZLMEDIAKIT_HLSMEDIASOURCE_H
#define ZLMEDIAKIT_HLSMEDIASOURCE_H
#include <atomic>
#include "Util/TimeTicker.h"
#include "Common/MediaSource.h"
#include "Common/MediaSource.h"
#include "Util/TimeTicker.h"
#include <atomic>
namespace
mediakit
{
namespace
mediakit
{
class
HlsMediaSource
:
public
MediaSource
{
class
HlsMediaSource
:
public
MediaSource
{
public
:
public
:
...
@@ -24,28 +24,25 @@ public:
...
@@ -24,28 +24,25 @@ public:
using
RingType
=
toolkit
::
RingBuffer
<
std
::
string
>
;
using
RingType
=
toolkit
::
RingBuffer
<
std
::
string
>
;
using
Ptr
=
std
::
shared_ptr
<
HlsMediaSource
>
;
using
Ptr
=
std
::
shared_ptr
<
HlsMediaSource
>
;
HlsMediaSource
(
const
std
::
string
&
vhost
,
const
std
::
string
&
app
,
const
std
::
string
&
stream_id
)
:
MediaSource
(
HLS_SCHEMA
,
vhost
,
app
,
stream_id
){}
HlsMediaSource
(
const
std
::
string
&
vhost
,
const
std
::
string
&
app
,
const
std
::
string
&
stream_id
)
:
MediaSource
(
HLS_SCHEMA
,
vhost
,
app
,
stream_id
)
{}
~
HlsMediaSource
()
override
=
default
;
~
HlsMediaSource
()
override
=
default
;
/**
/**
* 获取媒体源的环形缓冲
* 获取媒体源的环形缓冲
*/
*/
const
RingType
::
Ptr
&
getRing
()
const
{
const
RingType
::
Ptr
&
getRing
()
const
{
return
_ring
;
}
return
_ring
;
}
/**
/**
* 获取播放器个数
* 获取播放器个数
*/
*/
int
readerCount
()
override
{
int
readerCount
()
override
{
return
_ring
?
_ring
->
readerCount
()
:
0
;
}
return
_ring
?
_ring
->
readerCount
()
:
0
;
}
/**
/**
* 生成m3u8文件时触发
* 生成m3u8文件时触发
* @param
file_created 是否产生了hls文件
* @param
index_file m3u8文件内容
*/
*/
void
registHls
(
bool
file_created
)
{
void
registHls
(
std
::
string
index_file
)
{
if
(
!
_is_regist
)
{
if
(
!
_is_regist
)
{
_is_regist
=
true
;
_is_regist
=
true
;
std
::
weak_ptr
<
HlsMediaSource
>
weakSelf
=
std
::
dynamic_pointer_cast
<
HlsMediaSource
>
(
shared_from_this
());
std
::
weak_ptr
<
HlsMediaSource
>
weakSelf
=
std
::
dynamic_pointer_cast
<
HlsMediaSource
>
(
shared_from_this
());
...
@@ -61,56 +58,68 @@ public:
...
@@ -61,56 +58,68 @@ public:
regist
();
regist
();
}
}
if
(
!
file_created
)
{
if
(
index_file
.
empty
()
)
{
//没产生
文件
//没产生
索引文件, 只是为了触发媒体注册
return
;
return
;
}
}
//m3u8文件生成,发送给播放器
decltype
(
_list_cb
)
copy
;
//赋值m3u8索引文件内容
{
std
::
lock_guard
<
std
::
mutex
>
lck
(
_mtx_index
);
std
::
lock_guard
<
std
::
mutex
>
lck
(
_mtx_cb
);
_index_file
=
std
::
move
(
index_file
);
copy
.
swap
(
_list_cb
);
}
_list_cb
.
for_each
([
&
](
const
std
::
function
<
void
(
const
std
::
string
&
str
)
>
&
cb
)
{
cb
(
_index_file
);
});
copy
.
for_each
([](
const
std
::
function
<
void
()
>
&
cb
)
{
_list_cb
.
clear
();
cb
();
});
}
}
void
waitForFile
(
std
::
function
<
void
()
>
cb
)
{
void
getIndexFile
(
std
::
function
<
void
(
const
std
::
string
&
str
)
>
cb
)
{
std
::
lock_guard
<
std
::
mutex
>
lck
(
_mtx_index
);
if
(
!
_index_file
.
empty
())
{
cb
(
_index_file
);
return
;
}
//等待生成m3u8文件
//等待生成m3u8文件
std
::
lock_guard
<
std
::
mutex
>
lck
(
_mtx_cb
);
_list_cb
.
emplace_back
(
std
::
move
(
cb
));
_list_cb
.
emplace_back
(
std
::
move
(
cb
));
}
}
void
onSegmentSize
(
size_t
bytes
)
{
std
::
string
getIndexFile
()
const
{
_speed
[
TrackVideo
]
+=
bytes
;
std
::
lock_guard
<
std
::
mutex
>
lck
(
_mtx_index
);
return
_index_file
;
}
}
void
onSegmentSize
(
size_t
bytes
)
{
_speed
[
TrackVideo
]
+=
bytes
;
}
private
:
private
:
bool
_is_regist
=
false
;
bool
_is_regist
=
false
;
RingType
::
Ptr
_ring
;
RingType
::
Ptr
_ring
;
std
::
mutex
_mtx_cb
;
toolkit
::
List
<
std
::
function
<
void
()
>
>
_list_cb
;
std
::
string
_index_file
;
mutable
std
::
mutex
_mtx_index
;
toolkit
::
List
<
std
::
function
<
void
(
const
std
::
string
&
)
>
>
_list_cb
;
};
};
class
HlsCookieData
{
class
HlsCookieData
{
public
:
public
:
typedef
std
::
shared_ptr
<
HlsCookieData
>
Ptr
;
using
Ptr
=
std
::
shared_ptr
<
HlsCookieData
>
;
HlsCookieData
(
const
MediaInfo
&
info
,
const
std
::
shared_ptr
<
toolkit
::
SockInfo
>
&
sock_info
);
HlsCookieData
(
const
MediaInfo
&
info
,
const
std
::
shared_ptr
<
toolkit
::
SockInfo
>
&
sock_info
);
~
HlsCookieData
();
~
HlsCookieData
();
void
addByteUsage
(
size_t
bytes
);
void
addByteUsage
(
size_t
bytes
);
void
setMediaSource
(
const
HlsMediaSource
::
Ptr
&
src
);
HlsMediaSource
::
Ptr
getMediaSource
()
const
;
private
:
private
:
void
addReaderCount
();
void
addReaderCount
();
private
:
private
:
std
::
atomic
<
uint64_t
>
_bytes
{
0
};
std
::
atomic
<
uint64_t
>
_bytes
{
0
};
MediaInfo
_info
;
MediaInfo
_info
;
std
::
shared_ptr
<
bool
>
_added
;
std
::
shared_ptr
<
bool
>
_added
;
toolkit
::
Ticker
_ticker
;
toolkit
::
Ticker
_ticker
;
std
::
weak_ptr
<
HlsMediaSource
>
_src
;
std
::
shared_ptr
<
toolkit
::
SockInfo
>
_sock_info
;
std
::
shared_ptr
<
toolkit
::
SockInfo
>
_sock_info
;
HlsMediaSource
::
RingType
::
RingReader
::
Ptr
_ring_reader
;
HlsMediaSource
::
RingType
::
RingReader
::
Ptr
_ring_reader
;
};
};
}
//
namespace mediakit
}
//
namespace mediakit
#endif //ZLMEDIAKIT_HLSMEDIASOURCE_H
#endif //
ZLMEDIAKIT_HLSMEDIASOURCE_H
src/Record/HlsRecorder.h
查看文件 @
d432888a
...
@@ -39,7 +39,7 @@ public:
...
@@ -39,7 +39,7 @@ public:
setDelegate
(
listener
);
setDelegate
(
listener
);
_hls
->
getMediaSource
()
->
setListener
(
shared_from_this
());
_hls
->
getMediaSource
()
->
setListener
(
shared_from_this
());
//先注册媒体流,后续可以按需生成
//先注册媒体流,后续可以按需生成
_hls
->
getMediaSource
()
->
registHls
(
false
);
_hls
->
getMediaSource
()
->
registHls
(
""
);
}
}
int
readerCount
()
{
int
readerCount
()
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论