MalformedStreamException при публикации из сценария Tcl - PullRequest
0 голосов
/ 14 февраля 2012

Я создал сервлет, который использует API org.apache.commons.fileupload для загрузки файла CSV, который он затем должен загрузить в таблицу MySQL. Это прекрасно работает при публикации в сервлете из формы в браузере. Тем не менее, это не удается при попытке отправить форму с помощью сценария Tcl http://www.tcl.tk/man/tcl/TclCmd/http.htm#M20.

Сервлет бросает следующее MalformedStreamException:

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

Сервлет размещен на Tomcat версии 6.0.16.

Соединение успешно установлено с помощью сценария Tcl, так как он получает ответ HTTP / 1.1 200 OK, и сервлет возвращает некоторые операторы печати обратно клиентскому сценарию 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]

Ответы [ 3 ]

1 голос
/ 15 февраля 2012

Генерация правильного составного сообщения может сильно ухудшить ситуацию. mime пакет в Tcllib может помочь. Верхний пример на этой странице выглядит очень актуально.

0 голосов
/ 18 февраля 2012

Спасибо за помощь по этому вопросу, но я нашел свою конкретную проблему, и в конце концов она была простой. Кажется, что метод ServletFileUpload.parseRequest (request) в apache.commons.fileupload требует, чтобы окончания строк были в формате windows.

Как вы можете видеть в вопросе, окончание строки $ content было \n, изменив значение на \r\n, исправив проблему.

Использование только \r означало, что ошибка

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

больше не происходило, однако не удалось распознать различные элементы или детали в запросе. Сочетание \r\n окончания строк и оно работает правильно.

0 голосов
/ 17 февраля 2012

Хотя Донал Феллоуз, скорее всего, понял это правильно, я хочу указать на одну (типичную) ошибку с подходом Даниэля: когда кто-то использует язык высокого уровня, который имеет концепцию «строки символов» - в отличие от«строка байтов» - один из них должен проявлять особую осторожность при подготовке обрабатываемых данных для помещения в «провод».

В этом случае «провод» - это протокол HTTP, поэтому данныеподготовленный должен, скорее всего, пройти что-то вроде [encoding convertto utf-8 ...] или что-то подобное в зависимости от цели.(Кстати, Tcl имеет довольно обширную поддержку двоичных строк, так что они могут быть добавлены, объединены и т. Д., Не теряя своего свойства быть двоичным .)

Следующее, что может бытьРекомендуется привыкнуть к сетевому анализатору (или определенному анализатору HTTP).Отличное кроссплатформенное решение - Wireshark , на платформах Windows - Сетевой монитор (универсальный анализатор) и Fiddler (специфично для HTTP).Идея состоит в том, чтобы сначала захватить и внимательно изучить «контрольный» сеанс, выполняемый браузером, а затем захватить и проанализировать сеанс неправильного поведения, выполняемый вашей программой.Таким образом, вы просто сравниваете сессии и видите, где генерируемый трафик отличается, когда дело доходит до полезной нагрузки HTTP.

...