HttpsConnection::HttpsConnection() { hInternet = NULL; hRequest = NULL; hSession = NULL; agentName = ""; targetPort = INTERNET_DEFAULT_HTTPS_PORT; securityFlags = INTERNET_FLAG_RELOAD|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_NO_CACHE_WRITE |INTERNET_FLAG_SECURE|INTERNET_FLAG_IGNORE_CERT_CN_INVALID; } bool HttpsConnection::connectToHttpsServer(string httpVerb) { try { hInternet = InternetOpenA(agentName.c_str() ,INTERNET_OPEN_TYPE_PRECONFIG ,NULL ,NULL ,0); if (!hInternet) { ERROR("HttpsConnection::connectToHttpsServer()","Unable to open internet (code " + str(GetLastError()) + ")"); return false; } hSession = InternetConnectA(hInternet ,targetUrl.c_str() ,targetPort ,"" ,"" ,INTERNET_SERVICE_HTTP ,0 ,0); if (!hSession) { ERROR("HttpsConnection::connectToHttpsServer()","Unable to connect to internet (code " + str(GetLastError()) + ")"); clearHandles(); return false; } hRequest = HttpOpenRequestA(hSession ,httpVerb.c_str() ,targetHost.c_str() ,NULL ,"" ,NULL ,securityFlags ,0); if (!hRequest) { ERROR("HttpsConnection::connectToHttpsServer()","Cannot perform HTTP request (code " + str(GetLastError()) + ")"); clearHandles(); return false; } } catch (...) { ERROR("HttpsConnection::connectToHttpsServer()","Memory exception (code " + str(GetLastError()) + ")"); return false; } return true; } static string get_utf8(const std::wstring &wstr) { int sz = WideCharToMultiByte(CP_UTF8,0,&wstr[0],-1,0,0,0,0); std::string res(sz,0); WideCharToMultiByte(CP_UTF8,0,&wstr[0],-1,&res[0],sz,0,0); return res; } // if just going to read a response and don't need to send any data, leave args empty, // otherwise provide one or more headers and then one of either text *or* binary data (the latter // I added for protobuf use, since it won't survive the wstring/UTF8 conversion, // nor is it necessary) bool HttpsConnection::sendHttpsRequest(const string& sendHeaders, const string& sendContentText, string* sendContentBinary) { try { for (int tries = 0; tries < 20; ++tries) { int result; if (sendContentText.empty() && !sendContentBinary) result = HttpSendRequest(hRequest,NULL,0,NULL,0); else { std::wstring sendHeadersWide(sendHeaders.begin(),sendHeaders.end()); if (!sendContentText.empty()) { std::wstring sendContentWide(sendContentText.begin(),sendContentText.end()); string data = get_utf8(sendContentWide); result = HttpSendRequest(hRequest,sendHeadersWide.c_str(),sendHeadersWide.size(),&data[0],data.size()); } else // binary result = HttpSendRequest(hRequest,sendHeadersWide.c_str(),sendHeadersWide.size(),&(*sendContentBinary)[0],sendContentBinary->size()); } if (result) { if (!checkResponseHeader()) return false; return true; } ERROR("HttpsConnection::sendHttpsRequest()","Cannot perform HTTP request (code " + str(GetLastError()) + ")"); // will get this if no internet connection return false; } } catch (...) { ERROR("HttpsConnection::sendHttpsRequest()","Memory exception (code " + str(GetLastError()) + ")"); return false; } return false; } string HttpsConnection::getRequestResult() { DWORD numberBytesRead; char sz[1024]; string strResult; int result; do { result = InternetReadFile(hRequest,sz,1023,&numberBytesRead); sz[numberBytesRead] = '\0'; int x = strlen(sz); strResult += sz; memset(sz,0,1024); } while (result && (numberBytesRead != 0)); return strResult; } void HttpsConnection::clearHandles() { if (hInternet) { InternetCloseHandle(hInternet); hInternet = NULL; } if (hSession) { InternetCloseHandle(hSession); hSession = NULL; } } // confirm no issues with the latest response header, // returns true if okay, false if error // header is saved in HttpsConnection::responseHeader for reference (mainly while debugging) bool HttpsConnection::checkResponseHeader() { LPVOID lpOutBuffer = NULL; DWORD dwSize = 0; goto_retryQuery: // this call will fail on the first pass, b/c no buffer is allocated if (!HttpQueryInfo(hRequest,HTTP_QUERY_RAW_HEADERS_CRLF,(LPVOID)lpOutBuffer,&dwSize,NULL)) { if (GetLastError() == ERROR_HTTP_HEADER_NOT_FOUND) return true; // header not available else { // check for insufficient buffer if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { lpOutBuffer = new char[dwSize]; // allocate required buffer size goto goto_retryQuery; // try again } else { // error if (lpOutBuffer) delete [] lpOutBuffer; return false; } } } if (lpOutBuffer) { // convert to string via wstring wchar_t* t = (wchar_t*)lpOutBuffer; std::wstring responseHeaderWide = std::wstring(t); responseHeader.assign(responseHeaderWide.begin(),responseHeaderWide.end()); delete [] lpOutBuffer; if (responseHeader.find("HTTP/1.1 200") == string::npos) { ERROR("HttpsConnection::checkResponseHeader()","Connection failed, server response " + string(responseHeader.begin()+9,responseHeader.begin()+12)); // extract specific response code, which should be at that position return false; } } return true; }