SATOXのシテオク日記

~ふもっふ、ふもふも~

いまさら聞けないHTTPマルチパートフォームデータ送信

放蕩SATOXさん、最近、ネットワーク関連の勉強をしておりまして、アプリケーションからPHPを叩いたりしたりしています。
リモートプロシージャ的にマルチパートフォームデータで任意のコマンドやバイナリファイルを送ったりなんかするのですが、Socketを直に使っていたりするのでHTTPのプロトコルを使って通信しないといけません。
通信周りに詳しい方にとっては「今更そんなこと……」なんて言われてしまいそうなものですが、自分のためにもマルチパートフォームデータを使う際の送信内容について、覚え書きとして書いておこうと思った次第です。
ちなみに、マルチパートフォームデータとは、HTTPのリクエストで複数のフォームデータ(マルチパート)を送るための形式(HTTPのプロトコル)です。誰でもよく使っているもので、ブラウザであるページを開いて、名前の入力+画像ファイルのアップロード、なんてときに使われています。
 

■HTTPヘッダ部

コンテントタイプに以下を指定します。
Content-Type: multipart/form-data; boundary=「バウンダリ文字列」\r\n

バウンダリ文字列とは、複数の情報を続けて送る際の情報同士の「仕切線」の役目を果たします。この文字を調べて「仕切線」と判断するため、情報そのものにバウンダリ文字列が入っていてはいけません。
FireFoxで転送してみた内容を見てみると「---------------------------102852708831426」というように「-」27文字と数字15文字で構成されており、ランダムの数字が付いていました。
\r\nは改行文字を示します。
 

■ボディ部

フォームデータ
--「バウンダリ文字列」\r\n
Content-Disposition: form-data; name="「フォームデータ名」"\r\n
\r\n
「フォームデータ」\r\n

上記が1つの情報(コンテンツ)を示しています。
例えば、HTMLのINPUTタグでname="password" value="ponpoko"と入力したとき、name=「フォームデータ名」、value=「フォームデータ」と等価です。

バイナリデータ
Content-Disposition: form-data; name="submitfile"; filename="myfile.txt"\r\n
Content-Type: application/octet-stream\r\n
Content-Transfer-Encoding: binary\r\n
\r\n
「バイナリデータ」

マルチパートフォームデータにファイルの実体を含めたい場合があります。上記がバイナリ送信の例です。Content-TypeやContent-Transfer-Encodingなどは任意の設定を行ってください。
 

フッタ
--「バウンダリ文字列」--\r\n

マルチパートフォームデータの終端には上記のフッタを書き込みます。
 

■サンプル

以下、マルチパートフォームデータのポスト内容のサンプルです。
POST test.php HTTP/1.1\r\n
Host: satoxpochi.com\r\n
Content-Type: multipart/form-data; boundary=---------------------------102852708831426\r\n
Content-Length: 「ボディ部のサイズ」\r\n
\r\n
-----------------------------102852708831426\r\n
Content-Disposition: form-data; name="password"\r\n
\r\n
ponpoko\r\n
-----------------------------102852708831426\r\n
Content-Disposition: form-data; name="level"\r\n
\r\n
high\r\n
-----------------------------102852708831426\r\n
Content-Disposition: form-data; name="filename"; filename="text.txt"\r\n
Content-Type: application/octet-stream\r\n
Content-Transfer-Encoding: binary\r\n
\r\n
abcd
-----------------------------102852708831426--\r\n

この例では、フォームデータとしてpassword=ponpoko、level=highを送信し、「abcd」とだけ書かれたtext.txtをバイナリデータとして送信内容に含め、http://satoxpochi.com/test.php(存在しません)宛にポストしています。
ヘッダ部の内容はシンプルにしていて、Content-Lengthは正しい値を入れないといけないのですが、そこさえ入力すればこれだけでもPHPに必要な情報が渡せます。
さぁこれで、気になるあの娘にマルチパートフォームデータを投げつけられますね。