2012-02-14 11 views
0

私は、org.apache.commons.fileupload APIを使用してCSVファイルをアップロードし、その後、MySQLテーブルにロードする必要があるサーブレットを作成しました。これは、ブラウザのフォームからサーブレットにポストするときには完全に機能します。しかし、Tclスクリプトhttp://www.tcl.tk/man/tcl/TclCmd/http.htm#M20でフォームを投稿しようとすると失敗します。Tclスクリプトからの投稿時のMalformedStreamException

サーブレットは、次のMalformedStreamExceptionスロー:

org.apache.commons.fileupload.MultipartStream$MalformedStreamException: 
Stream ended unexpectedly 

サーブレットは、Tomcatのバージョン6.0.16でホストされています。

HTTP/1.1 200 OKレスポンスを受信して​​サーブレットがいくつかのprint文をクライアントのTclスクリプトに返すため、Tclスクリプトによって接続が成功します。しかし、入力ストリームを読み込もうとすると失敗します。

Tclスクリプト:

package require http 

proc upload { url csv } { 
    set boundary "-----WebKitFormBoundary[clock seconds][pid]" 

    set fid [open $csv r] 
    if {[catch {read $fid [file size $csv]} data]} { 
     return -code error $data 
    } 
    close $fid 

    set content {} 
    append content "--${boundary}\n" 
    append content "Content-Disposition: form-data; name=\"db\"\n\n" 
    append content "test\n" 
    append content "--${boundary}\n" 
    append content "Content-Disposition: form-data; name=\"table\"\n\n" 
    append content "testing\n" 
    append content "--${boundary}\n" 
    append content "Content-Disposition: form-data; name=\"file\"; filename=\"$csv\"\n" 
    append content "Content-Type: text/csv\n\n" 
    append content "$data\n" 
    append content "${boundary}--" 

    set headers "connection keep-alive" 
    set token [::http::geturl $url -keepalive 1 -headers $headers -query $content -type "multipart/form-data; boundary=$boundary"] 

    upvar 0 $token state 

    if {$state(http) == "HTTP/1.1 200 OK"} { 
     # no error reported in http headers 
     puts stdout $state(http) 
     puts stdout $state(body) 
     return 1 
    } else { 
     # error reported in http headers 
     puts stdout $state(http) 
     puts stdout $state(body) 
     return 0 
    } 
} 

set csv "data.csv" 
set url "http://ecat:8080/MySqlImport/MySqlImportServlet" 
set retVal [upload $url $csv] 
+0

投稿しているtclコードを投稿できますか?あなたがfileupload APIが期待しているマルチパートリクエストを投稿していない可能性があります。 –

+0

tclスクリプトを追加するように更新しました – Daniel

+0

終了境界は ' - $ {boundary} - \ n'と思ったのですか? –

答えて

0

ありがとうございましたが、私は特定の問題を発見しました。それは最後に単純なものでした。 apache.commons.fileuploadのServletFileUpload.parseRequest(リクエスト)メソッドは、行末がWindows形式である必要があります。

$ content行の末尾が\nで、これを\r\nに変更して問題を修正しました。ただ\rを使用して

エラーはもはや発生した

org.apache.commons.fileupload.MultipartStream$MalformedStreamException: 
Stream ended unexpectedly 

が、しかしそれは、要求内の別のアイテムやパーツを認識しなかったことを意味しました。 \r\n行末の組み合わせで正しく動作します。

1

適切なマルチパートメッセージの生成は非常に悪化することができます。 Tcllibのmime packageが役に立ちます。 this pageの上の例は非常に関連性が高いようです。

0

ドナルフェローズはおそらく正しいと思いますが、私はダニエルのアプローチで1つの(典型的な)間違いを指摘したいと思います: "文字列"という概念を持つ高水準言語を使用する場合— 「バイト列」— "ワイヤー"上に処理されるデータを準備する際には特に注意が必要です。

この場合、「ワイヤ」はHTTPプロトコルなので、準備されたデータはほとんどの場合、意図によっては[encoding convertto utf-8 ...]などのようなものを経由する必要があります。 (ところで、Tclはバイナリ文字列をかなり広範囲にサポートしているので、それらの文字列を付加することができ、連結されたものはbinaryという性質を失うことなく)。

次は、ネットワークに慣れることですスニファ(または特定のHTTPスニッファー)。大きなクロスプラットフォームソリューションはWiresharkで、WindowsプラットフォームではNetwork Monitor(一般的なスニファ)とFiddler(HTTP固有)があります。このアイデアは、ブラウザで実行された「参照」セッションを最初に取得して調査し、プログラムによって実行された不正なセッションを取得して分析することです。したがって、セッションを比較して、生成されたトラフィックがHTTPペイロードのどこで異なるかを確認するだけです。