2012-05-29 2 views
3

Я пытаюсь написать действительно тривиальное «эхо» webapp с помощью wai; все, что я хочу сделать, это ответить с данными, которые были добавлены к нему (мне действительно не нужен этот метод, но я использую завиток, а curl использует POST, так что это то, что я собираюсь). Мой тривиальным веб-сервер это:Неожиданное поведение кабелепровода с wai

import Network.Wai 
import Network.HTTP.Types (status200) 
import Network.Wai.Handler.Warp (run) 
import Control.Monad.Trans (liftIO) 
import Blaze.ByteString.Builder.ByteString (fromByteString) 
import qualified Data.Conduit.List as CondList 
import Data.Conduit (($$), ($=), Flush(Chunk)) 

application req = do 
    let src = requestBody req $= CondList.map (Chunk ∘ fromByteString) 
    return $ ResponseSource status200 [("Content-Type", "text/plain")] src 

main = run 3000 application 

То, что я ожидал, что это сделать в основном связать тело запроса тело ответа, так что, когда я бегу curl --data @/usr/share/dict/words localhost:3000; он вертел мне слова. Вместо этого он дает пустое тело. Запуск curl с «-v» показывает, что мое приложение отвечает «200 OK» и никаких данных. Я не уверен, что я делаю неправильно здесь.

Если я заменить прикладную функцию с этим:

_ ← requestBody req $$ CondList.mapM_ (liftIO ∘ print) 
return $ responseLBS status200 [("Content-Type", "text/plain")] "Hello world\n" 

и добавить OverloadedStrings Прагма, чтобы позволить «Hello World» часть для работы, то я вижу, что мое приложение печати всего тела запроса на стандартный вывод, поэтому я знаю, что завиток правильно передает данные. Я также получаю «Hello World», напечатанный на curl stdout, поэтому я знаю, что завиток работает так, как я ожидаю. Я должен что-то делать неправильно, когда я связываю свой запрос с моим источником ResponseSource, но я этого не вижу.

ответ

1

Вы правильно используете conduit, проблема в том, что поведение потоковой передачи, которое вы пытаетесь получить, не может надежно работать в контексте HTTP. По сути, вы хотите начать отправку тела ответа, пока клиент отправляет тело запроса. Это может привести к тупиковой ситуации, так как клиент и сервер могут застревать в режиме отправки. Чтобы избежать этого, Warp сбрасывает тело запроса перед отправкой ответа, поэтому тело запроса кажется пустым во время отправки тела ответа.

Для правильного правильного поведения эха вам необходимо строго использовать тело запроса, а затем отправить его обратно. Очевидно, что это может быть проблематично с точки зрения использования памяти, если есть большой объект запроса, но это неотъемлемый аспект HTTP. Если вы хотите постоянное эхо-память, моя рекомендация состояла бы в том, чтобы передать тело запроса в файл, а затем использовать ResponseFile для тела ответа.

+0

Это не имеет смысла для меня. Я не понимаю, почему вы добавили код, единственная цель которого - молча запретить полезное поведение. – sclv

+0

Поскольку вы не можете запустить HTTP-ответ, пока клиент все еще пытается отправить HTTP-запрос. Это может привести к тупиковой ситуации. Как бы вы реализовали веб-сервер без очистки тела запроса перед отправкой ответа? –

+0

Это очень возможно с использованием ввода-вывода типа epoll. Очень много веб-серверов способны это сделать. Как это может привести к тупиковой ситуации? – dflemstr

Смежные вопросы