2017-09-27 16:20:30 +08:00
/*
* MIT License
*
* 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-05-05 18:02:54 +08:00
# include "HttpClient.h"
# include "Rtsp/Rtsp.h"
namespace ZL {
namespace Http {
HttpClient : : HttpClient ( ) {
}
HttpClient : : ~ HttpClient ( ) {
}
void HttpClient : : sendRequest ( const string & strUrl ) {
auto protocol = FindField ( strUrl . data ( ) , NULL , " :// " ) ;
uint16_t defaultPort ;
bool isHttps ;
if ( strcasecmp ( protocol . data ( ) , " http " ) = = 0 ) {
defaultPort = 80 ;
isHttps = false ;
} else if ( strcasecmp ( protocol . data ( ) , " https " ) = = 0 ) {
defaultPort = 443 ;
isHttps = true ;
} else {
2017-08-09 18:39:30 +08:00
auto strErr = StrPrinter < < " 非法的协议: " < < protocol < < endl ;
2017-05-05 18:02:54 +08:00
throw std : : invalid_argument ( strErr ) ;
}
auto host = FindField ( strUrl . data ( ) , " :// " , " / " ) ;
if ( host . empty ( ) ) {
host = FindField ( strUrl . data ( ) , " :// " , NULL ) ;
}
_path = FindField ( strUrl . data ( ) , host . data ( ) , NULL ) ;
if ( _path . empty ( ) ) {
_path = " / " ;
}
auto port = atoi ( FindField ( host . data ( ) , " : " , NULL ) . data ( ) ) ;
if ( port < = 0 ) {
//默认端口
port = defaultPort ;
} else {
//服务器域名
host = FindField ( host . data ( ) , NULL , " : " ) ;
}
_header . emplace ( string ( " Host " ) , host ) ;
_header . emplace ( string ( " Tools " ) , " ZLMediaKit " ) ;
_header . emplace ( string ( " Connection " ) , " keep-alive " ) ;
2017-05-05 23:53:09 +08:00
_header . emplace ( string ( " Accept " ) , " */* " ) ;
2017-05-05 18:02:54 +08:00
_header . emplace ( string ( " Accept-Language " ) , " zh-CN,zh;q=0.8 " ) ;
_header . emplace ( string ( " User-Agent " ) , " Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 " ) ;
if ( ! _body . empty ( ) ) {
2017-05-25 17:41:58 +08:00
_header . emplace ( string ( " Content-Length " ) , to_string ( _body . size ( ) ) ) ;
2017-05-05 18:02:54 +08:00
_header . emplace ( string ( " Content-Type " ) , " application/x-www-form-urlencoded; charset=UTF-8 " ) ;
}
bool bChanged = ( _lastHost ! = host + " : " + to_string ( port ) ) | | ( _isHttps ! = isHttps ) ;
_lastHost = host + " : " + to_string ( port ) ;
_isHttps = isHttps ;
if ( ! alive ( ) | | bChanged ) {
InfoL < < " reconnet: " < < _lastHost ;
startConnect ( host , port ) ;
} else {
SockException ex ;
onConnect ( ex ) ;
}
}
void HttpClient : : onConnect ( const SockException & ex ) {
if ( ex ) {
onDisconnect ( ex ) ;
return ;
}
_recvedBodySize = - 1 ;
_recvedResponse . clear ( ) ;
send ( _method + " " ) ;
send ( _path + " HTTP/1.1 \r \n " ) ;
for ( auto & pr : _header ) {
send ( pr . first + " : " ) ;
send ( pr . second + " \r \n " ) ;
}
send ( " \r \n " ) ;
if ( ! _body . empty ( ) ) {
send ( _body ) ;
}
}
void HttpClient : : onRecv ( const Socket : : Buffer : : Ptr & pBuf ) {
onRecvBytes ( pBuf - > data ( ) , pBuf - > size ( ) ) ;
}
void HttpClient : : onErr ( const SockException & ex ) {
onDisconnect ( ex ) ;
}
void HttpClient : : onRecvBytes ( const char * data , int size ) {
if ( _recvedBodySize = = - 1 ) {
//还没有收到http body, 这只是http头
auto lastLen = _recvedResponse . size ( ) ;
_recvedResponse . append ( data , size ) ;
auto pos = _recvedResponse . find ( " \r \n \r \n " , lastLen ) ;
if ( pos = = string : : npos ) {
//http 头还未收到
return ;
}
_parser . Parse ( _recvedResponse . data ( ) ) ;
onResponseHeader ( _parser . Url ( ) , _parser . getValues ( ) ) ;
_totalBodySize = atoll ( ( ( HttpHeader & ) _parser . getValues ( ) ) [ " Content-Length " ] . data ( ) ) ;
_recvedBodySize = _recvedResponse . size ( ) - pos - 4 ;
if ( _totalBodySize < _recvedBodySize ) {
//http body 比声明的大 这个不可能的
2017-05-05 23:53:09 +08:00
_StrPrinter printer ;
for ( auto & pr : _parser . getValues ( ) ) {
printer < < pr . first < < " : " < < pr . second < < " \r \n " ;
}
FatalL < < _totalBodySize < < " : " < < _recvedBodySize < < " \r \n " < < ( printer < < endl ) ;
2017-05-05 18:02:54 +08:00
shutdown ( ) ;
return ;
}
if ( _recvedBodySize ) {
//_recvedResponse里面包含body负载
onResponseBody ( _recvedResponse . data ( ) + _recvedResponse . size ( ) - _recvedBodySize , _recvedBodySize , _recvedBodySize , _totalBodySize ) ;
}
if ( _recvedBodySize > = _totalBodySize ) {
onResponseCompleted ( ) ;
}
_recvedResponse . clear ( ) ;
return ;
}
//http body
if ( _recvedBodySize < _totalBodySize ) {
_recvedBodySize + = size ;
onResponseBody ( data , size , _recvedBodySize , _totalBodySize ) ;
if ( _recvedBodySize > = _totalBodySize ) {
onResponseCompleted ( ) ;
}
return ;
}
//http body 比声明的大 这个不可能的
2017-05-05 23:53:09 +08:00
_StrPrinter printer ;
for ( auto & pr : _parser . getValues ( ) ) {
printer < < pr . first < < " : " < < pr . second < < " \r \n " ;
}
FatalL < < _totalBodySize < < " : " < < _recvedBodySize < < " \r \n " < < ( printer < < endl ) ;
2017-05-05 18:02:54 +08:00
shutdown ( ) ;
}
} /* namespace Http */
} /* namespace ZL */