調べてみた。動作確認用のサーバは plackup で立てている。 app.psgi の中身は一番最後に。
--data (-d, --data-ascii)
application/x-www-form-urlencoded 形式で POST する。 @/path/to/file のように value の先頭が @ ではじまっているとファイルを読み込んで改行文字を取り除く。パラメータや @ つきで指定したファイルの中身はすべて URL エンコードされていることが期待される。つまり curl(1) は URL エンコードしてくれない。 -d を複数回指定するとすべてのパラメータが & で連結される。 @ でファイルを指定する場合、 -d 'file=@sale.txt' のようにすると中身が展開されないので注意 (file=@sale.txt という文字列が渡される)
$ curl -d 'foo=bar' -d 'discount=50% off' http://localhost:5000/ $VAR1 = { 'POSTDATA' => 'foo=bar&discount=50% off', # <-- URL エンコードされない 'Content-Type' => 'application/x-www-form-urlencoded' };
$ cat > sale.txt all books 50% off ^D $ curl -d '@sale.txt' http://localhost:5000/ $VAR1 = { 'POSTDATA' => 'all books50% off', # <-- 改行文字が取り除かれる 'Content-Type' => 'application/x-www-form-urlencoded' };
--data-binary
--data とほぼ同じだが、改行文字を取り除かない。バイナリファイルのデータをそのまま (as is) 送りたい場合に使うと良いらしい。でもそういう用途なら --form を使っておけば良い気がする。用途が違うってことなのかな。
追記@2011/08/01 http://b.hatena.ne.jp/mattn/20110801#bookmark-40093294 form keyの無いXMLRPCみたいなので使うのでは
というコメントをもらった、もっともですね
$ curl --data-binary '@sale.txt' http://localhost:5000/ $VAR1 = { 'POSTDATA' => 'all books # <-- 改行文字が含まれたまま 50% off ', 'Content-Type' => 'application/x-www-form-urlencoded' };
--data-urlencode
-
- data とほぼ同じだが、 URL エンコードしてくれる。
--form (-F)
multipart/form-data 形式で POST する。 key=value 形式で指定する。 @ を value の先頭に置くとファイルのデータを「添付して」送る。フォームでファイルアップロードした場合と同じ。 boundary とかも面倒みてくれる。 < を value の先頭に置くとファイルのデータを読み込んで「テキストフィールドの値として」送る。この違いがちょっとよくわかってない。
$ curl -F 'file=@sale.txt' http://localhost:5000/ $VAR1 = { 'POSTDATA' => '------------------------------d60ae256bff6 Content-Disposition: form-data; name="file"; filename="sale.txt" Content-Type: text/plain all books 50% off ------------------------------d60ae256bff6-- ', 'Content-Type' => 'multipart/form-data; boundary=----------------------------d60ae256bff6' };
複数のパラメータを送りたい場合は -F を複数回書く。
$ curl -F 'file=@sale.txt' -F 'Filename=sale.txt' http://localhost:5000/ $VAR1 = { 'POSTDATA' => '------------------------------35c31540d7a9 Content-Disposition: form-data; name="file"; filename="sale.txt" Content-Type: text/plain all books 50% off ------------------------------35c31540d7a9 Content-Disposition: form-data; name="Filename" sale.txt ------------------------------35c31540d7a9-- ', 'Content-Type' => 'multipart/form-data; boundary=----------------------------35c31540d7a9' };
@ じゃなくて < を使った場合。ちょっとマルチパートの中身が違う。 Content-Type がない。これもいまいち使いどころがわからない、というか @ との差がよくわからない。
$ curl -F 'file=<sale.txt' http://localhost:5000/ $VAR1 = { 'POSTDATA' => '------------------------------f0752eec7e81 Content-Disposition: form-data; name="file" all books 50% off ------------------------------f0752eec7e81-- ', 'Content-Type' => 'multipart/form-data; boundary=----------------------------f0752eec7e81' };
--form-string
--form とほぼ一緒で、唯一 @ と < が特別な意味を持たない点が違う。 -F 'screen_name=@kyanny' みたいなデータを送りたいときに、意図せず kyanny というファイルの中身を読みにいってしまう、みたいなのを抑止するためにあるらしい。
$ curl -F 'screen_name=@kyanny' http://localhost:5000/ curl: (26) failed creating formpost data
$ curl --form-string 'screen_name=@kyanny' http://localhost:5000/ $VAR1 = { 'POSTDATA' => '------------------------------686e87c00add Content-Disposition: form-data; name="screen_name" @kyanny ------------------------------686e87c00add-- ', 'Content-Type' => 'multipart/form-data; boundary=----------------------------686e87c00add' };
まとめ
- form タグによるフォーム送信と同じことをしたい場合は (-d) 事前に URL エンコードが必要。
- ファイルアップロードと同じことをしたい場合は -F を @ つきで使う。
- どちらにせよ curl(1) は URL エンコードをしないので、必要ならば URI::Escape 等を使って自前で頑張る。
googlability 低そうなトピックだ・・・ (@ とか < とか) これが誰かの助けになりますように (特に n ヶ月後のおれとか)
app.psgi はこんな感じ。ワンライナーで書けそうだけどごちゃごちゃしたのでファイルに書いた。
$ cat app.psgi #!/usr/bin/env perl use strict; use warnings; use Plack; use Data::Dumper; sub { my $env = shift; my $input = $env->{"psgi.input"}; my $postdata = do { local $/; <$input> }; return [ "200", ["Content-Type" => "text/plain"], [Dumper { "Content-Type" => $env->{"CONTENT_TYPE"}, "POSTDATA" => $postdata, }] ]; };