HttpSession.cpp 20.7 KB
Newer Older
xiongziliang committed
1
/*
xiongziliang committed
2
 * MIT License
xzl committed
3
 *
xiongziliang committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * 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.
xzl committed
25
 */
26 27 28 29
#if !defined(_WIN32)
#include <dirent.h>
#endif //!defined(_WIN32)

xzl committed
30 31 32 33
#include <stdio.h>
#include <sys/stat.h>
#include <algorithm>

xiongziliang committed
34
#include "Common/config.h"
xzl committed
35 36 37 38 39 40
#include "strCoding.h"
#include "HttpSession.h"
#include "Util/File.h"
#include "Util/util.h"
#include "Util/TimeTicker.h"
#include "Util/onceToken.h"
xiongzilaing committed
41
#include "Util/mini.h"
xzl committed
42
#include "Util/NoticeCenter.h"
xiongziliang committed
43
#include "Rtmp/utils.h"
44

xzl committed
45 46 47 48 49
using namespace ZL::Util;

namespace ZL {
namespace Http {

50 51
static int sock_flags = SOCKET_DEFAULE_FLAGS | FLAG_MORE;

xzl committed
52 53 54 55 56 57 58 59 60 61
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, '.');
xiongziliang committed
62
	static HttpSession::KeyValue mapType;
xzl committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
	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");
xiongziliang committed
89
        mapType.emplace(".flv","video/x-flv");
xzl committed
90 91 92 93
	}, nullptr);
	if(!dot){
		return "text/plain";
	}
xiongziliang committed
94
	auto it = mapType.find(dot);
xzl committed
95 96 97 98 99 100 101 102
	if (it == mapType.end()) {
		return "text/plain";
	}
	return it->second.data();
}


HttpSession::HttpSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock) :
103
		TcpSession(pTh, pSock) {
104

xiongziliang committed
105 106 107 108 109 110
	//设置10秒发送缓存
	pSock->setSendBufSecond(10);
	//设置15秒发送超时时间
	pSock->setSendTimeOutSecond(15);

    GET_CONFIG_AND_REGISTER(string,rootPath,Config::Http::kRootPath);
111
    m_strPath = rootPath;
xzl committed
112 113 114 115 116 117
}

HttpSession::~HttpSession() {
	//DebugL;
}

118
void HttpSession::onRecv(const Buffer::Ptr &pBuf) {
xzl committed
119 120 121
	onRecv(pBuf->data(),pBuf->size());
}
void HttpSession::onRecv(const char *data,int size){
122 123 124
    GET_CONFIG_AND_REGISTER(uint32_t,reqSize,Config::Http::kMaxReqSize);

    m_ticker.resetTime();
xzl committed
125 126
	if (m_strRcvBuf.size() + size >= reqSize) {
		WarnL << "接收缓冲区溢出:" << m_strRcvBuf.size() + size << "," << reqSize;
xzl committed
127 128 129
		shutdown();
		return;
	}
xzl committed
130
	m_strRcvBuf.append(data, size);
xzl committed
131 132 133 134 135 136
	size_t index;
	string onePkt;
	while ((index = m_strRcvBuf.find("\r\n\r\n")) != std::string::npos) {
		onePkt = m_strRcvBuf.substr(0, index + 4);
		m_strRcvBuf.erase(0, index + 4);
		switch (parserHttpReq(onePkt)) {
137
		case Http_failed:
xzl committed
138 139 140
			//失败
			shutdown();
			return;
141
		case Http_success:
xzl committed
142 143
			//成功
			break;
144
		case Http_moreData:
xzl committed
145 146 147 148 149 150 151 152
			//需要更多数据,恢复数据并退出
			m_strRcvBuf = onePkt + m_strRcvBuf;
			m_parser.Clear();
			return;
		}
	}
	m_parser.Clear();
}
153
inline HttpSession::HttpCode HttpSession::parserHttpReq(const string &str) {
xzl committed
154
	m_parser.Parse(str.data());
xiongziliang committed
155
	urlDecode(m_parser);
xzl committed
156
	string cmd = m_parser.Method();
xiongziliang committed
157 158 159 160 161 162 163 164

	typedef HttpSession::HttpCode (HttpSession::*HttpCMDHandle)();
	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);

