// ServerDlg.cpp : implementation file // #include "stdafx.h" #include "Server.h" #include "ServerDlg.h" #include "afxdialogex.h" // CServerDlg dialog const LPCTSTR CServerDlg::ADDRESS = _T("0.0.0.0"); const LPCTSTR CServerDlg::HTTP_NAME = _T("http"); const LPCTSTR CServerDlg::HTTPS_NAME = _T("https"); const USHORT CServerDlg::HTTP_PORT = 8080; const USHORT CServerDlg::HTTPS_PORT = 8443; CServerDlg::CServerDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CServerDlg::IDD, pParent) , m_HttpListener(this) , m_HttpsListener(this) , m_HttpServer(&m_HttpListener) , m_HttpsServer(&m_HttpsListener) { m_HttpListener.SetServer(HTTP_NAME, (IHttpServer*)&m_HttpServer); m_HttpsListener.SetServer(HTTPS_NAME, (IHttpServer*)&m_HttpsServer); m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CServerDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_INFO, m_Info); DDX_Control(pDX, IDC_START, m_Start); DDX_Control(pDX, IDC_STOP, m_Stop); DDX_Control(pDX, IDC_CONN_ID, m_ConnID); DDX_Control(pDX, IDC_DISCONNECT, m_DisConn); DDX_Control(pDX, IDC_RELEASE, m_Release); DDX_Control(pDX, IDC_HTTP, m_RadioHttp); DDX_Control(pDX, IDC_HTTPS, m_RadioHttps); } BEGIN_MESSAGE_MAP(CServerDlg, CDialogEx) ON_WM_PAINT() ON_WM_VKEYTOITEM() ON_WM_QUERYDRAGICON() ON_MESSAGE(USER_INFO_MSG, OnUserInfoMsg) ON_BN_CLICKED(IDC_START, &CServerDlg::OnBnClickedStart) ON_BN_CLICKED(IDC_STOP, &CServerDlg::OnBnClickedStop) ON_BN_CLICKED(IDC_DISCONNECT, &CServerDlg::OnBnClickedDisconnect) ON_EN_CHANGE(IDC_CONN_ID, &CServerDlg::OnEnChangeConnId) ON_BN_CLICKED(IDC_RELEASE, &CServerDlg::OnBnClickedRelease) END_MESSAGE_MAP() // CServerDlg message handlers BOOL CServerDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here CString strTitle; CString strOriginTitle; GetWindowText(strOriginTitle); strTitle.Format(_T("%s - (%s:%d/%d)"), strOriginTitle, ADDRESS, HTTP_PORT, HTTPS_PORT); SetWindowText(strTitle); m_RadioHttp.SetCheck(BST_CHECKED); ::SetMainWnd(this); ::SetInfoList(&m_Info); SetAppState(ST_STOPPED); return TRUE; // return TRUE unless you set the focus to a control } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CServerDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } // The system calls this function to obtain the cursor to display while the user drags // the minimized window. HCURSOR CServerDlg::OnQueryDragIcon() { return static_cast(m_hIcon); } BOOL CServerDlg::PreTranslateMessage(MSG* pMsg) { if ( pMsg->message == WM_KEYDOWN &&( pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_CANCEL || pMsg->wParam == VK_RETURN )) return TRUE; return CDialog::PreTranslateMessage(pMsg); } void CServerDlg::SetAppState(EnAppState state) { m_enState = state; if(this->GetSafeHwnd() == nullptr) return; m_Start.EnableWindow(m_enState == ST_STOPPED); m_Stop.EnableWindow(m_enState == ST_STARTED); m_RadioHttp.EnableWindow(m_enState == ST_STARTED && m_ConnID.GetWindowTextLength() > 0); m_RadioHttps.EnableWindow(m_enState == ST_STARTED && m_ConnID.GetWindowTextLength() > 0); m_DisConn.EnableWindow(m_enState == ST_STARTED && m_ConnID.GetWindowTextLength() > 0); m_Release.EnableWindow(m_enState == ST_STARTED && m_ConnID.GetWindowTextLength() > 0); } void CServerDlg::OnBnClickedStart() { SetAppState(ST_STARTING); g_SSL.Cleanup(); if(!g_SSL.Initialize(SSL_SM_SERVER, SSL_VM_NONE, g_s_lpszPemCertFile, g_s_lpszPemKeyFile, g_s_lpszKeyPasswod, g_s_lpszCAPemCertFileOrPath)) { ::LogServerStartFail(::GetLastError(), _T("initialize SSL env fail")); SetAppState(ST_STOPPED); return; } if(m_HttpServer.Start(ADDRESS, HTTP_PORT)) { ::LogServerStart(ADDRESS, HTTP_PORT, HTTP_NAME); if(m_HttpsServer.Start(ADDRESS, HTTPS_PORT)) { ::LogServerStart(ADDRESS, HTTPS_PORT, HTTPS_NAME); SetAppState(ST_STARTED); } else { m_HttpServer.Stop(); ::LogServerStartFail(m_HttpsServer.GetLastError(), m_HttpsServer.GetLastErrorDesc(), HTTPS_NAME); SetAppState(ST_STOPPED); } } else { ::LogServerStartFail(m_HttpServer.GetLastError(), m_HttpServer.GetLastErrorDesc(), HTTP_NAME); SetAppState(ST_STOPPED); } } void CServerDlg::OnBnClickedStop() { SetAppState(ST_STOPPING); if(!m_HttpsServer.Stop()) ASSERT(FALSE); ::LogServerStop(HTTPS_NAME); if(!m_HttpServer.Stop()) ASSERT(FALSE); ::LogServerStop(HTTP_NAME); SetAppState(ST_STOPPED); } void CServerDlg::OnBnClickedDisconnect() { CString strConnID; m_ConnID.GetWindowText(strConnID); CONNID dwConnID = (CONNID)_ttoi(strConnID); BOOL bHttp = m_RadioHttp.GetCheck() == BST_CHECKED; LPCTSTR lpszName = bHttp ? HTTP_NAME : HTTPS_NAME; IHttpServer* pServer = bHttp ? (IHttpServer*)&m_HttpServer : (IHttpServer*)&m_HttpsServer; if(pServer->Disconnect(dwConnID)) ::LogDisconnect(dwConnID, lpszName); else ::LogDisconnectFail(dwConnID, lpszName); } void CServerDlg::OnBnClickedRelease() { CString strConnID; m_ConnID.GetWindowText(strConnID); CONNID dwConnID = (CONNID)_ttoi(strConnID); BOOL bHttp = m_RadioHttp.GetCheck() == BST_CHECKED; LPCTSTR lpszName = bHttp ? HTTP_NAME : HTTPS_NAME; IHttpServer* pServer = bHttp ? (IHttpServer*)&m_HttpServer : (IHttpServer*)&m_HttpsServer; if(pServer->Release(dwConnID)) ::LogRelease(dwConnID, lpszName); else ::LogReleaseFail(dwConnID, lpszName); } void CServerDlg::OnEnChangeConnId() { m_RadioHttp.EnableWindow(m_enState == ST_STARTED && m_ConnID.GetWindowTextLength() > 0); m_RadioHttps.EnableWindow(m_enState == ST_STARTED && m_ConnID.GetWindowTextLength() > 0); m_DisConn.EnableWindow(m_enState == ST_STARTED && m_ConnID.GetWindowTextLength() > 0); m_Release.EnableWindow(m_enState == ST_STARTED && m_ConnID.GetWindowTextLength() > 0); } int CServerDlg::OnVKeyToItem(UINT nKey, CListBox* pListBox, UINT nIndex) { if(nKey == 'C') pListBox->ResetContent(); return __super::OnVKeyToItem(nKey, pListBox, nIndex); } LRESULT CServerDlg::OnUserInfoMsg(WPARAM wp, LPARAM lp) { info_msg* msg = (info_msg*)wp; ::LogInfoMsg(msg); return 0; } // ------------------------------------------------------------------------------------------------------------- // EnHandleResult CHttpServerListenerImpl::OnPrepareListen(SOCKET soListen) { TCHAR szAddress[40]; int iAddressLen = sizeof(szAddress) / sizeof(TCHAR); USHORT usPort; m_pServer->GetListenAddress(szAddress, iAddressLen, usPort); ::PostOnPrepareListen(szAddress, usPort, m_strName); return HR_OK; } EnHandleResult CHttpServerListenerImpl::OnAccept(CONNID dwConnID, SOCKET soClient) { BOOL bPass = TRUE; TCHAR szAddress[40]; int iAddressLen = sizeof(szAddress) / sizeof(TCHAR); USHORT usPort; m_pServer->GetRemoteAddress(dwConnID, szAddress, iAddressLen, usPort); ::PostOnAccept(dwConnID, szAddress, usPort, bPass, m_strName); return bPass ? HR_OK : HR_ERROR; } EnHandleResult CHttpServerListenerImpl::OnHandShake(CONNID dwConnID) { ::PostOnHandShake(dwConnID, m_strName); return HR_OK; } EnHandleResult CHttpServerListenerImpl::OnReceive(CONNID dwConnID, const BYTE* pData, int iLength) { ::PostOnReceive(dwConnID, pData, iLength, m_strName); return HR_OK; } EnHandleResult CHttpServerListenerImpl::OnSend(CONNID dwConnID, const BYTE* pData, int iLength) { ::PostOnSend(dwConnID, pData, iLength, m_strName); return HR_OK; } EnHandleResult CHttpServerListenerImpl::OnClose(CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode) { iErrorCode == SE_OK ? ::PostOnClose(dwConnID, m_strName) : ::PostOnError(dwConnID, enOperation, iErrorCode, m_strName) ; return HR_OK; } EnHandleResult CHttpServerListenerImpl::OnShutdown() { ::PostOnShutdown(m_strName); return HR_OK; } // ------------------------------------------------------------------------------------------------------------- // EnHttpParseResult CHttpServerListenerImpl::OnMessageBegin(CONNID dwConnID) { ::PostOnMessageBegin(dwConnID, m_strName); return HPR_OK; } EnHttpParseResult CHttpServerListenerImpl::OnRequestLine(CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszUrl) { ::PostOnRequestLine(dwConnID, lpszMethod, m_pServer->GetUrlFieldSet(dwConnID), lpszUrl, m_strName); return HPR_OK; } EnHttpParseResult CHttpServerListenerImpl::OnHeader(CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue) { ::PostOnHeader(dwConnID, lpszName, lpszValue, m_strName); return HPR_OK; } EnHttpParseResult CHttpServerListenerImpl::OnHeadersComplete(CONNID dwConnID) { CStringA strSummary = GetHeaderSummary(dwConnID, " ", 0, TRUE); ::PostOnHeadersComplete(dwConnID, strSummary, m_strName); return HPR_OK; } EnHttpParseResult CHttpServerListenerImpl::OnBody(CONNID dwConnID, const BYTE* pData, int iLength) { ::PostOnBody(dwConnID, pData, iLength, m_strName); return HPR_OK; } EnHttpParseResult CHttpServerListenerImpl::OnChunkHeader(CONNID dwConnID, int iLength) { ::PostOnChunkHeader(dwConnID, iLength, m_strName); return HPR_OK; } EnHttpParseResult CHttpServerListenerImpl::OnChunkComplete(CONNID dwConnID) { ::PostOnChunkComplete(dwConnID, m_strName); return HPR_OK; } EnHttpParseResult CHttpServerListenerImpl::OnMessageComplete(CONNID dwConnID) { ::PostOnMessageComplete(dwConnID, m_strName); if(m_pServer->IsUpgrade(dwConnID)) return HPR_OK; CStringA strBody = GetHeaderSummary(dwConnID, " ", 0, FALSE); int iBodyLength = strBody.GetLength(); BOOL bSkipBody = FALSE; if(strcmp(m_pServer->GetMethod(dwConnID), HTTP_METHOD_HEAD) == 0) bSkipBody = TRUE; CStringA strContentLength; strContentLength.Format("%u", iBodyLength); DWORD dwSeq = 1; LPCSTR lpszReqSequence = nullptr; if(m_pServer->GetCookie(dwConnID, "__reqSequence", &lpszReqSequence)) dwSeq += atoi(lpszReqSequence); CStringA strSeqCookie; strSeqCookie.Format("__reqSequence=%u; path=/", dwSeq); THeader header[] = {{"Content-Type", "text/plain"}, {"Content-Length", strContentLength}, {"Set-Cookie", strSeqCookie}}; int iHeaderCount = sizeof(header) / sizeof(THeader); if(bSkipBody) { strBody.Empty(); iBodyLength = 0; } m_pServer->SendResponse(dwConnID, HSC_OK, "HP Http Server OK", header, iHeaderCount, (const BYTE*)(LPCSTR)strBody, iBodyLength); if(!m_pServer->IsKeepAlive(dwConnID)) m_pServer->Release(dwConnID); return HPR_OK; } EnHttpParseResult CHttpServerListenerImpl::OnUpgrade(CONNID dwConnID, EnHttpUpgradeType enUpgradeType) { ::PostOnUpgrade(dwConnID, enUpgradeType, m_strName); if(enUpgradeType == HUT_HTTP_TUNNEL) { m_pServer->SendResponse(dwConnID, HSC_OK, "Connection Established"); } else if(enUpgradeType == HUT_WEB_SOCKET) { THeader header[] = {{"Connection", UPGRADE_HEADER}, {UPGRADE_HEADER, WEB_SOCKET_HEADER_VALUE}, {"Sec-WebSocket-Accept", "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="}, {"Sec-WebSocket-Protocol", "chat"}}; int iHeaderCount = sizeof(header) / sizeof(THeader); m_pServer->SendResponse(dwConnID, HSC_SWITCHING_PROTOCOLS, nullptr, header, iHeaderCount); } else ASSERT(FALSE); return HPR_OK; } EnHttpParseResult CHttpServerListenerImpl::OnParseError(CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc) { ::PostOnParseError(dwConnID, iErrorCode, lpszErrorDesc, m_strName); return HPR_OK; } CStringA CHttpServerListenerImpl::GetHeaderSummary(CONNID dwConnID, LPCSTR lpszSep, int iSepCount, BOOL bWithContentLength) { CStringA SEP1; for(int i = 0; i < iSepCount; i++) SEP1 += lpszSep; CStringA SEP2(SEP1); SEP2 += lpszSep; CStringA strResult; USHORT usUrlFieldSet = m_pServer->GetUrlFieldSet(dwConnID); strResult.AppendFormat("%s[URL Fields]%s", SEP1, CRLF); strResult.AppendFormat("%s%8s: %s%s", SEP2, "SCHEMA", m_pServer->GetUrlField(dwConnID, HUF_SCHEMA), CRLF); strResult.AppendFormat("%s%8s: %s%s", SEP2, "HOST", m_pServer->GetUrlField(dwConnID, HUF_HOST), CRLF); strResult.AppendFormat("%s%8s: %s%s", SEP2, "PORT", m_pServer->GetUrlField(dwConnID, HUF_PORT), CRLF); strResult.AppendFormat("%s%8s: %s%s", SEP2, "PATH", m_pServer->GetUrlField(dwConnID, HUF_PATH), CRLF); strResult.AppendFormat("%s%8s: %s%s", SEP2, "QUERY", m_pServer->GetUrlField(dwConnID, HUF_QUERY), CRLF); strResult.AppendFormat("%s%8s: %s%s", SEP2, "FRAGMENT", m_pServer->GetUrlField(dwConnID, HUF_FRAGMENT), CRLF); strResult.AppendFormat("%s%8s: %s%s", SEP2, "USERINFO", m_pServer->GetUrlField(dwConnID, HUF_USERINFO), CRLF); DWORD dwHeaderCount = 0; m_pServer->GetAllHeaders(dwConnID, nullptr, dwHeaderCount); strResult.AppendFormat("%s[Request Headers]%s", SEP1, CRLF); if(dwHeaderCount == 0) strResult.AppendFormat("%s(no header)%s", SEP2, CRLF); else { unique_ptr headers(new THeader[dwHeaderCount]); VERIFY(m_pServer->GetAllHeaders(dwConnID, headers.get(), dwHeaderCount)); for(DWORD i = 0; i < dwHeaderCount; i++) strResult.AppendFormat("%s%s: %s%s", SEP2, headers[i].name, headers[i].value, CRLF); } DWORD dwCookieCount = 0; m_pServer->GetAllCookies(dwConnID, nullptr, dwCookieCount); strResult.AppendFormat("%s[Cookies]%s", SEP1, CRLF); if(dwCookieCount == 0) strResult.AppendFormat("%s(no cookie)%s", SEP2, CRLF); else { unique_ptr cookies(new TCookie[dwCookieCount]); VERIFY(m_pServer->GetAllCookies(dwConnID, cookies.get(), dwCookieCount)); for(DWORD i = 0; i < dwCookieCount; i++) strResult.AppendFormat("%s%s: %s%s", SEP2, cookies[i].name, cookies[i].value, CRLF); } CStringA strVersion; ::GetHttpVersionStr((EnHttpVersion)m_pServer->GetVersion(dwConnID), strVersion); EnHttpUpgradeType enUpgType = m_pServer->GetUpgradeType(dwConnID); LPCSTR lpszUpgrade = enUpgType != HUT_NONE ? "true" : "false"; LPCSTR lpszKeepAlive = m_pServer->IsKeepAlive(dwConnID) ? "true" : "false"; strResult.AppendFormat("%s[Basic Info]%s", SEP1, CRLF); strResult.AppendFormat("%s%13s: %s%s", SEP2, "Version", strVersion, CRLF); strResult.AppendFormat("%s%13s: %s%s", SEP2, "Method", m_pServer->GetMethod(dwConnID), CRLF); strResult.AppendFormat("%s%13s: %s%s", SEP2, "IsUpgrade", lpszUpgrade, CRLF); if(enUpgType != HUT_NONE) strResult.AppendFormat("%s%13s: %d%s", SEP2, "UpgradeType", enUpgType, CRLF); strResult.AppendFormat("%s%13s: %s%s", SEP2, "IsKeepAlive", lpszKeepAlive, CRLF); if(bWithContentLength) strResult.AppendFormat("%s%13s: %lld%s", SEP2, "ContentLength", m_pServer->GetContentLength(dwConnID), CRLF); strResult.AppendFormat("%s%13s: %s%s", SEP2, "ContentType", m_pServer->GetContentType(dwConnID), CRLF); return strResult; }