HttpPushSession.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. #include "HttpPushSession.h"
  2. #include "Poco/Net/MediaType.h"
  3. #include "Poco/Exception.h"
  4. #include "Poco/Net/MultipartWriter.h"
  5. #include "Poco/Net/NameValueCollection.h"
  6. #include "ErrorCode.h"
  7. #include <fstream>
  8. #include "Poco/Buffer.h"
  9. #include "Poco/Timespan.h"
  10. #include "PhmsLogger.h"
  11. #include "Util.h"
  12. #include "GlobalTerminalLogoString.h"
  13. #include <sstream>
  14. #include "PhmsResponse.h"
  15. using Poco::Exception;
  16. using Poco::TimeoutException;
  17. using Poco::Net::MultipartWriter;
  18. using Poco::Net::MediaType;
  19. using Poco::Net::MessageHeader;
  20. using Poco::Buffer;
  21. using Poco::Timespan;
  22. using Poco::Net::NameValueCollection;
  23. using std::ifstream;
  24. CHttpPushSession::CHttpPushSession(void):m_bSsl(false)
  25. {
  26. m_pSession = new HTTPClientSession();
  27. m_pContext = NULL;
  28. }
  29. CHttpPushSession::CHttpPushSession(bool bSsl):m_bSsl(bSsl)
  30. {
  31. if(!m_bSsl)
  32. {
  33. m_pSession = new HTTPClientSession();
  34. m_pContext = NULL;
  35. }
  36. else
  37. {
  38. //不知道为什么调用Poco::Net::initializeSSL()不起作用,无参数的HTTPSClientSession构造函数报错,必须先创建一个Context
  39. //然后调用传入Context::Ptr类型的HTTPSClientSession构造函数,以后有时间在研究
  40. //不必考虑ssl初始化函数重入,Poco::Crypto::OpenSSLInitializer::initialize()函数做了互斥
  41. m_pContext = new Context(Context::CLIENT_USE, "", "", "", Context::VERIFY_NONE, 9, false);
  42. m_pSession = new HTTPSClientSession(m_pContext);
  43. }
  44. }
  45. CHttpPushSession::CHttpPushSession(CNetConfig netConfig):m_bSsl(netConfig.GetSsl())
  46. {
  47. if(!m_bSsl)
  48. {
  49. m_pSession = new HTTPClientSession();
  50. m_pContext = NULL;
  51. }
  52. else
  53. {
  54. m_pContext = new Context(Context::CLIENT_USE, "", "", "", Context::VERIFY_NONE, 9, false);
  55. m_pSession = new HTTPSClientSession(m_pContext);
  56. }
  57. }
  58. CHttpPushSession::~CHttpPushSession(void)
  59. {
  60. delete m_pSession;
  61. m_pSession = NULL;
  62. }
  63. //Getter
  64. bool CHttpPushSession::GetSsl()
  65. {
  66. return m_bSsl;
  67. }
  68. HTTPClientSession* CHttpPushSession::GetHttpClientSession()
  69. {
  70. return m_pSession;
  71. }
  72. int CHttpPushSession::ExecuteHttpPushSession(CNetConfig& netConfig, CPhmsRequest& phmsRequest, pHttpPushCallback pCallback)
  73. {
  74. //if(m_pSession->connected())
  75. {
  76. m_pSession->release();
  77. }
  78. int nRet = PHMS_SUCCESSFUL_RESULT;
  79. nRet = this->SetNetWork(netConfig);
  80. if(nRet != PHMS_SUCCESSFUL_RESULT)
  81. {
  82. //写日志
  83. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(nRet), __FUNCTION__, __FILE__, __LINE__);
  84. return nRet;
  85. }
  86. HTTPRequest httpRequest;
  87. string stringBoundary = MultipartWriter::createBoundary();
  88. this->GenerateHttpRequest(netConfig, phmsRequest, stringBoundary, httpRequest);
  89. try
  90. {
  91. m_pSession->setHttpPush();//设置推送http
  92. ostream &requestStream = m_pSession->sendRequest(httpRequest);
  93. nRet = this->SendPhms(requestStream, stringBoundary, phmsRequest);
  94. if(nRet != PHMS_SUCCESSFUL_RESULT)
  95. {
  96. //写日志
  97. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(nRet), __FUNCTION__, __FILE__, __LINE__);
  98. return nRet;
  99. }
  100. }
  101. catch(TimeoutException &e)
  102. {
  103. //写日志
  104. CPhmsLogger::GetPhmsLogger()->WriteLog(e, __FUNCTION__, __FILE__, __LINE__);
  105. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_SEND_TIMEOUT), __FUNCTION__, __FILE__, __LINE__);
  106. return COMMON_SEND_TIMEOUT;
  107. }
  108. catch(Exception& e)
  109. {
  110. //写日志
  111. CPhmsLogger::GetPhmsLogger()->WriteLog(e, __FUNCTION__, __FILE__, __LINE__);
  112. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_SEND_FAIL), __FUNCTION__, __FILE__, __LINE__);
  113. return COMMON_SEND_FAIL;
  114. }
  115. HTTPResponse httpResponse;
  116. try
  117. {
  118. m_pSession->receiveResponseHead(httpResponse);
  119. nRet = HandleHttpResponse(httpResponse);
  120. if(nRet != PHMS_SUCCESSFUL_RESULT)
  121. {
  122. //写日志
  123. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(nRet), __FUNCTION__, __FILE__, __LINE__);
  124. CPhmsLogger::GetPhmsLogger()->WriteLog(httpResponse.getReason(), __FUNCTION__, __FILE__, __LINE__);
  125. return nRet;
  126. }
  127. else
  128. {
  129. pCallback(NULL, 0);
  130. }
  131. int nChunkedLen = 0;
  132. do
  133. {
  134. string stringChunkedContent;
  135. nChunkedLen = m_pSession->receiveResponseBody_PUSH(stringChunkedContent);
  136. //判断Phms响应头
  137. if(nChunkedLen != 0)
  138. {
  139. CPhmsResponse phmsResponse;
  140. istringstream iPhmsResponse(stringChunkedContent);
  141. nRet = phmsResponse.SetPhmsResponse(&iPhmsResponse, this);
  142. if(nRet != PHMS_SUCCESSFUL_RESULT)
  143. {
  144. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(nRet), __FUNCTION__, __FILE__, __LINE__);
  145. return nRet;
  146. }
  147. string stringXmlContent;
  148. string stringXmlPath;
  149. nRet = phmsResponse.GetResult(1, stringXmlContent, stringXmlPath);
  150. if(nRet != PHMS_SUCCESSFUL_RESULT)
  151. {
  152. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(nRet), __FUNCTION__, __FILE__, __LINE__);
  153. return nRet;
  154. }
  155. if(pCallback != NULL)
  156. {
  157. pCallback(stringXmlContent.c_str(), (unsigned long)stringXmlContent.size());
  158. }
  159. }
  160. } while (nChunkedLen != 0);
  161. }
  162. //无timeout超时,推送是recv无限等待
  163. catch(Exception& e)
  164. {
  165. //写日志
  166. CPhmsLogger::GetPhmsLogger()->WriteLog(e, __FUNCTION__, __FILE__, __LINE__);
  167. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_RECV_FAIL), __FUNCTION__, __FILE__, __LINE__);
  168. return COMMON_RECV_FAIL;
  169. }
  170. return PHMS_SUCCESSFUL_RESULT;
  171. }
  172. int CHttpPushSession::GetHttpExceptionInfo(int& nCode, string& stringMsgName, string& stringMsgText)
  173. {
  174. const Exception* p = m_pSession->networkException();
  175. if(p != NULL)
  176. nCode = p->code();
  177. stringMsgName = p->name();
  178. stringMsgText = p->message();
  179. return PHMS_SUCCESSFUL_RESULT;
  180. }
  181. int CHttpPushSession::abort()
  182. {
  183. try
  184. {
  185. m_pSession->abort();
  186. }
  187. catch(Exception&)
  188. {
  189. //异常说明socket已经是无效的了,其效果等同于abort成功,所以异常捕获里无操作
  190. }
  191. return PHMS_SUCCESSFUL_RESULT;
  192. }
  193. int CHttpPushSession::SetNetWork(CNetConfig& netConfig)
  194. {
  195. if(m_bSsl != netConfig.GetSsl())
  196. {
  197. //写日志
  198. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_SSL_CONFLICT_ERROR), __FUNCTION__, __FILE__, __LINE__);
  199. return COMMON_SSL_CONFLICT_ERROR;
  200. }
  201. if(netConfig.ValidatePort()==false || netConfig.ValidAddrAndUrl()==false)
  202. {
  203. //写日志
  204. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_NET_CONFIG_ERROR), __FUNCTION__, __FILE__, __LINE__);
  205. return COMMON_NET_CONFIG_ERROR;
  206. }
  207. if(netConfig.GetPrpxyType() != NO_PROXY)
  208. {
  209. if(netConfig.ValidateProxyInfo() == false)
  210. {
  211. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_PROXY_INFO_ERROR), __FUNCTION__, __FILE__, __LINE__);
  212. return COMMON_PROXY_INFO_ERROR;
  213. }
  214. }
  215. m_pSession->setHost(netConfig.GetHost());
  216. m_pSession->setAddr(netConfig.GetAddr());
  217. m_pSession->setPort(netConfig.GetPort());
  218. if(netConfig.GetPrpxyType() == HTTP_PROXY)
  219. {
  220. m_pSession->setProxyType(HTTP_PROXY);
  221. m_pSession->setProxy(netConfig.GetProxyAddr(), netConfig.GetProxyPort());
  222. m_pSession->setProxyCredentials(netConfig.GetProxyUsername(), netConfig.GetProxyPassword());
  223. }
  224. if(netConfig.GetPrpxyType() == SOCK_PROXY)
  225. {
  226. m_pSession->setProxyType(SOCK_PROXY);
  227. m_pSession->setProxy(netConfig.GetProxyAddr(), netConfig.GetProxyPort());
  228. m_pSession->setProxyCredentials(netConfig.GetProxyUsername(), netConfig.GetProxyPassword());
  229. }
  230. return PHMS_SUCCESSFUL_RESULT;
  231. }
  232. int CHttpPushSession::GenerateHttpRequest(CNetConfig& netConfig, CPhmsRequest& phmsRequest, string stringBoundary, HTTPRequest& httpRequest)
  233. {
  234. httpRequest.setVersion(HTTPMessage::HTTP_1_1);
  235. httpRequest.setMethod(HTTPRequest::HTTP_POST);
  236. httpRequest.setURI(netConfig.GetUrl());
  237. httpRequest.setKeepAlive(false);
  238. httpRequest.set("pragma", "no-cache");
  239. httpRequest.set("User-Agent", g_stringTerminalType);
  240. if(phmsRequest.GetPhmsRequestHead().GetOperationCode() != "1002")
  241. {
  242. NameValueCollection nameValueCollection;
  243. nameValueCollection.add("PHPSESSID", phmsRequest.GetPhmsRequestHead().GetSessionId());
  244. httpRequest.setCookies(nameValueCollection);
  245. }
  246. if(phmsRequest.GetFilePath().size() == 0)
  247. {
  248. //无附加文件
  249. MediaType mediaType("application", "x-www-form-urlencoded");
  250. mediaType.setParameter("charset", "GB2312");
  251. httpRequest.setContentType(mediaType);
  252. string stringParameterName = "msg=";
  253. httpRequest.setContentLength(phmsRequest.ToString().size()+stringParameterName.size());
  254. }
  255. else
  256. {
  257. //有附件文件
  258. MediaType mediaType("multipart", "form-data");
  259. mediaType.setParameter("boundary", stringBoundary);
  260. httpRequest.setContentType(mediaType);
  261. //由于当前使用的Nginx版本,不支持客户端的chunked模式请求,所以暂时不使用chunked模式请求
  262. //Nginx服务器到版本1.3.9才支持chunked模式的请求
  263. //服务器添加了支持chunked请求的模块2012-12-25
  264. httpRequest.setChunkedTransferEncoding(true);
  265. }
  266. return PHMS_SUCCESSFUL_RESULT;
  267. }
  268. int CHttpPushSession::SendPhms(ostream& outputStream, string stringBoundary, CPhmsRequest& phmsRequest)
  269. {
  270. if(phmsRequest.GetFilePath().size() == 0)
  271. {
  272. //无附加文件
  273. try
  274. {
  275. outputStream.exceptions(ios::failbit|ios::badbit);
  276. outputStream<<"msg="<<phmsRequest.ToString();
  277. }
  278. catch(const ios::failure& error)
  279. {
  280. //写日志
  281. int nCode = 0;
  282. string stringMsgName;
  283. string stringMsgText;
  284. this->GetHttpExceptionInfo(nCode, stringMsgName, stringMsgText);
  285. CPhmsLogger::GetPhmsLogger()->WriteLog(stringMsgText, __FUNCTION__, __FILE__, __LINE__);
  286. CPhmsLogger::GetPhmsLogger()->WriteLog(error.what(), __FUNCTION__, __FILE__, __LINE__);
  287. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_OUTPUT_STREAM_FAIL), __FUNCTION__, __FILE__, __LINE__);
  288. return COMMON_OUTPUT_STREAM_FAIL;
  289. }
  290. catch(const TimeoutException& e)
  291. {
  292. CPhmsLogger::GetPhmsLogger()->WriteLog(e, __FUNCTION__, __FILE__, __LINE__);
  293. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_SEND_TIMEOUT), __FUNCTION__, __FILE__, __LINE__);
  294. return COMMON_SEND_TIMEOUT;
  295. }
  296. catch(const Exception& e)
  297. {
  298. CPhmsLogger::GetPhmsLogger()->WriteLog(e, __FUNCTION__, __FILE__, __LINE__);
  299. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_SEND_FAIL), __FUNCTION__, __FILE__, __LINE__);
  300. return COMMON_SEND_FAIL;
  301. }
  302. }
  303. else
  304. {
  305. //有附加文件
  306. MediaType mediaType1("");
  307. MediaType mediaType2("");
  308. MessageHeader messageHeader1;
  309. MessageHeader messageHeader2;
  310. mediaType1.setType("form-data");
  311. mediaType1.setParameter("name", "msg");
  312. mediaType2.setType("form-data");
  313. mediaType2.setParameter("name", "filename");
  314. mediaType2.setParameter("filename", phmsRequest.GetFilePath());
  315. messageHeader1.set("Content-Disposition", mediaType1.toString());
  316. messageHeader2.set("Content-Disposition", mediaType2.toString());
  317. try
  318. {
  319. MultipartWriter multipartWrite(outputStream, stringBoundary);
  320. multipartWrite.nextPart(messageHeader1);
  321. outputStream<<phmsRequest.ToString();
  322. multipartWrite.nextPart(messageHeader2);
  323. ifstream inputFileStream;
  324. inputFileStream.exceptions(ios::badbit);
  325. inputFileStream.open(phmsRequest.GetFilePath().c_str(), ios::in|ios::binary);
  326. if(inputFileStream.fail())
  327. {
  328. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_FILE_OPEN_FAIL), __FUNCTION__, __FILE__, __LINE__);
  329. return COMMON_FILE_OPEN_FAIL;
  330. }
  331. outputStream.exceptions(ios::failbit|ios::badbit);
  332. while(!inputFileStream.eof())
  333. {
  334. Buffer<char> bufFileContent(1024);
  335. memset(bufFileContent.begin(), 0, 1024);
  336. inputFileStream.read(bufFileContent.begin(), 1024);
  337. outputStream.write(bufFileContent.begin(), inputFileStream.gcount());
  338. }
  339. multipartWrite.close();
  340. inputFileStream.close();
  341. }
  342. catch(const ios::failure& error)
  343. {
  344. //写日志
  345. if(outputStream.fail() || outputStream.bad())
  346. {
  347. int nCode = 0;
  348. string stringMsgName;
  349. string stringMsgText;
  350. this->GetHttpExceptionInfo(nCode, stringMsgName, stringMsgText);
  351. CPhmsLogger::GetPhmsLogger()->WriteLog(stringMsgText, __FUNCTION__, __FILE__, __LINE__);
  352. }
  353. CPhmsLogger::GetPhmsLogger()->WriteLog(error.what(), __FUNCTION__, __FILE__, __LINE__);
  354. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_OUTPUT_STREAM_FAIL), __FUNCTION__, __FILE__, __LINE__);
  355. return COMMON_OUTPUT_STREAM_FAIL;
  356. }
  357. catch(const TimeoutException& e)
  358. {
  359. CPhmsLogger::GetPhmsLogger()->WriteLog(e, __FUNCTION__, __FILE__, __LINE__);
  360. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_SEND_TIMEOUT), __FUNCTION__, __FILE__, __LINE__);
  361. return COMMON_SEND_TIMEOUT;
  362. }
  363. catch(const Exception& e)
  364. {
  365. CPhmsLogger::GetPhmsLogger()->WriteLog(e, __FUNCTION__, __FILE__, __LINE__);
  366. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_SEND_FAIL), __FUNCTION__, __FILE__, __LINE__);
  367. return COMMON_SEND_FAIL;
  368. }
  369. }
  370. return PHMS_SUCCESSFUL_RESULT;
  371. }
  372. int CHttpPushSession::HandleHttpResponse(HTTPResponse& httpResponse)
  373. {
  374. switch(httpResponse.getStatus())
  375. {
  376. case HTTPResponse::HTTP_OK:
  377. return PHMS_SUCCESSFUL_RESULT;
  378. case HTTPResponse::HTTP_NOT_FOUND:
  379. case HTTPResponse::HTTP_FORBIDDEN:
  380. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_URL_NOT_FOUND), __FUNCTION__, __FILE__, __LINE__);
  381. return COMMON_URL_NOT_FOUND;
  382. default:
  383. CPhmsLogger::GetPhmsLogger()->WriteLog(CUtil::GetErrorMsg(COMMON_RECV_CONTENT_FAIL), __FUNCTION__, __FILE__, __LINE__);
  384. return COMMON_RECV_CONTENT_FAIL;
  385. }
  386. return PHMS_SUCCESSFUL_RESULT;
  387. }