diff --git a/Network/Wai/Handler/Warp.hs b/Network/Wai/Handler/Warp.hs
--- a/Network/Wai/Handler/Warp.hs
+++ b/Network/Wai/Handler/Warp.hs
@@ -64,6 +64,7 @@
     , fromException
     )
 import Control.Concurrent (forkIO, threadWaitWrite)
+import qualified Data.Char as C
 import Data.Maybe (fromMaybe)
 
 import Data.Typeable (Typeable)
@@ -206,19 +207,18 @@
 parseRequest' _ [] _ = E.throwError $ NotEnoughLines []
 parseRequest' port (firstLine:otherLines) remoteHost' = do
     (method, rpath', gets, httpversion) <- parseFirst firstLine
-    let rpath =
+    let (host',rpath) =
             if S.null rpath'
-                then "/"
-                else rpath'
+                then ("","/")
+                else if "http://" `S.isPrefixOf` rpath'
+                         then S.breakByte 47 $ S.drop 7 rpath' -- '/'
+                         else ("", rpath')
     let heads = map parseHeaderNoAttr otherLines
-    let host = fromMaybe "" $ lookup "host" heads
+    let host = fromMaybe host' $ lookup "host" heads
     let len =
             case lookup "content-length" heads of
                 Nothing -> 0
-                Just bs ->
-                    case reads $ B.unpack bs of -- FIXME could probably be optimized
-                        (x, _):_ -> x
-                        [] -> 0
+                Just bs -> fromIntegral $ B.foldl' (\i c -> i * 10 + C.digitToInt c) 0 $ B.takeWhile C.isDigit bs
     let serverName' = takeUntil 58 host -- ':'
     -- FIXME isolate takes an Integer instead of Int or Int64. If this is a
     -- performance penalty, we may need our own version.
@@ -245,18 +245,15 @@
 
 parseFirst :: ByteString
            -> E.Iteratee S.ByteString IO (ByteString, ByteString, ByteString, HttpVersion)
-parseFirst s = do
-    let pieces = S.split 32 s  -- ' '
-    (method, query, http') <-
-        case pieces of
-            [x, y, z] -> return (x, y, z)
-            _ -> E.throwError $ BadFirstLine $ B.unpack s
-    let (hfirst, hsecond) = B.splitAt 5 http'
-    if (hfirst == "HTTP/")
-        then
-            let (rpath, qstring) = B.break (== '?') query
-             in return (method, rpath, qstring, hsecond)
-        else E.throwError NonHttp
+parseFirst s = 
+    case S.split 32 s of  -- ' '
+        [method, query, http'] -> do
+            let (hfirst, hsecond) = B.splitAt 5 http'
+            if hfirst == "HTTP/"
+               then let (rpath, qstring) = S.breakByte 63 query  -- '?'
+                    in return (method, rpath, qstring, hsecond)
+               else E.throwError NonHttp
+        _ -> E.throwError $ BadFirstLine $ B.unpack s
 {-# INLINE parseFirst #-} -- FIXME is this inline necessary? the function is only called from one place and not exported
 
 httpBuilder, spaceBuilder, newlineBuilder, transferEncodingBuilder
@@ -329,8 +326,7 @@
         return True
   where
     headers' = headers hv s hs isChunked'
-    b' =
-        if isChunked'
+    b' = if isChunked'
             then headers'
                  `mappend` chunkedTransferEncoding b
                  `mappend` chunkedTransferTerminator
@@ -342,14 +338,12 @@
     res go
   where
     -- FIXME perhaps alloca a buffer per thread and reuse that in all functiosn below. Should lessen greatly the GC burden (I hope)
-    go s hs
-        | not (hasBody s req) = do
+    go s hs | not (hasBody s req) = do
             liftIO $ Sock.sendMany socket
                    $ L.toChunks $ toLazyByteString
                    $ headers hv s hs False
             return True
-    go s hs =
-            chunk'
+    go s hs = chunk'
           $ E.enumList 1 [headers hv s hs isChunked']
          $$ E.joinI $ builderToByteString -- FIXME unsafeBuilderToByteString
          $$ (iterSocket th socket >> return isKeepAlive)
@@ -357,10 +351,9 @@
         hasLength = lookup "content-length" hs /= Nothing
         isChunked' = isChunked hv && not hasLength
         isKeepAlive = isChunked' || hasLength
-        chunk' i =
-            if isChunked'
-                then E.joinI $ chunk $$ i
-                else i
+        chunk' i = if isChunked'
+                      then E.joinI $ chunk $$ i
+                      else i
         chunk :: E.Enumeratee Builder Builder IO Bool
         chunk = E.checkDone $ E.continue . step
         step k E.EOF = k (E.Chunks [chunkedTransferTerminator]) >>== return
@@ -374,8 +367,8 @@
         restLen = S.length rest
         -- FIXME check for colon without following space?
         rest' = if restLen > 1 && SU.unsafeTake 2 rest == ": "
-                    then SU.unsafeDrop 2 rest
-                    else rest
+                   then SU.unsafeDrop 2 rest
+                   else rest
      in (mkCIByteString k, rest')
 
 enumSocket :: T.Handle -> Int -> Socket -> E.Enumerator ByteString IO a
@@ -386,13 +379,9 @@
         bs <- liftIO $ Sock.recv socket len
         liftIO $ T.tickle th
         if S.null bs
-            then E.throwError SocketTimeout
-            else go k bs
+            then E.continue k
+            else k (E.Chunks [bs]) >>== inner
     inner step = E.returnI step
-    go k bs
-        | S.length bs == 0 = E.continue k
-        | otherwise = k (E.Chunks [bs]) >>== enumSocket th len socket
-
 ------ The functions below are not warp-specific and could be split out into a
 --separate package.
 
diff --git a/warp.cabal b/warp.cabal
--- a/warp.cabal
+++ b/warp.cabal
@@ -1,5 +1,5 @@
 Name:                warp
-Version:             0.3.2.2
+Version:             0.3.2.3
 Synopsis:            A fast, light-weight web server for WAI applications.
 License:             BSD3
 License-file:        LICENSE
