[Haskell-cafe] Contributing to http-conduit

Myles C. Maxfield myles.maxfield at gmail.com
Tue Jan 24 07:37:53 CET 2012


I have attached a patch to add a redirect chain to the Response datatype.
Comments on this patch are very welcome.

I was originally going to include the entire Request object in the
redirection chain, but Request objects are parameterized with a type 'm',
so including a 'Request m' field would force the Response type to be
parameterized as well. I felt that would be too large a change, so I made
the type of the redirection chain W.Ascii.

Perhaps its worth using the 'forall' keyword to get rid of the pesky 'm'
type parameter for Requests?

data RequestBody
    = RequestBodyLBS L.ByteString
    | RequestBodyBS S.ByteString
    | RequestBodyBuilder Int64 Blaze.Builder
    | forall m. RequestBodySource Int64 (C.Source m Blaze.Builder)
    | forall m. RequestBodySourceChunked (C.Source m Blaze.Builder)

--Myles

On Mon, Jan 23, 2012 at 3:31 AM, Michael Snoyman <michael at snoyman.com>wrote:

> On Mon, Jan 23, 2012 at 1:20 PM, Aristid Breitkreuz
> <aristidb at googlemail.com> wrote:
> > Rejecting cookies is not without precedent.
> >
> > If you must force cookie handling upon us, at least make it possible to
> > selectively reject them.
> >
> > Aristid
>
> If you turn off automatic redirects, then you won't have cookie
> handling. I'd be interested to hear of a use case where you would want
> to avoid passing cookies after a redirect.
>
> Michael
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20120123/030d417e/attachment.htm>
-------------- next part --------------
From d60bc1adf4af5a038432c35cde222654dfabf6dd Mon Sep 17 00:00:00 2001
From: "Myles C. Maxfield" <litherum at gmail.com>
Date: Mon, 23 Jan 2012 21:44:12 -0800
Subject: [PATCH] Adding a redirection chain field to Responses

---
 Network/HTTP/Conduit.hs          |    7 ++++---
 Network/HTTP/Conduit/Request.hs  |   24 +++++++++++++++++++++++-
 Network/HTTP/Conduit/Response.hs |    7 ++++---
 3 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/Network/HTTP/Conduit.hs b/Network/HTTP/Conduit.hs
index 794a62a..879d5a8 100644
--- a/Network/HTTP/Conduit.hs
+++ b/Network/HTTP/Conduit.hs
@@ -147,7 +147,7 @@ http
     -> Manager
     -> ResourceT m (Response (C.Source m S.ByteString))
 http req0 manager = do
-    res@(Response status hs body) <-
+    res@(Response _ status hs body) <-
         if redirectCount req0 == 0
             then httpRaw req0 manager
             else go (redirectCount req0) req0
@@ -160,7 +160,7 @@ http req0 manager = do
   where
     go 0 _ = liftBase $ throwIO TooManyRedirects
     go count req = do
-        res@(Response (W.Status code _) hs _) <- httpRaw req manager
+        res@(Response uri (W.Status code _) hs _) <- httpRaw req manager
         case (300 <= code && code < 400, lookup "location" hs) of
             (True, Just l'') -> do
                 -- Prepend scheme, host and port if missing
@@ -192,7 +192,8 @@ http req0 manager = do
                                 then "GET"
                                 else method l
                         }
-                go (count - 1) req'
+                response <- go (count - 1) req'
+                return $ response {requestChain = (head uri) : (requestChain response)}
             _ -> return res
 
 -- | Get a 'Response' without any redirect following.
diff --git a/Network/HTTP/Conduit/Request.hs b/Network/HTTP/Conduit/Request.hs
index e6e8876..a777285 100644
--- a/Network/HTTP/Conduit/Request.hs
+++ b/Network/HTTP/Conduit/Request.hs
@@ -7,6 +7,7 @@ module Network.HTTP.Conduit.Request
     , ContentType
     , Proxy (..)
     , parseUrl
+    , unParseUrl
     , browserDecompress
     , HttpException (..)
     , alwaysDecompress
@@ -39,7 +40,7 @@ import qualified Network.HTTP.Types as W
 
 import Control.Exception (Exception, SomeException, toException)
 import Control.Failure (Failure (failure))
-import Codec.Binary.UTF8.String (encodeString)
+import Codec.Binary.UTF8.String (encode, encodeString)
 import qualified Data.CaseInsensitive as CI
 import qualified Data.ByteString.Base64 as B64
 
@@ -207,6 +208,27 @@ parseUrl2 full sec s = do
                 (readDec rest)
             x -> error $ "parseUrl1: this should never happen: " ++ show x
 
+unParseUrl :: Request m -> W.Ascii
+unParseUrl Request { secure = secure'
+                   , host = host'
+                   , port = port'
+                   , path = path'
+                   , queryString = querystring'
+                   } = S.concat
+  [ "http"
+  , if secure' then "s" else S.empty
+  , "://"
+  , host'
+  , case (secure', port') of
+      (True, 443) -> S.empty
+      (True, p) -> S.pack $ encode $ ":" ++ show p
+      (False, 80) -> S.empty
+      (False, p) -> S.pack $ encode $ ":" ++ show p
+  , path'
+  , "?"
+  , querystring'
+  ]
+
 data HttpException = StatusCodeException W.Status W.ResponseHeaders
                    | InvalidUrlException String String
                    | TooManyRedirects
diff --git a/Network/HTTP/Conduit/Response.hs b/Network/HTTP/Conduit/Response.hs
index 5c6fd23..c183e34 100644
--- a/Network/HTTP/Conduit/Response.hs
+++ b/Network/HTTP/Conduit/Response.hs
@@ -33,7 +33,8 @@ import Network.HTTP.Conduit.Chunk
 
 -- | A simple representation of the HTTP response created by 'lbsConsumer'.
 data Response body = Response
-    { statusCode :: W.Status
+    { requestChain :: [W.Ascii]
+    , statusCode :: W.Status
     , responseHeaders :: W.ResponseHeaders
     , responseBody :: body
     }
@@ -41,7 +42,7 @@ data Response body = Response
 
 -- | Since 1.1.2.
 instance Functor Response where
-    fmap f (Response status headers body) = Response status headers (f body)
+    fmap f res@(Response {responseBody = body}) = res {responseBody = (f body)}
 
 -- | Convert a 'Response' that has a 'C.Source' body to one with a lazy
 -- 'L.ByteString' body.
@@ -90,7 +91,7 @@ getResponse connRelease req@(Request {..}) bsrc = do
                             else bsrc'
                 return $ addCleanup cleanup bsrc''
 
-    return $ Response s hs' body
+    return $ Response [unParseUrl req] s hs' body
 
 -- | Add some cleanup code to the given 'C.Source'. General purpose
 -- function, could be included in conduit itself.
-- 
1.7.7.4


More information about the Haskell-Cafe mailing list