Журнал всех запросов и ответов для http-проводника - PullRequest
0 голосов
/ 07 мая 2018

Я написал это ManagerSettings, чтобы регистрировать все запросы и ответы для моего приложения http-проводника. (Кстати, я импортирую ClassyPrelude).

tracingManagerSettings :: ManagerSettings
tracingManagerSettings =
  tlsManagerSettings { managerModifyRequest = \req -> do
                         putStr "TRACE: "
                         print req
                         putStrLn ""
                         pure req
                     , managerModifyResponse = \r -> do
                         responseChunks <- brConsume $ responseBody r
                         let fullResponse = mconcat responseChunks
                         putStr "TRACE: RESPONSE: "
                         putStrLn $ decodeUtf8 fullResponse
                         pure $ r { responseBody = pure fullResponse }
                     }

Однако это не работает - когда я его использую, приложение зависает и пытается использовать всю оперативную память в машине после печати первого запроса и первого ответа, что предполагает некоторый бесконечный цикл.

Также запрос печатается дважды.

Я сделал предыдущую попытку, которая была похожа, но не изменила r. Это не удалось, поскольку после того, как я полностью прочитал ответ, больше не осталось данных для чтения.

Если я заменю это на tlsManagerSettings, http-conduit снова будет работать.

Мое приложение использует libstackexchange, который я изменил, чтобы разрешить настройку ManagerSettings. Я использую http-проводник версии 2.2.4.

Как я могу диагностировать проблему? Как я могу это исправить?

1 Ответ

0 голосов
/ 07 мая 2018

managerModifyResponse не работает с Response ByteString, он работает с Response BodyReader, где type BodyReader = IO ByteString вместе с контрактом о том, что, если он выдает непустое ByteString, имеется больше входных данных, которые могут быть читать.

Проблема, с которой вы сталкиваетесь, заключается в том, что pure fullResponse никогда не возвращает пустое ByteString, если это не всегда так. Вам нужно предоставить несколько более сложное действие ввода-вывода для захвата предполагаемого поведения. Может быть, что-то вроде этого (не проверено):

returnOnce :: Monoid a => a -> IO (IO a)
returnOnce x = do
    ref <- newIORef x
    pure $ readIORef ref <* writeIORef ref mempty

А как отладить это? Не уверен насчет универсальных методов. Я просто подозревал, что вам, вероятно, нужно решение в этом направлении, и документы для BodyReader подтвердили это.

...