2019-12-27 12:22:17 +08:00
|
|
|
|
/*
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
2017-09-27 16:20:30 +08:00
|
|
|
|
*
|
2021-01-17 18:31:50 +08:00
|
|
|
|
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
|
2017-09-27 16:20:30 +08:00
|
|
|
|
*
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* Use of this source code is governed by MIT license that can be found in the
|
|
|
|
|
* LICENSE file in the root of the source tree. All contributing project authors
|
|
|
|
|
* may be found in the AUTHORS file in the root of the source tree.
|
2017-04-01 16:35:56 +08:00
|
|
|
|
*/
|
2020-04-04 20:30:09 +08:00
|
|
|
|
|
2017-04-01 16:35:56 +08:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <algorithm>
|
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"
|
2021-01-02 21:24:06 +08:00
|
|
|
|
#include "HttpConst.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);
|
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
|
|
|
|
}
|
|
|
|
|
|
2021-01-19 16:05:38 +08:00
|
|
|
|
void HttpSession::Handle_Req_HEAD(ssize_t &content_len){
|
2020-03-16 09:33:00 +08:00
|
|
|
|
//暂时全部返回200 OK,因为HTTP GET存在按需生成流的操作,所以不能按照HTTP GET的流程返回
|
|
|
|
|
//如果直接返回404,那么又会导致按需生成流的逻辑失效,所以HTTP HEAD在静态文件或者已存在资源时才有效
|
|
|
|
|
//对于按需生成流的直播场景并不适用
|
2021-09-29 00:46:09 +08:00
|
|
|
|
sendResponse(200, false);
|
2020-03-11 20:58:41 +08:00
|
|
|
|
}
|
2021-06-28 10:09:44 +08:00
|
|
|
|
|
|
|
|
|
void HttpSession::Handle_Req_OPTIONS(ssize_t &content_len) {
|
|
|
|
|
KeyValue header;
|
|
|
|
|
header.emplace("Allow", "GET, POST, OPTIONS");
|
|
|
|
|
header.emplace("Access-Control-Allow-Origin", "*");
|
|
|
|
|
header.emplace("Access-Control-Allow-Credentials", "true");
|
|
|
|
|
header.emplace("Access-Control-Request-Methods", "GET, POST, OPTIONS");
|
|
|
|
|
header.emplace("Access-Control-Request-Headers", "Accept,Accept-Language,Content-Language,Content-Type");
|
|
|
|
|
sendResponse(200, true, nullptr, header);
|
2021-06-25 10:59:06 +08:00
|
|
|
|
}
|
2020-03-11 20:58:41 +08:00
|
|
|
|
|
2021-01-19 16:05:38 +08:00
|
|
|
|
ssize_t HttpSession::onRecvHeader(const char *header,size_t len) {
|
|
|
|
|
typedef void (HttpSession::*HttpCMDHandle)(ssize_t &);
|
2020-03-20 11:51:24 +08:00
|
|
|
|
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);
|
2020-03-16 09:33:00 +08:00
|
|
|
|
s_func_map.emplace("HEAD",&HttpSession::Handle_Req_HEAD);
|
2021-06-25 10:59:06 +08:00
|
|
|
|
s_func_map.emplace("OPTIONS",&HttpSession::Handle_Req_OPTIONS);
|
2020-03-11 20:58:41 +08:00
|
|
|
|
}, nullptr);
|
2018-08-10 11:55:18 +08:00
|
|
|
|
|
2020-03-20 11:51:24 +08:00
|
|
|
|
_parser.Parse(header);
|
2021-09-03 18:02:31 +08:00
|
|
|
|
CHECK(_parser.Url()[0] == '/');
|
|
|
|
|
|
2020-03-20 11:51:24 +08:00
|
|
|
|
urlDecode(_parser);
|
|
|
|
|
string cmd = _parser.Method();
|
|
|
|
|
auto it = s_func_map.find(cmd);
|
|
|
|
|
if (it == s_func_map.end()) {
|
2020-04-24 12:39:22 +08:00
|
|
|
|
WarnP(this) << "不支持该命令:" << cmd;
|
2021-01-02 21:24:06 +08:00
|
|
|
|
sendResponse(405, true);
|
2019-05-29 18:08:50 +08:00
|
|
|
|
return 0;
|
2020-03-20 11:51:24 +08:00
|
|
|
|
}
|
2018-09-20 17:50:58 +08:00
|
|
|
|
|
2019-07-30 16:07:00 +08:00
|
|
|
|
//跨域
|
|
|
|
|
_origin = _parser["Origin"];
|
|
|
|
|
|
|
|
|
|
//默认后面数据不是content而是header
|
2021-01-19 16:05:38 +08:00
|
|
|
|
ssize_t content_len = 0;
|
2020-03-20 11:51:24 +08:00
|
|
|
|
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()));
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-20 11:51:24 +08:00
|
|
|
|
//清空解析器节省内存
|
|
|
|
|
_parser.Clear();
|
|
|
|
|
//返回content长度
|
|
|
|
|
return content_len;
|
2017-04-01 16:35:56 +08:00
|
|
|
|
}
|
2018-09-20 17:50:58 +08:00
|
|
|
|
|
2021-01-17 18:31:50 +08:00
|
|
|
|
void HttpSession::onRecvContent(const char *data,size_t len) {
|
2020-03-20 11:51:24 +08:00
|
|
|
|
if(_contentCallBack){
|
|
|
|
|
if(!_contentCallBack(data,len)){
|
|
|
|
|
_contentCallBack = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-20 17:50:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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());
|
2018-09-20 17:50:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-01 16:35:56 +08:00
|
|
|
|
void HttpSession::onError(const SockException& err) {
|
2021-08-13 10:59:13 +08:00
|
|
|
|
if (_is_live_stream) {
|
2020-09-20 00:21:46 +08:00
|
|
|
|
//flv/ts播放器
|
2021-08-13 10:59:13 +08:00
|
|
|
|
uint64_t duration = _ticker.createdTime() / 1000;
|
2020-09-20 19:45:37 +08:00
|
|
|
|
WarnP(this) << "FLV/TS/FMP4播放器("
|
2019-10-23 12:00:53 +08:00
|
|
|
|
<< _mediaInfo._vhost << "/"
|
|
|
|
|
<< _mediaInfo._app << "/"
|
|
|
|
|
<< _mediaInfo._streamid
|
2020-02-13 12:10:08 +08:00
|
|
|
|
<< ")断开:" << err.what()
|
|
|
|
|
<< ",耗时(s):" << duration;
|
2019-10-23 12:00:53 +08:00
|
|
|
|
|
2021-08-13 10:59:13 +08:00
|
|
|
|
GET_CONFIG(uint32_t, iFlowThreshold, General::kFlowThreshold);
|
|
|
|
|
if (_total_bytes_usage >= iFlowThreshold * 1024) {
|
|
|
|
|
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _mediaInfo, _total_bytes_usage,
|
|
|
|
|
duration, true, static_cast<SockInfo &>(*this));
|
2019-10-23 12:00:53 +08:00
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//http客户端
|
2021-08-13 10:59:13 +08:00
|
|
|
|
TraceP(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){
|
2020-03-20 11:51:24 +08:00
|
|
|
|
//1分钟超时
|
2021-08-12 16:07:31 +08:00
|
|
|
|
shutdown(SockException(Err_timeout,"session timeout"));
|
2020-03-20 11:51:24 +08:00
|
|
|
|
}
|
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(){
|
2020-03-20 11:51:24 +08:00
|
|
|
|
auto Sec_WebSocket_Key = _parser["Sec-WebSocket-Key"];
|
2020-08-08 12:17:06 +08:00
|
|
|
|
if (Sec_WebSocket_Key.empty()) {
|
2020-03-20 11:51:24 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-09-20 00:21:46 +08:00
|
|
|
|
auto Sec_WebSocket_Accept = encodeBase64(SHA1::encode_bin(Sec_WebSocket_Key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
|
2020-03-20 11:51:24 +08:00
|
|
|
|
|
|
|
|
|
KeyValue headerOut;
|
|
|
|
|
headerOut["Upgrade"] = "websocket";
|
|
|
|
|
headerOut["Connection"] = "Upgrade";
|
|
|
|
|
headerOut["Sec-WebSocket-Accept"] = Sec_WebSocket_Accept;
|
2020-08-08 12:17:06 +08:00
|
|
|
|
if (!_parser["Sec-WebSocket-Protocol"].empty()) {
|
2020-03-20 11:51:24 +08:00
|
|
|
|
headerOut["Sec-WebSocket-Protocol"] = _parser["Sec-WebSocket-Protocol"];
|
|
|
|
|
}
|
2019-08-23 09:45:01 +08:00
|
|
|
|
|
2020-08-08 12:17:06 +08:00
|
|
|
|
auto res_cb = [this, headerOut]() {
|
2020-09-20 00:21:46 +08:00
|
|
|
|
_live_over_websocket = true;
|
2021-01-02 21:24:06 +08:00
|
|
|
|
sendResponse(101, false, nullptr, headerOut, nullptr, true);
|
2019-08-23 09:45:01 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//判断是否为websocket-flv
|
2020-09-20 00:21:46 +08:00
|
|
|
|
if (checkLiveStreamFlv(res_cb)) {
|
2019-08-23 09:45:01 +08:00
|
|
|
|
//这里是websocket-flv直播请求
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
//判断是否为websocket-ts
|
|
|
|
|
if (checkLiveStreamTS(res_cb)) {
|
|
|
|
|
//这里是websocket-ts直播请求
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-20 19:45:37 +08:00
|
|
|
|
//判断是否为websocket-fmp4
|
|
|
|
|
if (checkLiveStreamFMP4(res_cb)) {
|
|
|
|
|
//这里是websocket-fmp4直播请求
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
//这是普通的websocket连接
|
2020-08-08 12:17:06 +08:00
|
|
|
|
if (!onWebSocketConnect(_parser)) {
|
2021-01-02 21:24:06 +08:00
|
|
|
|
sendResponse(501, true, nullptr, headerOut);
|
2019-09-16 17:42:52 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-01-02 21:24:06 +08:00
|
|
|
|
sendResponse(101, false, nullptr, headerOut, nullptr, true);
|
2020-03-20 11:51:24 +08:00
|
|
|
|
return true;
|
2018-09-20 18:20:43 +08:00
|
|
|
|
}
|
2019-11-30 11:38:00 +08:00
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
bool HttpSession::checkLiveStream(const string &schema, const string &url_suffix, const function<void(const MediaSource::Ptr &src)> &cb){
|
2020-09-20 00:55:22 +08:00
|
|
|
|
auto pos = strcasestr(_parser.Url().data(), url_suffix.data());
|
|
|
|
|
if (!pos || pos + url_suffix.size() != 1 + &_parser.Url().back()) {
|
2020-09-20 00:21:46 +08:00
|
|
|
|
//未找到后缀
|
2020-03-20 11:51:24 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-15 15:31:00 +08:00
|
|
|
|
//url去除特殊后缀
|
|
|
|
|
auto url = _parser.Url().substr(0, _parser.Url().size() - url_suffix.size());
|
|
|
|
|
//带参数的url
|
|
|
|
|
url = _parser.Params().empty() ? url : (url + "?" + _parser.Params());
|
|
|
|
|
//解析带上协议+参数完整的url
|
|
|
|
|
_mediaInfo.parse(schema + "://" + _parser["Host"] + url);
|
|
|
|
|
|
|
|
|
|
if (_mediaInfo._app.empty() || _mediaInfo._streamid.empty()) {
|
2020-03-20 11:51:24 +08:00
|
|
|
|
//url不合法
|
2019-05-27 22:49:30 +08:00
|
|
|
|
return false;
|
2020-03-20 11:51:24 +08:00
|
|
|
|
}
|
2021-09-15 15:31:00 +08:00
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
bool close_flag = !strcasecmp(_parser["Connection"].data(), "close");
|
|
|
|
|
weak_ptr<HttpSession> weak_self = dynamic_pointer_cast<HttpSession>(shared_from_this());
|
2020-05-25 17:38:36 +08:00
|
|
|
|
|
|
|
|
|
//鉴权结果回调
|
2020-09-20 00:21:46 +08:00
|
|
|
|
auto onRes = [cb, weak_self, close_flag](const string &err) {
|
|
|
|
|
auto strong_self = weak_self.lock();
|
|
|
|
|
if (!strong_self) {
|
2019-05-27 22:49:30 +08:00
|
|
|
|
//本对象已经销毁
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-05-25 17:38:36 +08:00
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
if (!err.empty()) {
|
2020-05-25 17:38:36 +08:00
|
|
|
|
//播放鉴权失败
|
2021-01-02 21:24:06 +08:00
|
|
|
|
strong_self->sendResponse(401, close_flag, nullptr, KeyValue(), std::make_shared<HttpStringBody>(err));
|
2018-02-05 15:56:44 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2020-05-25 17:38:36 +08:00
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
//异步查找直播流
|
|
|
|
|
MediaSource::findAsync(strong_self->_mediaInfo, strong_self, [weak_self, close_flag, cb](const MediaSource::Ptr &src) {
|
|
|
|
|
auto strong_self = weak_self.lock();
|
|
|
|
|
if (!strong_self) {
|
2020-05-25 17:38:36 +08:00
|
|
|
|
//本对象已经销毁
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-20 00:21:46 +08:00
|
|
|
|
if (!src) {
|
2020-05-25 17:38:36 +08:00
|
|
|
|
//未找到该流
|
2020-09-20 00:21:46 +08:00
|
|
|
|
strong_self->sendNotFound(close_flag);
|
2020-05-25 17:38:36 +08:00
|
|
|
|
return;
|
2019-05-27 22:49:30 +08:00
|
|
|
|
}
|
2020-09-20 00:21:46 +08:00
|
|
|
|
strong_self->_is_live_stream = true;
|
|
|
|
|
//触发回调
|
|
|
|
|
cb(src);
|
2020-05-25 17:38:36 +08:00
|
|
|
|
});
|
|
|
|
|
};
|
2019-05-27 22:49:30 +08:00
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
Broadcast::AuthInvoker invoker = [weak_self, onRes](const string &err) {
|
|
|
|
|
auto strongSelf = weak_self.lock();
|
2020-05-25 17:38:36 +08:00
|
|
|
|
if (!strongSelf) {
|
|
|
|
|
return;
|
2019-05-27 22:49:30 +08:00
|
|
|
|
}
|
2020-05-25 17:38:36 +08:00
|
|
|
|
strongSelf->async([onRes, err]() {
|
|
|
|
|
onRes(err);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed, _mediaInfo, invoker, static_cast<SockInfo &>(*this));
|
|
|
|
|
if (!flag) {
|
|
|
|
|
//该事件无人监听,默认不鉴权
|
|
|
|
|
onRes("");
|
|
|
|
|
}
|
2018-02-05 15:56:44 +08:00
|
|
|
|
return true;
|
2017-12-15 16:01:21 +08:00
|
|
|
|
}
|
2019-05-16 17:09:29 +08:00
|
|
|
|
|
2020-09-20 19:45:37 +08:00
|
|
|
|
//http-fmp4 链接格式:http://vhost-url:port/app/streamid.live.mp4?key1=value1&key2=value2
|
|
|
|
|
bool HttpSession::checkLiveStreamFMP4(const function<void()> &cb){
|
|
|
|
|
return checkLiveStream(FMP4_SCHEMA, ".live.mp4", [this, cb](const MediaSource::Ptr &src) {
|
|
|
|
|
auto fmp4_src = dynamic_pointer_cast<FMP4MediaSource>(src);
|
|
|
|
|
assert(fmp4_src);
|
|
|
|
|
if (!cb) {
|
|
|
|
|
//找到源,发送http头,负载后续发送
|
2021-01-02 21:24:06 +08:00
|
|
|
|
sendResponse(200, false, HttpFileManager::getContentType(".mp4").data(), KeyValue(), nullptr, true);
|
2020-09-20 19:45:37 +08:00
|
|
|
|
} else {
|
|
|
|
|
//自定义发送http头
|
|
|
|
|
cb();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//直播牺牲延时提升发送性能
|
|
|
|
|
setSocketFlags();
|
|
|
|
|
onWrite(std::make_shared<BufferString>(fmp4_src->getInitSegment()), true);
|
|
|
|
|
weak_ptr<HttpSession> weak_self = dynamic_pointer_cast<HttpSession>(shared_from_this());
|
2021-09-29 00:04:36 +08:00
|
|
|
|
fmp4_src->pause(false);
|
2020-09-20 19:45:37 +08:00
|
|
|
|
_fmp4_reader = fmp4_src->getRing()->attach(getPoller());
|
|
|
|
|
_fmp4_reader->setDetachCB([weak_self]() {
|
|
|
|
|
auto strong_self = weak_self.lock();
|
|
|
|
|
if (!strong_self) {
|
|
|
|
|
//本对象已经销毁
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
strong_self->shutdown(SockException(Err_shutdown, "fmp4 ring buffer detached"));
|
|
|
|
|
});
|
|
|
|
|
_fmp4_reader->setReadCB([weak_self](const FMP4MediaSource::RingDataType &fmp4_list) {
|
|
|
|
|
auto strong_self = weak_self.lock();
|
|
|
|
|
if (!strong_self) {
|
|
|
|
|
//本对象已经销毁
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-01-17 18:31:50 +08:00
|
|
|
|
size_t i = 0;
|
|
|
|
|
auto size = fmp4_list->size();
|
2020-09-20 19:45:37 +08:00
|
|
|
|
fmp4_list->for_each([&](const FMP4Packet::Ptr &ts) {
|
|
|
|
|
strong_self->onWrite(ts, ++i == size);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-20 00:55:22 +08:00
|
|
|
|
//http-ts 链接格式:http://vhost-url:port/app/streamid.live.ts?key1=value1&key2=value2
|
2020-09-20 00:21:46 +08:00
|
|
|
|
bool HttpSession::checkLiveStreamTS(const function<void()> &cb){
|
2020-09-20 00:55:22 +08:00
|
|
|
|
return checkLiveStream(TS_SCHEMA, ".live.ts", [this, cb](const MediaSource::Ptr &src) {
|
2020-09-20 00:21:46 +08:00
|
|
|
|
auto ts_src = dynamic_pointer_cast<TSMediaSource>(src);
|
|
|
|
|
assert(ts_src);
|
|
|
|
|
if (!cb) {
|
|
|
|
|
//找到源,发送http头,负载后续发送
|
2021-01-02 21:24:06 +08:00
|
|
|
|
sendResponse(200, false, HttpFileManager::getContentType(".ts").data(), KeyValue(), nullptr, true);
|
2020-09-20 00:21:46 +08:00
|
|
|
|
} else {
|
|
|
|
|
//自定义发送http头
|
|
|
|
|
cb();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//直播牺牲延时提升发送性能
|
|
|
|
|
setSocketFlags();
|
2020-09-20 00:57:34 +08:00
|
|
|
|
weak_ptr<HttpSession> weak_self = dynamic_pointer_cast<HttpSession>(shared_from_this());
|
2021-09-29 00:04:36 +08:00
|
|
|
|
ts_src->pause(false);
|
2020-09-20 00:21:46 +08:00
|
|
|
|
_ts_reader = ts_src->getRing()->attach(getPoller());
|
2020-09-20 00:57:34 +08:00
|
|
|
|
_ts_reader->setDetachCB([weak_self](){
|
|
|
|
|
auto strong_self = weak_self.lock();
|
|
|
|
|
if (!strong_self) {
|
|
|
|
|
//本对象已经销毁
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
strong_self->shutdown(SockException(Err_shutdown,"ts ring buffer detached"));
|
|
|
|
|
});
|
|
|
|
|
_ts_reader->setReadCB([weak_self](const TSMediaSource::RingDataType &ts_list) {
|
|
|
|
|
auto strong_self = weak_self.lock();
|
|
|
|
|
if (!strong_self) {
|
2020-09-20 00:21:46 +08:00
|
|
|
|
//本对象已经销毁
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-01-17 18:31:50 +08:00
|
|
|
|
size_t i = 0;
|
|
|
|
|
auto size = ts_list->size();
|
2020-09-20 00:21:46 +08:00
|
|
|
|
ts_list->for_each([&](const TSPacket::Ptr &ts) {
|
2020-09-20 00:57:34 +08:00
|
|
|
|
strong_self->onWrite(ts, ++i == size);
|
2020-09-20 00:21:46 +08:00
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//http-flv 链接格式:http://vhost-url:port/app/streamid.flv?key1=value1&key2=value2
|
|
|
|
|
bool HttpSession::checkLiveStreamFlv(const function<void()> &cb){
|
|
|
|
|
return checkLiveStream(RTMP_SCHEMA, ".flv", [this, cb](const MediaSource::Ptr &src) {
|
|
|
|
|
auto rtmp_src = dynamic_pointer_cast<RtmpMediaSource>(src);
|
|
|
|
|
assert(rtmp_src);
|
|
|
|
|
if (!cb) {
|
|
|
|
|
//找到源,发送http头,负载后续发送
|
2021-01-02 21:24:06 +08:00
|
|
|
|
sendResponse(200, false, HttpFileManager::getContentType(".flv").data(), KeyValue(), nullptr, true);
|
2020-09-20 00:21:46 +08:00
|
|
|
|
} else {
|
|
|
|
|
//自定义发送http头
|
|
|
|
|
cb();
|
|
|
|
|
}
|
|
|
|
|
//直播牺牲延时提升发送性能
|
|
|
|
|
setSocketFlags();
|
2021-01-09 19:03:02 +08:00
|
|
|
|
|
|
|
|
|
//非H264/AAC时打印警告日志,防止用户提无效问题
|
|
|
|
|
auto tracks = src->getTracks(false);
|
|
|
|
|
for (auto &track : tracks) {
|
|
|
|
|
switch (track->getCodecId()) {
|
|
|
|
|
case CodecH264:
|
|
|
|
|
case CodecAAC:
|
|
|
|
|
break;
|
|
|
|
|
default: {
|
|
|
|
|
WarnP(this) << "flv播放器一般只支持H264和AAC编码,该编码格式可能不被播放器支持:" << track->getCodecName();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
start(getPoller(), rtmp_src);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-19 16:05:38 +08:00
|
|
|
|
void HttpSession::Handle_Req_GET(ssize_t &content_len) {
|
2020-03-16 09:33:00 +08:00
|
|
|
|
Handle_Req_GET_l(content_len, true);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-19 16:05:38 +08:00
|
|
|
|
void HttpSession::Handle_Req_GET_l(ssize_t &content_len, bool sendBody) {
|
2020-03-20 11:51:24 +08:00
|
|
|
|
//先看看是否为WebSocket请求
|
2020-09-20 00:21:46 +08:00
|
|
|
|
if (checkWebSocket()) {
|
2020-03-20 11:51:24 +08:00
|
|
|
|
content_len = -1;
|
2021-01-17 18:31:50 +08:00
|
|
|
|
_contentCallBack = [this](const char *data, size_t len) {
|
2020-09-20 00:21:46 +08:00
|
|
|
|
WebSocketSplitter::decode((uint8_t *) data, len);
|
2020-03-20 11:51:24 +08:00
|
|
|
|
//_contentCallBack是可持续的,后面还要处理后续数据
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-09-20 18:20:43 +08:00
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
if (emitHttpEvent(false)) {
|
2019-10-29 09:16:52 +08:00
|
|
|
|
//拦截http api事件
|
2020-03-20 11:51:24 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2018-09-20 18:20:43 +08:00
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
if (checkLiveStreamFlv()) {
|
2019-10-29 09:16:52 +08:00
|
|
|
|
//拦截http-flv播放器
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
if (checkLiveStreamTS()) {
|
|
|
|
|
//拦截http-ts播放器
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-05-16 17:31:48 +08:00
|
|
|
|
|
2020-09-20 19:45:37 +08:00
|
|
|
|
if (checkLiveStreamFMP4()) {
|
|
|
|
|
//拦截http-fmp4播放器
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
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());
|
2021-01-02 21:24:06 +08:00
|
|
|
|
HttpFileManager::onAccessPath(*this, _parser, [weakSelf, bClose](int code, const string &content_type,
|
2019-11-30 11:38:00 +08:00
|
|
|
|
const StrCaseMap &responseHeader, const HttpBody::Ptr &body) {
|
|
|
|
|
auto strongSelf = weakSelf.lock();
|
|
|
|
|
if (!strongSelf) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
return;
|
2019-05-16 17:31:48 +08:00
|
|
|
|
}
|
2021-01-02 21:24:06 +08:00
|
|
|
|
strongSelf->async([weakSelf, bClose, code, content_type, responseHeader, body]() {
|
2019-11-30 11:38:00 +08:00
|
|
|
|
auto strongSelf = weakSelf.lock();
|
|
|
|
|
if (!strongSelf) {
|
|
|
|
|
return;
|
2019-06-14 18:42:09 +08:00
|
|
|
|
}
|
2021-01-02 21:24:06 +08:00
|
|
|
|
strongSelf->sendResponse(code, 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-28 13:11:41 +08:00
|
|
|
|
class AsyncSenderData {
|
|
|
|
|
public:
|
|
|
|
|
friend class AsyncSender;
|
|
|
|
|
typedef std::shared_ptr<AsyncSenderData> Ptr;
|
|
|
|
|
AsyncSenderData(const TcpSession::Ptr &session, const HttpBody::Ptr &body, bool close_when_complete) {
|
|
|
|
|
_session = dynamic_pointer_cast<HttpSession>(session);
|
|
|
|
|
_body = body;
|
|
|
|
|
_close_when_complete = close_when_complete;
|
|
|
|
|
}
|
|
|
|
|
~AsyncSenderData() = default;
|
|
|
|
|
private:
|
|
|
|
|
std::weak_ptr<HttpSession> _session;
|
|
|
|
|
HttpBody::Ptr _body;
|
|
|
|
|
bool _close_when_complete;
|
|
|
|
|
bool _read_complete = false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class AsyncSender {
|
|
|
|
|
public:
|
|
|
|
|
typedef std::shared_ptr<AsyncSender> Ptr;
|
|
|
|
|
static bool onSocketFlushed(const AsyncSenderData::Ptr &data) {
|
|
|
|
|
if (data->_read_complete) {
|
|
|
|
|
if (data->_close_when_complete) {
|
|
|
|
|
//发送完毕需要关闭socket
|
|
|
|
|
shutdown(data->_session.lock());
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GET_CONFIG(uint32_t, sendBufSize, Http::kSendBufSize);
|
|
|
|
|
data->_body->readDataAsync(sendBufSize, [data](const Buffer::Ptr &sendBuf) {
|
|
|
|
|
auto session = data->_session.lock();
|
|
|
|
|
if (!session) {
|
|
|
|
|
//本对象已经销毁
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
session->async([data, sendBuf]() {
|
|
|
|
|
auto session = data->_session.lock();
|
|
|
|
|
if (!session) {
|
|
|
|
|
//本对象已经销毁
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
onRequestData(data, session, sendBuf);
|
|
|
|
|
}, false);
|
|
|
|
|
});
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
static void onRequestData(const AsyncSenderData::Ptr &data, const std::shared_ptr<HttpSession> &session, const Buffer::Ptr &sendBuf) {
|
|
|
|
|
session->_ticker.resetTime();
|
|
|
|
|
if (sendBuf && session->send(sendBuf) != -1) {
|
|
|
|
|
//文件还未读完,还需要继续发送
|
|
|
|
|
if (!session->isSocketBusy()) {
|
|
|
|
|
//socket还可写,继续请求数据
|
|
|
|
|
onSocketFlushed(data);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
//文件写完了
|
|
|
|
|
data->_read_complete = true;
|
|
|
|
|
if (!session->isSocketBusy() && data->_close_when_complete) {
|
|
|
|
|
shutdown(session);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void shutdown(const std::shared_ptr<HttpSession> &session) {
|
|
|
|
|
if(session){
|
|
|
|
|
session->shutdown(SockException(Err_shutdown, StrPrinter << "close connection after send http body completed."));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
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";
|
|
|
|
|
|
2021-01-02 21:24:06 +08:00
|
|
|
|
void HttpSession::sendResponse(int code,
|
2019-10-29 00:35:44 +08:00
|
|
|
|
bool bClose,
|
|
|
|
|
const char *pcContentType,
|
|
|
|
|
const HttpSession::KeyValue &header,
|
|
|
|
|
const HttpBody::Ptr &body,
|
2020-08-08 12:17:06 +08:00
|
|
|
|
bool no_content_length ){
|
2019-10-29 00:35:44 +08:00
|
|
|
|
GET_CONFIG(string,charSet,Http::kCharSet);
|
|
|
|
|
GET_CONFIG(uint32_t,keepAliveSec,Http::kKeepAliveSecond);
|
|
|
|
|
|
|
|
|
|
//body默认为空
|
2021-01-19 16:05:38 +08:00
|
|
|
|
ssize_t size = 0;
|
2019-10-29 00:35:44 +08:00
|
|
|
|
if (body && body->remainSize()) {
|
|
|
|
|
//有body,获取body大小
|
|
|
|
|
size = body->remainSize();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-08 12:17:06 +08:00
|
|
|
|
if(no_content_length){
|
2019-12-24 10:25:28 +08:00
|
|
|
|
//http-flv直播是Keep-Alive类型
|
2019-10-29 00:35:44 +08:00
|
|
|
|
bClose = false;
|
2021-02-04 18:09:06 +08:00
|
|
|
|
}else if((size_t) size >= SIZE_MAX || size < 0 ){
|
2019-12-24 10:25:28 +08:00
|
|
|
|
//不固定长度的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());
|
2021-10-16 16:58:03 +08:00
|
|
|
|
headerOut.emplace(kServer, kServerName);
|
2019-12-26 15:02:28 +08:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2021-02-07 22:56:36 +08:00
|
|
|
|
if(!no_content_length && size >= 0 && (size_t)size < SIZE_MAX){
|
2019-12-24 10:25:28 +08:00
|
|
|
|
//文件长度为固定值,且不是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";
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-31 18:24:03 +08:00
|
|
|
|
if((size || no_content_length) && pcContentType){
|
2019-10-29 00:35:44 +08:00
|
|
|
|
//有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 " ;
|
2021-01-02 21:26:23 +08:00
|
|
|
|
str += to_string(code);
|
|
|
|
|
str += ' ';
|
2021-01-02 21:24:06 +08:00
|
|
|
|
str += getHttpStatusMessage(code) ;
|
2019-12-26 15:02:28 +08:00
|
|
|
|
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";
|
2020-04-23 17:50:12 +08:00
|
|
|
|
SockSender::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){
|
2021-01-02 21:24:06 +08:00
|
|
|
|
shutdown(SockException(Err_shutdown,StrPrinter << "close connection after send http header completed with status code:" << code));
|
2019-10-28 16:50:15 +08:00
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-28 13:11:41 +08:00
|
|
|
|
GET_CONFIG(uint32_t, sendBufSize, Http::kSendBufSize);
|
2019-10-28 16:50:15 +08:00
|
|
|
|
if(body->remainSize() > sendBufSize){
|
|
|
|
|
//文件下载提升发送性能
|
|
|
|
|
setSocketFlags();
|
|
|
|
|
}
|
2019-12-28 13:11:41 +08:00
|
|
|
|
|
|
|
|
|
//发送http body
|
|
|
|
|
AsyncSenderData::Ptr data = std::make_shared<AsyncSenderData>(shared_from_this(),body,bClose);
|
2020-09-12 19:03:52 +08:00
|
|
|
|
getSock()->setOnFlush([data](){
|
2019-12-28 13:11:41 +08:00
|
|
|
|
return AsyncSender::onSocketFlushed(data);
|
|
|
|
|
});
|
|
|
|
|
AsyncSender::onSocketFlushed(data);
|
2019-10-28 16:50:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-08 22:37:17 +08:00
|
|
|
|
string HttpSession::urlDecode(const string &str){
|
2020-03-20 11:51:24 +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);
|
2020-03-20 11:51:24 +08:00
|
|
|
|
bool isGb2312 = !strcasecmp(charSet.data(), "gb2312");
|
|
|
|
|
if (isGb2312) {
|
|
|
|
|
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){
|
2020-03-20 11:51:24 +08:00
|
|
|
|
parser.setUrl(urlDecode(parser.Url()));
|
|
|
|
|
for(auto &pr : _parser.getUrlArgs()){
|
|
|
|
|
const_cast<string &>(pr.second) = urlDecode(pr.second);
|
|
|
|
|
}
|
2017-12-08 22:37:17 +08:00
|
|
|
|
}
|
2017-04-01 16:35:56 +08:00
|
|
|
|
|
2019-09-16 17:42:52 +08:00
|
|
|
|
bool HttpSession::emitHttpEvent(bool doInvoke){
|
2019-11-30 14:29:44 +08:00
|
|
|
|
bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
|
2020-03-20 11:51:24 +08:00
|
|
|
|
/////////////////////异步回复Invoker///////////////////////////////
|
|
|
|
|
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
|
2021-01-02 21:24:06 +08:00
|
|
|
|
HttpResponseInvoker invoker = [weakSelf,bClose](int code, const KeyValue &headerOut, const HttpBody::Ptr &body){
|
2020-03-20 11:51:24 +08:00
|
|
|
|
auto strongSelf = weakSelf.lock();
|
|
|
|
|
if(!strongSelf) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-01-02 21:24:06 +08:00
|
|
|
|
strongSelf->async([weakSelf, bClose, code, headerOut, body]() {
|
2020-03-20 11:51:24 +08:00
|
|
|
|
auto strongSelf = weakSelf.lock();
|
2021-01-02 21:24:06 +08:00
|
|
|
|
if (!strongSelf) {
|
2019-10-28 16:50:15 +08:00
|
|
|
|
//本对象已经销毁
|
2020-03-20 11:51:24 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2021-01-02 21:24:06 +08:00
|
|
|
|
strongSelf->sendResponse(code, bClose, nullptr, headerOut, body);
|
2020-03-20 11:51:24 +08:00
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
///////////////////广播HTTP事件///////////////////////////
|
|
|
|
|
bool consumed = false;//该事件是否被消费
|
2020-04-23 21:38:44 +08:00
|
|
|
|
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastHttpRequest,_parser,invoker,consumed,static_cast<SockInfo &>(*this));
|
2020-03-20 11:51:24 +08:00
|
|
|
|
if(!consumed && doInvoke){
|
|
|
|
|
//该事件无人消费,所以返回404
|
2021-01-02 21:24:06 +08:00
|
|
|
|
invoker(404,KeyValue(), HttpBody::Ptr());
|
2020-03-20 11:51:24 +08:00
|
|
|
|
}
|
|
|
|
|
return consumed;
|
2017-12-08 22:37:17 +08:00
|
|
|
|
}
|
2019-09-16 17:42:52 +08:00
|
|
|
|
|
2021-01-19 16:05:38 +08:00
|
|
|
|
void HttpSession::Handle_Req_POST(ssize_t &content_len) {
|
2021-01-17 18:31:50 +08:00
|
|
|
|
GET_CONFIG(size_t,maxReqSize,Http::kMaxReqSize);
|
2018-09-20 23:05:32 +08:00
|
|
|
|
|
2021-01-19 16:05:38 +08:00
|
|
|
|
ssize_t totalContentLen = _parser["Content-Length"].empty() ? -1 : atoll(_parser["Content-Length"].data());
|
2018-09-20 23:05:32 +08:00
|
|
|
|
|
2020-03-20 11:51:24 +08:00
|
|
|
|
if(totalContentLen == 0){
|
|
|
|
|
//content为空
|
|
|
|
|
//emitHttpEvent内部会选择是否关闭连接
|
|
|
|
|
emitHttpEvent(true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-09-20 17:50:58 +08:00
|
|
|
|
|
2021-01-19 16:05:38 +08:00
|
|
|
|
if(totalContentLen > 0 && (size_t)totalContentLen < maxReqSize ){
|
2020-03-20 11:51:24 +08:00
|
|
|
|
//返回固定长度的content
|
|
|
|
|
content_len = totalContentLen;
|
|
|
|
|
auto parserCopy = _parser;
|
2021-01-17 18:31:50 +08:00
|
|
|
|
_contentCallBack = [this,parserCopy](const char *data,size_t len){
|
2020-03-20 11:51:24 +08:00
|
|
|
|
//恢复http头
|
|
|
|
|
_parser = parserCopy;
|
|
|
|
|
//设置content
|
|
|
|
|
_parser.setContent(string(data,len));
|
|
|
|
|
//触发http事件,emitHttpEvent内部会选择是否关闭连接
|
|
|
|
|
emitHttpEvent(true);
|
|
|
|
|
//清空数据,节省内存
|
|
|
|
|
_parser.Clear();
|
|
|
|
|
//content已经接收完毕
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
}else{
|
2021-01-19 16:05:38 +08:00
|
|
|
|
//返回不固定长度的content或者超过长度限制的content
|
2020-03-20 11:51:24 +08:00
|
|
|
|
content_len = -1;
|
|
|
|
|
auto parserCopy = _parser;
|
2021-01-17 20:15:08 +08:00
|
|
|
|
std::shared_ptr<size_t> recvedContentLen = std::make_shared<size_t>(0);
|
2020-03-20 11:51:24 +08:00
|
|
|
|
bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
|
|
|
|
|
|
2021-01-17 18:31:50 +08:00
|
|
|
|
_contentCallBack = [this,parserCopy,totalContentLen,recvedContentLen,bClose](const char *data,size_t len){
|
2020-03-20 11:51:24 +08:00
|
|
|
|
*(recvedContentLen) += len;
|
2021-01-19 16:05:38 +08:00
|
|
|
|
if (totalContentLen < 0) {
|
|
|
|
|
//不固定长度的content,源源不断接收数据
|
|
|
|
|
onRecvUnlimitedContent(parserCopy, data, len, SIZE_MAX, *(recvedContentLen));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-03-20 11:51:24 +08:00
|
|
|
|
|
2021-01-19 16:05:38 +08:00
|
|
|
|
//长度超过限制的content
|
2020-03-20 11:51:24 +08:00
|
|
|
|
onRecvUnlimitedContent(parserCopy,data,len,totalContentLen,*(recvedContentLen));
|
|
|
|
|
|
2021-01-19 16:05:38 +08:00
|
|
|
|
if(*(recvedContentLen) < (size_t)totalContentLen){
|
2020-03-20 11:51:24 +08:00
|
|
|
|
//数据还没接收完毕
|
2018-10-24 15:43:52 +08:00
|
|
|
|
//_contentCallBack是可持续的,后面还要处理后续content数据
|
2018-09-21 09:41:40 +08:00
|
|
|
|
return true;
|
2020-03-20 11:51:24 +08:00
|
|
|
|
}
|
2018-09-21 09:41:40 +08:00
|
|
|
|
|
2020-03-20 11:51:24 +08:00
|
|
|
|
//数据接收完毕
|
2018-09-21 09:41:40 +08:00
|
|
|
|
if(!bClose){
|
2020-03-20 11:51:24 +08:00
|
|
|
|
//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 ;
|
2020-03-20 11:51:24 +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);
|
2021-01-02 21:24:06 +08:00
|
|
|
|
sendResponse(404, bClose,"text/html",KeyValue(),std::make_shared<HttpStringBody>(notFound));
|
2017-04-01 16:35:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-04 18:57:54 +08:00
|
|
|
|
void HttpSession::setSocketFlags(){
|
2020-04-29 11:08:43 +08:00
|
|
|
|
GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
|
|
|
|
|
if(mergeWriteMS > 0) {
|
2019-09-04 18:57:54 +08:00
|
|
|
|
//推流模式下,关闭TCP_NODELAY会增加推流端的延时,但是服务器性能将提高
|
2020-09-12 19:03:52 +08:00
|
|
|
|
SockUtil::setNoDelay(getSock()->rawFD(), false);
|
2019-09-04 18:57:54 +08:00
|
|
|
|
//播放模式下,开启MSG_MORE会增加延时,但是能提高发送性能
|
2020-04-23 17:50:12 +08:00
|
|
|
|
setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE);
|
2019-09-04 18:57:54 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-08-30 19:29:54 +08:00
|
|
|
|
|
2020-04-09 16:19:03 +08:00
|
|
|
|
void HttpSession::onWrite(const Buffer::Ptr &buffer, bool flush) {
|
|
|
|
|
if(flush){
|
|
|
|
|
//需要flush那么一次刷新缓存
|
|
|
|
|
HttpSession::setSendFlushFlag(true);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-20 11:51:24 +08:00
|
|
|
|
_ticker.resetTime();
|
2020-09-20 00:21:46 +08:00
|
|
|
|
if (!_live_over_websocket) {
|
|
|
|
|
_total_bytes_usage += buffer->size();
|
2019-08-12 18:14:51 +08:00
|
|
|
|
send(buffer);
|
2020-09-20 00:21:46 +08:00
|
|
|
|
} else {
|
2020-04-09 16:19:03 +08:00
|
|
|
|
WebSocketHeader header;
|
|
|
|
|
header._fin = true;
|
|
|
|
|
header._reserved = 0;
|
|
|
|
|
header._opcode = WebSocketHeader::BINARY;
|
|
|
|
|
header._mask_flag = false;
|
2020-09-20 00:21:46 +08:00
|
|
|
|
WebSocketSplitter::encode(header, buffer);
|
2019-08-12 18:14:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-20 00:21:46 +08:00
|
|
|
|
if (flush) {
|
2020-04-09 16:19:03 +08:00
|
|
|
|
//本次刷新缓存后,下次不用刷新缓存
|
|
|
|
|
HttpSession::setSendFlushFlag(false);
|
|
|
|
|
}
|
2019-08-12 18:14:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-01 03:41:35 +08:00
|
|
|
|
void HttpSession::onWebSocketEncodeData(Buffer::Ptr buffer){
|
2020-09-20 00:21:46 +08:00
|
|
|
|
_total_bytes_usage += buffer->size();
|
2020-11-01 03:41:35 +08:00
|
|
|
|
send(std::move(buffer));
|
2017-12-15 16:01:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-08-08 12:17:06 +08:00
|
|
|
|
void HttpSession::onWebSocketDecodeComplete(const WebSocketHeader &header_in){
|
|
|
|
|
WebSocketHeader& header = const_cast<WebSocketHeader&>(header_in);
|
|
|
|
|
header._mask_flag = false;
|
|
|
|
|
|
|
|
|
|
switch (header._opcode) {
|
|
|
|
|
case WebSocketHeader::CLOSE: {
|
|
|
|
|
encode(header, nullptr);
|
|
|
|
|
shutdown(SockException(Err_shutdown, "recv close request from client"));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default : break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-30 19:29:54 +08:00
|
|
|
|
void HttpSession::onDetach() {
|
2020-03-20 11:51:24 +08:00
|
|
|
|
shutdown(SockException(Err_shutdown,"rtmp ring buffer detached"));
|
2018-08-30 19:29:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<FlvMuxer> HttpSession::getSharedPtr(){
|
2020-03-20 11:51:24 +08:00
|
|
|
|
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 */
|