xzl committed
165 166 167 168
	auto it = g_mapCmdIndex.find(cmd);
	if (it == g_mapCmdIndex.end()) {
		WarnL << cmd;
		sendResponse("403 Forbidden", makeHttpHeader(true), "");
169
		return Http_failed;
xzl committed
170 171 172 173 174 175
	}
	auto fun = it->second;
	return (this->*fun)();
}
void HttpSession::onError(const SockException& err) {
	//WarnL << err.what();
176 177
    GET_CONFIG_AND_REGISTER(uint32_t,iFlowThreshold,Broadcast::kFlowThreshold);

xiongziliang committed
178 179
    if(m_ui64TotalBytes > iFlowThreshold * 1024){
        NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,m_mediaInfo,m_ui64TotalBytes,*this);
180
    }
xzl committed
181 182 183
}

void HttpSession::onManager() {
184 185 186
    GET_CONFIG_AND_REGISTER(uint32_t,keepAliveSec,Config::Http::kKeepAliveSecond);

    if(m_ticker.elapsedTime() > keepAliveSec * 1000){
xzl committed
187
		//1分钟超时
188
		WarnL<<"HttpSession timeouted!";
xzl committed
189 190 191
		shutdown();
	}
}
192 193
//http-flv 链接格式:http://vhost-url:port/app/streamid.flv?key1=value1&key2=value2
//如果url(除去?以及后面的参数)后缀是.flv,那么表明该url是一个http-flv直播。
xiongziliang committed
194 195 196 197 198 199 200 201 202 203
inline bool HttpSession::checkLiveFlvStream(){
	auto pos = strrchr(m_parser.Url().data(),'.');
	if(!pos){
		//未找到".flv"后缀
		return false;
	}
	if(strcasecmp(pos,".flv") != 0){
		//未找到".flv"后缀
		return false;
	}
204 205
    //拼接成完整url
    auto fullUrl = string(HTTP_SCHEMA) + "://" + m_parser["Host"] + m_parser.FullUrl();
206 207
    m_mediaInfo.parse(fullUrl);
    m_mediaInfo.m_streamid.erase(m_mediaInfo.m_streamid.size() - 4);//去除.flv后缀
208

209
	auto mediaSrc = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTMP_SCHEMA,m_mediaInfo.m_vhost,m_mediaInfo.m_app,m_mediaInfo.m_streamid));
210
	if(!mediaSrc){
xiongziliang committed
211
		//该rtmp源不存在
212
		return false;
xiongziliang committed
213 214
	}

215 216
    auto onRes = [this,mediaSrc](const string &err){
        bool authSuccess = err.empty();
217
        if(!authSuccess){
218
            sendResponse("401 Unauthorized", makeHttpHeader(true,err.size()),err);
219 220 221 222 223
            shutdown();
            return ;
        }
        //找到rtmp源,发送http头,负载后续发送
        sendResponse("200 OK", makeHttpHeader(false,0,get_mime_type(".flv")), "");
xiongziliang committed
224

225
        //开始发送rtmp负载
226 227 228 229
        //关闭tcp_nodelay ,优化性能
        SockUtil::setNoDelay(_sock->rawFD(),false);
        (*this) << SocketFlags(sock_flags);

xiongziliang committed
230 231 232 233 234 235
		try{
			start(mediaSrc);
		}catch (std::exception &ex){
			//该rtmp源不存在
			shutdown();
		}
236 237 238
    };

    weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
239
    Broadcast::AuthInvoker invoker = [weakSelf,onRes](const string &err){
240 241 242 243
        auto strongSelf = weakSelf.lock();
        if(!strongSelf){
            return;
        }
244
        strongSelf->async([weakSelf,onRes,err](){
245 246 247 248
            auto strongSelf = weakSelf.lock();
            if(!strongSelf){
                return;
            }
249
            onRes(err);
250 251
        });
    };
