« ^ »
[WIP]

Webhookのテストにはmitmproxyを使う

所要時間: 約 4分

今回はmitmproxyを使うことにした。

インストール

今回はmacOS上にMITMProxyの環境を構築する。インストール方法はいくつかある。Python製であるため、直接pipを使用してインストールできるが、私は横断的に使用するツールはHomebrewを用いてインストールしているため、ここでもHomebrewを用いることにする。

brew install mitmproxy

起動

インストールが完了すると、mitmproxyコマンドが使用できる。実行するとサーバーが立ち上がり、TCPの8080番を待ち受ける。

mitmproxy

受信したリクエストをexample.comにプロキシする

例として受信したリクエストを example.com に送信する。つまりクライアントと example.com との間に立ち、中間者になるということだ。ここでは例として全てのリクエストをexample.comへ転送し、 /testing で始まるURLパスへアクセスするリクエストは5回に1回失敗するように実装する。

import json
import random

from mitmproxy import http


def request(flow: http.HTTPFlow) -> None:
    flow.request.host = "example.com"
    flow.request.port = 443
    flow.request.scheme = "https"
    if flow.request.path.startswith("/testing") and random.randint(0, 5) == 0:
        flow.kill()


def response(flow: http.HTTPFlow) -> None:
    if flow.request.path.startswith("/testing"):
        data = {
            "status": "OK",
            "message": "yay!!",
        }
        flow.response.content = json.dumps(data).encode()

通常、mitmproxyはTCPの8080番を待ち受ける。 http://localhost:8080 にブラウザなどでアクセスすると example.com のページが見えるだろう。

外部サービスなどから送信されるリクエストを受け取る

外部からのリクエストを受信するためには、それを中継するための手段が必要になる。いくつかの手段を考えつくが、ここではngrokというサービスを使用する方法 とCloudflare Tunnelを使う方法について考えることにする。

ngrokと組み合わせる

外部サービスなどから送信されるリクエストを受け取るためには、mitmproxyまで通信を到達させる必要がある。Webサービスから送信されるWebhookなどを受信するためには、インターネットからアクセス可能なIPアドレスを持っている必要がある。この方法はさまざまあるが、てっとり早くそれを整備する方法として、ngrokを使用する方法がある。

ngrokは接続を開始すると、インターネット上にアクセス可能なドメインを準備し、そこに送信された通信を受け取るために、インターネット上の環境とのトンネルを確立する。ローカル環境で動作しているngrokは、そのトンネル経由で受信したリクエストをローカルの指定されたポート番号へプロキシする。そのため開発中のWeb APIを即座にインターネットに公開できる。

ngrokからのリクエストをmitmproxyに中継すると、どのようなリクエストを受信しているのかを確認でき、またそのリクエストやレスポンスを自由に書き換えることができる。そのため開発中のWeb APIのテストには非常に重宝する。

構成としては以下のようになる。


INTERNET

      +-----------------------------+
      |                             |
      |    ngrok                    |
      |                             |
      +------+----------------------+
             |
             | Tunnel
             |
+------------|-------------------------------------------+
| LOCAL      |                                           |
|            |                                           |
|     +------+--------------+                            |
|     |                     |                            |
|     |    ngrok            |                            |
|     |                     |                            |
|     +------+--------------+                            |
|            |                                           |
|     +------+--------------+                            |
|     |                     |                            |
|     |    mitmproxy        +--- main.py                 |
|     |   localhost:8080    |                            |
|     +---------------------+                            |
|                                                        |
+--------------------------------------------------------+

構成方法も特に難しくない。mitmproxyを起動した状態で、ngrokを起動するだけだ。ngrokの起動時に、どのポートにリクエストを流すかを指定するため、mitmproxyの待ち受けているポート番号を指定する。

ngrok http --region us --subdomain=${TEST_SUB_DOMAIN} 8080

Cloudflare tunnelと組み合わせる

Cloudflareも上記と同様の機能を提供している。しかも無料で提供しているところがよい。もしドメインを所有していれば、無料でこれを使用できる。 構成としては以下のようになる。


INTERNET

      +-----------------------------+
      |                             |
      |    Cloudflare Tunnel        |
      |                             |
      +------+----------------------+
             |
             | Tunnel
             |
+------------|-------------------------------------------+
| LOCAL      |                                           |
|            |                                           |
|     +------+--------------+                            |
|     |                     |                            |
|     |    cloudflared      |                            |
|     |                     |                            |
|     +------+--------------+                            |
|            |                                           |
|     +------+--------------+                            |
|     |                     |                            |
|     |    mitmproxy        +--- main.py                 |
|     |   localhost:8080    |                            |
|     +---------------------+                            |
|                                                        |
+--------------------------------------------------------+

構成としてはほとんど変わらない。

トンネルの作成とドメインの割り当てについてはCloudflare Tunnelを使うに記述した。準備が済んだら以下のコマンドでトンネルを開始できる。

cloudflared tunnel run --url http://localhost:8080 MY_TUNNEL_NAME