#include "RestfulFunc.h" #include #include #if defined(_MSC_VER) #include #endif //_MSC_VER using namespace utility; // Common utilities like string conversions using namespace web; // Common features like URIs. using namespace web::http; // Common HTTP functionality using namespace web::http::client; // HTTP client features GetRestfulTokenCallBack g_tokenCall = NULL; RVCRESTFULSDK_API void SetRestfulTokenCallBack(GetRestfulTokenCallBack t_callBack) { g_tokenCall = t_callBack; } RestfulClient& RestfulClient::getInstance() { static RestfulClient c; return c; } RestfulClient::RestfulClient() { } RestfulClient::~RestfulClient() { } bool HttpClientRequestConfig::getToken(std::string& t_channelId, std::string& t_token, std::string& terminalNo, std::string& reserve1) const { if (m_withToken && g_tokenCall != NULL) { g_tokenCall(t_channelId, t_token, terminalNo, reserve1); if (t_channelId.length() > 0 && t_token.length() > 0) return true; } return false; } namespace { const http::method MappingHttpRequestMethod(HttpRequestMethod provideMethod) { switch (provideMethod) { case GET: return http::methods::GET; break; case POST: return http::methods::POST; break; case PUT: return http::methods::PUT; break; case DEL: return http::methods::DEL; break; case HEAD: return http::methods::HEAD; break; case OPTIONS: return http::methods::OPTIONS; break; case TRCE: return http::methods::TRCE; break; case CONNECT: return http::methods::CONNECT; break; case MERGE: return http::methods::MERGE; break; case PATCH: return http::methods::PATCH; break; case UPLOAD: return http::methods::POST; break; case DOWNLOAD: return http::methods::POST; break; default: break; } return http::methods::GET; } void GetFileNameAndType(const std::string& absoluteFilePath, std::string& fileName, std::string& contentType) { size_t pos = absoluteFilePath.find_last_of("/\\"); fileName = absoluteFilePath.substr(pos + 1); contentType = "application/octet-stream"; pos = fileName.find_last_of("."); if (pos != std::string::npos) { std::string ext = fileName.substr(pos + 1); std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); if (ext == "jpg" || ext == "jpeg") { contentType = "image/jpeg"; } else if (ext == "txt" /*|| ext == "log"*/) { contentType = "text/plain"; } } } #if defined(_MSC_VER) static std::wstring s2w(const std::string str) { wchar_t* wstr = NULL; int n = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0); if (n > 0) { wstr = new wchar_t[n + 1]; if (wstr == NULL) { return std::wstring(); } std::memset(wstr, 0, (n + 1) * sizeof(wchar_t)); ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, &wstr[0], n); std::wstring strr(wstr); delete wstr; return strr; } return std::wstring(); } #endif //_MSC_VER std::string w2s(const std::wstring wstr) { #if defined(_MSC_VER) char* str = NULL; int n = ::WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL); if (n > 0) { str = new char[n + 1]; if (str == NULL) { return std::string(); } std::memset(str, 0, sizeof(char) * (n + 1)); ::WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &str[0], n, NULL, NULL); std::string strr(str); delete str; return strr; } return std::string(); #else if (wstr.empty()) { return ""; } unsigned len = wcstombs(NULL, wstr.c_str(), 0) + 1; if (NULL == setlocale(LC_ALL, "zh_CN.gbk")) { } char* p = new char[len]; wcstombs(p, wstr.c_str(), len); p[len - 1] = '\0'; std::string str(p); delete[] p; return str; #endif // _MSC_VER } } #if defined(_MSC_VER) #define STRW(str) s2w(str) #define WSTR(str) w2s(str) #else #define STRW(str) (str) #define WSTR(str) (str) #endif //_MSC_VER void RestfulClient::Do(const HttpClientRequestConfig* const pRequestConfig, HttpClientResponseResult* pResponse) const { http_client_config config; config.set_validate_certificates(pRequestConfig->NeedValidCert()); const uint32_t timeoutVal = pRequestConfig->GetTimeout(); if (timeoutVal != 0) { config.set_timeout(utility::seconds(timeoutVal)); } web::http::client::http_client client(STRW(pRequestConfig->GetBaseUri()), config); http_request request(MappingHttpRequestMethod(pRequestConfig->GetRequestType())); uri_builder urib(STRW(pRequestConfig->GetSubUri())); if (pRequestConfig->GetQueryPairs().size() > 0) { const auto& queries = pRequestConfig->GetQueryPairs(); for (auto it = queries.cbegin(); it != queries.cend(); ++it) { urib.append_query(STRW(it->first), STRW(it->second)); } } request.set_request_uri(urib.to_string()); request.headers().add(header_names::accept, STRW(pRequestConfig->GetAcceptType())); std::string token, channelId, terminalno, reserve1; if (pRequestConfig->getToken(channelId, token, terminalno, reserve1)) { request.headers().add(STRW("channelId"), STRW(channelId)); request.headers().add(STRW("token"), STRW(token)); request.headers().add(STRW("terminalno"), STRW(terminalno)); } if (pRequestConfig->GetRequestType() != HttpRequestMethod::GET) { request.set_body(STRW(pRequestConfig->GetBodyContent()), STRW(pRequestConfig->GetContentType())); } if (pRequestConfig->GetRequestType() == HttpRequestMethod::DOWNLOAD) { pplx::task requestTask = client.request(request) .then([pResponse](http_response response) ->pplx::task { pResponse->statusCode = response.status_code(); if (pResponse->ResponseOK()) { return response.extract_string(); } else { std::cout << "response status result: " << response.status_code() << std::endl; return pplx::task_from_result(utility::string_t()); } }) .then([pResponse](pplx::task vt) { try { pResponse->content = WSTR(vt.get()); } catch (const http_exception& ex) { pResponse->statusCode = -1; pResponse->content = ex.what(); } }); try { requestTask.wait(); } catch (const std::exception& ex) { pResponse->statusCode = -1; pResponse->content = ex.what(); } } else { pplx::task requestTask = client.request(request) .then([pResponse](http_response response) ->pplx::task { pResponse->statusCode = response.status_code(); if (pResponse->ResponseOK()) { return response.extract_json(); } else { std::cout << "response status result: " << response.status_code() << std::endl; return pplx::task_from_result(json::value()); } }) .then([pResponse](pplx::task vt) { try { json::value const& v = vt.get(); pResponse->content = WSTR(v.to_string()); } catch (const http_exception& ex) { pResponse->statusCode = -1; pResponse->content = ex.what(); } }); try { requestTask.wait(); } catch (const std::exception& ex) { pResponse->statusCode = -1; pResponse->content = ex.what(); } } } std::pair HttpClientUploadRequest::BuildBodyContent() const { std::stringstream data; std::string boundary{}; for (int i = 0; i < 50; i++) { boundary += (rand() % 26) + 'A'; } for (auto& param : mParams) { data << "\r\n--"; data << boundary; data << "\r\nContent-Disposition: form-data; name=\""; data << param.first; data << "\"\r\n\r\n"; data << param.second; } for (auto& file : mFiles) { std::string inputFileName; std::string contentType; GetFileNameAndType(file.second, inputFileName, contentType); std::ifstream inputFile; inputFile.open(file.second, std::ios::binary | std::ios::in); std::string inputFileContent = std::string((std::istreambuf_iterator(inputFile)), (std::istreambuf_iterator())); data << "\r\n--"; data << boundary; data << "\r\nContent-Disposition: form-data; name=\""; data << file.first; data << "\"; filename=\""; data << inputFileName; data << "\"\r\nContent-Type: "; data << contentType; data << "\r\n\r\n"; data << inputFileContent; } data << "\r\n--"; data << boundary; data << "--\r\n"; return { boundary, data.str() }; }