前回の記事で、MicrosoftがGitHubでオープンソースとして公開しているcpprestsdkを使い、VC++でHTTP通信(POST/GET/PUT/DELETEといったREST APIの実行)ができるようになりました。
今回は、cpprestsdkを使ったファイルダウンロードの方法を解説します。
環境構築
まずは前回の記事の通り、環境構築を行って下さい。
その上で、サンプルコードを実装していきます。
サンプルコード
HttpClient
「C:\src\components\component1\component1.vcxproj」のHttpClientクラスに、ファイルダウンロード用のメソッドを追加します。
src/components/component1/HttpClient.h
#pragma once
#include <stdio.h>
#include "cpprest/http_client.h"
#include "cpprest/filestream.h"
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace concurrency::streams;
// HTTP(S)クライアント
class HttpClient
{
public:
// 前回と同じPOST/GET/PUT/DELETEなどのpublicメソッド
// ファイルダウンロード
int download(const std::string& inUrl, const std::string& inFilePath);
private:
// 前回と同じPOST/GET/PUT/DELETEなどのprivateメソッド
void _download(istream inBody, size_t inChunk, size_t inLength, size_t inContentLength, streambuf<unsigned char>& outBuff);
pplx::task<int> _download(const std::string& inUrl, const std::string& inFilePath);
private:
json::value _m_cResultValue;
int _m_nStatusCode;
};
src/components/component1/HttpClient.cpp
#include "HttpClient.h"
// 前回と同じPOST/GET/PUT/DELETEなどのpublicメソッド
int HttpClient::download(const std::string& inUrl, const std::string& inFilePath)
{
try {
this->_download(inUrl, inFilePath).wait();
} catch (const std::exception& e) {
::printf("<!> %s \n", e.what());
if (this->_m_nStatusCode == 0) return 1;
else return this->_m_nStatusCode;
}
if (this->_m_nStatusCode == 200) return 0;
else if (this->_m_nStatusCode == 0) return 1;
else return this->_m_nStatusCode;
}
// 前回と同じPOST/GET/PUT/DELETEなどのprivateメソッド
void HttpClient::_download(istream inBody, size_t inChunk, size_t inLength, size_t inContentLength, streambuf<unsigned char>& outBuff)
{
size_t nLength = inBody.read(outBuff, inChunk).get();
if (nLength > 0) {
::printf("[Download] %llu/%llu \n", inLength + nLength, inContentLength);
this->_download(inBody, inChunk, inLength + nLength, inContentLength, outBuff);
} else {
return;
}
}
pplx::task<int> HttpClient::_download(const std::string& inUrl, const std::string& inFilePath)
{
const std::string sUrl = inUrl;
static std::string sFilePath;
sFilePath = inFilePath;
this->_m_cResultValue = json::value::null();
this->_m_nStatusCode = 0;
size_t nContentLength(0);
// 実行タスク生成
return pplx::create_task([sUrl]
{
utility::string_t sUtf16 = utility::conversions::utf8_to_utf16(sUrl);
sUtf16 = uri::encode_uri(sUtf16, uri::components::component::query);
http_client cClient(sUtf16);
http_request cRequest(methods::GET);
return cClient.request(cRequest);
}).then([this, &nContentLength, sUrl](http_response cResponse)
{
nContentLength = cResponse.headers().content_length();
if (cResponse.status_code() == status_codes::OK) {
::printf("[GET] %s success. \n", sUrl.c_str());
} else {
::printf("<!> [GET] %s failed. status=%d \n", sUrl.c_str(), cResponse.status_code());
}
this->_m_nStatusCode = cResponse.status_code();
return cResponse.body();
}).then([this, &nContentLength](istream cStream)
{
utility::string_t sUtf16 = utility::conversions::utf8_to_utf16(sFilePath);
streambuf<unsigned char> cBuff = file_buffer<unsigned char>::open(sUtf16).get();
if (nContentLength == 0) ::printf("<!> Content length is zero. \n");
else {
size_t nChunkSize = nContentLength / 10;
this->_download(cStream, nChunkSize, 0, nContentLength, cBuff);
}
cBuff.close().wait();
return 0;
});
}
メインプログラム
メインプログラムのサンプルコードです。
src/components/component1/main.cpp
#include "HttpClient.h"
int main(int argc, const char** argv)
{
int ret;
json::value cOutData;
// URL
std::string sUrl = "http://localhost/hoge.pdf"; // ダウンロードしたいファイルのURLを指定
// ダウンロード先
std::string sLocalFilePath = "C:/hoge.pdf"; // ダウンロード先となるローカルのファイルパスをフルパスで指定
// REST API実行
HttpClient cHttpClient;
ret = cHttpClient.download(sUrl, sLocalFilePath);
if (ret == 0) {
::printf("downloaded \n");
}
return 0;
}
前回の記事の通りビルドし、component1.exeを実行すると、HTTP通信が実行されます。
以上で、cpprestsdkを使ったHTTP通信(ファイルダウンロード)をすることができるようになりました。