ZLMediaKit/src/Http/HttpSession.cpp

730 lines
22 KiB
C++
Raw Normal View History

2017-10-09 22:11:01 +08:00
/*
2017-09-27 16:20:30 +08:00
* MIT License
2017-04-01 16:35:56 +08:00
*
2017-09-27 16:20:30 +08:00
* Copyright (c) 2016 xiongziliang <771730766@qq.com>
*
* 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>
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"
#include "Util/File.h"
#include "Util/util.h"
#include "Util/TimeTicker.h"
#include "Util/onceToken.h"
2017-04-25 11:35:41 +08:00
#include "Util/mini.h"
2017-04-01 16:35:56 +08:00
#include "Util/NoticeCenter.h"
2018-09-20 18:20:43 +08:00
#include "Util/base64.h"
#include "Util/SHA1.h"
2017-12-15 16:01:21 +08:00
#include "Rtmp/utils.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
static int kSockFlags = SOCKET_DEFAULE_FLAGS | FLAG_MORE;
2018-02-06 16:34:02 +08:00
2017-04-01 16:35:56 +08:00
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;
}
static const char*
get_mime_type(const char* name) {
const char* dot;
dot = strrchr(name, '.');
2017-12-15 16:01:21 +08:00
static HttpSession::KeyValue mapType;
2017-04-01 16:35:56 +08:00
static onceToken token([&]() {
mapType.emplace(".html","text/html");
mapType.emplace(".htm","text/html");
mapType.emplace(".mp4","video/mp4");
mapType.emplace(".m3u8","application/vnd.apple.mpegurl");
mapType.emplace(".jpg","image/jpeg");
mapType.emplace(".jpeg","image/jpeg");
mapType.emplace(".gif","image/gif");
mapType.emplace(".png","image/png");
mapType.emplace(".ico","image/x-icon");
mapType.emplace(".css","text/css");
mapType.emplace(".js","application/javascript");
mapType.emplace(".au","audio/basic");
mapType.emplace(".wav","audio/wav");
mapType.emplace(".avi","video/x-msvideo");
mapType.emplace(".mov","video/quicktime");
mapType.emplace(".qt","video/quicktime");
mapType.emplace(".mpeg","video/mpeg");
mapType.emplace(".mpe","video/mpeg");
mapType.emplace(".vrml","model/vrml");
mapType.emplace(".wrl","model/vrml");
mapType.emplace(".midi","audio/midi");
mapType.emplace(".mid","audio/midi");
mapType.emplace(".mp3","audio/mpeg");
mapType.emplace(".ogg","application/ogg");
mapType.emplace(".pac","application/x-ns-proxy-autoconfig");
2017-12-15 16:01:21 +08:00
mapType.emplace(".flv","video/x-flv");
2017-04-01 16:35:56 +08:00
}, nullptr);
if(!dot){
return "text/plain";
}
2017-12-15 16:01:21 +08:00
auto it = mapType.find(dot);
2017-04-01 16:35:56 +08:00
if (it == mapType.end()) {
return "text/plain";
}
return it->second.data();
}
HttpSession::HttpSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock) :
2018-02-23 15:36:51 +08:00
TcpSession(pTh, pSock) {
2018-02-09 11:42:55 +08:00
//设置10秒发送缓存
pSock->setSendBufSecond(10);
//设置15秒发送超时时间
pSock->setSendTimeOutSecond(15);
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(string,rootPath,Http::kRootPath);
2018-10-24 15:43:52 +08:00
_strPath = rootPath;
2017-04-01 16:35:56 +08:00
}
HttpSession::~HttpSession() {
//DebugL;
}
2018-09-23 00:55:00 +08:00
int64_t HttpSession::onRecvHeader(const char *header,uint64_t len) {
typedef bool (HttpSession::*HttpCMDHandle)(int64_t &);
static unordered_map<string, HttpCMDHandle> g_mapCmdIndex;
static onceToken token([]() {
g_mapCmdIndex.emplace("GET",&HttpSession::Handle_Req_GET);
g_mapCmdIndex.emplace("POST",&HttpSession::Handle_Req_POST);
}, nullptr);
2018-10-24 15:43:52 +08:00
_parser.Parse(header);
urlDecode(_parser);
string cmd = _parser.Method();
2017-04-01 16:35:56 +08:00
auto it = g_mapCmdIndex.find(cmd);
if (it == g_mapCmdIndex.end()) {
WarnL << cmd;
sendResponse("403 Forbidden", makeHttpHeader(true), "");
shutdown();
return 0;
}
//默认后面数据不是content而是header
int64_t content_len = 0;
auto &fun = it->second;
if(!(this->*fun)(content_len)){
shutdown();
2017-04-01 16:35:56 +08:00
}
//清空解析器节省内存
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) {
onRecv(pBuf->data(),pBuf->size());
}
void HttpSession::onRecv(const char *data,int size){
2018-10-24 15:43:52 +08:00
_ticker.resetTime();
2018-09-23 00:55:00 +08:00
input(data,size);
}
2017-04-01 16:35:56 +08:00
void HttpSession::onError(const SockException& err) {
//WarnL << err.what();
2018-02-09 11:42:55 +08:00
GET_CONFIG_AND_REGISTER(uint32_t,iFlowThreshold,Broadcast::kFlowThreshold);
2018-10-24 15:43:52 +08:00
if(_ui64TotalBytes > iFlowThreshold * 1024){
2018-10-09 09:36:03 +08:00
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,
2018-10-24 15:43:52 +08:00
_mediaInfo,
_ui64TotalBytes,
_ticker.createdTime()/1000,
2018-10-09 09:36:03 +08:00
*this);
}
2017-04-01 16:35:56 +08:00
}
void HttpSession::onManager() {
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(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分钟超时
2017-08-09 18:39:30 +08:00
WarnL<<"HttpSession timeouted!";
2017-04-01 16:35:56 +08:00
shutdown();
}
}
2018-09-20 18:20:43 +08:00
inline 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"));
KeyValue headerOut;
headerOut["Upgrade"] = "websocket";
headerOut["Connection"] = "Upgrade";
headerOut["Sec-WebSocket-Accept"] = Sec_WebSocket_Accept;
sendResponse("101 Switching Protocols",headerOut,"");
return true;
}
//http-flv 链接格式:http://vhost-url:port/app/streamid.flv?key1=value1&key2=value2
//如果url(除去?以及后面的参数)后缀是.flv,那么表明该url是一个http-flv直播。
2017-12-15 16:01:21 +08:00
inline bool HttpSession::checkLiveFlvStream(){
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;
}
if(strcasecmp(pos,".flv") != 0){
//未找到".flv"后缀
return false;
}
//拼接成完整url
2018-10-24 15:43:52 +08:00
auto fullUrl = string(HTTP_SCHEMA) + "://" + _parser["Host"] + _parser.FullUrl();
_mediaInfo.parse(fullUrl);
_mediaInfo._streamid.erase(_mediaInfo._streamid.size() - 4);//去除.flv后缀
2018-10-24 15:43:52 +08:00
auto mediaSrc = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTMP_SCHEMA,_mediaInfo._vhost,_mediaInfo._app,_mediaInfo._streamid));
if(!mediaSrc){
2017-12-15 16:01:21 +08:00
//该rtmp源不存在
return false;
2017-12-15 16:01:21 +08:00
}
2018-02-06 16:17:37 +08:00
auto onRes = [this,mediaSrc](const string &err){
bool authSuccess = err.empty();
if(!authSuccess){
2018-02-05 17:25:22 +08:00
sendResponse("401 Unauthorized", makeHttpHeader(true,err.size()),err);
shutdown();
return ;
}
//找到rtmp源发送http头负载后续发送
sendResponse("200 OK", makeHttpHeader(false,0,get_mime_type(".flv")), "");
2017-12-15 16:01:21 +08:00
//开始发送rtmp负载
2018-02-23 15:36:51 +08:00
//关闭tcp_nodelay ,优化性能
SockUtil::setNoDelay(_sock->rawFD(),false);
(*this) << SocketFlags(kSockFlags);
2018-02-23 15:36:51 +08:00
2018-08-30 19:29:54 +08:00
try{
start(mediaSrc);
}catch (std::exception &ex){
//该rtmp源不存在
shutdown();
}
};
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
2018-02-06 16:17:37 +08:00
Broadcast::AuthInvoker invoker = [weakSelf,onRes](const string &err){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
}
2018-02-06 16:17:37 +08:00
strongSelf->async([weakSelf,onRes,err](){
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
}
2018-02-06 16:17:37 +08:00
onRes(err);
});
};
2018-10-24 15:43:52 +08:00
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,_mediaInfo,invoker,*this);
if(!flag){
//该事件无人监听,默认不鉴权
2018-02-06 16:17:37 +08:00
onRes("");
}
return true;
2017-12-15 16:01:21 +08:00
}
inline bool HttpSession::Handle_Req_GET(int64_t &content_len) {
2018-09-20 18:20:43 +08:00
//先看看是否为WebSocket请求
if(checkWebSocket()){
content_len = -1;
2018-10-24 15:43:52 +08:00
auto parserCopy = _parser;
_contentCallBack = [this,parserCopy](const char *data,uint64_t len){
2018-09-23 00:55:00 +08:00
onRecvWebSocketData(parserCopy,data,len);
2018-10-24 15:43:52 +08:00
//_contentCallBack是可持续的后面还要处理后续数据
2018-09-20 18:20:43 +08:00
return true;
};
return true;
}
2017-12-08 22:37:17 +08:00
//先看看该http事件是否被拦截
if(emitHttpEvent(false)){
return true;
2017-10-10 00:04:07 +08:00
}
2018-09-20 18:20:43 +08:00
2018-03-14 22:32:36 +08:00
//再看看是否为http-flv直播请求
2017-12-15 16:01:21 +08:00
if(checkLiveFlvStream()){
return true;
2017-12-15 16:01:21 +08:00
}
2018-09-20 18:20:43 +08:00
//事件未被拦截则认为是http下载请求
2018-10-24 15:43:52 +08:00
auto fullUrl = string(HTTP_SCHEMA) + "://" + _parser["Host"] + _parser.FullUrl();
_mediaInfo.parse(fullUrl);
2018-10-24 15:43:52 +08:00
string strFile = _strPath + "/" + _mediaInfo._vhost + _parser.Url();
2017-12-08 22:37:17 +08:00
/////////////HTTP连接是否需要被关闭////////////////
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(uint32_t,reqCnt,Http::kMaxReqCount);
2018-02-09 11:42:55 +08:00
2018-10-24 15:43:52 +08:00
bool bClose = (strcasecmp(_parser["Connection"].data(),"close") == 0) || ( ++_iReqCnt > reqCnt);
2017-12-08 22:37:17 +08:00
//访问的是文件夹
2017-04-01 16:35:56 +08:00
if (strFile.back() == '/') {
2017-12-08 22:37:17 +08:00
//生成文件夹菜单索引
2017-04-01 16:35:56 +08:00
string strMeun;
2018-10-24 15:43:52 +08:00
if (!makeMeun(strFile,_mediaInfo._vhost, strMeun)) {
2017-12-08 22:37:17 +08:00
//文件夹不存在
2017-04-01 16:35:56 +08:00
sendNotFound(bClose);
return !bClose;
2017-04-01 16:35:56 +08:00
}
sendResponse("200 OK", makeHttpHeader(bClose,strMeun.size() ), strMeun);
return !bClose;
2017-04-01 16:35:56 +08:00
}
2017-12-08 22:37:17 +08:00
//访问的是文件
2017-04-01 16:35:56 +08:00
struct stat tFileStat;
if (0 != stat(strFile.data(), &tFileStat)) {
2017-12-08 22:37:17 +08:00
//文件不存在
2017-04-01 16:35:56 +08:00
sendNotFound(bClose);
return !bClose;
2017-04-01 16:35:56 +08:00
}
2018-03-14 22:32:36 +08:00
//文件智能指针,防止退出时未关闭
std::shared_ptr<FILE> pFilePtr(fopen(strFile.data(), "rb"), [](FILE *pFile) {
if(pFile){
fclose(pFile);
}
});
if (!pFilePtr) {
2017-12-08 22:37:17 +08:00
//打开文件失败
2017-04-01 16:35:56 +08:00
sendNotFound(bClose);
return !bClose;
2017-04-01 16:35:56 +08:00
}
2018-03-14 22:32:36 +08:00
2017-12-08 22:37:17 +08:00
//判断是不是分节下载
2018-10-24 15:43:52 +08:00
auto &strRange = _parser["Range"];
2017-04-01 16:35:56 +08:00
int64_t iRangeStart = 0, iRangeEnd = 0;
iRangeStart = atoll(FindField(strRange.data(), "bytes=", "-").data());
iRangeEnd = atoll(FindField(strRange.data(), "-", "\r\n").data());
if (iRangeEnd == 0) {
iRangeEnd = tFileStat.st_size - 1;
}
const char *pcHttpResult = NULL;
if (strRange.size() == 0) {
2017-12-08 22:37:17 +08:00
//全部下载
2017-04-01 16:35:56 +08:00
pcHttpResult = "200 OK";
} else {
2017-12-08 22:37:17 +08:00
//分节下载
2017-04-01 16:35:56 +08:00
pcHttpResult = "206 Partial Content";
2018-03-14 22:32:36 +08:00
fseek(pFilePtr.get(), iRangeStart, SEEK_SET);
2017-04-01 16:35:56 +08:00
}
2017-12-08 22:37:17 +08:00
auto httpHeader=makeHttpHeader(bClose, iRangeEnd - iRangeStart + 1, get_mime_type(strFile.data()));
2017-04-01 16:35:56 +08:00
if (strRange.size() != 0) {
2017-12-08 22:37:17 +08:00
//分节下载返回Content-Range头
2017-04-01 16:35:56 +08:00
httpHeader.emplace("Content-Range",StrPrinter<<"bytes " << iRangeStart << "-" << iRangeEnd << "/" << tFileStat.st_size<< endl);
}
2018-10-24 15:43:52 +08:00
auto Origin = _parser["Origin"];
2018-01-30 17:25:19 +08:00
if(!Origin.empty()){
httpHeader["Access-Control-Allow-Origin"] = Origin;
httpHeader["Access-Control-Allow-Credentials"] = "true";
}
2017-12-08 22:37:17 +08:00
//先回复HTTP头部分
2017-04-01 16:35:56 +08:00
sendResponse(pcHttpResult, httpHeader, "");
if (iRangeEnd - iRangeStart < 0) {
2017-12-15 16:01:21 +08:00
//文件是空的!
return !bClose;
2017-04-01 16:35:56 +08:00
}
2017-12-08 22:37:17 +08:00
//回复Content部分
2017-04-01 16:35:56 +08:00
std::shared_ptr<int64_t> piLeft(new int64_t(iRangeEnd - iRangeStart + 1));
2018-03-14 22:32:36 +08:00
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(uint32_t,sendBufSize,Http::kSendBufSize);
2018-02-09 11:42:55 +08:00
2017-04-01 16:35:56 +08:00
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
2018-01-31 09:31:07 +08:00
auto onFlush = [pFilePtr,bClose,weakSelf,piLeft]() {
2017-04-01 16:35:56 +08:00
TimeTicker();
auto strongSelf = weakSelf.lock();
while(*piLeft && strongSelf){
2018-01-31 09:31:07 +08:00
//更新超时定时器
2018-10-24 15:43:52 +08:00
strongSelf->_ticker.resetTime();
2018-01-31 09:31:07 +08:00
//从循环池获取一个内存片
2018-02-23 15:36:51 +08:00
auto sendBuf = strongSelf->obtainBuffer();
2018-01-31 09:31:07 +08:00
sendBuf->setCapacity(sendBufSize);
//本次需要读取文件字节数
2017-04-01 16:35:56 +08:00
int64_t iReq = MIN(sendBufSize,*piLeft);
2018-01-31 11:20:50 +08:00
//读文件
int iRead;
do{
iRead = fread(sendBuf->data(), 1, iReq, pFilePtr.get());
}while(-1 == iRead && UV_EINTR == get_uv_error(false));
2018-01-31 09:31:07 +08:00
//文件剩余字节数
2018-01-31 11:20:50 +08:00
2017-04-01 16:35:56 +08:00
*piLeft -= iRead;
2018-01-31 09:31:07 +08:00
2017-04-01 16:35:56 +08:00
if (iRead < iReq || !*piLeft) {
2018-01-31 09:31:07 +08:00
//文件读完
2018-01-31 11:20:50 +08:00
//InfoL << "send complete!" << iRead << " " << iReq << " " << *piLeft;
2017-04-01 16:35:56 +08:00
if(iRead>0) {
sendBuf->setSize(iRead);
2018-02-23 15:36:51 +08:00
strongSelf->send(sendBuf);
2017-04-01 16:35:56 +08:00
}
if(bClose) {
strongSelf->shutdown();
}
return false;
}
2018-01-31 09:31:07 +08:00
//文件还未读完
sendBuf->setSize(iRead);
2018-02-23 15:36:51 +08:00
int iSent = strongSelf->send(sendBuf);
2017-04-01 16:35:56 +08:00
if(iSent == -1) {
2018-01-31 11:20:50 +08:00
//InfoL << "send error";
2017-04-01 16:35:56 +08:00
return false;
}
if(iSent < iRead) {
2018-01-31 11:20:50 +08:00
//数据回滚
fseek(pFilePtr.get(), -iRead, SEEK_CUR);
*piLeft += iRead;
2017-04-01 16:35:56 +08:00
return true;
}
2018-03-14 14:51:54 +08:00
if(strongSelf->isSocketBusy()){
//套接字忙,那么停止继续写
return true;
}
2017-04-01 16:35:56 +08:00
//send success
}
return false;
};
2018-01-30 11:47:56 +08:00
//关闭tcp_nodelay ,优化性能
2018-02-23 15:36:51 +08:00
SockUtil::setNoDelay(_sock->rawFD(),false);
2018-03-14 22:32:36 +08:00
//设置MSG_MORE优化性能
(*this) << SocketFlags(kSockFlags);
2018-03-14 22:32:36 +08:00
2018-02-23 15:36:51 +08:00
onFlush();
_sock->setOnFlush(onFlush);
return true;
2017-04-01 16:35:56 +08:00
}
inline bool HttpSession::makeMeun(const string &strFullPath,const string &vhost, string &strRet) {
2017-04-01 16:35:56 +08:00
string strPathPrefix(strFullPath);
strPathPrefix = strPathPrefix.substr(0, strPathPrefix.length() - 1);
if (!File::is_dir(strPathPrefix.data())) {
return false;
}
strRet = "<html>\r\n"
"<head>\r\n"
"<title>文件索引</title>\r\n"
"</head>\r\n"
"<body>\r\n"
"<h1>文件索引:";
string strPath = strFullPath;
2018-10-24 15:43:52 +08:00
strPath = strPath.substr(_strPath.length() + vhost.length() + 1);
2017-04-01 16:35:56 +08:00
strRet += strPath;
strRet += "</h1>\r\n";
if (strPath != "/") {
strRet += "<li><a href=\"";
strRet += "/";
strRet += "\">";
2017-10-10 00:04:07 +08:00
strRet += "根目录";
2017-04-01 16:35:56 +08:00
strRet += "</a></li>\r\n";
strRet += "<li><a href=\"";
strRet += "../";
strRet += "\">";
2017-10-10 00:04:07 +08:00
strRet += "上级目录";
2017-04-01 16:35:56 +08:00
strRet += "</a></li>\r\n";
}
DIR *pDir;
dirent *pDirent;
if ((pDir = opendir(strPathPrefix.data())) == NULL) {
return false;
}
set<string> setFile;
while ((pDirent = readdir(pDir)) != NULL) {
if (File::is_special_dir(pDirent->d_name)) {
continue;
}
if(pDirent->d_name[0] == '.'){
continue;
}
setFile.emplace(pDirent->d_name);
}
for(auto &strFile :setFile ){
string strAbsolutePath = strPathPrefix + "/" + strFile;
if (File::is_dir(strAbsolutePath.data())) {
strRet += "<li><a href=\"";
strRet += strFile;
strRet += "/\">";
strRet += strFile;
strRet += "/</a></li>\r\n";
} else { //是文件
strRet += "<li><a href=\"";
strRet += strFile;
strRet += "\">";
strRet += strFile;
struct stat fileData;
if (0 == stat(strAbsolutePath.data(), &fileData)) {
auto &fileSize = fileData.st_size;
if (fileSize < 1024) {
strRet += StrPrinter << " (" << fileData.st_size << "B)" << endl;
} else if (fileSize < 1024 * 1024) {
strRet += StrPrinter << " (" << fileData.st_size / 1024 << "KB)" << endl;
} else if (fileSize < 1024 * 1024 * 1024) {
strRet += StrPrinter << " (" << fileData.st_size / 1024 / 1024 << "MB)" << endl;
} else {
strRet += StrPrinter << " (" << fileData.st_size / 1024 / 1024 / 1024 << "GB)" << endl;
}
}
strRet += "</a></li>\r\n";
}
}
closedir(pDir);
strRet += "<ul>\r\n";
strRet += "</ul>\r\n</body></html>";
return true;
}
inline void HttpSession::sendResponse(const char* pcStatus, const KeyValue& header, const string& strContent) {
_StrPrinter printer;
2018-11-13 17:59:12 +08:00
printer << "HTTP/1.1 " << pcStatus << "\r\n";
2017-04-01 16:35:56 +08:00
for (auto &pr : header) {
printer << pr.first << ": " << pr.second << "\r\n";
}
printer << "\r\n" << strContent;
auto strSend = printer << endl;
//DebugL << strSend;
send(strSend);
2018-10-24 15:43:52 +08:00
_ticker.resetTime();
2017-04-01 16:35:56 +08:00
}
inline HttpSession::KeyValue HttpSession::makeHttpHeader(bool bClose, int64_t iContentSize,const char* pcContentType) {
KeyValue headerOut;
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(string,charSet,Http::kCharSet);
GET_CONFIG_AND_REGISTER(uint32_t,keepAliveSec,Http::kKeepAliveSecond);
GET_CONFIG_AND_REGISTER(uint32_t,reqCnt,Http::kMaxReqCount);
2017-04-01 16:35:56 +08:00
2017-12-15 16:01:21 +08:00
headerOut.emplace("Date", dateStr());
headerOut.emplace("Server", SERVER_NAME);
2017-12-09 16:24:07 +08:00
headerOut.emplace("Connection", bClose ? "close" : "keep-alive");
2017-12-15 16:01:21 +08:00
if(!bClose){
headerOut.emplace("Keep-Alive",StrPrinter << "timeout=" << keepAliveSec << ", max=" << reqCnt << endl);
}
if(pcContentType){
2017-04-01 16:35:56 +08:00
auto strContentType = StrPrinter << pcContentType << "; charset=" << charSet << endl;
2017-12-15 16:01:21 +08:00
headerOut.emplace("Content-Type",strContentType);
}
if(iContentSize > 0){
2017-04-01 16:35:56 +08:00
headerOut.emplace("Content-Length", StrPrinter<<iContentSize<<endl);
}
return headerOut;
}
2017-12-08 22:37:17 +08:00
string HttpSession::urlDecode(const string &str){
auto ret = strCoding::UrlUTF8Decode(str);
2017-10-10 00:04:07 +08:00
#ifdef _WIN32
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(string,charSet,Http::kCharSet);
2018-02-09 11:42:55 +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
2017-12-08 22:37:17 +08:00
inline void HttpSession::urlDecode(Parser &parser){
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
2017-12-08 22:37:17 +08:00
inline bool HttpSession::emitHttpEvent(bool doInvoke){
///////////////////是否断开本链接///////////////////////
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(uint32_t,reqCnt,Http::kMaxReqCount);
2018-02-09 11:42:55 +08:00
2018-10-24 15:43:52 +08:00
bool bClose = (strcasecmp(_parser["Connection"].data(),"close") == 0) || ( ++_iReqCnt > reqCnt);
auto Origin = _parser["Origin"];
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());
2017-12-09 16:43:47 +08:00
HttpResponseInvoker invoker = [weakSelf,bClose,Origin](const string &codeOut, const KeyValue &headerOut, const string &contentOut){
2017-04-10 17:24:06 +08:00
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
2017-12-09 16:43:47 +08:00
strongSelf->async([weakSelf,bClose,codeOut,headerOut,contentOut,Origin]() {
2017-04-10 17:24:06 +08:00
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
2017-12-09 16:43:47 +08:00
strongSelf->responseDelay(Origin,bClose,codeOut,headerOut,contentOut);
2017-04-10 17:24:06 +08:00
if(bClose){
strongSelf->shutdown();
}
});
};
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
2017-04-10 17:24:06 +08:00
invoker("404 Not Found",KeyValue(),"");
2018-09-21 09:59:04 +08:00
if(bClose){
//close类型回复完毕关闭连接
shutdown();
}
2017-04-01 16:35:56 +08:00
}
2017-12-08 22:37:17 +08:00
return consumed;
}
inline bool HttpSession::Handle_Req_POST(int64_t &content_len) {
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(uint64_t,maxReqSize,Http::kMaxReqSize);
GET_CONFIG_AND_REGISTER(int,maxReqCnt,Http::kMaxReqCount);
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);
2018-09-21 09:59:04 +08:00
return true;
}
2018-09-21 09:41:40 +08:00
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);
2018-10-24 15:43:52 +08:00
bool bClose = (strcasecmp(_parser["Connection"].data(),"close") == 0) || ( ++_iReqCnt > maxReqCnt);
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就关闭连接
shutdown();
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数据要处理,暂时不关闭连接
return true;
2017-04-10 17:24:06 +08:00
}
2017-12-09 16:43:47 +08:00
void HttpSession::responseDelay(const string &Origin,bool bClose,
const string &codeOut,const KeyValue &headerOut,
const string &contentOut){
2017-04-10 17:24:06 +08:00
if(codeOut.empty()){
sendNotFound(bClose);
return;
}
2017-12-08 22:37:17 +08:00
auto headerOther=makeHttpHeader(bClose,contentOut.size(),"text/plain");
2017-12-09 16:43:47 +08:00
if(!Origin.empty()){
headerOther["Access-Control-Allow-Origin"] = Origin;
headerOther["Access-Control-Allow-Credentials"] = "true";
}
2017-12-08 22:37:17 +08:00
const_cast<KeyValue &>(headerOut).insert(headerOther.begin(), headerOther.end());
2017-04-10 17:24:06 +08:00
sendResponse(codeOut.data(), headerOut, contentOut);
2017-04-01 16:35:56 +08:00
}
inline void HttpSession::sendNotFound(bool bClose) {
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(string,notFound,Http::kNotFound);
2018-02-09 11:42:55 +08:00
sendResponse("404 Not Found", makeHttpHeader(bClose, notFound.size()), notFound);
2017-04-01 16:35:56 +08:00
}
2018-08-30 19:29:54 +08:00
void HttpSession::onWrite(const Buffer::Ptr &buffer) {
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
async([weakSelf,buffer](){
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
2018-10-24 15:43:52 +08:00
strongSelf->_ticker.resetTime();
strongSelf->_ui64TotalBytes += buffer->size();
2018-08-30 19:29:54 +08:00
strongSelf->send(buffer);
});
2017-12-15 16:01:21 +08:00
}
2018-08-30 19:29:54 +08:00
void HttpSession::onWrite(const char *data, int len) {
BufferRaw::Ptr buffer(new BufferRaw);
buffer->assign(data,len);
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
async([weakSelf,buffer](){
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
2018-10-24 15:43:52 +08:00
strongSelf->_ticker.resetTime();
strongSelf->_ui64TotalBytes += buffer->size();
2018-08-30 19:29:54 +08:00
strongSelf->send(buffer);
});
2017-12-15 16:01:21 +08:00
}
2018-08-30 19:29:54 +08:00
void HttpSession::onDetach() {
safeShutdown();
}
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 */