ClientDlg.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  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_bAsyncConn = FALSE;
  65. return TRUE; // return TRUE unless you set the focus to a control
  66. }
  67. // If you add a minimize button to your dialog, you will need the code below
  68. // to draw the icon. For MFC applications using the document/view model,
  69. // this is automatically done for you by the framework.
  70. void CClientDlg::OnPaint()
  71. {
  72. if (IsIconic())
  73. {
  74. CPaintDC dc(this); // device context for painting
  75. SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
  76. // Center icon in client rectangle
  77. int cxIcon = GetSystemMetrics(SM_CXICON);
  78. int cyIcon = GetSystemMetrics(SM_CYICON);
  79. CRect rect;
  80. GetClientRect(&rect);
  81. int x = (rect.Width() - cxIcon + 1) / 2;
  82. int y = (rect.Height() - cyIcon + 1) / 2;
  83. // Draw the icon
  84. dc.DrawIcon(x, y, m_hIcon);
  85. }
  86. else
  87. {
  88. CDialogEx::OnPaint();
  89. }
  90. }
  91. // The system calls this function to obtain the cursor to display while the user drags
  92. // the minimized window.
  93. HCURSOR CClientDlg::OnQueryDragIcon()
  94. {
  95. return static_cast<HCURSOR>(m_hIcon);
  96. }
  97. BOOL CClientDlg::PreTranslateMessage(MSG* pMsg)
  98. {
  99. if (
  100. pMsg->message == WM_KEYDOWN
  101. &&( pMsg->wParam == VK_ESCAPE
  102. || pMsg->wParam == VK_CANCEL
  103. || (pMsg->wParam == VK_RETURN && pMsg->hwnd == this->GetSafeHwnd())
  104. ))
  105. return TRUE;
  106. return CDialog::PreTranslateMessage(pMsg);
  107. }
  108. void CClientDlg::SetAppState(EnAppState state)
  109. {
  110. m_enState = state;
  111. if(this->GetSafeHwnd() == nullptr)
  112. return;
  113. m_Async.EnableWindow(m_enState == ST_STOPPED);
  114. m_Start.EnableWindow(m_enState == ST_STOPPED);
  115. m_Stop.EnableWindow(m_enState == ST_STARTED);
  116. m_Send.EnableWindow(m_enState == ST_STARTED);
  117. m_Schema.EnableWindow(m_enState == ST_STOPPED);
  118. m_Address.EnableWindow(m_enState == ST_STOPPED);
  119. m_Port.EnableWindow(m_enState == ST_STOPPED);
  120. m_Body.EnableWindow(m_Method.GetCurSel() <= 2);
  121. m_Path.EnableWindow(m_Method.GetCurSel() != 8);
  122. }
  123. void CClientDlg::OnBnClickedHeaderAdd()
  124. {
  125. CString strName;
  126. CString strValue;
  127. m_HeaderName.GetWindowText(strName);
  128. m_HeaderValue.GetWindowText(strValue);
  129. strName.Trim();
  130. strValue.Trim();
  131. if(!strName.IsEmpty())
  132. {
  133. if(strName == _T("Content-Length"))
  134. {
  135. MessageBox(_T("'Content-Length' header can't be specified!"), _T("Add Header"), MB_OK | MB_ICONINFORMATION);
  136. m_HeaderName.SetFocus();
  137. return;
  138. }
  139. CString strHeader;
  140. strHeader.Format(_T("%s: %s"), strName, strValue);
  141. m_Headers.AddString(strHeader);
  142. m_HeaderName.SetWindowText(_T(""));
  143. m_HeaderValue.SetWindowText(_T(""));
  144. }
  145. }
  146. void CClientDlg::OnBnClickedSend()
  147. {
  148. USES_CONVERSION;
  149. CString strMethod;
  150. CString strSchema;
  151. CString strAddress;
  152. CString strPort;
  153. CString strPath;
  154. m_Method.GetWindowText(strMethod);
  155. m_Schema.GetWindowText(strSchema);
  156. m_Address.GetWindowText(strAddress);
  157. m_Port.GetWindowText(strPort);
  158. if(m_Method.GetCurSel() != 8)
  159. {
  160. m_Path.GetWindowText(strPath);
  161. strPath.Trim();
  162. if(strPath.IsEmpty() || strPath.GetAt(0) != '/')
  163. strPath.Insert(0, '/');
  164. }
  165. THeaderMap headers;
  166. int iCount = m_Headers.GetCount();
  167. for(int i = 0; i < iCount; i++)
  168. {
  169. CString strHeader;
  170. m_Headers.GetText(i, strHeader);
  171. int j = 0;
  172. CString strName = strHeader.Tokenize(_T(": "), j);
  173. CString strValue = strHeader.Mid(j + 1);
  174. headers.emplace(THeaderMap::value_type(T2A(strName), T2A(strValue)));
  175. }
  176. THeaderMapCI it = headers.find("Host");
  177. if(it == headers.end() || it->second.IsEmpty())
  178. {
  179. CString strHost;
  180. strHost.Format(_T("%s:%s"), strAddress, strPort);
  181. headers.erase("Host");
  182. headers.emplace(THeaderMap::value_type("Host", T2A(strHost)));
  183. }
  184. CStringA strBodyA;
  185. CStringA strPathA;
  186. if(m_Method.GetCurSel() <= 2)
  187. {
  188. CString strBody;
  189. m_Body.GetWindowText(strBody);
  190. strBodyA = T2A(strBody);
  191. }
  192. else if(m_Method.GetCurSel() == 8)
  193. strPathA = headers.find("Host")->second;
  194. if(strPathA.IsEmpty())
  195. strPathA = T2A(strPath);
  196. DWORD dwIndex = 0;
  197. DWORD dwSize = (DWORD)headers.size();
  198. unique_ptr<THeader[]> szHeaders(new THeader[dwSize]);
  199. for(THeaderMapCI it = headers.begin(), end = headers.end(); it != end; ++it, ++dwIndex)
  200. {
  201. szHeaders[dwIndex].name = it->first;
  202. szHeaders[dwIndex].value = it->second;
  203. }
  204. CString strContent;
  205. strContent.Format(_T("[%s] %s://%s:%s%s"), strMethod, strSchema, strAddress, strPort, strPath);
  206. if(m_pClient->SendRequest(T2A(strMethod), strPathA, szHeaders.get(), dwSize, (const BYTE*)(LPCSTR)strBodyA, strBodyA.GetLength()))
  207. ::LogSend(m_pClient->GetConnectionID(), strContent);
  208. else
  209. ::LogSendFail(m_pClient->GetConnectionID(), ::GetLastError(), ::GetSocketErrorDesc(SE_DATA_SEND));
  210. }
  211. void CClientDlg::OnBnClickedStart()
  212. {
  213. SetAppState(ST_STARTING);
  214. g_SSL.Cleanup();
  215. if(!g_SSL.Initialize(SSL_SM_CLIENT, SSL_VM_NONE, g_c_lpszPemCertFile, g_c_lpszPemKeyFile, g_c_lpszKeyPasswod, g_c_lpszCAPemCertFileOrPath))
  216. {
  217. ::LogClientStartFail(::GetLastError(), _T("initialize SSL env fail"));
  218. SetAppState(ST_STOPPED);
  219. return;
  220. }
  221. CString strAddress;
  222. CString strPort;
  223. m_Address.GetWindowText(strAddress);
  224. m_Port.GetWindowText(strPort);
  225. USHORT usPort = (USHORT)_ttoi(strPort);
  226. m_bAsyncConn = m_Async.GetCheck();
  227. BOOL isHttp = m_Schema.GetCurSel() == 0;
  228. if(isHttp)
  229. m_pClient.reset((IHttpClient*)(new CHttpClient(this)));
  230. else
  231. m_pClient.reset((IHttpClient*)(new CHttpsClient(this)));
  232. ::LogClientStarting(strAddress, usPort);
  233. if(m_pClient->Start(strAddress, usPort, m_bAsyncConn))
  234. {
  235. }
  236. else
  237. {
  238. ::LogClientStartFail(m_pClient->GetLastError(), m_pClient->GetLastErrorDesc());
  239. SetAppState(ST_STOPPED);
  240. }
  241. }
  242. void CClientDlg::OnBnClickedStop()
  243. {
  244. SetAppState(ST_STOPPING);
  245. if(m_pClient->Stop())
  246. ::LogClientStopping(m_pClient->GetConnectionID());
  247. else
  248. ASSERT(FALSE);
  249. }
  250. void CClientDlg::OnCbnSelchangeMethod()
  251. {
  252. m_Body.EnableWindow(m_Method.GetCurSel() <= 2);
  253. m_Path.EnableWindow(m_Method.GetCurSel() != 8);
  254. }
  255. int CClientDlg::OnVKeyToItem(UINT nKey, CListBox* pListBox, UINT nIndex)
  256. {
  257. if(nKey == 'C')
  258. pListBox->ResetContent();
  259. else if(nKey == 'D' && pListBox == &m_Headers)
  260. {
  261. int index = pListBox->GetCurSel();
  262. if(index != LB_ERR)
  263. {
  264. pListBox->DeleteString(index);
  265. int count = pListBox->GetCount();
  266. if(index < count)
  267. pListBox->SetCurSel(index);
  268. else if(index > 0)
  269. pListBox->SetCurSel(index - 1);
  270. }
  271. }
  272. return __super::OnVKeyToItem(nKey, pListBox, nIndex);
  273. }
  274. LRESULT CClientDlg::OnUserInfoMsg(WPARAM wp, LPARAM lp)
  275. {
  276. info_msg* msg = (info_msg*)wp;
  277. ::LogInfoMsg(msg);
  278. return 0;
  279. }
  280. EnHandleResult CClientDlg::OnConnect(IClient* pClient)
  281. {
  282. TCHAR szAddress[40];
  283. int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);
  284. USHORT usPort;
  285. pClient->GetLocalAddress(szAddress, iAddressLen, usPort);
  286. ::PostOnConnect(pClient->GetConnectionID(), szAddress, usPort);
  287. return HR_OK;
  288. }
  289. EnHandleResult CClientDlg::OnHandShake(IClient* pClient)
  290. {
  291. ::PostOnHandShake(pClient->GetConnectionID());
  292. SetAppState(ST_STARTED);
  293. return HR_OK;
  294. }
  295. EnHandleResult CClientDlg::OnSend(IClient* pClient, const BYTE* pData, int iLength)
  296. {
  297. ::PostOnSend(pClient->GetConnectionID(), pData, iLength);
  298. return HR_OK;
  299. }
  300. EnHandleResult CClientDlg::OnReceive(IClient* pClient, const BYTE* pData, int iLength)
  301. {
  302. ::PostOnReceive(pClient->GetConnectionID(), pData, iLength);
  303. return HR_OK;
  304. }
  305. EnHandleResult CClientDlg::OnClose(IClient* pClient, EnSocketOperation enOperation, int iErrorCode)
  306. {
  307. iErrorCode == SE_OK ? ::PostOnClose(pClient->GetConnectionID()) :
  308. ::PostOnError(pClient->GetConnectionID(), enOperation, iErrorCode) ;
  309. SetAppState(ST_STOPPED);
  310. return HR_OK;
  311. }
  312. // ------------------------------------------------------------------------------------------------------------- //
  313. EnHttpParseResult CClientDlg::OnMessageBegin(IHttp* pHttp)
  314. {
  315. ::PostOnMessageBegin(((IHttpClient*)pHttp)->GetConnectionID());
  316. return HPR_OK;
  317. }
  318. EnHttpParseResult CClientDlg::OnStatusLine(IHttp* pHttp, USHORT usStatusCode, LPCSTR lpszDesc)
  319. {
  320. ::PostOnStatusLine(((IHttpClient*)pHttp)->GetConnectionID(), usStatusCode, lpszDesc);
  321. return HPR_OK;
  322. }
  323. EnHttpParseResult CClientDlg::OnHeader(IHttp* pHttp, LPCSTR lpszName, LPCSTR lpszValue)
  324. {
  325. ::PostOnHeader(((IHttpClient*)pHttp)->GetConnectionID(), lpszName, lpszValue);
  326. return HPR_OK;
  327. }
  328. EnHttpParseResult CClientDlg::OnHeadersComplete(IHttp* pHttp)
  329. {
  330. IHttpClient* pHttpClient = (IHttpClient*)pHttp;
  331. CheckSetCookie(pHttpClient);
  332. CStringA strSummary = GetHeaderSummary(pHttpClient, " ", 0, TRUE);
  333. ::PostOnHeadersComplete(pHttpClient->GetConnectionID(), strSummary);
  334. return HPR_OK;
  335. }
  336. EnHttpParseResult CClientDlg::OnBody(IHttp* pHttp, const BYTE* pData, int iLength)
  337. {
  338. ::PostOnBody(((IHttpClient*)pHttp)->GetConnectionID(), pData, iLength);
  339. return HPR_OK;
  340. }
  341. EnHttpParseResult CClientDlg::OnChunkHeader(IHttp* pHttp, int iLength)
  342. {
  343. ::PostOnChunkHeader(((IHttpClient*)pHttp)->GetConnectionID(), iLength);
  344. return HPR_OK;
  345. }
  346. EnHttpParseResult CClientDlg::OnChunkComplete(IHttp* pHttp)
  347. {
  348. ::PostOnChunkComplete(((IHttpClient*)pHttp)->GetConnectionID());
  349. return HPR_OK;
  350. }
  351. EnHttpParseResult CClientDlg::OnMessageComplete(IHttp* pHttp)
  352. {
  353. ::PostOnMessageComplete(((IHttpClient*)pHttp)->GetConnectionID());
  354. return HPR_OK;
  355. }
  356. EnHttpParseResult CClientDlg::OnUpgrade(IHttp* pHttp, EnHttpUpgradeType enUpgradeType)
  357. {
  358. ::PostOnUpgrade(((IHttpClient*)pHttp)->GetConnectionID(), enUpgradeType);
  359. return HPR_OK;
  360. }
  361. EnHttpParseResult CClientDlg::OnParseError(IHttp* pHttp, int iErrorCode, LPCSTR lpszErrorDesc)
  362. {
  363. ::PostOnParseError(((IHttpClient*)pHttp)->GetConnectionID(), iErrorCode, lpszErrorDesc);
  364. return HPR_OK;
  365. }
  366. void CClientDlg::CheckSetCookie(IHttpClient* pHttpClient)
  367. {
  368. DWORD dwHeaderCount = 0;
  369. pHttpClient->GetHeaders("Set-Cookie", nullptr, dwHeaderCount);
  370. if(dwHeaderCount == 0)
  371. return;
  372. unique_ptr<LPCSTR[]> values(new LPCSTR[dwHeaderCount]);
  373. VERIFY(pHttpClient->GetHeaders("Set-Cookie", values.get(), dwHeaderCount));
  374. for(DWORD i = 0; i < dwHeaderCount; i++)
  375. {
  376. CStringA strValue = values[i];
  377. int j = 0;
  378. CStringA strItem = strValue.Tokenize("; ", j);
  379. if(j <= 0)
  380. continue;
  381. int k = strItem.Find('=');
  382. if(k <= 0)
  383. continue;
  384. pHttpClient->AddCookie(strItem.Left(k), strItem.Mid(k + 1));
  385. }
  386. }
  387. CStringA CClientDlg::GetHeaderSummary(IHttpClient* pHttpClient, LPCSTR lpszSep, int iSepCount, BOOL bWithContentLength)
  388. {
  389. CStringA SEP1;
  390. for(int i = 0; i < iSepCount; i++)
  391. SEP1 += lpszSep;
  392. CStringA SEP2(SEP1);
  393. SEP2 += lpszSep;
  394. CStringA strResult;
  395. strResult.AppendFormat("%s[Status Fields]%s", SEP1, CRLF);
  396. strResult.AppendFormat("%s%13s: %u%s", SEP2, "Status Code", pHttpClient->GetStatusCode(), CRLF);
  397. DWORD dwHeaderCount = 0;
  398. pHttpClient->GetAllHeaders(nullptr, dwHeaderCount);
  399. strResult.AppendFormat("%s[Response Headers]%s", SEP1, CRLF);
  400. if(dwHeaderCount == 0)
  401. strResult.AppendFormat("%s(no header)%s", SEP2, CRLF);
  402. else
  403. {
  404. unique_ptr<THeader[]> headers(new THeader[dwHeaderCount]);
  405. VERIFY(pHttpClient->GetAllHeaders(headers.get(), dwHeaderCount));
  406. for(DWORD i = 0; i < dwHeaderCount; i++)
  407. strResult.AppendFormat("%s%s: %s%s", SEP2, headers[i].name, headers[i].value, CRLF);
  408. }
  409. DWORD dwCookieCount = 0;
  410. pHttpClient->GetAllCookies(nullptr, dwCookieCount);
  411. strResult.AppendFormat("%s[Cookies]%s", SEP1, CRLF);
  412. if(dwCookieCount == 0)
  413. strResult.AppendFormat("%s(no cookie)%s", SEP2, CRLF);
  414. else
  415. {
  416. unique_ptr<TCookie[]> cookies(new TCookie[dwCookieCount]);
  417. VERIFY(pHttpClient->GetAllCookies(cookies.get(), dwCookieCount));
  418. for(DWORD i = 0; i < dwCookieCount; i++)
  419. strResult.AppendFormat("%s%s: %s%s", SEP2, cookies[i].name, cookies[i].value, CRLF);
  420. }
  421. CStringA strVersion;
  422. ::GetHttpVersionStr((EnHttpVersion)pHttpClient->GetVersion(), strVersion);
  423. EnHttpUpgradeType enUpgType = pHttpClient->GetUpgradeType();
  424. LPCSTR lpszUpgrade = enUpgType != HUT_NONE ? "true" : "false";
  425. LPCSTR lpszKeepAlive = pHttpClient->IsKeepAlive() ? "true" : "false";
  426. strResult.AppendFormat("%s[Basic Info]%s", SEP1, CRLF);
  427. strResult.AppendFormat("%s%13s: %s%s", SEP2, "Version", strVersion, CRLF);
  428. strResult.AppendFormat("%s%13s: %u%s", SEP2, "Status Code", pHttpClient->GetStatusCode(), CRLF);
  429. strResult.AppendFormat("%s%13s: %s%s", SEP2, "IsUpgrade", lpszUpgrade, CRLF);
  430. if(enUpgType != HUT_NONE)
  431. strResult.AppendFormat("%s%13s: %d%s", SEP2, "UpgradeType", enUpgType, CRLF);
  432. strResult.AppendFormat("%s%13s: %s%s", SEP2, "IsKeepAlive", lpszKeepAlive, CRLF);
  433. if(bWithContentLength)
  434. strResult.AppendFormat("%s%13s: %lld%s", SEP2, "ContentLength", pHttpClient->GetContentLength(), CRLF);
  435. strResult.AppendFormat("%s%13s: %s%s", SEP2, "ContentType", pHttpClient->GetContentType(), CRLF);
  436. return strResult;
  437. }