curlコマンドとwgetコマンドでバイナリをPOST

curlコマンドまたはwgetコマンドを使い、HTTP(S) POSTメソッドのリクエスト本体でバイナリを送る方法です。

httpbin

HTTP(S)の通信をテストするには httpbin というサイトが便利です。

以下のようにhttpbinにHTTPリクエストを送信すると、リクエストの内容がレスポンスとして返されます。

$ curl 'http://httpbin.org/get' 
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.68.0", 
    "X-Amzn-Trace-Id": "Root=1-5f8bd296-24f5bbf764560c2432655930"
  }, 
  "origin": "999.999.999.999", 
  "url": "http://httpbin.org/get"
}

X-Amzn-Trace-Id というリクエストヘッダーは curl コマンドが付与するものではなく、AWSのALBが付与するものです。httpbinのサービスがALBの後ろで動いているんだと思います。

curlコマンド

--data-binary というオプションでバイナリの保存されているファイル名を指定します。ファイル名の前に @ を付けます。

$ curl -H "Content-Type: application/octet-stream" -X POST --data-binary @data.txt 'http://httpbin.org/post'
{
  "args": {}, 
  "data": "data:application/octet-stream;base64,YQBigGM=", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "5", 
    "Content-Type": "application/octet-stream", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.68.0", 
    "X-Amzn-Trace-Id": "Root=1-5f8bd13d-70f0515e6ebaa60411533998"
  }, 
  "json": null, 
  "origin": "999.999.999.999", 
  "url": "http://httpbin.org/post"
}

レスポンスのdataが "data:application/octet-stream;base64,...という表記になっていますが、httpbinはバイナリを受け取るとBASE64エンコードして返すようです。ソースコードを見るとわかります。

curlコマンドのオプションを --data-binary @- とすれば標準入力からバイナリを取り込みます。

$ printf "a\0b\x80c" | curl -H "Content-Type: application/octet-stream" -X POST --data-binary @- 'http://httpbin.org/post'

ちなみに -d ではバイナリを扱えません。

$ curl -H "Content-Type: application/octet-stream" -X POST -d @data.txt 'http://httpbin.org/post'
{
  "args": {}, 
  "data": "a", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "1", 
    "Content-Type": "application/octet-stream", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.68.0", 
    "X-Amzn-Trace-Id": "Root=1-5f8bcfb2-16756c172d8a435a142afea7"
  }, 
  "json": null, 
  "origin": "999.999.999.999", 
  "url": "http://httpbin.org/post"
}

なお、data.txt は以下のコマンドで作成したファイルです。これはUTF-8ではデコードできないバイナリです。

$ printf "a\0b\x80c" > data.txt 

wgetコマンド

--post-file というオプションでファイル名を指定します。

$ wget --post-file=data.txt --header='Content-Type: application/octet-stream' 'http://httpbin.org/post' -q -O -
{
  "args": {}, 
  "data": "data:application/octet-stream;base64,YQBigGM=", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "identity", 
    "Content-Length": "5", 
    "Content-Type": "application/octet-stream", 
    "Host": "httpbin.org", 
    "User-Agent": "Wget/1.20.3 (linux-gnu)", 
    "X-Amzn-Trace-Id": "Root=1-5f8bd025-012893945a1be31b382629db"
  }, 
  "json": null, 
  "origin": "999.999.999.999", 
  "url": "http://httpbin.org/post"
}

--post-file=---post-file=/dev/stdin などとしても標準入力は使えませんでした。