mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2026-06-27 04:22:20 +08:00
tab统一替换为4个空格键:#242
This commit is contained in:
@@ -148,7 +148,7 @@ protected:
|
||||
* 接收http回复完毕,
|
||||
*/
|
||||
virtual void onResponseCompleted(){
|
||||
DebugL;
|
||||
DebugL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,11 +29,11 @@
|
||||
namespace mediakit {
|
||||
|
||||
void HttpClientImp::onConnect(const SockException &ex) {
|
||||
if(!_isHttps){
|
||||
HttpClient::onConnect(ex);
|
||||
} else {
|
||||
TcpClientWithSSL<HttpClient>::onConnect(ex);
|
||||
}
|
||||
if(!_isHttps){
|
||||
HttpClient::onConnect(ex);
|
||||
} else {
|
||||
TcpClientWithSSL<HttpClient>::onConnect(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -36,11 +36,11 @@ namespace mediakit {
|
||||
|
||||
class HttpClientImp: public TcpClientWithSSL<HttpClient> {
|
||||
public:
|
||||
typedef std::shared_ptr<HttpClientImp> Ptr;
|
||||
HttpClientImp() {}
|
||||
virtual ~HttpClientImp() {}
|
||||
typedef std::shared_ptr<HttpClientImp> Ptr;
|
||||
HttpClientImp() {}
|
||||
virtual ~HttpClientImp() {}
|
||||
protected:
|
||||
void onConnect(const SockException &ex) override ;
|
||||
void onConnect(const SockException &ex) override ;
|
||||
};
|
||||
|
||||
} /* namespace mediakit */
|
||||
|
||||
@@ -36,75 +36,75 @@ HttpDownloader::HttpDownloader() {
|
||||
}
|
||||
|
||||
HttpDownloader::~HttpDownloader() {
|
||||
closeFile();
|
||||
closeFile();
|
||||
}
|
||||
|
||||
void HttpDownloader::startDownload(const string& url, const string& filePath,bool bAppend,float timeOutSecond) {
|
||||
_filePath = filePath;
|
||||
if(_filePath.empty()){
|
||||
_filePath = exeDir() + "HttpDownloader/" + MD5(url).hexdigest();
|
||||
}
|
||||
_saveFile = File::createfile_file(_filePath.data(),bAppend ? "ab" : "wb");
|
||||
if(!_saveFile){
|
||||
auto strErr = StrPrinter << "打开文件失败:" << filePath << endl;
|
||||
throw std::runtime_error(strErr);
|
||||
}
|
||||
_bDownloadSuccess = false;
|
||||
if(bAppend){
|
||||
auto currentLen = ftell(_saveFile);
|
||||
if(currentLen){
|
||||
//最少续传一个字节,怕遇到http 416的错误
|
||||
currentLen -= 1;
|
||||
fseek(_saveFile,-1,SEEK_CUR);
|
||||
}
|
||||
addHeader("Range", StrPrinter << "bytes=" << currentLen << "-" << endl);
|
||||
}
|
||||
setMethod("GET");
|
||||
sendRequest(url,timeOutSecond);
|
||||
_filePath = filePath;
|
||||
if(_filePath.empty()){
|
||||
_filePath = exeDir() + "HttpDownloader/" + MD5(url).hexdigest();
|
||||
}
|
||||
_saveFile = File::createfile_file(_filePath.data(),bAppend ? "ab" : "wb");
|
||||
if(!_saveFile){
|
||||
auto strErr = StrPrinter << "打开文件失败:" << filePath << endl;
|
||||
throw std::runtime_error(strErr);
|
||||
}
|
||||
_bDownloadSuccess = false;
|
||||
if(bAppend){
|
||||
auto currentLen = ftell(_saveFile);
|
||||
if(currentLen){
|
||||
//最少续传一个字节,怕遇到http 416的错误
|
||||
currentLen -= 1;
|
||||
fseek(_saveFile,-1,SEEK_CUR);
|
||||
}
|
||||
addHeader("Range", StrPrinter << "bytes=" << currentLen << "-" << endl);
|
||||
}
|
||||
setMethod("GET");
|
||||
sendRequest(url,timeOutSecond);
|
||||
}
|
||||
|
||||
int64_t HttpDownloader::onResponseHeader(const string& status,const HttpHeader& headers) {
|
||||
if(status != "200" && status != "206"){
|
||||
//失败
|
||||
shutdown(SockException(Err_shutdown,StrPrinter << "Http Status:" << status));
|
||||
}
|
||||
//后续全部是content
|
||||
return -1;
|
||||
//失败
|
||||
shutdown(SockException(Err_shutdown,StrPrinter << "Http Status:" << status));
|
||||
}
|
||||
//后续全部是content
|
||||
return -1;
|
||||
}
|
||||
|
||||
void HttpDownloader::onResponseBody(const char* buf, int64_t size, int64_t recvedSize, int64_t totalSize) {
|
||||
if(_saveFile){
|
||||
fwrite(buf,size,1,_saveFile);
|
||||
}
|
||||
fwrite(buf,size,1,_saveFile);
|
||||
}
|
||||
}
|
||||
|
||||
void HttpDownloader::onResponseCompleted() {
|
||||
closeFile();
|
||||
//InfoL << "md5Sum:" << getMd5Sum(_filePath);
|
||||
_bDownloadSuccess = true;
|
||||
if(_onResult){
|
||||
_onResult(Err_success,"success",_filePath);
|
||||
_onResult = nullptr;
|
||||
}
|
||||
closeFile();
|
||||
//InfoL << "md5Sum:" << getMd5Sum(_filePath);
|
||||
_bDownloadSuccess = true;
|
||||
if(_onResult){
|
||||
_onResult(Err_success,"success",_filePath);
|
||||
_onResult = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void HttpDownloader::onDisconnect(const SockException &ex) {
|
||||
closeFile();
|
||||
if(!_bDownloadSuccess){
|
||||
File::delete_file(_filePath.data());
|
||||
}
|
||||
if(_onResult){
|
||||
_onResult(ex.getErrCode(),ex.what(),_filePath);
|
||||
_onResult = nullptr;
|
||||
}
|
||||
closeFile();
|
||||
if(!_bDownloadSuccess){
|
||||
File::delete_file(_filePath.data());
|
||||
}
|
||||
if(_onResult){
|
||||
_onResult(ex.getErrCode(),ex.what(),_filePath);
|
||||
_onResult = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void HttpDownloader::closeFile() {
|
||||
if(_saveFile){
|
||||
fflush(_saveFile);
|
||||
fclose(_saveFile);
|
||||
_saveFile = nullptr;
|
||||
}
|
||||
if(_saveFile){
|
||||
fflush(_saveFile);
|
||||
fclose(_saveFile);
|
||||
_saveFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,30 +33,30 @@ namespace mediakit {
|
||||
|
||||
class HttpDownloader: public HttpClientImp {
|
||||
public:
|
||||
typedef std::shared_ptr<HttpDownloader> Ptr;
|
||||
typedef std::function<void(ErrCode code,const string &errMsg,const string &filePath)> onDownloadResult;
|
||||
HttpDownloader();
|
||||
virtual ~HttpDownloader();
|
||||
//开始下载文件,默认断点续传方式下载
|
||||
void startDownload(const string &url,const string &filePath = "",bool bAppend = false, float timeOutSecond = 10 );
|
||||
void startDownload(const string &url,const onDownloadResult &cb,float timeOutSecond = 10){
|
||||
setOnResult(cb);
|
||||
startDownload(url,"",false,timeOutSecond);
|
||||
}
|
||||
void setOnResult(const onDownloadResult &cb){
|
||||
_onResult = cb;
|
||||
}
|
||||
typedef std::shared_ptr<HttpDownloader> Ptr;
|
||||
typedef std::function<void(ErrCode code,const string &errMsg,const string &filePath)> onDownloadResult;
|
||||
HttpDownloader();
|
||||
virtual ~HttpDownloader();
|
||||
//开始下载文件,默认断点续传方式下载
|
||||
void startDownload(const string &url,const string &filePath = "",bool bAppend = false, float timeOutSecond = 10 );
|
||||
void startDownload(const string &url,const onDownloadResult &cb,float timeOutSecond = 10){
|
||||
setOnResult(cb);
|
||||
startDownload(url,"",false,timeOutSecond);
|
||||
}
|
||||
void setOnResult(const onDownloadResult &cb){
|
||||
_onResult = cb;
|
||||
}
|
||||
private:
|
||||
int64_t onResponseHeader(const string &status,const HttpHeader &headers) override;
|
||||
void onResponseBody(const char *buf,int64_t size,int64_t recvedSize,int64_t totalSize) override;
|
||||
void onResponseCompleted() override;
|
||||
void onDisconnect(const SockException &ex) override;
|
||||
int64_t onResponseHeader(const string &status,const HttpHeader &headers) override;
|
||||
void onResponseBody(const char *buf,int64_t size,int64_t recvedSize,int64_t totalSize) override;
|
||||
void onResponseCompleted() override;
|
||||
void onDisconnect(const SockException &ex) override;
|
||||
void closeFile();
|
||||
private:
|
||||
FILE *_saveFile = nullptr;
|
||||
string _filePath;
|
||||
onDownloadResult _onResult;
|
||||
bool _bDownloadSuccess = false;
|
||||
FILE *_saveFile = nullptr;
|
||||
string _filePath;
|
||||
onDownloadResult _onResult;
|
||||
bool _bDownloadSuccess = false;
|
||||
};
|
||||
|
||||
} /* namespace mediakit */
|
||||
|
||||
@@ -45,8 +45,8 @@ HttpSession::HttpSession(const Socket::Ptr &pSock) : TcpSession(pSock) {
|
||||
TraceP(this);
|
||||
GET_CONFIG(uint32_t,keep_alive_sec,Http::kKeepAliveSecond);
|
||||
pSock->setSendTimeOutSecond(keep_alive_sec);
|
||||
//起始接收buffer缓存设置为4K,节省内存
|
||||
pSock->setReadBuffer(std::make_shared<BufferRaw>(4 * 1024));
|
||||
//起始接收buffer缓存设置为4K,节省内存
|
||||
pSock->setReadBuffer(std::make_shared<BufferRaw>(4 * 1024));
|
||||
}
|
||||
|
||||
HttpSession::~HttpSession() {
|
||||
@@ -61,48 +61,48 @@ void HttpSession::Handle_Req_HEAD(int64_t &content_len){
|
||||
}
|
||||
|
||||
int64_t HttpSession::onRecvHeader(const char *header,uint64_t len) {
|
||||
typedef void (HttpSession::*HttpCMDHandle)(int64_t &);
|
||||
static unordered_map<string, HttpCMDHandle> s_func_map;
|
||||
static onceToken token([]() {
|
||||
s_func_map.emplace("GET",&HttpSession::Handle_Req_GET);
|
||||
s_func_map.emplace("POST",&HttpSession::Handle_Req_POST);
|
||||
typedef void (HttpSession::*HttpCMDHandle)(int64_t &);
|
||||
static unordered_map<string, HttpCMDHandle> s_func_map;
|
||||
static onceToken token([]() {
|
||||
s_func_map.emplace("GET",&HttpSession::Handle_Req_GET);
|
||||
s_func_map.emplace("POST",&HttpSession::Handle_Req_POST);
|
||||
s_func_map.emplace("HEAD",&HttpSession::Handle_Req_HEAD);
|
||||
}, nullptr);
|
||||
|
||||
_parser.Parse(header);
|
||||
urlDecode(_parser);
|
||||
string cmd = _parser.Method();
|
||||
auto it = s_func_map.find(cmd);
|
||||
if (it == s_func_map.end()) {
|
||||
WarnL << "不支持该命令:" << cmd;
|
||||
sendResponse("405 Not Allowed", true);
|
||||
_parser.Parse(header);
|
||||
urlDecode(_parser);
|
||||
string cmd = _parser.Method();
|
||||
auto it = s_func_map.find(cmd);
|
||||
if (it == s_func_map.end()) {
|
||||
WarnL << "不支持该命令:" << cmd;
|
||||
sendResponse("405 Not Allowed", true);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//跨域
|
||||
_origin = _parser["Origin"];
|
||||
|
||||
//默认后面数据不是content而是header
|
||||
int64_t content_len = 0;
|
||||
auto &fun = it->second;
|
||||
int64_t content_len = 0;
|
||||
auto &fun = it->second;
|
||||
try {
|
||||
(this->*fun)(content_len);
|
||||
}catch (exception &ex){
|
||||
shutdown(SockException(Err_shutdown,ex.what()));
|
||||
}
|
||||
|
||||
//清空解析器节省内存
|
||||
_parser.Clear();
|
||||
//返回content长度
|
||||
return content_len;
|
||||
//清空解析器节省内存
|
||||
_parser.Clear();
|
||||
//返回content长度
|
||||
return content_len;
|
||||
}
|
||||
|
||||
void HttpSession::onRecvContent(const char *data,uint64_t len) {
|
||||
if(_contentCallBack){
|
||||
if(!_contentCallBack(data,len)){
|
||||
_contentCallBack = nullptr;
|
||||
}
|
||||
}
|
||||
if(_contentCallBack){
|
||||
if(!_contentCallBack(data,len)){
|
||||
_contentCallBack = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HttpSession::onRecv(const Buffer::Ptr &pBuf) {
|
||||
@@ -140,25 +140,25 @@ void HttpSession::onManager() {
|
||||
GET_CONFIG(uint32_t,keepAliveSec,Http::kKeepAliveSecond);
|
||||
|
||||
if(_ticker.elapsedTime() > keepAliveSec * 1000){
|
||||
//1分钟超时
|
||||
shutdown(SockException(Err_timeout,"session timeouted"));
|
||||
}
|
||||
//1分钟超时
|
||||
shutdown(SockException(Err_timeout,"session timeouted"));
|
||||
}
|
||||
}
|
||||
|
||||
bool HttpSession::checkWebSocket(){
|
||||
auto Sec_WebSocket_Key = _parser["Sec-WebSocket-Key"];
|
||||
if(Sec_WebSocket_Key.empty()){
|
||||
return false;
|
||||
}
|
||||
auto Sec_WebSocket_Accept = encodeBase64(SHA1::encode_bin(Sec_WebSocket_Key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
|
||||
auto Sec_WebSocket_Key = _parser["Sec-WebSocket-Key"];
|
||||
if(Sec_WebSocket_Key.empty()){
|
||||
return false;
|
||||
}
|
||||
auto Sec_WebSocket_Accept = encodeBase64(SHA1::encode_bin(Sec_WebSocket_Key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
|
||||
|
||||
KeyValue headerOut;
|
||||
headerOut["Upgrade"] = "websocket";
|
||||
headerOut["Connection"] = "Upgrade";
|
||||
headerOut["Sec-WebSocket-Accept"] = Sec_WebSocket_Accept;
|
||||
if(!_parser["Sec-WebSocket-Protocol"].empty()){
|
||||
headerOut["Sec-WebSocket-Protocol"] = _parser["Sec-WebSocket-Protocol"];
|
||||
}
|
||||
KeyValue headerOut;
|
||||
headerOut["Upgrade"] = "websocket";
|
||||
headerOut["Connection"] = "Upgrade";
|
||||
headerOut["Sec-WebSocket-Accept"] = Sec_WebSocket_Accept;
|
||||
if(!_parser["Sec-WebSocket-Protocol"].empty()){
|
||||
headerOut["Sec-WebSocket-Protocol"] = _parser["Sec-WebSocket-Protocol"];
|
||||
}
|
||||
|
||||
auto res_cb = [this,headerOut](){
|
||||
_flv_over_websocket = true;
|
||||
@@ -177,28 +177,28 @@ bool HttpSession::checkWebSocket(){
|
||||
return true;
|
||||
}
|
||||
sendResponse("101 Switching Protocols",false, nullptr,headerOut);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//http-flv 链接格式:http://vhost-url:port/app/streamid.flv?key1=value1&key2=value2
|
||||
//如果url(除去?以及后面的参数)后缀是.flv,那么表明该url是一个http-flv直播。
|
||||
bool HttpSession::checkLiveFlvStream(const function<void()> &cb){
|
||||
auto pos = strrchr(_parser.Url().data(),'.');
|
||||
if(!pos){
|
||||
//未找到".flv"后缀
|
||||
return false;
|
||||
}
|
||||
if(strcasecmp(pos,".flv") != 0){
|
||||
//未找到".flv"后缀
|
||||
return false;
|
||||
}
|
||||
|
||||
//这是个.flv的流
|
||||
_mediaInfo.parse(string(RTMP_SCHEMA) + "://" + _parser["Host"] + _parser.FullUrl());
|
||||
if(_mediaInfo._app.empty() || _mediaInfo._streamid.size() < 5){
|
||||
//url不合法
|
||||
auto pos = strrchr(_parser.Url().data(),'.');
|
||||
if(!pos){
|
||||
//未找到".flv"后缀
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(strcasecmp(pos,".flv") != 0){
|
||||
//未找到".flv"后缀
|
||||
return false;
|
||||
}
|
||||
|
||||
//这是个.flv的流
|
||||
_mediaInfo.parse(string(RTMP_SCHEMA) + "://" + _parser["Host"] + _parser.FullUrl());
|
||||
if(_mediaInfo._app.empty() || _mediaInfo._streamid.size() < 5){
|
||||
//url不合法
|
||||
return false;
|
||||
}
|
||||
_mediaInfo._streamid.erase(_mediaInfo._streamid.size() - 4);//去除.flv后缀
|
||||
bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
|
||||
|
||||
@@ -270,21 +270,21 @@ void HttpSession::Handle_Req_GET(int64_t &content_len) {
|
||||
}
|
||||
|
||||
void HttpSession::Handle_Req_GET_l(int64_t &content_len, bool sendBody) {
|
||||
//先看看是否为WebSocket请求
|
||||
if(checkWebSocket()){
|
||||
content_len = -1;
|
||||
_contentCallBack = [this](const char *data,uint64_t len){
|
||||
//先看看是否为WebSocket请求
|
||||
if(checkWebSocket()){
|
||||
content_len = -1;
|
||||
_contentCallBack = [this](const char *data,uint64_t len){
|
||||
WebSocketSplitter::decode((uint8_t *)data,len);
|
||||
//_contentCallBack是可持续的,后面还要处理后续数据
|
||||
return true;
|
||||
};
|
||||
return;
|
||||
}
|
||||
//_contentCallBack是可持续的,后面还要处理后续数据
|
||||
return true;
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if(emitHttpEvent(false)){
|
||||
if(emitHttpEvent(false)){
|
||||
//拦截http api事件
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(checkLiveFlvStream()){
|
||||
//拦截http-flv播放器
|
||||
@@ -498,111 +498,111 @@ void HttpSession::sendResponse(const char *pcStatus,
|
||||
}
|
||||
|
||||
string HttpSession::urlDecode(const string &str){
|
||||
auto ret = strCoding::UrlDecode(str);
|
||||
auto ret = strCoding::UrlDecode(str);
|
||||
#ifdef _WIN32
|
||||
GET_CONFIG(string,charSet,Http::kCharSet);
|
||||
bool isGb2312 = !strcasecmp(charSet.data(), "gb2312");
|
||||
if (isGb2312) {
|
||||
ret = strCoding::UTF8ToGB2312(ret);
|
||||
}
|
||||
bool isGb2312 = !strcasecmp(charSet.data(), "gb2312");
|
||||
if (isGb2312) {
|
||||
ret = strCoding::UTF8ToGB2312(ret);
|
||||
}
|
||||
#endif // _WIN32
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HttpSession::urlDecode(Parser &parser){
|
||||
parser.setUrl(urlDecode(parser.Url()));
|
||||
for(auto &pr : _parser.getUrlArgs()){
|
||||
const_cast<string &>(pr.second) = urlDecode(pr.second);
|
||||
}
|
||||
parser.setUrl(urlDecode(parser.Url()));
|
||||
for(auto &pr : _parser.getUrlArgs()){
|
||||
const_cast<string &>(pr.second) = urlDecode(pr.second);
|
||||
}
|
||||
}
|
||||
|
||||
bool HttpSession::emitHttpEvent(bool doInvoke){
|
||||
bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
|
||||
/////////////////////异步回复Invoker///////////////////////////////
|
||||
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
|
||||
HttpResponseInvoker invoker = [weakSelf,bClose](const string &codeOut, const KeyValue &headerOut, const HttpBody::Ptr &body){
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
}
|
||||
strongSelf->async([weakSelf,bClose,codeOut,headerOut,body]() {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
/////////////////////异步回复Invoker///////////////////////////////
|
||||
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
|
||||
HttpResponseInvoker invoker = [weakSelf,bClose](const string &codeOut, const KeyValue &headerOut, const HttpBody::Ptr &body){
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
}
|
||||
strongSelf->async([weakSelf,bClose,codeOut,headerOut,body]() {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
//本对象已经销毁
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
strongSelf->sendResponse(codeOut.data(), bClose, nullptr, headerOut, body);
|
||||
});
|
||||
};
|
||||
///////////////////广播HTTP事件///////////////////////////
|
||||
bool consumed = false;//该事件是否被消费
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastHttpRequest,_parser,invoker,consumed,*this);
|
||||
if(!consumed && doInvoke){
|
||||
//该事件无人消费,所以返回404
|
||||
invoker("404 Not Found",KeyValue(), HttpBody::Ptr());
|
||||
}
|
||||
return consumed;
|
||||
});
|
||||
};
|
||||
///////////////////广播HTTP事件///////////////////////////
|
||||
bool consumed = false;//该事件是否被消费
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastHttpRequest,_parser,invoker,consumed,*this);
|
||||
if(!consumed && doInvoke){
|
||||
//该事件无人消费,所以返回404
|
||||
invoker("404 Not Found",KeyValue(), HttpBody::Ptr());
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void HttpSession::Handle_Req_POST(int64_t &content_len) {
|
||||
GET_CONFIG(uint64_t,maxReqSize,Http::kMaxReqSize);
|
||||
GET_CONFIG(uint64_t,maxReqSize,Http::kMaxReqSize);
|
||||
|
||||
int64_t totalContentLen = _parser["Content-Length"].empty() ? -1 : atoll(_parser["Content-Length"].data());
|
||||
|
||||
if(totalContentLen == 0){
|
||||
//content为空
|
||||
//emitHttpEvent内部会选择是否关闭连接
|
||||
emitHttpEvent(true);
|
||||
return;
|
||||
}
|
||||
if(totalContentLen == 0){
|
||||
//content为空
|
||||
//emitHttpEvent内部会选择是否关闭连接
|
||||
emitHttpEvent(true);
|
||||
return;
|
||||
}
|
||||
|
||||
//根据Content-Length设置接收缓存大小
|
||||
if(totalContentLen > 0){
|
||||
_sock->setReadBuffer(std::make_shared<BufferRaw>(MIN(totalContentLen + 1,256 * 1024)));
|
||||
}else{
|
||||
//不定长度的Content-Length
|
||||
//不定长度的Content-Length
|
||||
_sock->setReadBuffer(std::make_shared<BufferRaw>(256 * 1024));
|
||||
}
|
||||
}
|
||||
|
||||
if(totalContentLen > 0 && totalContentLen < maxReqSize ){
|
||||
//返回固定长度的content
|
||||
content_len = totalContentLen;
|
||||
auto parserCopy = _parser;
|
||||
_contentCallBack = [this,parserCopy](const char *data,uint64_t len){
|
||||
//恢复http头
|
||||
_parser = parserCopy;
|
||||
//设置content
|
||||
_parser.setContent(string(data,len));
|
||||
//触发http事件,emitHttpEvent内部会选择是否关闭连接
|
||||
emitHttpEvent(true);
|
||||
//清空数据,节省内存
|
||||
_parser.Clear();
|
||||
//content已经接收完毕
|
||||
return false;
|
||||
};
|
||||
}else{
|
||||
//返回不固定长度的content
|
||||
content_len = -1;
|
||||
auto parserCopy = _parser;
|
||||
std::shared_ptr<uint64_t> recvedContentLen = std::make_shared<uint64_t>(0);
|
||||
bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
|
||||
//返回固定长度的content
|
||||
content_len = totalContentLen;
|
||||
auto parserCopy = _parser;
|
||||
_contentCallBack = [this,parserCopy](const char *data,uint64_t len){
|
||||
//恢复http头
|
||||
_parser = parserCopy;
|
||||
//设置content
|
||||
_parser.setContent(string(data,len));
|
||||
//触发http事件,emitHttpEvent内部会选择是否关闭连接
|
||||
emitHttpEvent(true);
|
||||
//清空数据,节省内存
|
||||
_parser.Clear();
|
||||
//content已经接收完毕
|
||||
return false;
|
||||
};
|
||||
}else{
|
||||
//返回不固定长度的content
|
||||
content_len = -1;
|
||||
auto parserCopy = _parser;
|
||||
std::shared_ptr<uint64_t> recvedContentLen = std::make_shared<uint64_t>(0);
|
||||
bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
|
||||
|
||||
_contentCallBack = [this,parserCopy,totalContentLen,recvedContentLen,bClose](const char *data,uint64_t len){
|
||||
*(recvedContentLen) += len;
|
||||
_contentCallBack = [this,parserCopy,totalContentLen,recvedContentLen,bClose](const char *data,uint64_t len){
|
||||
*(recvedContentLen) += len;
|
||||
|
||||
onRecvUnlimitedContent(parserCopy,data,len,totalContentLen,*(recvedContentLen));
|
||||
onRecvUnlimitedContent(parserCopy,data,len,totalContentLen,*(recvedContentLen));
|
||||
|
||||
if(*(recvedContentLen) < totalContentLen){
|
||||
//数据还没接收完毕
|
||||
if(*(recvedContentLen) < totalContentLen){
|
||||
//数据还没接收完毕
|
||||
//_contentCallBack是可持续的,后面还要处理后续content数据
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//数据接收完毕
|
||||
//数据接收完毕
|
||||
if(!bClose){
|
||||
//keep-alive类型连接
|
||||
//content接收完毕,后续都是http header
|
||||
setContentLen(0);
|
||||
//keep-alive类型连接
|
||||
//content接收完毕,后续都是http header
|
||||
setContentLen(0);
|
||||
//content已经接收完毕
|
||||
return false;
|
||||
}
|
||||
@@ -611,9 +611,9 @@ void HttpSession::Handle_Req_POST(int64_t &content_len) {
|
||||
shutdown(SockException(Err_shutdown,"recv http content completed"));
|
||||
//content已经接收完毕
|
||||
return false ;
|
||||
};
|
||||
}
|
||||
//有后续content数据要处理,暂时不关闭连接
|
||||
};
|
||||
}
|
||||
//有后续content数据要处理,暂时不关闭连接
|
||||
}
|
||||
|
||||
void HttpSession::sendNotFound(bool bClose) {
|
||||
@@ -632,7 +632,7 @@ void HttpSession::setSocketFlags(){
|
||||
}
|
||||
|
||||
void HttpSession::onWrite(const Buffer::Ptr &buffer) {
|
||||
_ticker.resetTime();
|
||||
_ticker.resetTime();
|
||||
if(!_flv_over_websocket){
|
||||
_ui64TotalBytes += buffer->size();
|
||||
send(buffer);
|
||||
@@ -653,11 +653,11 @@ void HttpSession::onWebSocketEncodeData(const Buffer::Ptr &buffer){
|
||||
}
|
||||
|
||||
void HttpSession::onDetach() {
|
||||
shutdown(SockException(Err_shutdown,"rtmp ring buffer detached"));
|
||||
shutdown(SockException(Err_shutdown,"rtmp ring buffer detached"));
|
||||
}
|
||||
|
||||
std::shared_ptr<FlvMuxer> HttpSession::getSharedPtr(){
|
||||
return dynamic_pointer_cast<FlvMuxer>(shared_from_this());
|
||||
return dynamic_pointer_cast<FlvMuxer>(shared_from_this());
|
||||
}
|
||||
|
||||
} /* namespace mediakit */
|
||||
|
||||
@@ -45,51 +45,51 @@ class HttpSession: public TcpSession,
|
||||
public HttpRequestSplitter,
|
||||
public WebSocketSplitter {
|
||||
public:
|
||||
typedef StrCaseMap KeyValue;
|
||||
typedef HttpResponseInvokerImp HttpResponseInvoker;
|
||||
friend class AsyncSender;
|
||||
/**
|
||||
* @param errMsg 如果为空,则代表鉴权通过,否则为错误提示
|
||||
* @param accessPath 运行或禁止访问的根目录
|
||||
* @param cookieLifeSecond 鉴权cookie有效期
|
||||
**/
|
||||
typedef std::function<void(const string &errMsg,const string &accessPath, int cookieLifeSecond)> HttpAccessPathInvoker;
|
||||
typedef StrCaseMap KeyValue;
|
||||
typedef HttpResponseInvokerImp HttpResponseInvoker;
|
||||
friend class AsyncSender;
|
||||
/**
|
||||
* @param errMsg 如果为空,则代表鉴权通过,否则为错误提示
|
||||
* @param accessPath 运行或禁止访问的根目录
|
||||
* @param cookieLifeSecond 鉴权cookie有效期
|
||||
**/
|
||||
typedef std::function<void(const string &errMsg,const string &accessPath, int cookieLifeSecond)> HttpAccessPathInvoker;
|
||||
|
||||
HttpSession(const Socket::Ptr &pSock);
|
||||
virtual ~HttpSession();
|
||||
HttpSession(const Socket::Ptr &pSock);
|
||||
virtual ~HttpSession();
|
||||
|
||||
virtual void onRecv(const Buffer::Ptr &) override;
|
||||
virtual void onError(const SockException &err) override;
|
||||
virtual void onManager() override;
|
||||
static string urlDecode(const string &str);
|
||||
virtual void onRecv(const Buffer::Ptr &) override;
|
||||
virtual void onError(const SockException &err) override;
|
||||
virtual void onManager() override;
|
||||
static string urlDecode(const string &str);
|
||||
protected:
|
||||
//FlvMuxer override
|
||||
void onWrite(const Buffer::Ptr &data) override ;
|
||||
void onDetach() override;
|
||||
std::shared_ptr<FlvMuxer> getSharedPtr() override;
|
||||
//FlvMuxer override
|
||||
void onWrite(const Buffer::Ptr &data) override ;
|
||||
void onDetach() override;
|
||||
std::shared_ptr<FlvMuxer> getSharedPtr() override;
|
||||
|
||||
//HttpRequestSplitter override
|
||||
int64_t onRecvHeader(const char *data,uint64_t len) override;
|
||||
void onRecvContent(const char *data,uint64_t len) override;
|
||||
//HttpRequestSplitter override
|
||||
int64_t onRecvHeader(const char *data,uint64_t len) override;
|
||||
void onRecvContent(const char *data,uint64_t len) override;
|
||||
|
||||
/**
|
||||
* 重载之用于处理不定长度的content
|
||||
* 这个函数可用于处理大文件上传、http-flv推流
|
||||
* @param header http请求头
|
||||
* @param data content分片数据
|
||||
* @param len content分片数据大小
|
||||
* @param totalSize content总大小,如果为0则是不限长度content
|
||||
* @param recvedSize 已收数据大小
|
||||
*/
|
||||
virtual void onRecvUnlimitedContent(const Parser &header,
|
||||
const char *data,
|
||||
uint64_t len,
|
||||
uint64_t totalSize,
|
||||
uint64_t recvedSize){
|
||||
/**
|
||||
* 重载之用于处理不定长度的content
|
||||
* 这个函数可用于处理大文件上传、http-flv推流
|
||||
* @param header http请求头
|
||||
* @param data content分片数据
|
||||
* @param len content分片数据大小
|
||||
* @param totalSize content总大小,如果为0则是不限长度content
|
||||
* @param recvedSize 已收数据大小
|
||||
*/
|
||||
virtual void onRecvUnlimitedContent(const Parser &header,
|
||||
const char *data,
|
||||
uint64_t len,
|
||||
uint64_t totalSize,
|
||||
uint64_t recvedSize){
|
||||
shutdown(SockException(Err_shutdown,"http post content is too huge,default closed"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* websocket客户端连接上事件
|
||||
* @param header http头
|
||||
* @return true代表允许websocket连接,否则拒绝
|
||||
@@ -99,31 +99,31 @@ protected:
|
||||
return false;
|
||||
}
|
||||
|
||||
//WebSocketSplitter override
|
||||
/**
|
||||
//WebSocketSplitter override
|
||||
/**
|
||||
* 发送数据进行websocket协议打包后回调
|
||||
* @param buffer websocket协议数据
|
||||
*/
|
||||
void onWebSocketEncodeData(const Buffer::Ptr &buffer) override;
|
||||
void onWebSocketEncodeData(const Buffer::Ptr &buffer) override;
|
||||
private:
|
||||
void Handle_Req_GET(int64_t &content_len);
|
||||
void Handle_Req_GET(int64_t &content_len);
|
||||
void Handle_Req_GET_l(int64_t &content_len, bool sendBody);
|
||||
void Handle_Req_POST(int64_t &content_len);
|
||||
void Handle_Req_HEAD(int64_t &content_len);
|
||||
|
||||
bool checkLiveFlvStream(const function<void()> &cb = nullptr);
|
||||
bool checkWebSocket();
|
||||
bool emitHttpEvent(bool doInvoke);
|
||||
void urlDecode(Parser &parser);
|
||||
void sendNotFound(bool bClose);
|
||||
void sendResponse(const char *pcStatus, bool bClose, const char *pcContentType = nullptr,
|
||||
const HttpSession::KeyValue &header = HttpSession::KeyValue(),
|
||||
bool checkWebSocket();
|
||||
bool emitHttpEvent(bool doInvoke);
|
||||
void urlDecode(Parser &parser);
|
||||
void sendNotFound(bool bClose);
|
||||
void sendResponse(const char *pcStatus, bool bClose, const char *pcContentType = nullptr,
|
||||
const HttpSession::KeyValue &header = HttpSession::KeyValue(),
|
||||
const HttpBody::Ptr &body = nullptr,bool is_http_flv = false);
|
||||
|
||||
//设置socket标志
|
||||
void setSocketFlags();
|
||||
//设置socket标志
|
||||
void setSocketFlags();
|
||||
private:
|
||||
string _origin;
|
||||
string _origin;
|
||||
Parser _parser;
|
||||
Ticker _ticker;
|
||||
//消耗的总流量
|
||||
@@ -132,8 +132,8 @@ private:
|
||||
MediaInfo _mediaInfo;
|
||||
//处理content数据的callback
|
||||
function<bool (const char *data,uint64_t len) > _contentCallBack;
|
||||
bool _flv_over_websocket = false;
|
||||
bool _is_flv_stream = false;
|
||||
bool _flv_over_websocket = false;
|
||||
bool _is_flv_stream = false;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -36,76 +36,76 @@ namespace mediakit {
|
||||
//////////////////////////通用///////////////////////
|
||||
void UTF8ToUnicode(wchar_t* pOut, const char *pText)
|
||||
{
|
||||
char* uchar = (char *)pOut;
|
||||
uchar[1] = ((pText[0] & 0x0F) << 4) + ((pText[1] >> 2) & 0x0F);
|
||||
uchar[0] = ((pText[1] & 0x03) << 6) + (pText[2] & 0x3F);
|
||||
return;
|
||||
char* uchar = (char *)pOut;
|
||||
uchar[1] = ((pText[0] & 0x0F) << 4) + ((pText[1] >> 2) & 0x0F);
|
||||
uchar[0] = ((pText[1] & 0x03) << 6) + (pText[2] & 0x3F);
|
||||
return;
|
||||
}
|
||||
void UnicodeToUTF8(char* pOut, const wchar_t* pText)
|
||||
{
|
||||
// 注意 WCHAR高低字的顺序,低字节在前,高字节在后
|
||||
const char* pchar = (const char *)pText;
|
||||
pOut[0] = (0xE0 | ((pchar[1] & 0xF0) >> 4));
|
||||
pOut[1] = (0x80 | ((pchar[1] & 0x0F) << 2)) + ((pchar[0] & 0xC0) >> 6);
|
||||
pOut[2] = (0x80 | (pchar[0] & 0x3F));
|
||||
return;
|
||||
// 注意 WCHAR高低字的顺序,低字节在前,高字节在后
|
||||
const char* pchar = (const char *)pText;
|
||||
pOut[0] = (0xE0 | ((pchar[1] & 0xF0) >> 4));
|
||||
pOut[1] = (0x80 | ((pchar[1] & 0x0F) << 2)) + ((pchar[0] & 0xC0) >> 6);
|
||||
pOut[2] = (0x80 | (pchar[0] & 0x3F));
|
||||
return;
|
||||
}
|
||||
|
||||
char CharToInt(char ch)
|
||||
{
|
||||
if (ch >= '0' && ch <= '9')return (char)(ch - '0');
|
||||
if (ch >= 'a' && ch <= 'f')return (char)(ch - 'a' + 10);
|
||||
if (ch >= 'A' && ch <= 'F')return (char)(ch - 'A' + 10);
|
||||
return -1;
|
||||
if (ch >= '0' && ch <= '9')return (char)(ch - '0');
|
||||
if (ch >= 'a' && ch <= 'f')return (char)(ch - 'a' + 10);
|
||||
if (ch >= 'A' && ch <= 'F')return (char)(ch - 'A' + 10);
|
||||
return -1;
|
||||
}
|
||||
char StrToBin(const char *str)
|
||||
{
|
||||
char tempWord[2];
|
||||
char chn;
|
||||
tempWord[0] = CharToInt(str[0]); //make the B to 11 -- 00001011
|
||||
tempWord[1] = CharToInt(str[1]); //make the 0 to 0 -- 00000000
|
||||
chn = (tempWord[0] << 4) | tempWord[1]; //to change the BO to 10110000
|
||||
return chn;
|
||||
char tempWord[2];
|
||||
char chn;
|
||||
tempWord[0] = CharToInt(str[0]); //make the B to 11 -- 00001011
|
||||
tempWord[1] = CharToInt(str[1]); //make the 0 to 0 -- 00000000
|
||||
chn = (tempWord[0] << 4) | tempWord[1]; //to change the BO to 10110000
|
||||
return chn;
|
||||
}
|
||||
|
||||
string strCoding::UrlEncode(const string &str) {
|
||||
string out;
|
||||
string out;
|
||||
size_t len = str.size();
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
char ch = str[i];
|
||||
if (isalnum((uint8_t)ch)) {
|
||||
if (isalnum((uint8_t)ch)) {
|
||||
out.push_back(ch);
|
||||
}else {
|
||||
char buf[4];
|
||||
sprintf(buf, "%%%X%X", (uint8_t)ch >> 4,(uint8_t)ch & 0x0F);
|
||||
}else {
|
||||
char buf[4];
|
||||
sprintf(buf, "%%%X%X", (uint8_t)ch >> 4,(uint8_t)ch & 0x0F);
|
||||
out.append(buf);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
string strCoding::UrlDecode(const string &str) {
|
||||
string output = "";
|
||||
char tmp[2];
|
||||
int i = 0, len = str.length();
|
||||
while (i < len) {
|
||||
if (str[i] == '%') {
|
||||
if(i > len - 3){
|
||||
//防止内存溢出
|
||||
string output = "";
|
||||
char tmp[2];
|
||||
int i = 0, len = str.length();
|
||||
while (i < len) {
|
||||
if (str[i] == '%') {
|
||||
if(i > len - 3){
|
||||
//防止内存溢出
|
||||
break;
|
||||
}
|
||||
tmp[0] = str[i + 1];
|
||||
tmp[1] = str[i + 2];
|
||||
output += StrToBin(tmp);
|
||||
i = i + 3;
|
||||
} else if (str[i] == '+') {
|
||||
output += ' ';
|
||||
i++;
|
||||
} else {
|
||||
output += str[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
tmp[0] = str[i + 1];
|
||||
tmp[1] = str[i + 2];
|
||||
output += StrToBin(tmp);
|
||||
i = i + 3;
|
||||
} else if (str[i] == '+') {
|
||||
output += ' ';
|
||||
i++;
|
||||
} else {
|
||||
output += str[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,73 +113,73 @@ string strCoding::UrlDecode(const string &str) {
|
||||
#if defined(_WIN32)
|
||||
void UnicodeToGB2312(char* pOut, wchar_t uData)
|
||||
{
|
||||
WideCharToMultiByte(CP_ACP, NULL, &uData, 1, pOut, sizeof(wchar_t), NULL, NULL);
|
||||
WideCharToMultiByte(CP_ACP, NULL, &uData, 1, pOut, sizeof(wchar_t), NULL, NULL);
|
||||
}
|
||||
void Gb2312ToUnicode(wchar_t* pOut, const char *gbBuffer)
|
||||
{
|
||||
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, gbBuffer, 2, pOut, 1);
|
||||
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, gbBuffer, 2, pOut, 1);
|
||||
}
|
||||
|
||||
string strCoding::UTF8ToGB2312(const string &str) {
|
||||
auto len = str.size();
|
||||
auto pText = str.data();
|
||||
char Ctemp[4] = {0};
|
||||
char *pOut = new char[len + 1];
|
||||
memset(pOut, 0, len + 1);
|
||||
auto len = str.size();
|
||||
auto pText = str.data();
|
||||
char Ctemp[4] = {0};
|
||||
char *pOut = new char[len + 1];
|
||||
memset(pOut, 0, len + 1);
|
||||
|
||||
int i = 0, j = 0;
|
||||
while (i < len)
|
||||
{
|
||||
if (pText[i] >= 0)
|
||||
{
|
||||
pOut[j++] = pText[i++];
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t Wtemp;
|
||||
UTF8ToUnicode(&Wtemp, pText + i);
|
||||
UnicodeToGB2312(Ctemp, Wtemp);
|
||||
pOut[j] = Ctemp[0];
|
||||
pOut[j + 1] = Ctemp[1];
|
||||
i += 3;
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
string ret = pOut;
|
||||
delete[] pOut;
|
||||
return ret;
|
||||
int i = 0, j = 0;
|
||||
while (i < len)
|
||||
{
|
||||
if (pText[i] >= 0)
|
||||
{
|
||||
pOut[j++] = pText[i++];
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t Wtemp;
|
||||
UTF8ToUnicode(&Wtemp, pText + i);
|
||||
UnicodeToGB2312(Ctemp, Wtemp);
|
||||
pOut[j] = Ctemp[0];
|
||||
pOut[j + 1] = Ctemp[1];
|
||||
i += 3;
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
string ret = pOut;
|
||||
delete[] pOut;
|
||||
return ret;
|
||||
}
|
||||
|
||||
string strCoding::GB2312ToUTF8(const string &str) {
|
||||
auto len = str.size();
|
||||
auto pText = str.data();
|
||||
char buf[4] = { 0 };
|
||||
int nLength = len * 3;
|
||||
char* pOut = new char[nLength];
|
||||
memset(pOut, 0, nLength);
|
||||
int i = 0, j = 0;
|
||||
while (i < len)
|
||||
{
|
||||
//如果是英文直接复制就可以
|
||||
if (*(pText + i) >= 0)
|
||||
{
|
||||
pOut[j++] = pText[i++];
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t pbuffer;
|
||||
Gb2312ToUnicode(&pbuffer, pText + i);
|
||||
UnicodeToUTF8(buf, &pbuffer);
|
||||
pOut[j] = buf[0];
|
||||
pOut[j + 1] = buf[1];
|
||||
pOut[j + 2] = buf[2];
|
||||
j += 3;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
string ret = pOut;
|
||||
delete[] pOut;
|
||||
return ret;
|
||||
auto len = str.size();
|
||||
auto pText = str.data();
|
||||
char buf[4] = { 0 };
|
||||
int nLength = len * 3;
|
||||
char* pOut = new char[nLength];
|
||||
memset(pOut, 0, nLength);
|
||||
int i = 0, j = 0;
|
||||
while (i < len)
|
||||
{
|
||||
//如果是英文直接复制就可以
|
||||
if (*(pText + i) >= 0)
|
||||
{
|
||||
pOut[j++] = pText[i++];
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t pbuffer;
|
||||
Gb2312ToUnicode(&pbuffer, pText + i);
|
||||
UnicodeToUTF8(buf, &pbuffer);
|
||||
pOut[j] = buf[0];
|
||||
pOut[j + 1] = buf[1];
|
||||
pOut[j + 2] = buf[2];
|
||||
j += 3;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
string ret = pOut;
|
||||
delete[] pOut;
|
||||
return ret;
|
||||
}
|
||||
#endif//defined(_WIN32)
|
||||
|
||||
|
||||
@@ -36,15 +36,15 @@ namespace mediakit {
|
||||
|
||||
class strCoding {
|
||||
public:
|
||||
static string UrlEncode(const string &str); //urlutf8 编码
|
||||
static string UrlDecode(const string &str); //urlutf8解码
|
||||
static string UrlEncode(const string &str); //urlutf8 编码
|
||||
static string UrlDecode(const string &str); //urlutf8解码
|
||||
#if defined(_WIN32)
|
||||
static string UTF8ToGB2312(const string &str);//utf_8转为gb2312
|
||||
static string GB2312ToUTF8(const string &str); //gb2312 转utf_8
|
||||
static string UTF8ToGB2312(const string &str);//utf_8转为gb2312
|
||||
static string GB2312ToUTF8(const string &str); //gb2312 转utf_8
|
||||
#endif//defined(_WIN32)
|
||||
private:
|
||||
strCoding(void);
|
||||
virtual ~strCoding(void);
|
||||
strCoding(void);
|
||||
virtual ~strCoding(void);
|
||||
};
|
||||
|
||||
} /* namespace mediakit */
|
||||
|
||||
Reference in New Issue
Block a user