ZLMediaKit/src/Http/HttpSession.cpp

624 lines
20 KiB
C++
Raw Normal View History

2019-12-26 15:02:28 +08:00
/*
2017-09-27 16:20:30 +08:00
* MIT License
2017-04-01 16:35:56 +08:00
*
2019-05-08 15:40:07 +08:00
* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com>
2017-09-27 16:20:30 +08:00
*
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
2017-04-01 16:35:56 +08:00
*/
2017-08-10 14:06:51 +08:00
#if !defined(_WIN32)
#include <dirent.h>
#endif //!defined(_WIN32)
2017-04-01 16:35:56 +08:00
#include <stdio.h>
#include <sys/stat.h>
#include <algorithm>
#include <iomanip>
2017-04-01 16:35:56 +08:00
2017-05-02 17:15:12 +08:00
#include "Common/config.h"
2017-04-01 16:35:56 +08:00
#include "strCoding.h"
#include "HttpSession.h"
2018-09-20 18:20:43 +08:00
#include "Util/base64.h"
#include "Util/SHA1.h"
2018-10-24 17:17:55 +08:00
using namespace toolkit;
2017-08-10 14:06:51 +08:00
2018-10-24 17:17:55 +08:00
namespace mediakit {
2017-04-01 16:35:56 +08:00
2018-12-20 10:42:51 +08:00
HttpSession::HttpSession(const Socket::Ptr &pSock) : TcpSession(pSock) {
2019-05-29 18:08:50 +08:00
TraceP(this);
2019-05-30 10:41:25 +08:00
GET_CONFIG(uint32_t,keep_alive_sec,Http::kKeepAliveSecond);
pSock->setSendTimeOutSecond(keep_alive_sec);
//起始接收buffer缓存设置为4K节省内存
pSock->setReadBuffer(std::make_shared<BufferRaw>(4 * 1024));
2017-04-01 16:35:56 +08:00
}
HttpSession::~HttpSession() {
2019-05-29 18:08:50 +08:00
TraceP(this);
2017-04-01 16:35:56 +08:00
}
2018-09-23 00:55:00 +08:00
int64_t HttpSession::onRecvHeader(const char *header,uint64_t len) {
2019-05-30 10:59:14 +08:00
typedef void (HttpSession::*HttpCMDHandle)(int64_t &);
2019-11-30 11:38:00 +08:00
static unordered_map<string, HttpCMDHandle> s_func_map;
static onceToken token([]() {
2019-11-30 11:38:00 +08:00
s_func_map.emplace("GET",&HttpSession::Handle_Req_GET);
s_func_map.emplace("POST",&HttpSession::Handle_Req_POST);
}, nullptr);
2018-10-24 15:43:52 +08:00
_parser.Parse(header);
urlDecode(_parser);
string cmd = _parser.Method();
2019-11-30 11:38:00 +08:00
auto it = s_func_map.find(cmd);
if (it == s_func_map.end()) {
2019-10-29 00:35:44 +08:00
sendResponse("403 Forbidden", true);
2019-05-29 18:08:50 +08:00
return 0;
}
2019-07-30 16:07:00 +08:00
//跨域
_origin = _parser["Origin"];
//默认后面数据不是content而是header
int64_t content_len = 0;
auto &fun = it->second;
2019-05-30 10:59:14 +08:00
try {
(this->*fun)(content_len);
}catch (exception &ex){
shutdown(SockException(Err_shutdown,ex.what()));
}
//清空解析器节省内存
2018-10-24 15:43:52 +08:00
_parser.Clear();
//返回content长度
return content_len;
2017-04-01 16:35:56 +08:00
}
2018-09-23 00:55:00 +08:00
void HttpSession::onRecvContent(const char *data,uint64_t len) {
2018-10-24 15:43:52 +08:00
if(_contentCallBack){
if(!_contentCallBack(data,len)){
_contentCallBack = nullptr;
}
}
}
void HttpSession::onRecv(const Buffer::Ptr &pBuf) {
2018-10-24 15:43:52 +08:00
_ticker.resetTime();
2018-12-19 16:54:11 +08:00
input(pBuf->data(),pBuf->size());
}
2017-04-01 16:35:56 +08:00
void HttpSession::onError(const SockException& err) {
2019-10-23 12:00:53 +08:00
if(_is_flv_stream){
//flv播放器
WarnP(this) << "播放器("
<< _mediaInfo._vhost << "/"
<< _mediaInfo._app << "/"
<< _mediaInfo._streamid
<< ")断开:" << err.what();
GET_CONFIG(uint32_t,iFlowThreshold,General::kFlowThreshold);
if(_ui64TotalBytes > iFlowThreshold * 1024){
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,
_mediaInfo,
_ui64TotalBytes,
_ticker.createdTime()/1000,
true,
*this);
}
return;
}
//http客户端
2019-05-29 18:08:50 +08:00
if(_ticker.createdTime() < 10 * 1000){
TraceP(this) << err.what();
}else{
WarnP(this) << err.what();
}
2017-04-01 16:35:56 +08:00
}
void HttpSession::onManager() {
2019-05-28 17:14:36 +08:00
GET_CONFIG(uint32_t,keepAliveSec,Http::kKeepAliveSecond);
2018-02-09 11:42:55 +08:00
2018-10-24 15:43:52 +08:00
if(_ticker.elapsedTime() > keepAliveSec * 1000){
2017-04-01 16:35:56 +08:00
//1分钟超时
2019-05-29 18:08:50 +08:00
shutdown(SockException(Err_timeout,"session timeouted"));
2017-04-01 16:35:56 +08:00
}
}
2018-09-20 18:20:43 +08:00
2019-09-16 17:42:52 +08:00
bool HttpSession::checkWebSocket(){
2018-10-24 15:43:52 +08:00
auto Sec_WebSocket_Key = _parser["Sec-WebSocket-Key"];
2018-09-29 11:08:02 +08:00
if(Sec_WebSocket_Key.empty()){
2018-09-20 18:20:43 +08:00
return false;
}
auto Sec_WebSocket_Accept = encodeBase64(SHA1::encode_bin(Sec_WebSocket_Key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
2019-10-29 00:35:44 +08:00
KeyValue headerOut;
2018-09-20 18:20:43 +08:00
headerOut["Upgrade"] = "websocket";
headerOut["Connection"] = "Upgrade";
headerOut["Sec-WebSocket-Accept"] = Sec_WebSocket_Accept;
2019-04-02 15:07:54 +08:00
if(!_parser["Sec-WebSocket-Protocol"].empty()){
headerOut["Sec-WebSocket-Protocol"] = _parser["Sec-WebSocket-Protocol"];
}
2019-08-23 09:45:01 +08:00
auto res_cb = [this,headerOut](){
_flv_over_websocket = true;
sendResponse("101 Switching Protocols",false,nullptr,headerOut,nullptr, true);
2019-08-23 09:45:01 +08:00
};
//判断是否为websocket-flv
if(checkLiveFlvStream(res_cb)){
//这里是websocket-flv直播请求
return true;
}
//如果checkLiveFlvStream返回false,则代表不是websocket-flv而是普通的websocket连接
2019-09-16 17:42:52 +08:00
if(!onWebSocketConnect(_parser)){
2019-10-29 00:35:44 +08:00
sendResponse("501 Not Implemented",true, nullptr, headerOut);
2019-09-16 17:42:52 +08:00
return true;
}
2019-10-29 00:35:44 +08:00
sendResponse("101 Switching Protocols",false, nullptr,headerOut);
2018-09-20 18:20:43 +08:00
return true;
}
2019-11-30 11:38:00 +08:00
//http-flv 链接格式:http://vhost-url:port/app/streamid.flv?key1=value1&key2=value2
//如果url(除去?以及后面的参数)后缀是.flv,那么表明该url是一个http-flv直播。
2019-09-16 17:42:52 +08:00
bool HttpSession::checkLiveFlvStream(const function<void()> &cb){
2018-10-24 15:43:52 +08:00
auto pos = strrchr(_parser.Url().data(),'.');
2017-12-15 16:01:21 +08:00
if(!pos){
//未找到".flv"后缀
return false;
}
2018-11-27 11:05:44 +08:00
if(strcasecmp(pos,".flv") != 0){
2017-12-15 16:01:21 +08:00
//未找到".flv"后缀
return false;
}
2019-05-27 22:49:30 +08:00
//这是个.flv的流
_mediaInfo.parse(string(RTMP_SCHEMA) + "://" + _parser["Host"] + _parser.FullUrl());
if(_mediaInfo._app.empty() || _mediaInfo._streamid.size() < 5){
//url不合法
return false;
2017-12-15 16:01:21 +08:00
}
2019-05-27 22:49:30 +08:00
_mediaInfo._streamid.erase(_mediaInfo._streamid.size() - 4);//去除.flv后缀
bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
2019-12-03 16:10:02 +08:00
MediaSource::findAsync(_mediaInfo,weakSelf.lock(),[weakSelf,bClose,this,cb](const MediaSource::Ptr &src){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
2019-05-27 22:49:30 +08:00
//本对象已经销毁
return;
}
auto rtmp_src = dynamic_pointer_cast<RtmpMediaSource>(src);
if(!rtmp_src){
//未找到该流
2019-08-23 09:45:01 +08:00
sendNotFound(bClose);
return;
}
2019-05-27 22:49:30 +08:00
//找到流了
2019-08-23 09:45:01 +08:00
auto onRes = [this,rtmp_src,cb](const string &err){
2019-05-27 22:49:30 +08:00
bool authSuccess = err.empty();
if(!authSuccess){
2019-10-29 00:35:44 +08:00
sendResponse("401 Unauthorized", true, nullptr, KeyValue(), std::make_shared<HttpStringBody>(err));
2019-05-27 22:49:30 +08:00
return ;
}
2019-08-23 09:45:01 +08:00
if(!cb) {
2019-08-12 18:14:51 +08:00
//找到rtmp源发送http头负载后续发送
sendResponse("200 OK", false, "video/x-flv",KeyValue(),nullptr,true);
2019-08-23 09:45:01 +08:00
}else{
cb();
2019-08-12 18:14:51 +08:00
}
2019-05-27 22:49:30 +08:00
//http-flv直播牺牲延时提升发送性能
setSocketFlags();
2019-05-27 22:49:30 +08:00
try{
start(getPoller(),rtmp_src);
2019-10-23 12:00:53 +08:00
_is_flv_stream = true;
2019-05-27 22:49:30 +08:00
}catch (std::exception &ex){
//该rtmp源不存在
2019-05-29 18:08:50 +08:00
shutdown(SockException(Err_shutdown,"rtmp mediasource released"));
2019-05-27 22:49:30 +08:00
}
};
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
Broadcast::AuthInvoker invoker = [weakSelf,onRes](const string &err){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
}
2019-05-27 22:49:30 +08:00
strongSelf->async([weakSelf,onRes,err](){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
}
onRes(err);
});
};
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,_mediaInfo,invoker,*this);
if(!flag){
//该事件无人监听,默认不鉴权
onRes("");
}
});
return true;
2017-12-15 16:01:21 +08:00
}
2019-09-16 17:42:52 +08:00
void HttpSession::Handle_Req_GET(int64_t &content_len) {
2018-09-20 18:20:43 +08:00
//先看看是否为WebSocket请求
if(checkWebSocket()){
content_len = -1;
2019-09-16 17:42:52 +08:00
_contentCallBack = [this](const char *data,uint64_t len){
WebSocketSplitter::decode((uint8_t *)data,len);
2018-10-24 15:43:52 +08:00
//_contentCallBack是可持续的后面还要处理后续数据
2018-09-20 18:20:43 +08:00
return true;
};
2019-05-30 10:59:14 +08:00
return;
2018-09-20 18:20:43 +08:00
}
2017-12-08 22:37:17 +08:00
if(emitHttpEvent(false)){
2019-10-29 09:16:52 +08:00
//拦截http api事件
2019-05-30 10:59:14 +08:00
return;
2017-10-10 00:04:07 +08:00
}
2018-09-20 18:20:43 +08:00
2019-10-29 09:16:52 +08:00
if(checkLiveFlvStream()){
//拦截http-flv播放器
return;
}
bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
2019-11-30 11:38:00 +08:00
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
HttpFileManager::onAccessPath(*this, _parser, [weakSelf, bClose](const string &status_code, const string &content_type,
const StrCaseMap &responseHeader, const HttpBody::Ptr &body) {
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
2019-06-12 17:53:48 +08:00
return;
}
2019-11-30 11:38:00 +08:00
strongSelf->async([weakSelf, bClose, status_code, content_type, responseHeader, body]() {
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
return;
}
2019-11-30 11:56:40 +08:00
strongSelf->sendResponse(status_code.data(), bClose, content_type.data(), responseHeader, body);
2019-11-30 11:38:00 +08:00
});
2019-06-12 17:53:48 +08:00
});
2017-04-01 16:35:56 +08:00
}
2019-11-30 11:38:00 +08:00
static string dateStr() {
char buf[64];
time_t tt = time(NULL);
strftime(buf, sizeof buf, "%a, %b %d %Y %H:%M:%S GMT", gmtime(&tt));
return buf;
2017-04-01 16:35:56 +08:00
}
2019-09-16 17:42:52 +08:00
2019-12-26 15:02:28 +08:00
static const string kDate = "Date";
static const string kServer = "Server";
static const string kConnection = "Connection";
static const string kKeepAlive = "Keep-Alive";
static const string kContentType = "Content-Type";
static const string kContentLength = "Content-Length";
static const string kAccessControlAllowOrigin = "Access-Control-Allow-Origin";
static const string kAccessControlAllowCredentials = "Access-Control-Allow-Credentials";
static const string kServerName = SERVER_NAME;
2019-10-29 00:35:44 +08:00
void HttpSession::sendResponse(const char *pcStatus,
bool bClose,
const char *pcContentType,
const HttpSession::KeyValue &header,
const HttpBody::Ptr &body,
bool is_http_flv ){
2019-10-29 00:35:44 +08:00
GET_CONFIG(string,charSet,Http::kCharSet);
GET_CONFIG(uint32_t,keepAliveSec,Http::kKeepAliveSecond);
//body默认为空
int64_t size = 0;
if (body && body->remainSize()) {
//有body获取body大小
size = body->remainSize();
}
if(is_http_flv){
//http-flv直播是Keep-Alive类型
2019-10-29 00:35:44 +08:00
bClose = false;
}else if(size >= INT64_MAX){
//不固定长度的body那么发送完body后应该关闭socket以便浏览器做下载完毕的判断
bClose = true;
2019-10-29 00:35:44 +08:00
}
HttpSession::KeyValue &headerOut = const_cast<HttpSession::KeyValue &>(header);
2019-12-26 15:02:28 +08:00
headerOut.emplace(kDate, dateStr());
headerOut.emplace(kServer, kServerName);
headerOut.emplace(kConnection, bClose ? "close" : "keep-alive");
2019-10-29 00:35:44 +08:00
if(!bClose){
2019-12-26 15:02:28 +08:00
string keepAliveString = "timeout=";
keepAliveString += to_string(keepAliveSec);
keepAliveString += ", max=100";
headerOut.emplace(kKeepAlive,std::move(keepAliveString));
2019-10-29 00:35:44 +08:00
}
if(!_origin.empty()){
//设置跨域
2019-12-26 15:02:28 +08:00
headerOut.emplace(kAccessControlAllowOrigin,_origin);
headerOut.emplace(kAccessControlAllowCredentials, "true");
2019-10-29 00:35:44 +08:00
}
if(!is_http_flv && size >= 0 && size < INT64_MAX){
//文件长度为固定值,且不是http-flv强制设置Content-Length
2019-12-26 15:02:28 +08:00
headerOut[kContentLength] = to_string(size);
2019-10-29 00:35:44 +08:00
}
if(size && !pcContentType){
//有body时设置缺省类型
pcContentType = "text/plain";
}
if(size && pcContentType){
//有body时设置文件类型
2019-12-26 15:02:28 +08:00
string strContentType = pcContentType;
strContentType += "; charset=";
strContentType += charSet;
headerOut.emplace(kContentType,std::move(strContentType));
2019-10-29 00:35:44 +08:00
}
2019-10-28 16:50:15 +08:00
//发送http头
2019-12-26 15:02:28 +08:00
string str;
str.reserve(256);
str += "HTTP/1.1 " ;
str += pcStatus ;
str += "\r\n";
2019-10-28 16:50:15 +08:00
for (auto &pr : header) {
2019-12-26 15:02:28 +08:00
str += pr.first ;
str += ": ";
str += pr.second;
str += "\r\n";
2019-10-28 16:50:15 +08:00
}
2019-12-26 15:02:28 +08:00
str += "\r\n";
send(std::move(str));
2019-10-28 16:50:15 +08:00
_ticker.resetTime();
2019-10-29 00:35:44 +08:00
if(!size){
2019-10-28 16:50:15 +08:00
//没有body
if(bClose){
2019-11-30 11:38:00 +08:00
shutdown(SockException(Err_shutdown,StrPrinter << "close connection after send http header completed with status code:" << pcStatus));
2019-10-28 16:50:15 +08:00
}
return;
}
//发送http body
GET_CONFIG(uint32_t,sendBufSize,Http::kSendBufSize);
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
2019-11-30 11:38:00 +08:00
string status_code = pcStatus;
auto onFlush = [body,bClose,weakSelf,status_code]() {
2019-10-28 16:50:15 +08:00
auto strongSelf = weakSelf.lock();
if(!strongSelf){
//本对象已经销毁
return false;
}
while(true){
//更新超时计时器
strongSelf->_ticker.resetTime();
//读取文件
auto sendBuf = body->readData(sendBufSize);
if (!sendBuf) {
//文件读完
if(strongSelf->isSocketBusy() && bClose){
//套接字忙,我们等待触发下一次onFlush事件
//待所有数据flush到socket fd再移除onFlush事件监听
//标记文件读写完毕
return true;
}
//文件全部flush到socket fd可以直接关闭socket了
break;
}
//文件还未读完
if(strongSelf->send(sendBuf) == -1) {
//socket已经销毁不再监听onFlush事件
return false;
}
if(strongSelf->isSocketBusy()){
//socket忙那么停止继续写,等待下一次onFlush事件然后再读文件写socket
return true;
}
//socket还可写继续写socket
}
if(bClose) {
//最后一次flush事件文件也发送完毕了可以关闭socket了
2019-11-30 11:38:00 +08:00
strongSelf->shutdown(SockException(Err_shutdown, StrPrinter << "close connection after send http body completed with status code:" << status_code));
2019-10-28 16:50:15 +08:00
}
//不再监听onFlush事件
return false;
};
if(body->remainSize() > sendBufSize){
//文件下载提升发送性能
setSocketFlags();
}
onFlush();
_sock->setOnFlush(onFlush);
}
2017-12-08 22:37:17 +08:00
string HttpSession::urlDecode(const string &str){
2019-05-27 12:13:27 +08:00
auto ret = strCoding::UrlDecode(str);
2017-10-10 00:04:07 +08:00
#ifdef _WIN32
2019-05-28 17:14:36 +08:00
GET_CONFIG(string,charSet,Http::kCharSet);
2018-11-27 11:05:44 +08:00
bool isGb2312 = !strcasecmp(charSet.data(), "gb2312");
2017-10-10 00:04:07 +08:00
if (isGb2312) {
2017-12-08 22:37:17 +08:00
ret = strCoding::UTF8ToGB2312(ret);
2017-10-10 00:04:07 +08:00
}
#endif // _WIN32
2017-12-08 22:37:17 +08:00
return ret;
}
2017-10-10 00:04:07 +08:00
2019-09-16 17:42:52 +08:00
void HttpSession::urlDecode(Parser &parser){
2017-12-08 22:37:17 +08:00
parser.setUrl(urlDecode(parser.Url()));
2018-10-24 15:43:52 +08:00
for(auto &pr : _parser.getUrlArgs()){
2017-12-08 22:37:17 +08:00
const_cast<string &>(pr.second) = urlDecode(pr.second);
}
}
2017-04-01 16:35:56 +08:00
2019-09-16 17:42:52 +08:00
bool HttpSession::emitHttpEvent(bool doInvoke){
bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
2017-12-08 22:37:17 +08:00
/////////////////////异步回复Invoker///////////////////////////////
2017-04-10 17:24:06 +08:00
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
2019-10-28 16:50:15 +08:00
HttpResponseInvoker invoker = [weakSelf,bClose](const string &codeOut, const KeyValue &headerOut, const HttpBody::Ptr &body){
2017-04-10 17:24:06 +08:00
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
2019-10-28 16:50:15 +08:00
strongSelf->async([weakSelf,bClose,codeOut,headerOut,body]() {
2017-04-10 17:24:06 +08:00
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
2019-10-28 16:50:15 +08:00
//本对象已经销毁
2017-04-10 17:24:06 +08:00
return;
}
2019-10-29 00:35:44 +08:00
strongSelf->sendResponse(codeOut.data(), bClose, nullptr, headerOut, body);
2017-04-10 17:24:06 +08:00
});
};
2017-12-08 22:37:17 +08:00
///////////////////广播HTTP事件///////////////////////////
bool consumed = false;//该事件是否被消费
2018-10-24 17:17:55 +08:00
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastHttpRequest,_parser,invoker,consumed,*this);
2017-12-08 22:37:17 +08:00
if(!consumed && doInvoke){
//该事件无人消费所以返回404
2019-10-28 16:50:15 +08:00
invoker("404 Not Found",KeyValue(), HttpBody::Ptr());
2017-04-01 16:35:56 +08:00
}
2017-12-08 22:37:17 +08:00
return consumed;
}
2019-09-16 17:42:52 +08:00
void HttpSession::Handle_Req_POST(int64_t &content_len) {
2019-05-28 17:14:36 +08:00
GET_CONFIG(uint64_t,maxReqSize,Http::kMaxReqSize);
2018-09-20 23:05:32 +08:00
2018-10-24 15:43:52 +08:00
int64_t totalContentLen = _parser["Content-Length"].empty() ? -1 : atoll(_parser["Content-Length"].data());
2018-09-20 23:05:32 +08:00
2018-09-21 09:41:40 +08:00
if(totalContentLen == 0){
2018-09-21 09:59:04 +08:00
//content为空
//emitHttpEvent内部会选择是否关闭连接
2018-09-20 23:05:32 +08:00
emitHttpEvent(true);
2019-05-30 10:59:14 +08:00
return;
}
//根据Content-Length设置接收缓存大小
if(totalContentLen > 0){
_sock->setReadBuffer(std::make_shared<BufferRaw>(MIN(totalContentLen + 1,256 * 1024)));
}else{
//不定长度的Content-Length
_sock->setReadBuffer(std::make_shared<BufferRaw>(256 * 1024));
}
if(totalContentLen > 0 && totalContentLen < maxReqSize ){
//返回固定长度的content
2018-09-21 09:41:40 +08:00
content_len = totalContentLen;
2018-10-24 15:43:52 +08:00
auto parserCopy = _parser;
_contentCallBack = [this,parserCopy](const char *data,uint64_t len){
//恢复http头
2018-10-24 15:43:52 +08:00
_parser = parserCopy;
//设置content
2018-10-24 15:43:52 +08:00
_parser.setContent(string(data,len));
2018-09-21 09:59:04 +08:00
//触发http事件emitHttpEvent内部会选择是否关闭连接
emitHttpEvent(true);
//清空数据,节省内存
2018-10-24 15:43:52 +08:00
_parser.Clear();
2018-09-21 09:59:04 +08:00
//content已经接收完毕
return false;
};
}else{
//返回不固定长度的content
content_len = -1;
2018-10-24 15:43:52 +08:00
auto parserCopy = _parser;
2018-09-23 00:55:00 +08:00
std::shared_ptr<uint64_t> recvedContentLen = std::make_shared<uint64_t>(0);
bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
2018-09-21 09:59:04 +08:00
2018-10-24 15:43:52 +08:00
_contentCallBack = [this,parserCopy,totalContentLen,recvedContentLen,bClose](const char *data,uint64_t len){
2018-09-23 00:55:00 +08:00
*(recvedContentLen) += len;
2018-09-21 09:41:40 +08:00
2018-09-23 00:55:00 +08:00
onRecvUnlimitedContent(parserCopy,data,len,totalContentLen,*(recvedContentLen));
2018-09-21 09:41:40 +08:00
if(*(recvedContentLen) < totalContentLen){
//数据还没接收完毕
2018-10-24 15:43:52 +08:00
//_contentCallBack是可持续的后面还要处理后续content数据
2018-09-21 09:41:40 +08:00
return true;
}
//数据接收完毕
if(!bClose){
//keep-alive类型连接
//content接收完毕后续都是http header
setContentLen(0);
2018-09-21 09:59:04 +08:00
//content已经接收完毕
2018-09-21 09:41:40 +08:00
return false;
}
//连接类型是close类型收完content就关闭连接
2019-05-29 18:08:50 +08:00
shutdown(SockException(Err_shutdown,"recv http content completed"));
2018-09-21 09:59:04 +08:00
//content已经接收完毕
2018-09-21 09:41:40 +08:00
return false ;
};
}
2018-09-21 09:59:04 +08:00
//有后续content数据要处理,暂时不关闭连接
2017-04-10 17:24:06 +08:00
}
2019-09-16 17:42:52 +08:00
void HttpSession::sendNotFound(bool bClose) {
2019-05-28 17:14:36 +08:00
GET_CONFIG(string,notFound,Http::kNotFound);
2019-10-29 00:35:44 +08:00
sendResponse("404 Not Found", bClose,"text/html",KeyValue(),std::make_shared<HttpStringBody>(notFound));
2017-04-01 16:35:56 +08:00
}
void HttpSession::setSocketFlags(){
GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay);
if(!ultraLowDelay) {
//推流模式下关闭TCP_NODELAY会增加推流端的延时但是服务器性能将提高
SockUtil::setNoDelay(_sock->rawFD(), false);
//播放模式下开启MSG_MORE会增加延时但是能提高发送性能
(*this) << SocketFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE);
}
}
2018-08-30 19:29:54 +08:00
void HttpSession::onWrite(const Buffer::Ptr &buffer) {
_ticker.resetTime();
2019-08-12 18:14:51 +08:00
if(!_flv_over_websocket){
_ui64TotalBytes += buffer->size();
send(buffer);
return;
}
WebSocketHeader header;
header._fin = true;
header._reserved = 0;
header._opcode = WebSocketHeader::BINARY;
header._mask_flag = false;
WebSocketSplitter::encode(header,buffer);
2019-08-12 18:14:51 +08:00
}
void HttpSession::onWebSocketEncodeData(const Buffer::Ptr &buffer){
_ui64TotalBytes += buffer->size();
send(buffer);
2017-12-15 16:01:21 +08:00
}
2018-08-30 19:29:54 +08:00
void HttpSession::onDetach() {
2019-05-29 18:08:50 +08:00
shutdown(SockException(Err_shutdown,"rtmp ring buffer detached"));
2018-08-30 19:29:54 +08:00
}
std::shared_ptr<FlvMuxer> HttpSession::getSharedPtr(){
return dynamic_pointer_cast<FlvMuxer>(shared_from_this());
2018-01-30 11:47:56 +08:00
}
2018-10-24 17:17:55 +08:00
} /* namespace mediakit */