How can I catch the 404 status exception thrown by simpleHttp Http.Conduit

I am trying to download all png files contained in an html file. I have problems catching 404 exceptions, although my program just worked.

Here is an example to demonstrate:

import Network.HTTP.Conduit import qualified Data.ByteString.Lazy as L main = do let badUrl = "http://www.google.com/intl/en_com/images/srpr/WRONG.png" imgData <- (simpleHttp badUrl) `catch` statusExceptionHandler L.writeFile "my.png" imgData statusExceptionHandler :: t -> IO L.ByteString statusExceptionHandler e = (putStrLn "oops") >> (return L.empty) 

The message "oops" never prints; instead, the application crashes with:

StatusCodeException (Status {statusCode = 404, statusMessage = "Not Found"}) [("Content-Type", "text / html; charset = UTF-8"), ("X-Content-Type-Options", "nosniff "), (" Date "," Fri, 27 Jan 2012 03:10:34 GMT "), (" Server "," sffe "), (" Content-Length "," 964 "), (" X-XSS -Protection "," 1; mode = block ")]

What am I doing wrong?

Update:

Following Thoma's advice, I changed my code to the next snippet and now I have the correct exception handling.

 main = do let badUrl = "http://www.google.com/intl/en_com/images/srpr/WRONG.png" imgData <- (simpleHttp badUrl) `X.catch` statusExceptionHandler case imgData of x | x == L.empty -> return () | otherwise -> L.writeFile "my.png" imgData statusExceptionHandler :: HttpException -> IO L.ByteString statusExceptionHandler (StatusCodeException status headers) = putStr "An error occured during download: " >> (putStrLn $ show status) >> (return L.empty) 
+6
source share
2 answers

You should probably read Marlow paper on extensible exceptions . The original catch exported by Prelude and used in your snipt only works for IOError. The HTTP conduit code throws another type of exception, an HttpException , to be precise. (dynamic typing occurs, passing through the Typeable class, see article).

Decision? Use the catch from Control.Exception and only catch the types of errors you want to handle (or SomeException for all of them).

 import Network.HTTP.Conduit import qualified Data.ByteString.Lazy as L import Control.Exception as X main = do let badUrl = "http://www.google.com/intl/en_com/images/srpr/WRONG.png" imgData <- (simpleHttp badUrl) `X.catch` statusExceptionHandler L.writeFile "my.png" imgData statusExceptionHandler :: SomeException -> IO L.ByteString statusExceptionHandler e = (putStrLn "oops") >> (return L.empty) 
+6
source

In addition to Thomas's answer, you can tell http-conduit not to throw an exception by overriding the checkStatus record of your Request type.

+8
source

Source: https://habr.com/ru/post/906995/


All Articles