#include "RestfulFunc.h" #include 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 RestfulClient& RestfulClient::getInstance() { static RestfulClient c; return c; } RestfulClient::RestfulClient() { } RestfulClient::~RestfulClient() { } 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"; } } } } 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(pRequestConfig->GetBaseUri(), config); http_request request(MappingHttpRequestMethod(pRequestConfig->GetRequestType())); uri_builder urib(pRequestConfig->GetSubUri()); if (pRequestConfig->GetQueryPairs().size() > 0) { const auto& queries = pRequestConfig->GetQueryPairs(); for (auto it = queries.cbegin(); it != queries.cend(); ++it) { urib.append_query(it->first, it->second); } } request.set_request_uri(urib.to_string()); request.headers().add(header_names::accept, pRequestConfig->GetAcceptType()); if (pRequestConfig->GetRequestType() != HttpRequestMethod::GET) { request.set_body(pRequestConfig->GetBodyContent(), 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(std::string()); } }) .then([pResponse](pplx::task vt) { try { pResponse->content = 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 = 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() }; }