252
    auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,m_mediaInfo,invoker,*this);
253 254
    if(!flag){
        //该事件无人监听,默认不鉴权
255
        onRes("");
256 257
    }
    return true;
xiongziliang committed
258
}
259
inline HttpSession::HttpCode HttpSession::Handle_Req_GET() {
xiongziliang committed
260 261 262
	//先看看该http事件是否被拦截
	if(emitHttpEvent(false)){
		return Http_success;
263
	}
264
    //再看看是否为http-flv直播请求
xiongziliang committed
265 266 267
	if(checkLiveFlvStream()){
		return Http_success;
	}
xiongziliang committed
268
	//事件未被拦截,则认为是http下载请求
269

270
	auto fullUrl = string(HTTP_SCHEMA) + "://" + m_parser["Host"] + m_parser.FullUrl();
271
    m_mediaInfo.parse(fullUrl);
272

273
	string strFile = m_strPath + "/" + m_mediaInfo.m_vhost + m_parser.Url();
xiongziliang committed
274
	/////////////HTTP连接是否需要被关闭////////////////
275 276
    GET_CONFIG_AND_REGISTER(uint32_t,reqCnt,Config::Http::kMaxReqCount);

277
    bool bClose = (strcasecmp(m_parser["Connection"].data(),"close") == 0) || ( ++m_iReqCnt > reqCnt);
278
	HttpCode eHttpCode = bClose ? Http_failed : Http_success;
xiongziliang committed
279
	//访问的是文件夹
xzl committed
280
	if (strFile.back() == '/') {
xiongziliang committed
281
		//生成文件夹菜单索引
xzl committed
282
		string strMeun;
283
		if (!makeMeun(strFile,m_mediaInfo.m_vhost, strMeun)) {
xiongziliang committed
284
			//文件夹不存在
xzl committed
285
			sendNotFound(bClose);
286
			return eHttpCode;
xzl committed
287 288
		}
		sendResponse("200 OK", makeHttpHeader(bClose,strMeun.size() ), strMeun);
289
		return eHttpCode;
xzl committed
290
	}
xiongziliang committed
291
	//访问的是文件
xzl committed
292 293
	struct stat tFileStat;
	if (0 != stat(strFile.data(), &tFileStat)) {
xiongziliang committed
294
		//文件不存在
xzl committed
295
		sendNotFound(bClose);
296
		return eHttpCode;
xzl committed
297
	}
298 299 300 301 302 303 304 305
    //文件智能指针,防止退出时未关闭
    std::shared_ptr<FILE> pFilePtr(fopen(strFile.data(), "rb"), [](FILE *pFile) {
        if(pFile){
            fclose(pFile);
        }
    });

	if (!pFilePtr) {
xiongziliang committed
306
		//打开文件失败
xzl committed
307
		sendNotFound(bClose);
308
		return eHttpCode;
xzl committed
309
	}
310

xiongziliang committed
311
	//判断是不是分节下载
xzl committed
312 313 314 315 316 317 318 319 320
	auto &strRange = m_parser["Range"];
	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) {
xiongziliang committed
321
		//全部下载
xzl committed
322 323
		pcHttpResult = "200 OK";
	} else {
xiongziliang committed
324
		//分节下载
xzl committed
325
		pcHttpResult = "206 Partial Content";
326
		fseek(pFilePtr.get(), iRangeStart, SEEK_SET);
xzl committed
327
	}
xiongziliang committed
328
	auto httpHeader=makeHttpHeader(bClose, iRangeEnd - iRangeStart + 1, get_mime_type(strFile.data()));
xzl committed
329
	if (strRange.size() != 0) {
xiongziliang committed
330
		//分节下载返回Content-Range头
xzl committed
331 332
		httpHeader.emplace("Content-Range",StrPrinter<<"bytes " << iRangeStart << "-" << iRangeEnd << "/" << tFileStat.st_size<< endl);
	}
