From: okkez Date: 2006-03-25T12:20:29+09:00 Subject: [ruby-dev:28470] cgi.rbを使ったファイルアップロードについて はじめまして。 okkezといいます。 Ruby1.8.2やRuby1.8.4に標準添付されているcgi.rbでファイルをアップロードできるスクリプトを作ったときに気付いた事です。 最後に検証に使ったクライアント側のコードを載せます。 RFC2388や1867によると、下記のコードのうち(1)の場合のみ成功することを期待されているようですが、cgi.rbを使ってmultipart/form-dataを受け取った場合に(2)や(3)のパターン((2)と(3)は同じ事を表していますが)も受け取れてしまいます。 ここで簡単に(1)-(3)の説明をしておきます。 (1) RFC1867に載っていたサンプルのboundaryの頭に"-"をたくさん付けてみたものです。 (2) 上のものから、最後の\r\nの前にある"--"を取り除いたもの (3) .NETのWebClient#UploadFileで送られるデータをEtheralでキャプチャして書き写したもの。 ただし、以下のサイトによるとこの挙動はこのメソッドのバグらしいです。 vbCity/DevCity.NET Forums :: .NET :: C# :: C#.Net and PHP co-operation with FileUpload (or not....) http://www.vbcity.com/forums/topic.asp?tid=87848 それで、検証のために他の言語でもアップロードされたファイルを受け取るプログラムを書いてみました。(PHPに関しては上のURIで出ていました) ここではJakarta プロジェクトの Commons FileUploadを使ってみました。結果は (1) 予想通り成功 (2) 失敗 MalformedStreamException という例外がthrowされて、 "Stream ended unexpectedly"というメッセージが出力される (3) 失敗 (2)と同じ。 なので、cgi.rbでも同じ仕様にするべきだと思います。 現象の報告だけになりますが、よろしくお願いします。 post.rb #!/usr/bin/ruby require 'net/http' boundary='-----------------------AaB03x' boundary3='---------------------8c81442a4846cb6' contents='a,b,c' data = "--#{boundary}\r\n" + "content-disposition: form-data; name=\"field1\"\r\n\r\n" + "Joe Blow\r\n" + "--#{boundary}\r\n" + "content-disposition: form-data; name=\"file\"; filename=\"file1.txt\"\r\n" + "Content-Type: text/plain\r\n\r\n" + "... contents of file1.txt ...\r\n" + "--#{boundary}--\r\n" data2 = "--#{boundary}\r\n" + "content-disposition: form-data; name=\"field1\"\r\n\r\n" + "Joe Blow\r\n" + "--#{boundary}\r\n" + "content-disposition: form-data; name=\"file\"; filename=\"file1.txt\"\r\n" + "Content-Type: text/plain\r\n\r\n" + "... contents of file1.txt ...\r\n" + "--#{boundary}\r\n" data3 ="--#{boundary3}\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"test.txt\"\r\n" + "Content-Type: text/plain\r\n\r\n" + contents + "\r\n" + "--#{boundary3}\r\n" header ={ 'Content-Length' => data.length.to_s, 'Content-type' => "multipart/form-data; boundary=#{boundary}" } header3 ={ 'Content-Length' => data3.length.to_s, 'Content-type' => "multipart/form-data; boundary=#{boundary3}", 'Expect' => '100-continue', 'Connection' => 'keep-Alive', 'Host' => 'localhost' } def post(boundary, header, data) print data puts '====' Net::HTTP.start('localhost', 80){|http| res= http.post('/upload.rhtml',data,header) print res.body } end post(boundary, header, data) #=> アップロード成功 -- (1) post(boundary, header, data2) #=> アップロード成功するが失敗してほしい -- (2) post(boundary3, header, data3) #=> アップロード成功するが失敗してほしい -- (3) -- okkez okkez000@gmail.com