diff -ur HTTP-4000.0.9/CHANGES HTTP-4000.1.1/CHANGES --- HTTP-4000.0.9/CHANGES 2009-12-20 21:51:02.000000000 +0000 +++ HTTP-4000.1.1/CHANGES 2010-11-28 11:30:02.000000000 +0000 @@ -1,4 +1,22 @@ -Version 4004.0.9: release 2009-12-20 +Version 4000.1.0: release 2010-11-09 + * Retroactively fixed CHANGES to refer to 4000.x.x instead of + 4004.x.x. + * Fix problem with close looping on certain URLs due to trying + to munch the rest of the stream even on EOF. Modified from + a fix by Daniel Wagner. + * This involves a new class member for HStream and is thus an + API change, but one that will only affect clients that + define their own payload type to replace String/ByteString. + * Applied patch by Antoine Latter to fix problem with 301 and 307 + redirects. + +Version 4000.0.10: release 2010-10-29 + * Bump base dependency to support GHC 7.0. + * Stop using 'fail' from the Either monad and instead build Left + values explicitly; the behaviour of fail is changing in GHC 7.0 + and this avoids being sensitive to the change. + +Version 4000.0.9: release 2009-12-20 * Export headerMap from Network.HTTP.Headers (suggested by David Leuschner.) @@ -12,7 +30,7 @@ * drop unused type argument from Network.Browser.BrowserEvent; needlessly general. (patch provided by Daniel Wagner.) -Version 4004.0.8: release 2009-08-05 +Version 4000.0.8: release 2009-08-05 * Incorporated proxy setting lookup and parsing contribution by Eric Kow; provided in Network.HTTP.Proxy @@ -34,7 +52,7 @@ header, simply assume / realm and proceed. Preferable than failing, even if server is the wrong. -Version 4004.0.7: release 2009-05-22 +Version 4000.0.7: release 2009-05-22 * Minor release. * Added @@ -46,7 +64,7 @@ for interfacing to pre-existing @Socket@s. Contributed and suggested by . -Version 4004.0.6: release 2009-04-21; changes from 4004.0.5 +Version 4000.0.6: release 2009-04-21; changes from 4000.0.5 * Network.Browser: use HTTP.HandleStream.sendHTTP_notify, not HTTP.sendHTTP_notify when issuing requests. The latter runs the risk of undoing request normalization. @@ -56,7 +74,7 @@ * Network.Browser: don't fail on seeing invalid cookie values, but report them as errors and continue. -Version 4004.0.5: release 2009-03-30; changes from 4004.0.4 +Version 4000.0.5: release 2009-03-30; changes from 4000.0.4 * Get serious about comments and Haddock documentation. * Cleaned up normalization of requests, fixing bugs and bringing together diff -ur HTTP-4000.0.9/HTTP.cabal HTTP-4000.1.1/HTTP.cabal --- HTTP-4000.0.9/HTTP.cabal 2009-12-20 21:51:02.000000000 +0000 +++ HTTP-4000.1.1/HTTP.cabal 2010-11-28 11:30:02.000000000 +0000 @@ -1,5 +1,5 @@ Name: HTTP -Version: 4000.0.9 +Version: 4000.1.1 Cabal-Version: >= 1.2 Build-type: Simple License: BSD3 @@ -14,7 +14,7 @@ Copyright 2007 Robin Bate Boerop Copyright 2008- Sigbjorn Finne Author: Warrick Gray -Maintainer: Sigbjorn Finne +Maintainer: Ganesh Sittampalam Homepage: http://projects.haskell.org/http/ Category: Network Synopsis: A library for client-side HTTP @@ -50,7 +50,7 @@ > fmap (take 100) (getResponseBody rsp) > . - Git repository available at + Git repository available at Extra-Source-Files: CHANGES @@ -80,7 +80,7 @@ Network.HTTP.MD5Aux, Network.HTTP.Utils GHC-options: -fwarn-missing-signatures -Wall - Build-depends: base >= 2 && < 4, network, parsec, mtl + Build-depends: base >= 2 && < 4.4, network, parsec, mtl if flag(old-base) Build-depends: base < 3 else diff -ur HTTP-4000.0.9/Network/Browser.hs HTTP-4000.1.1/Network/Browser.hs --- HTTP-4000.0.9/Network/Browser.hs 2009-12-20 21:51:02.000000000 +0000 +++ HTTP-4000.1.1/Network/Browser.hs 2010-11-28 11:30:02.000000000 +0000 @@ -846,8 +846,8 @@ } rq - (3,0,x) | x `elem` [2,3,1,7] -> do -- Redirect using GET request method. - out ("30" ++ show x ++ " - redirect using GET") + (3,0,x) | x /= 5 -> do + out ("30" ++ show x ++ " - redirect") allow_redirs <- allowRedirect rqState case allow_redirs of False -> return (Right (uri,rsp)) @@ -867,13 +867,20 @@ return (Right (uri, rsp)) | otherwise -> do out ("Redirecting to " ++ show newURI_abs ++ " ...") - let rq1 = rq { rqMethod=GET, rqURI=newURI_abs, rqBody=nullVal } + + -- Redirect using GET request method, depending on + -- response code. + let toGet = x `elem` [2,3] + method = if toGet then GET else rqMethod rq + rq1 = rq { rqMethod=method, rqURI=newURI_abs } + rq2 = if toGet then (replaceHeader HdrContentLength "0") (rq1 {rqBody = nullVal}) else rq1 + request' nullVal rqState{ reqDenies = 0 , reqRedirects = succ(reqRedirects rqState) , reqStopOnDeny = True } - (replaceHeader HdrContentLength "0" rq1) + rq2 where newURI_abs = maybe newURI id (newURI `relativeTo` uri) diff -ur HTTP-4000.0.9/Network/BufferType.hs HTTP-4000.1.1/Network/BufferType.hs --- HTTP-4000.0.9/Network/BufferType.hs 2009-12-20 21:51:02.000000000 +0000 +++ HTTP-4000.1.1/Network/BufferType.hs 2010-11-28 11:30:02.000000000 +0000 @@ -38,7 +38,7 @@ import System.IO ( Handle ) import Data.Word ( Word8 ) -import Network.HTTP.Utils ( crlf ) +import Network.HTTP.Utils ( crlf, lf ) -- | The @BufferType@ class encodes, in a mixed-mode way, the interface -- that the library requires to operate over data embedded in HTTP @@ -106,11 +106,13 @@ , buf_splitAt = Strict.splitAt , buf_span = Strict.span , buf_empty = Strict.empty - , buf_isLineTerm = \ b -> Strict.length b == 2 && p_crlf == b + , buf_isLineTerm = \ b -> Strict.length b == 2 && p_crlf == b || + Strict.length b == 1 && p_lf == b , buf_isEmpty = Strict.null } where p_crlf = Strict.pack crlf + p_lf = Strict.pack lf -- | @lazyBufferOp@ is the 'BufferOp' definition over @ByteString@s, -- the non-strict kind. @@ -129,11 +131,13 @@ , buf_splitAt = \ i x -> Lazy.splitAt (fromIntegral i) x , buf_span = Lazy.span , buf_empty = Lazy.empty - , buf_isLineTerm = \ b -> Lazy.length b == 2 && p_crlf == b + , buf_isLineTerm = \ b -> Lazy.length b == 2 && p_crlf == b || + Lazy.length b == 1 && p_lf == b , buf_isEmpty = Lazy.null } where p_crlf = Lazy.pack crlf + p_lf = Lazy.pack lf -- | @stringBufferOp@ is the 'BufferOp' definition over @String@s. -- It is defined in terms of @strictBufferOp@ operations, @@ -154,7 +158,7 @@ case Strict.span p (Strict.pack a) of (x,y) -> (Strict.unpack x, Strict.unpack y) , buf_empty = [] - , buf_isLineTerm = \ b -> b == crlf + , buf_isLineTerm = \ b -> b == crlf || b == lf , buf_isEmpty = null } diff -ur HTTP-4000.0.9/Network/HTTP/Utils.hs HTTP-4000.1.1/Network/HTTP/Utils.hs --- HTTP-4000.0.9/Network/HTTP/Utils.hs 2009-12-20 21:51:02.000000000 +0000 +++ HTTP-4000.1.1/Network/HTTP/Utils.hs 2010-11-28 11:30:02.000000000 +0000 @@ -16,6 +16,7 @@ , trimR -- :: String -> String , crlf -- :: String + , lf -- :: String , sp -- :: String , split -- :: Eq a => a -> [a] -> Maybe ([a],[a]) @@ -36,6 +37,10 @@ crlf :: String crlf = "\r\n" +-- | @lf@ is a tolerated line terminator, per RFC 2616 section 19.3. +lf :: String +lf = "\n" + -- | @sp@ lets you save typing one character. sp :: String sp = " " diff -ur HTTP-4000.0.9/Network/Stream.hs HTTP-4000.1.1/Network/Stream.hs --- HTTP-4000.0.9/Network/Stream.hs 2009-12-20 21:51:02.000000000 +0000 +++ HTTP-4000.1.1/Network/Stream.hs 2010-11-28 11:30:02.000000000 +0000 @@ -29,6 +29,7 @@ , failParse -- :: String -> Result a , failWith -- :: ConnError -> Result a + , failMisc -- :: String -> Result a ) where import Control.Monad.Error @@ -44,6 +45,12 @@ noMsg = strMsg "unknown error" strMsg x = ErrorMisc x +-- in GHC 7.0 the Monad instance for Error no longer +-- uses fail x = Left (strMsg x). failMisc is therefore +-- used instead. +failMisc :: String -> Result a +failMisc x = failWith (strMsg x) + failParse :: String -> Result a failParse x = failWith (ErrorParse x) diff -ur HTTP-4000.0.9/Network/TCP.hs HTTP-4000.1.1/Network/TCP.hs --- HTTP-4000.0.9/Network/TCP.hs 2009-12-20 21:51:02.000000000 +0000 +++ HTTP-4000.1.1/Network/TCP.hs 2010-11-28 11:30:02.000000000 +0000 @@ -47,6 +47,7 @@ ( ConnError(..) , Result , failWith + , failMisc ) import Network.BufferType @@ -139,6 +140,7 @@ readBlock :: HandleStream bufType -> Int -> IO (Result bufType) writeBlock :: HandleStream bufType -> bufType -> IO (Result ()) close :: HandleStream bufType -> IO () + closeQuick :: HandleStream bufType -> IO () closeOnEnd :: HandleStream bufType -> Bool -> IO () instance HStream Strict.ByteString where @@ -147,7 +149,8 @@ readBlock c n = readBlockBS c n readLine c = readLineBS c writeBlock c str = writeBlockBS c str - close c = closeIt c Strict.null + close c = closeIt c Strict.null True + closeQuick c = closeIt c Strict.null False closeOnEnd c f = closeEOF c f instance HStream Lazy.ByteString where @@ -156,7 +159,8 @@ readBlock c n = readBlockBS c n readLine c = readLineBS c writeBlock c str = writeBlockBS c str - close c = closeIt c Lazy.null + close c = closeIt c Lazy.null True + closeQuick c = closeIt c Lazy.null False closeOnEnd c f = closeEOF c f instance Stream.Stream Connection where @@ -182,8 +186,11 @@ -- allow any of the other Stream functions. Notice that a Connection may close -- at any time before a call to this function. This function is idempotent. -- (I think the behaviour here is TCP specific) - close c = closeIt c null + close c = closeIt c null True + -- Closes a Connection without munching the rest of the stream. + closeQuick c = closeIt c null False + closeOnEnd c f = closeEOF c f -- | @openTCPPort uri port@ establishes a connection to a remote @@ -325,9 +332,11 @@ (connHooks' conn) return x -closeIt :: HStream ty => HandleStream ty -> (ty -> Bool) -> IO () -closeIt c p = do - closeConnection c (readLineBS c >>= \ x -> case x of { Right xs -> return (p xs); _ -> return True}) +closeIt :: HStream ty => HandleStream ty -> (ty -> Bool) -> Bool -> IO () +closeIt c p b = do + closeConnection c (if b + then readLineBS c >>= \ x -> case x of { Right xs -> return (p xs); _ -> return True} + else return True) conn <- readMVar (getRef c) maybe (return ()) (hook_close) @@ -348,14 +357,14 @@ (\ e -> if isEOFError e then do - when (connCloseEOF conn) $ catch (close ref) (\ _ -> return ()) + when (connCloseEOF conn) $ catch (closeQuick ref) (\ _ -> return ()) return (return (buf_empty (connBuffer conn))) - else return (fail (show e))) + else return (failMisc (show e))) bufferPutBlock :: BufferOp a -> Handle -> a -> IO (Result ()) bufferPutBlock ops h b = Prelude.catch (buf_hPut ops h b >> hFlush h >> return (return ())) - (\ e -> return (fail (show e))) + (\ e -> return (failMisc (show e))) bufferReadLine :: HStream a => HandleStream a -> IO (Result a) bufferReadLine ref = onNonClosedDo ref $ \ conn -> do @@ -371,9 +380,9 @@ (\ e -> if isEOFError e then do - when (connCloseEOF conn) $ catch (close ref) (\ _ -> return ()) + when (connCloseEOF conn) $ catch (closeQuick ref) (\ _ -> return ()) return (return (buf_empty (connBuffer conn))) - else return (fail (show e))) + else return (failMisc (show e))) where -- yes, this s**ks.. _may_ have to be addressed if perf -- suggests worthiness.