333 334 335 336 337
	auto Origin = m_parser["Origin"];
	if(!Origin.empty()){
		httpHeader["Access-Control-Allow-Origin"] = Origin;
		httpHeader["Access-Control-Allow-Credentials"] = "true";
	}
xiongziliang committed
338
	//先回复HTTP头部分
xzl committed
339 340
	sendResponse(pcHttpResult, httpHeader, "");
	if (iRangeEnd - iRangeStart < 0) {
xiongziliang committed
341
		//文件是空的!
342
		return eHttpCode;
xzl committed
343
	}
xiongziliang committed
344
	//回复Content部分
xzl committed
345
	std::shared_ptr<int64_t> piLeft(new int64_t(iRangeEnd - iRangeStart + 1));
346

347 348
    GET_CONFIG_AND_REGISTER(uint32_t,sendBufSize,Config::Http::kSendBufSize);

xzl committed
349
	weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
350
	auto onFlush = [pFilePtr,bClose,weakSelf,piLeft]() {
xzl committed
351 352 353
		TimeTicker();
		auto strongSelf = weakSelf.lock();
		while(*piLeft && strongSelf){
354 355 356
            //更新超时定时器
            strongSelf->m_ticker.resetTime();
            //从循环池获取一个内存片
357
            auto sendBuf = strongSelf->obtainBuffer();
358 359
            sendBuf->setCapacity(sendBufSize);
            //本次需要读取文件字节数
xzl committed
360
			int64_t iReq = MIN(sendBufSize,*piLeft);
root committed
361 362 363 364 365
            //读文件	
			int iRead;
			do{
				 iRead = fread(sendBuf->data(), 1, iReq, pFilePtr.get());
			}while(-1 == iRead && UV_EINTR == get_uv_error(false));
366
            //文件剩余字节数
root committed
367
			
xzl committed
368
			*piLeft -= iRead;
369

xzl committed
370
			if (iRead < iReq || !*piLeft) {
371
                //文件读完
root committed
372
				//InfoL << "send complete!" << iRead << " " << iReq << " " << *piLeft;
xzl committed
373
				if(iRead>0) {
374
					sendBuf->setSize(iRead);
375
					strongSelf->send(sendBuf);
xzl committed
376 377 378 379 380 381
				}
				if(bClose) {
					strongSelf->shutdown();
				}
				return false;
			}
382 383
            //文件还未读完
            sendBuf->setSize(iRead);
384
            int iSent = strongSelf->send(sendBuf);
xzl committed
385
			if(iSent == -1) {
root committed
386
				//InfoL << "send error";
xzl committed
387 388 389
				return false;
			}
			if(iSent < iRead) {
root committed
390 391 392
				//数据回滚
				fseek(pFilePtr.get(), -iRead, SEEK_CUR);
				*piLeft += iRead;
xzl committed
393 394
				return true;
			}
xiongziliang committed
395 396 397 398
            if(strongSelf->isSocketBusy()){
                //套接字忙,那么停止继续写
                return true;
            }
xzl committed
399 400 401 402
			//send success
		}
		return false;
	};
403
	//关闭tcp_nodelay ,优化性能
404
	SockUtil::setNoDelay(_sock->rawFD(),false);
405
    //设置MSG_MORE,优化性能
406
    (*this) << SocketFlags(sock_flags);
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426

    //后台线程执行onFlush
    auto onFlushWrapper = [onFlush,weakSelf](){
        auto strongSelf = weakSelf.lock();
        if(!strongSelf){
            return false;
        }
        strongSelf->async([onFlush,weakSelf](){
            //在后台线程完成文件读取,释放主线程性能
            if(!onFlush()){
                //如果onFlush返回false,则说明不再监听flush事件
                auto strongSelf = weakSelf.lock();
                if(strongSelf){
                    strongSelf->_sock->setOnFlush(nullptr);
                }
            }
        });
        return true;
    };

427
    onFlush();
428
	_sock->setOnFlush(onFlushWrapper);
429
	return Http_success;
xzl committed
430 431
}

