curlを簡単に使うC++ライブラリ(libcurlxx)を作った
c++でHttpの通信をしようと思うとなかなかにめんどくさくて、毎回CurlというHttp通信などに特化したライブラリを使うわけですが、CurlはC言語で書かれておりC++で使おうと思ったらなんからのクラスでラッピングしてやる必要があります。
さすがにCurlなんて超有名なライブラリはすでにC++のラッピングクラスの実装があったりするのですが、どうもなんかしっくり来なかったり、Modern C++じゃなかったりなのでこれを期に自分で作りました。
使い方など
Githubにすでにリポジトリは作っていまして、つまりここをみたほうが早いです
https://github.com/chromabox/libcurlcxx
httpのPostならこのように簡単に記述できます
#include <map>
#include <memory>
#include "curlcxx_cdtor.h"
#include "curlcxx_mime.h"
#include "curlcxx_http_req.h"
#include "curlcxx_utility.h"
#include "curlcxx_error.h"
using libcurlcxx::curl_base_cdtor;
using libcurlcxx::curl_base_stringstream;
using libcurlcxx::curl_base_utility;
using libcurlcxx::curl_base_exception;
using libcurlcxx::curl_base_mime;
using libcurlcxx::curl_http_request;
using libcurlcxx::curl_http_request_param;
using std::string;
using std::ostream;
using std::ostringstream;
using std::map;
// 使用の際はこれの定義が必要
static libcurlcxx::curl_base_cdtor _libcurl;
// 引数付きGETリクエストサンプル
int main()
{
std::string_view url("https://httpbin.org/post");
curl_http_request req(std::make_shared<curl_base_stringstream>());
try {
// POSTとして投げるデータを設定。
// 文字列だけならcurl_http_request_paramを使ったほうが楽
curl_http_request_param para;
para["name"] = "aaa";
para["pass"] = "psps";
req.RequestSetupPost(url, para);
} catch (curl_base_exception &error) {
// エラー内容表示
std::cerr << error.what() << std::endl;
return -1;
}
std::cout << "url: " << req.get_url() << std::endl;
try {
req.perform();
} catch (curl_base_exception &error) {
// エラー内容表示
std::cerr << error.what() << std::endl;
return -1;
}
// httpコード取得
if(req.get_responceCode() != 200){
std::cout << "htto code error " << req.get_responceCode() << std::endl;
return -1;
}
std::cout << req.get_ContentString() << std::endl;
return 0;
}
Mastodonのタイムラインを読むとかだとこんな感じです。
#include <map>
#include <memory>
#include "curlcxx_cdtor.h"
#include "curlcxx_http_req.h"
#include "curlcxx_utility.h"
#include "curlcxx_error.h"
using libcurlcxx::curl_base_cdtor;
using libcurlcxx::curl_base_stringstream;
using libcurlcxx::curl_base_utility;
using libcurlcxx::curl_base_exception;
using libcurlcxx::curl_base_mime;
using libcurlcxx::curl_http_request;
using libcurlcxx::curl_http_request_param;
using std::string;
using std::ostream;
using std::ostringstream;
using std::map;
// 使用の際はこれの定義が必要
static libcurlcxx::curl_base_cdtor _libcurl;
// mastodonのPublicタイムライン取得用エンドポイント
static constexpr std::string_view mastodon_fetch_public_endpoint("/api/v1/timelines/public");
// 接続したいサーバをここに書く
static constexpr std::string_view mastodon_server("https://mstdn.jp");
// Mastdonのサーバからタイムライン取得
// surl: 対象サーバ
// local: ローカル限定かどうか。
// true : ローカルタイムライン(LTL)取得
// false : 連合タイムライン(GTL)取得
int mastodon_fetch_public(std::string_view surl, bool local)
{
curl_http_request req(std::make_shared<curl_base_stringstream>());
std::string url(surl);
url += mastodon_fetch_public_endpoint;
curl_http_request_param para;
if(local){
para["local"] = "true";
}else{
para["local"] = "false";
}
// para["limit"] = "2"; // limitをつけると取得数制限できる
req.appendHeader("User-Agent: curl/7.81.0"); // UAを指定しないと403になる
req.RequestSetupGet(url, para);
std::cout << "url: " << req.get_url() << std::endl;
try {
std::cout << "contacting mastodon..... " << std::endl;
req.perform();
} catch (curl_base_exception &error) {
// 何らかのHTTPS的な失敗をした場合はここでエラー内容表示して終わり
std::cerr << error.what() << std::endl;
return -1;
}
// httpコード取得
if(req.get_responceCode() != 200){
std::cout << "http code error " << req.get_responceCode() << std::endl;
std::cout << "raw message:" << std::endl;
std::cout << req.get_ContentString() << std::endl;
return -1;
}
if(req.get_ContentType().find("application/json") == std::string::npos){
// JSONではない。何らかのエラーである
std::cout << "mastodon request error : " << req.get_ContentString() << std::endl;
return -1;
}
std::cout << req.get_ContentString() << std::endl;
return 0;
}
int main()
{
int ret;
ret = mastodon_fetch_public(mastodon_server, true);
return ret;
}
Json解析部分は省いています。全文はこちら
https://github.com/chromabox/libcurlcxx/blob/master/sample/mastodon_public_read.cpp
blueskyでも似たような感じですが、流石に長くなるのでこちらを見てください。
blueskyは認証しないと読めないので、そのへんの処理がちょっとありますね
https://github.com/chromabox/libcurlcxx/blob/master/sample/bluesky_timeline_read.cpp
外部のプロジェクトで使いたいとかのサンプルはこちらになります。
cmakeを導入していると簡単に導入できます。
https://github.com/chromabox/libcurlcxx_sample
ビルドに関して言えば、cmakeがシステムに入っていれば簡単にできます。
一応現状はUbuntuのみ確認というか対応していまして、まだWindowsでの確認はしていませんが多分Mingwでビルドすればできるんじゃないかなと思います。
(Windows環境の場合、curl本体のビルドの段階でssl関連がどうなるかちょっとわかりませんが…おいおい手順を載せて対応しましたと言えたらよいなと…)
Curlは結構色々対応しているライブラリでさすがにこれ全部ラッピングはしていません。
とりあえず自分が使いそうな機能をラッピングしています。
今後なにか自分が必要に迫られたら実装というかそんな感じですね
(websocketはまだ無いんですが、blueskyで使っているらしい?ので、そのうち実装すると思います)
Modern C++と言っておきながら、C++は本当に難しくちょっと自信がない部分もあるんですがCurlのハンドル等をスマートポインタで管理したりなどして一応モダンにしたつもりです
普段あまりしないlinter(cpplint)も通して読みやすくはしています
殆ど自分用に作ったわけですが、もしよろしければ使ってくださいということで……
おしらせ
明日3/4はボクの誕生日です
普段は他人様におねだりするのは良くないと思っているのですが、誕生日だけは古事記をしてもいいというルールがあるのでちょっとフライングですが、Amazonの欲しい物リスト貼っておきます
最近はPythonにも興味があり、本を蒐集しております。皆様何卒よろしくおねがいします
https://www.amazon.co.jp/hz/wishlist/ls/23TQMSM3EB8EA