見出し画像

[Drogon]実験!HTTPリクエスト

さて今回は、次に書こうと思っている記事の前情報のために、実験を一つ行いたいと思います。

Drogonのコントローラで、パスに対して紐付けられるメソッドには最低限書かなければならないシグネチャあります。
それがこの二つです。

  • const HttpRequestPtr& req

  • std::function<void (const HttpResponsePtr &)> &&callback

req に渡ってくるのは、クライアントからのHttpリクエストに関する情報全般が格納されたオブジェクトへのポインタ、
callback はHTTPresponseを返すための処理のエントリポイントを返すためのポインタです。

以前の記事でファイルのアップロードを行った際には、このreqを通じてHTTPリクエストボディに格納されたファイルの情報へアクセスしました。
そのことからわかるように、Drogonのコントローラはこのreqによって渡ってきた情報を基に様々な処理を行います。

詳細なマニュアルは公式のページにも詳しいですが、分量が多く、読了にはかなりの時間を要しますので、ここではよく使いそうな内容に絞ってどのようなデータが取れるのか、実際にどのように取ったらいいのか、見ていきたいと思います。

実際に取ってみるコード

今回は特にプロジェクトを作ったり、コントローラを作ったりとかはしません。実験用なのできったないコードですし、既存のプロジェクトにでも入れてもらえればいいかと思います。

まずは以下のコードをコントローラのreqを受けているハンドラメソッドに書いてみましょう。

  • コードの例

auto viewData = drogon::HttpViewData();
std::stringstream ss;
viewData.insert("peerIP", req->getPeerAddr().toIp());

ss << req->getPeerAddr().toPort();
viewData.insert("peerPort", ss.str());
ss.str("");

ss << req->getPeerAddr().isIntranetIp();
viewData.insert("isInet", ss.str());
ss.str("");

ss << req->getPeerAddr().isIpV6();
viewData.insert("isIpV6", ss.str());
ss.str("");

viewData.insert("localAddr", req->getLocalAddr().toIp());

ss << req->getLocalAddr().toPort();
viewData.insert("localPort", ss.str());
ss.str("");

viewData.insert("Header", 
    req->getHeader("User-Agent") +
    "<br>" + req->getHeader("Accept") +
    "<br>" + req->getHeader("Accept-Language") +
    "<br>" + req->getHeader("Accept-Encoding"));

ss << req->getHeader("Accept").length();
viewData.insert("HeaderLength", ss.str());
ss.str("");

viewData.insert("RequestBody", req->bodyData());

ss << req->bodyLength();
viewData.insert("BodyLength", ss.str());
ss.str("");

callback(drogon::HttpResponse::newHttpViewResponse("/*ご自身のViewのcsp*/", viewData));

次に、コントローラから渡ってきたソースコードを書き出すcspファイルを用意します。

ちょっと見にくかったので、私の場合は最低限のcssを利用してこんな感じ

  • cspファイルの例

<!DOCTYPE html>
<html>
<%c++
    auto peerIP=@@.get<std::string>("peerIP");
    auto peerPort=@@.get<std::string>("peerPort");
    auto isInet=@@.get<std::string>("isInet");
    auto isIpV6=@@.get<std::string>("isIpV6");
    auto localAddr=@@.get<std::string>("localAddr");
    auto localPort=@@.get<std::string>("localPort");
    auto Header=@@.get<std::string>("Header");
    auto HeaderLength=@@.get<std::string>("HeaderLength");
    auto RequestBody=@@.get<std::string>("RequestBody");
    auto BodyLength=@@.get<std::string>("BodyLength");
%>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="Content-Style-Type" content="text/css">
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">

    <meta name="description" content="DrogonのCSS利用サンプル">
    <meta name="keywords" content="Drogon,CSS,MVCフレームワーク,C++,高速">
    <meta name="Mizinko-Kinako" content="MKnote">
    <meta name="copyright" content="Mizinko-Kinako">
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="sample.css">
    <title>HTTPRequestPtrから取れる色々</title>
    
</head>

<body>
    <table>
        <thead>
        <tr>
            <th colspan="3">HTTPRequestPtrから取れる接続情報の一例</th>
        </tr>
        </thead>
    <tr>
        <td>getPeerAddr().toIp() </td><td>{% peerIP %}</td><td>接続してきたクライアントのIP</td>
    </tr>
    <tr>
        <td>getPeerAddr().toPort()</td><td>{% peerPort %}</td><td>接続してきたクライアントのポート</td>
    </tr>
    <tr>
        <td>getPeerAddr().isIntranetIp()</td><td>{% isInet %}</td><td>接続してきたのは外部のマシンから?</td>
    </tr>
    <tr>
        <td>getPeerAddr().isIpV6()</td><td>{% isIpV6 %}</td><td>IPV6のアドレス?</td>
    </tr>
    <tr>
        <td>getLocalAddr().toIp()</td><td>{% localAddr %}</td><td>サーバ側のIPアドレス</td>
    </tr>
    <tr>
        <td>getLocalAddr().toIp()</td><td>{% localPort %}</td><td>サーバ側のポート</td>
    </tr>
    <tr>
        <td>getHeader("取りたいキー")</td><td>{% Header %}</td><td>HTTPリクエストヘッダの任意のキー</td>
    </tr>
    <tr>
        <td>getHeader().length()</td><td>{% HeaderLength %}</td><td>HTTPリクエストヘッダ長さ</td>
    </tr>
    <tr>
        <td>bodyData()</td><td></td><td>HTTPリクエストボディ、Getだから今はないけど</td>
    </tr>
    <tr>
        <td>bodyLength()</td><td>{% BodyLength %}</td><td>HTTPリクエストボディ長さ</td>
    </tr>
    </table>
</body>
</html>
 

実行してみる

不都合な情報は要所要所隠していますが、ビルド&実行してみると、以下のような画面が表示されます。

結構色々取れる

さいごに

今回はControllerにわたってきたHttpRequestPtrから、接続に関する様々な情報を拾い上げる方法を実験してみました。
実験した内容以外にも、HttpRequestPtr を経由すれば、CookieやJsonObjectなど、HTTPでやり取りするデータは大抵のものが取れます。
また、Cookie の扱いに特化したクラスなども存在しますので、それはまたの機会に解説します。

前回までに書いた内容を利用すれば、Webアプリケーションの主要な機能の大半は独自に作れるようになってきていると思いますので、
次回の記事では実際にサービスを公開する前に絶対に入れておきたいセキュリティ機能に関する部分、
サービスへのアクセスに対して望まざるアクセスを排除するFilterという機能について解説します。

それでは

いいなと思ったら応援しよう!