432
inline bool HttpSession::makeMeun(const string &strFullPath,const string &vhost, string &strRet) {
xzl committed
433 434 435 436 437 438 439 440 441 442 443 444 445
	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;
446
	strPath = strPath.substr(m_strPath.length() + vhost.length() + 1);
xzl committed
447 448 449 450 451 452
	strRet += strPath;
	strRet += "</h1>\r\n";
	if (strPath != "/") {
		strRet += "<li><a href=\"";
		strRet += "/";
		strRet += "\">";
453
		strRet += "根目录";
xzl committed
454 455 456 457 458
		strRet += "</a></li>\r\n";

		strRet += "<li><a href=\"";
		strRet += "../";
		strRet += "\">";
459
		strRet += "上级目录";
xzl committed
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
		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;
	printer << "HTTP/1.1 " << pcStatus << " \r\n";
	for (auto &pr : header) {
		printer << pr.first << ": " << pr.second << "\r\n";
	}
	printer << "\r\n" << strContent;
	auto strSend = printer << endl;
	//DebugL << strSend;
	send(strSend);
	m_ticker.resetTime();
}
inline HttpSession::KeyValue HttpSession::makeHttpHeader(bool bClose, int64_t iContentSize,const char* pcContentType) {
	KeyValue headerOut;
526 527 528
    GET_CONFIG_AND_REGISTER(string,charSet,Config::Http::kCharSet);
    GET_CONFIG_AND_REGISTER(uint32_t,keepAliveSec,Config::Http::kKeepAliveSecond);
    GET_CONFIG_AND_REGISTER(uint32_t,reqCnt,Config::Http::kMaxReqCount);
xzl committed
529

xiongziliang committed
530
	headerOut.emplace("Date", dateStr());
531
	headerOut.emplace("Server", SERVER_NAME);
xiongziliang committed
532
	headerOut.emplace("Connection", bClose ? "close" : "keep-alive");
xiongziliang committed
533 534 535 536
	if(!bClose){
		headerOut.emplace("Keep-Alive",StrPrinter << "timeout=" << keepAliveSec << ", max=" << reqCnt << endl);
	}
	if(pcContentType){
xzl committed
537
		auto strContentType = StrPrinter << pcContentType << "; charset=" << charSet << endl;
xiongziliang committed
538 539 540
		headerOut.emplace("Content-Type",strContentType);
	}
	if(iContentSize > 0){
xzl committed
541 542 543 544 545
		headerOut.emplace("Content-Length", StrPrinter<<iContentSize<<endl);
	}
	return headerOut;
}

xiongziliang committed
546 547
string HttpSession::urlDecode(const string &str){
	auto ret = strCoding::UrlUTF8Decode(str);
548
#ifdef _WIN32
549 550
    GET_CONFIG_AND_REGISTER(string,charSet,Config::Http::kCharSet);
	bool isGb2312 = !strcasecmp(charSet.data(), "gb2312");
551
	if (isGb2312) {
xiongziliang committed
552
		ret = strCoding::UTF8ToGB2312(ret);
553 554
	}
#endif // _WIN32
xiongziliang committed
555 556
    return ret;
}
557

xiongziliang committed
558 559 560 561 562 563
inline void HttpSession::urlDecode(Parser &parser){
	parser.setUrl(urlDecode(parser.Url()));
	for(auto &pr : m_parser.getUrlArgs()){
		const_cast<string &>(pr.second) = urlDecode(pr.second);
	}
}
xzl committed
564

xiongziliang committed
565 566
inline bool HttpSession::emitHttpEvent(bool doInvoke){
	///////////////////是否断开本链接///////////////////////
567 568
    GET_CONFIG_AND_REGISTER(uint32_t,reqCnt,Config::Http::kMaxReqCount);

569
    bool bClose = (strcasecmp(m_parser["Connection"].data(),"close") == 0) || ( ++m_iReqCnt > reqCnt);
xiongziliang committed
570
	auto Origin = m_parser["Origin"];
xiongziliang committed
571
	/////////////////////异步回复Invoker///////////////////////////////
572
	weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
xiongziliang committed
573
	HttpResponseInvoker invoker = [weakSelf,bClose,Origin](const string &codeOut, const KeyValue &headerOut, const string &contentOut){
574 575 576 577
		auto strongSelf = weakSelf.lock();
		if(!strongSelf) {
			return;
		}
xiongziliang committed
578
		strongSelf->async([weakSelf,bClose,codeOut,headerOut,contentOut,Origin]() {
579 580 581 582
			auto strongSelf = weakSelf.lock();
			if(!strongSelf) {
				return;
			}
xiongziliang committed
583
			strongSelf->responseDelay(Origin,bClose,codeOut,headerOut,contentOut);
584 585 586 587 588
			if(bClose){
				strongSelf->shutdown();
			}
		});
	};
xiongziliang committed
589 590
	///////////////////广播HTTP事件///////////////////////////
	bool consumed = false;//该事件是否被消费
591
	NoticeCenter::Instance().emitEvent(Config::Broadcast::kBroadcastHttpRequest,m_parser,invoker,consumed,*this);
xiongziliang committed
592 593
	if(!consumed && doInvoke){
		//该事件无人消费,所以返回404
594
		invoker("404 Not Found",KeyValue(),"");
xzl committed
595
	}
xiongziliang committed
596 597 598 599 600 601 602 603 604 605 606 607
	return consumed;
}
inline HttpSession::HttpCode HttpSession::Handle_Req_POST() {
	//////////////获取HTTP POST Content/////////////
	int iContentLen = atoi(m_parser["Content-Length"].data());
	if ((int) m_strRcvBuf.size() < iContentLen) {
		return Http_moreData; //需要更多数据
	}
	m_parser.setContent(m_strRcvBuf.substr(0, iContentLen));
	m_strRcvBuf.erase(0, iContentLen);
	//广播事件
	emitHttpEvent(true);
608 609
	return Http_success;
}
xiongziliang committed
610 611 612
void HttpSession::responseDelay(const string &Origin,bool bClose,
								const string &codeOut,const KeyValue &headerOut,
								const string &contentOut){
613 614 615 616
	if(codeOut.empty()){
		sendNotFound(bClose);
		return;
	}
xiongziliang committed
617
	auto headerOther=makeHttpHeader(bClose,contentOut.size(),"text/plain");
xiongziliang committed
618 619 620 621
	if(!Origin.empty()){
		headerOther["Access-Control-Allow-Origin"] = Origin;
		headerOther["Access-Control-Allow-Credentials"] = "true";
	}
xiongziliang committed
622
	const_cast<KeyValue &>(headerOut).insert(headerOther.begin(), headerOther.end());
623
	sendResponse(codeOut.data(), headerOut, contentOut);
xzl committed
624 625
}
inline void HttpSession::sendNotFound(bool bClose) {
626 627
    GET_CONFIG_AND_REGISTER(string,notFound,Config::Http::kNotFound);
    sendResponse("404 Not Found", makeHttpHeader(bClose, notFound.size()), notFound);
xzl committed
628 629
}

xiongziliang committed
630 631 632 633 634 635 636 637

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;
		}
638
		strongSelf->m_ticker.resetTime();
xiongziliang committed
639 640 641
		strongSelf->m_ui64TotalBytes += buffer->size();
		strongSelf->send(buffer);
	});
xiongziliang committed
642 643
}

xiongziliang committed
644 645 646 647 648 649 650 651 652 653
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;
		}
654
		strongSelf->m_ticker.resetTime();
xiongziliang committed
655 656 657
		strongSelf->m_ui64TotalBytes += buffer->size();
		strongSelf->send(buffer);
	});
xiongziliang committed
658 659
}

xiongziliang committed
660 661 662 663 664 665
void HttpSession::onDetach() {
	safeShutdown();
}

std::shared_ptr<FlvMuxer> HttpSession::getSharedPtr(){
	return dynamic_pointer_cast<FlvMuxer>(shared_from_this());
666 667
}

xzl committed
668 669
} /* namespace Http */
} /* namespace ZL */