开源的socket服务端客户端,支持C# C++

ClientDlg.cpp 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. // ClientDlg.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "Client.h"
  5. #include "ClientDlg.h"
  6. #include "afxdialogex.h"
  7. // CClientDlg dialog
  8. #define DEFAULT_PATH _T("req/path?p1=v1&p2=v2")
  9. #define DEFAULT_ADDRESS _T("127.0.0.1")
  10. #define DEFAULT_PORT _T("8080")
  11. CClientDlg::CClientDlg(CWnd* pParent /*=NULL*/)
  12. : CDialogEx(CClientDlg::IDD, pParent)
  13. {
  14. m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  15. }
  16. void CClientDlg::DoDataExchange(CDataExchange* pDX)
  17. {
  18. CDialogEx::DoDataExchange(pDX);
  19. DDX_Control(pDX, IDC_SEND, m_Send);
  20. DDX_Control(pDX, IDC_INFO, m_Info);
  21. DDX_Control(pDX, IDC_ADDRESS, m_Address);
  22. DDX_Control(pDX, IDC_PORT, m_Port);
  23. DDX_Control(pDX, IDC_ASYNC, m_Async);
  24. DDX_Control(pDX, IDC_START, m_Start);
  25. DDX_Control(pDX, IDC_STOP, m_Stop);
  26. DDX_Control(pDX, IDC_METHOD, m_Method);
  27. DDX_Control(pDX, IDC_SCHEMA, m_Schema);
  28. DDX_Control(pDX, IDC_PATH, m_Path);
  29. DDX_Control(pDX, IDC_HEADER_NAME, m_HeaderName);
  30. DDX_Control(pDX, IDC_HEADER_VALUE, m_HeaderValue);
  31. DDX_Control(pDX, IDC_HEADER_ADD, m_HeaderAdd);
  32. DDX_Control(pDX, IDC_HEADERS, m_Headers);
  33. DDX_Control(pDX, IDC_BODY, m_Body);
  34. }
  35. BEGIN_MESSAGE_MAP(CClientDlg, CDialogEx)
  36. ON_WM_PAINT()
  37. ON_WM_QUERYDRAGICON()
  38. ON_BN_CLICKED(IDC_SEND, &CClientDlg::OnBnClickedSend)
  39. ON_BN_CLICKED(IDC_START, &CClientDlg::OnBnClickedStart)
  40. ON_BN_CLICKED(IDC_STOP, &CClientDlg::OnBnClickedStop)
  41. ON_BN_CLICKED(IDC_HEADER_ADD, &CClientDlg::OnBnClickedHeaderAdd)
  42. ON_CBN_SELCHANGE(IDC_METHOD, &CClientDlg::OnCbnSelchangeMethod)
  43. ON_MESSAGE(USER_INFO_MSG, OnUserInfoMsg)
  44. ON_WM_VKEYTOITEM()
  45. END_MESSAGE_MAP()
  46. // CClientDlg message handlers
  47. BOOL CClientDlg::OnInitDialog()
  48. {
  49. CDialogEx::OnInitDialog();
  50. // Set the icon for this dialog. The framework does this automatically
  51. // when the application's main window is not a dialog
  52. SetIcon(m_hIcon, TRUE); // Set big icon
  53. SetIcon(m_hIcon, FALSE); // Set small icon
  54. // TODO: Add extra initialization here
  55. m_Method.SetCurSel(3);
  56. m_Schema.SetCurSel(0);
  57. m_Path.SetWindowText(DEFAULT_PATH);
  58. m_Address.SetWindowText(DEFAULT_ADDRESS);
  59. m_Port.SetWindowText(DEFAULT_PORT);
  60. m_Async.SetCheck(BST_CHECKED);
  61. ::SetMainWnd(this);
  62. ::SetInfoList(&m_Info);
  63. SetAppState(ST_STOPPED);
  64. m_bWebSocket = FALSE;
  65. m_bAsyncConn = FALSE;
  66. return TRUE; // return TRUE unless you set the focus to a control
  67. }
  68. // If you add a minimize button to your dialog, you will need the code below
  69. // to draw the icon. For MFC applications using the document/view model,
  70. // this is automatically done for you by the framework.
  71. void CClientDlg::OnPaint()
  72. {
  73. if (IsIconic())
  74. {
  75. CPaintDC dc(this); // device context for painting
  76. SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
  77. // Center icon in client rectangle
  78. int cxIcon = GetSystemMetrics(SM_CXICON);
  79. int cyIcon = GetSystemMetrics(SM_CYICON);
  80. CRect rect;
  81. GetClientRect(&rect);
  82. int x = (rect.Width() - cxIcon + 1) / 2;
  83. int y = (rect.Height() - cyIcon + 1) / 2;
  84. // Draw the icon
  85. dc.DrawIcon(x, y, m_hIcon);
  86. }
  87. else
  88. {
  89. CDialogEx::OnPaint();
  90. }
  91. }
  92. // The system calls this function to obtain the cursor to display while the user drags
  93. // the minimized window.
  94. HCURSOR CClientDlg::OnQueryDragIcon()
  95. {
  96. return static_cast<HCURSOR>(m_hIcon);
  97. }
  98. BOOL CClientDlg::PreTranslateMessage(MSG* pMsg)
  99. {
  100. if (
  101. pMsg->message == WM_KEYDOWN
  102. &&( pMsg->wParam == VK_ESCAPE
  103. || pMsg->wParam == VK_CANCEL
  104. || (pMsg->wParam == VK_RETURN && pMsg->hwnd == this->GetSafeHwnd())
  105. ))
  106. return TRUE;
  107. return CDialog::PreTranslateMessage(pMsg);
  108. }
  109. void CClientDlg::SetAppState(EnAppState state)
  110. {
  111. m_enState = state;
  112. if(this->GetSafeHwnd() == nullptr)
  113. return;
  114. m_Async.EnableWindow(m_enState == ST_STOPPED);
  115. m_Start.EnableWindow(m_enState == ST_STOPPED);
  116. m_Stop.EnableWindow(m_enState == ST_STARTED);
  117. m_Send.EnableWindow(m_enState == ST_STARTED);
  118. m_Schema.EnableWindow(m_enState == ST_STOPPED);
  119. m_Address.EnableWindow(m_enState == ST_STOPPED);
  120. m_Port.EnableWindow(m_enState == ST_STOPPED);
  121. m_Body.EnableWindow(m_Method.GetCurSel() <= 2 || m_bWebSocket);
  122. m_Path.EnableWindow(m_Method.GetCurSel() != 8);
  123. }
  124. void CClientDlg::OnBnClickedHeaderAdd()
  125. {
  126. CString strName;
  127. CString strValue;
  128. m_HeaderName.GetWindowText(strName);
  129. m_HeaderValue.GetWindowText(strValue);
  130. strName.Trim();
  131. strValue.Trim();
  132. if(!strName.IsEmpty())
  133. {
  134. if(strName == _T("Content-Length"))
  135. {
  136. MessageBox(_T("'Content-Length' header can't be specified!"), _T("Add Header"), MB_OK | MB_ICONINFORMATION);
  137. m_HeaderName.SetFocus();
  138. return;
  139. }
  140. CString strHeader;
  141. strHeader.Format(_T("%s: %s"), strName, strValue);
  142. m_Headers.AddString(strHeader);
  143. m_HeaderName.SetWindowText(_T(""));
  144. m_HeaderValue.SetWindowText(_T(""));
  145. }
  146. }
  147. void CClientDlg::OnBnClickedSend()
  148. {
  149. m_bWebSocket ? SendWebSocket() : SendHttp();
  150. }
  151. void CClientDlg::SendHttp()
  152. {
  153. USES_CONVERSION;
  154. CString strMethod;
  155. CString strSchema;
  156. CString strAddress;
  157. CString strPort;
  158. CString strPath;
  159. m_Method.GetWindowText(strMethod);
  160. m_Schema.GetWindowText(strSchema);
  161. m_Address.GetWindowText(strAddress);
  162. m_Port.GetWindowText(strPort);
  163. if(m_Method.GetCurSel() != 8)
  164. {
  165. m_Path.GetWindowText(strPath);
  166. strPath.Trim();
  167. if(strPath.IsEmpty() || strPath.GetAt(0) != '/')
  168. strPath.Insert(0, '/');
  169. }
  170. THttpHeaderMap headers;
  171. int iCount = m_Headers.GetCount();
  172. for(int i = 0; i < iCount; i++)
  173. {
  174. CString strHeader;
  175. m_Headers.GetText(i, strHeader);
  176. int j = 0;
  177. CString strName = strHeader.Tokenize(_T(": "), j);
  178. CString strValue = strHeader.Mid(j + 1);
  179. headers.emplace(THttpHeaderMap::value_type(T2A(strName), T2A(strValue)));
  180. }
  181. CStringA strBodyA;
  182. CStringA strPathA;
  183. if(m_Method.GetCurSel() <= 2)
  184. {
  185. CString strBody;
  186. m_Body.GetWindowText(strBody);
  187. strBodyA = T2A(strBody);
  188. }
  189. else if(m_Method.GetCurSel() == 8)
  190. {
  191. THttpHeaderMapCI it = headers.find("Host");
  192. if(it != headers.end() && !it->second.IsEmpty())
  193. strPathA = it->second;
  194. else
  195. {
  196. CString strHost;
  197. strHost.Format(_T("%s:%s"), strAddress, strPort);
  198. strPathA = strHost;
  199. }
  200. }
  201. if(strPathA.IsEmpty())
  202. strPathA = T2A(strPath);
  203. DWORD dwIndex = 0;
  204. DWORD dwSize = (DWORD)headers.size();
  205. unique_ptr<THeader[]> szHeaders(new THeader[dwSize]);
  206. for(THttpHeaderMapCI it = headers.begin(), end = headers.end(); it != end; ++it, ++dwIndex)
  207. {
  208. szHeaders[dwIndex].name = it->first;
  209. szHeaders[dwIndex].value = it->second;
  210. }
  211. CString strContent;
  212. strContent.Format(_T("[%s] %s://%s:%s%s"), strMethod, strSchema, strAddress, strPort, strPath);
  213. if(m_pClient->SendRequest(T2A(strMethod), strPathA, szHeaders.get(), dwSize, (const BYTE*)(LPCSTR)strBodyA, strBodyA.GetLength()))
  214. ::LogSend(m_pClient->GetConnectionID(), strContent);
  215. else
  216. ::LogSendFail(m_pClient->GetConnectionID(), ::GetLastError(), ::GetSocketErrorDesc(SE_DATA_SEND));
  217. }
  218. void CClientDlg::SendWebSocket()
  219. {
  220. static LPCSTR CLOSE_FLAG = "$close";
  221. static const BYTE MASK_KEY[] = {0x1, 0x2, 0x3, 0x4};
  222. USES_CONVERSION;
  223. CString strBody;
  224. m_Body.GetWindowText(strBody);
  225. CStringA strBodyA = T2A(strBody);
  226. if(strBodyA.CompareNoCase(CLOSE_FLAG) != 0)
  227. m_pClient->SendWSMessage(TRUE, 0, 0x1, MASK_KEY, (BYTE*)(LPCSTR)strBodyA, strBodyA.GetLength());
  228. else
  229. {
  230. m_pClient->SendWSMessage(TRUE, 0, 0x8, MASK_KEY, nullptr, 0);
  231. m_Body.SetWindowText(_T(""));
  232. }
  233. }
  234. void CClientDlg::OnBnClickedStart()
  235. {
  236. SetAppState(ST_STARTING);
  237. g_SSL.Cleanup();
  238. if(!g_SSL.Initialize(SSL_SM_CLIENT, SSL_VM_NONE, g_c_lpszPemCertFile, g_c_lpszPemKeyFile, g_c_lpszKeyPasswod, g_c_lpszCAPemCertFileOrPath))
  239. {
  240. ::LogClientStartFail(::GetLastError(), _T("initialize SSL env fail"));
  241. SetAppState(ST_STOPPED);
  242. return;
  243. }
  244. CString strAddress;
  245. CString strPort;
  246. m_Address.GetWindowText(strAddress);
  247. m_Port.GetWindowText(strPort);
  248. USHORT usPort = (USHORT)_ttoi(strPort);
  249. m_bAsyncConn = m_Async.GetCheck();
  250. BOOL isHttp = m_Schema.GetCurSel() == 0;
  251. if(isHttp)
  252. m_pClient.reset((IHttpClient*)(new CHttpClient(this)));
  253. else
  254. m_pClient.reset((IHttpClient*)(new CHttpsClient(this)));
  255. ::LogClientStarting(strAddress, usPort);
  256. if(m_pClient->Start(strAddress, usPort, m_bAsyncConn))
  257. {
  258. }
  259. else
  260. {
  261. ::LogClientStartFail(m_pClient->GetLastError(), m_pClient->GetLastErrorDesc());
  262. SetAppState(ST_STOPPED);
  263. }
  264. }
  265. void CClientDlg::OnBnClickedStop()
  266. {
  267. SetAppState(ST_STOPPING);
  268. if(m_pClient->Stop())
  269. ::LogClientStopping(m_pClient->GetConnectionID());
  270. else
  271. ASSERT(FALSE);
  272. }
  273. void CClientDlg::OnCbnSelchangeMethod()
  274. {
  275. m_Body.EnableWindow(m_Method.GetCurSel() <= 2 || m_bWebSocket);
  276. m_Path.EnableWindow(m_Method.GetCurSel() != 8);
  277. }
  278. int CClientDlg::OnVKeyToItem(UINT nKey, CListBox* pListBox, UINT nIndex)
  279. {
  280. if(nKey == 'C')
  281. pListBox->ResetContent();
  282. else if(nKey == 'D' && pListBox == &m_Headers)
  283. {
  284. int index = pListBox->GetCurSel();
  285. if(index != LB_ERR)
  286. {
  287. pListBox->DeleteString(index);
  288. int count = pListBox->GetCount();
  289. if(index < count)
  290. pListBox->SetCurSel(index);
  291. else if(index > 0)
  292. pListBox->SetCurSel(index - 1);
  293. }
  294. }
  295. return __super::OnVKeyToItem(nKey, pListBox, nIndex);
  296. }
  297. LRESULT CClientDlg::OnUserInfoMsg(WPARAM wp, LPARAM lp)
  298. {
  299. info_msg* msg = (info_msg*)wp;
  300. ::LogInfoMsg(msg);
  301. return 0;
  302. }
  303. EnHandleResult CClientDlg::OnConnect(ITcpClient* pSender, CONNID dwConnID)
  304. {
  305. TCHAR szAddress[40];
  306. int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);
  307. USHORT usPort;
  308. pSender->GetLocalAddress(szAddress, iAddressLen, usPort);
  309. ::PostOnConnect(dwConnID, szAddress, usPort);
  310. return HR_OK;
  311. }
  312. EnHandleResult CClientDlg::OnHandShake(ITcpClient* pSender, CONNID dwConnID)
  313. {
  314. ::PostOnHandShake(dwConnID);
  315. IHttpClient::FromS(pSender)->AddCookie("__reqSequence", "1");
  316. SetAppState(ST_STARTED);
  317. return HR_OK;
  318. }
  319. EnHandleResult CClientDlg::OnSend(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
  320. {
  321. ::PostOnSend(dwConnID, pData, iLength);
  322. return HR_OK;
  323. }
  324. EnHandleResult CClientDlg::OnReceive(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
  325. {
  326. ::PostOnReceive(dwConnID, pData, iLength);
  327. return HR_OK;
  328. }
  329. EnHandleResult CClientDlg::OnClose(ITcpClient* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
  330. {
  331. iErrorCode == SE_OK ? ::PostOnClose(dwConnID) :
  332. ::PostOnError(dwConnID, enOperation, iErrorCode) ;
  333. m_bWebSocket = FALSE;
  334. SetAppState(ST_STOPPED);
  335. return HR_OK;
  336. }
  337. // ------------------------------------------------------------------------------------------------------------- //
  338. EnHttpParseResult CClientDlg::OnMessageBegin(IHttpClient* pSender, CONNID dwConnID)
  339. {
  340. ::PostOnMessageBegin(dwConnID);
  341. return HPR_OK;
  342. }
  343. EnHttpParseResult CClientDlg::OnStatusLine(IHttpClient* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc)
  344. {
  345. ::PostOnStatusLine(dwConnID, usStatusCode, lpszDesc);
  346. return HPR_OK;
  347. }
  348. EnHttpParseResult CClientDlg::OnHeader(IHttpClient* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)
  349. {
  350. ::PostOnHeader(dwConnID, lpszName, lpszValue);
  351. return HPR_OK;
  352. }
  353. EnHttpParseResult CClientDlg::OnHeadersComplete(IHttpClient* pSender, CONNID dwConnID)
  354. {
  355. CheckSetCookie(pSender);
  356. CStringA strSummary = GetHeaderSummary(pSender, " ", 0, TRUE);
  357. ::PostOnHeadersComplete(dwConnID, strSummary);
  358. return HPR_OK;
  359. }
  360. EnHttpParseResult CClientDlg::OnBody(IHttpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
  361. {
  362. ::PostOnBody(dwConnID, pData, iLength);
  363. return HPR_OK;
  364. }
  365. EnHttpParseResult CClientDlg::OnChunkHeader(IHttpClient* pSender, CONNID dwConnID, int iLength)
  366. {
  367. ::PostOnChunkHeader(dwConnID, iLength);
  368. return HPR_OK;
  369. }
  370. EnHttpParseResult CClientDlg::OnChunkComplete(IHttpClient* pSender, CONNID dwConnID)
  371. {
  372. ::PostOnChunkComplete(dwConnID);
  373. return HPR_OK;
  374. }
  375. EnHttpParseResult CClientDlg::OnMessageComplete(IHttpClient* pSender, CONNID dwConnID)
  376. {
  377. ::PostOnMessageComplete(dwConnID);
  378. return HPR_OK;
  379. }
  380. EnHttpParseResult CClientDlg::OnUpgrade(IHttpClient* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)
  381. {
  382. ::PostOnUpgrade(dwConnID, enUpgradeType);
  383. if(enUpgradeType == HUT_WEB_SOCKET)
  384. {
  385. m_bWebSocket = TRUE;
  386. OnCbnSelchangeMethod();
  387. }
  388. return HPR_OK;
  389. }
  390. EnHttpParseResult CClientDlg::OnParseError(IHttpClient* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc)
  391. {
  392. ::PostOnParseError(dwConnID, iErrorCode, lpszErrorDesc);
  393. return HPR_OK;
  394. }
  395. // ------------------------------------------------------------------------------------------------------------- //
  396. EnHandleResult CClientDlg::OnWSMessageHeader(IHttpClient* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
  397. {
  398. ::PostOnWSMessageHeader(dwConnID, bFinal, iReserved, iOperationCode, lpszMask, ullBodyLen);
  399. return HR_OK;
  400. }
  401. EnHandleResult CClientDlg::OnWSMessageBody(IHttpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
  402. {
  403. ::PostOnWSMessageBody(dwConnID, pData, iLength);
  404. return HR_OK;
  405. }
  406. EnHandleResult CClientDlg::OnWSMessageComplete(IHttpClient* pSender, CONNID dwConnID)
  407. {
  408. ::PostOnWSMessageComplete(dwConnID);
  409. BYTE iOperationCode;
  410. VERIFY(pSender->GetWSMessageState(nullptr, nullptr, &iOperationCode, nullptr, nullptr, nullptr));
  411. if(iOperationCode == 0x8)
  412. return HR_ERROR;
  413. return HR_OK;
  414. }
  415. // ------------------------------------------------------------------------------------------------------------- //
  416. void CClientDlg::CheckSetCookie(IHttpClient* pHttpClient)
  417. {
  418. DWORD dwHeaderCount = 0;
  419. pHttpClient->GetHeaders("Set-Cookie", nullptr, dwHeaderCount);
  420. if(dwHeaderCount == 0)
  421. return;
  422. unique_ptr<LPCSTR[]> values(new LPCSTR[dwHeaderCount]);
  423. VERIFY(pHttpClient->GetHeaders("Set-Cookie", values.get(), dwHeaderCount));
  424. for(DWORD i = 0; i < dwHeaderCount; i++)
  425. {
  426. CStringA strValue = values[i];
  427. int j = 0;
  428. CStringA strItem = strValue.Tokenize("; ", j);
  429. if(j <= 0)
  430. continue;
  431. int k = strItem.Find('=');
  432. if(k <= 0)
  433. continue;
  434. pHttpClient->AddCookie(strItem.Left(k), strItem.Mid(k + 1));
  435. }
  436. }
  437. CStringA CClientDlg::GetHeaderSummary(IHttpClient* pHttpClient, LPCSTR lpszSep, int iSepCount, BOOL bWithContentLength)
  438. {
  439. CStringA SEP1;
  440. for(int i = 0; i < iSepCount; i++)
  441. SEP1 += lpszSep;
  442. CStringA SEP2(SEP1);
  443. SEP2 += lpszSep;
  444. CStringA strResult;
  445. strResult.AppendFormat("%s[Status Fields]%s", SEP1, CRLF);
  446. strResult.AppendFormat("%s%13s: %u%s", SEP2, "Status Code", pHttpClient->GetStatusCode(), CRLF);
  447. DWORD dwHeaderCount = 0;
  448. pHttpClient->GetAllHeaders(nullptr, dwHeaderCount);
  449. strResult.AppendFormat("%s[Response Headers]%s", SEP1, CRLF);
  450. if(dwHeaderCount == 0)
  451. strResult.AppendFormat("%s(no header)%s", SEP2, CRLF);
  452. else
  453. {
  454. unique_ptr<THeader[]> headers(new THeader[dwHeaderCount]);
  455. VERIFY(pHttpClient->GetAllHeaders(headers.get(), dwHeaderCount));
  456. for(DWORD i = 0; i < dwHeaderCount; i++)
  457. strResult.AppendFormat("%s%s: %s%s", SEP2, headers[i].name, headers[i].value, CRLF);
  458. }
  459. DWORD dwCookieCount = 0;
  460. pHttpClient->GetAllCookies(nullptr, dwCookieCount);
  461. strResult.AppendFormat("%s[Cookies]%s", SEP1, CRLF);
  462. if(dwCookieCount == 0)
  463. strResult.AppendFormat("%s(no cookie)%s", SEP2, CRLF);
  464. else
  465. {
  466. unique_ptr<TCookie[]> cookies(new TCookie[dwCookieCount]);
  467. VERIFY(pHttpClient->GetAllCookies(cookies.get(), dwCookieCount));
  468. for(DWORD i = 0; i < dwCookieCount; i++)
  469. strResult.AppendFormat("%s%s: %s%s", SEP2, cookies[i].name, cookies[i].value, CRLF);
  470. }
  471. CStringA strVersion;
  472. ::HttpVersionToString((EnHttpVersion)pHttpClient->GetVersion(), strVersion);
  473. EnHttpUpgradeType enUpgType = pHttpClient->GetUpgradeType();
  474. LPCSTR lpszUpgrade = enUpgType != HUT_NONE ? "true" : "false";
  475. LPCSTR lpszKeepAlive = pHttpClient->IsKeepAlive() ? "true" : "false";
  476. strResult.AppendFormat("%s[Basic Info]%s", SEP1, CRLF);
  477. strResult.AppendFormat("%s%13s: %s%s", SEP2, "Version", strVersion, CRLF);
  478. strResult.AppendFormat("%s%13s: %u%s", SEP2, "Status Code", pHttpClient->GetStatusCode(), CRLF);
  479. strResult.AppendFormat("%s%13s: %s%s", SEP2, "IsUpgrade", lpszUpgrade, CRLF);
  480. if(enUpgType != HUT_NONE)
  481. strResult.AppendFormat("%s%13s: %d%s", SEP2, "UpgradeType", enUpgType, CRLF);
  482. strResult.AppendFormat("%s%13s: %s%s", SEP2, "IsKeepAlive", lpszKeepAlive, CRLF);
  483. if(bWithContentLength)
  484. strResult.AppendFormat("%s%13s: %lld%s", SEP2, "ContentLength", pHttpClient->GetContentLength(), CRLF);
  485. strResult.AppendFormat("%s%13s: %s%s", SEP2, "ContentType", pHttpClient->GetContentType(), CRLF);
  486. return strResult;
  487. }