@@ -11,7 +11,6 @@ module Network.Wai.Parse
1111 , RequestBodyType (..)
1212 , getRequestBodyType
1313 , sinkRequestBody
14− , sinkRequestBodyEx
1514 , BackEnd
1615 , lbsBackEnd
1716 , tempFileBackEnd
@@ -20,24 +19,8 @@ module Network.Wai.Parse
2019 , File
2120 , FileInfo (..)
2221 , parseContentType
23− , ParseRequestBodyOptions
24− , defaultParseRequestBodyOptions
25− , noLimitParseRequestBodyOptions
22+ , ParseRequestBodyOptions (..)
2623 , parseRequestBodyEx
27− , setMaxRequestKeyLength
28− , clearMaxRequestKeyLength
29− , setMaxRequestNumFiles
30− , clearMaxRequestNumFiles
31− , setMaxRequestFileSize
32− , clearMaxRequestFileSize
33− , setMaxRequestFilesSize
34− , clearMaxRequestFilesSize
35− , setMaxRequestParmsSize
36− , clearMaxRequestParmsSize
37− , setMaxHeaderLines
38− , clearMaxHeaderLines
39− , setMaxHeaderLineLength
40− , clearMaxHeaderLineLength
4124#if TEST
4225 , Bound (..)
4326 , findBound
@@ -48,10 +31,11 @@ module Network.Wai.Parse
4831#endif
4932 ) where
5033
51−import qualified Control.Exception as E
34+import qualified Data.ByteString.Search as Search
5235import qualified Data.ByteString as S
5336import qualified Data.ByteString.Lazy as L
5437import qualified Data.ByteString.Char8 as S8
38+import Data.Default (Default, def)
5539import Data.Word (Word8)
5640import Data.Int (Int64)
5741import Data.Maybe (catMaybes, fromMaybe)
@@ -59,20 +43,15 @@ import Data.List (sortBy)
5943import Data.Function (on, fix)
6044import System.Directory (removeFile, getTemporaryDirectory)
6145import System.IO (hClose, openBinaryTempFile)
62−import System.IO.Error (isDoesNotExistError)
6346import Network.Wai
6447import qualified Network.HTTP.Types as H
6548import Control.Applicative ((<$>))
66−import Control.Exception (catchJust)
67−import Control.Monad (when, unless, guard)
49+import Control.Monad (when, unless)
6850import Control.Monad.Trans.Resource (allocate, release, register, InternalState, runInternalState)
6951import Data.IORef
7052import Network.HTTP.Types (hContentType)
71−import Network.HTTP2( HTTP2Error (..), ErrorCodeId (..) )
7253import Data.CaseInsensitive (mk)
7354
74−import Prelude hiding (lines)
75−
7655breakDiscard :: Word8 -> S.ByteString -> (S.ByteString, S.ByteString)
7756breakDiscard w s =
7857 let (x, y) = S.break (== w) s
@@ -131,7 +110,7 @@ tempFileBackEndOpts :: IO FilePath -- ^ get temporary directory
131110 -> IO FilePath
132111tempFileBackEndOpts getTmpDir pattrn internalState _ _ popper = do
133112 (key, (fp, h)) <- flip runInternalState internalState $ allocate it (hClose . snd)
134− _ <- runInternalState (register $ removeFileQuiet fp) internalState
113+ _ <- runInternalState (register $ removeFile fp) internalState
135114 fix $ \loop -> do
136115 bs <- popper
137116 unless (S.null bs) $ do
@@ -143,146 +122,31 @@ tempFileBackEndOpts getTmpDir pattrn internalState _ _ popper = do
143122 it = do
144123 tempDir <- getTmpDir
145124 openBinaryTempFile tempDir pattrn
146− removeFileQuiet fp = catchJust (guard . isDoesNotExistError)
147− (removeFile fp)
148− (const $ return ())
149125
150126-- | A data structure that describes the behavior of
151127-- the parseRequestBodyEx function.
152−--
153−-- @since 3.0.16.0
154128data ParseRequestBodyOptions = ParseRequestBodyOptions
155129 { -- | The maximum length of a filename
156− prboKeyLength :: Maybe Int
130+ prboKeyLength :: Int
157131 , -- | The maximum number of files.
158− prboMaxNumFiles :: Maybe Int
132+ prboMaxNumFiles :: Int
159133 , -- | The maximum filesize per file.
160134 prboMaxFileSize :: Maybe Int64
161135 , -- | The maximum total filesize.
162136 prboMaxFilesSize :: Maybe Int64
163− , -- | The maximum size of the sum of all parameters
164− prboMaxParmsSize :: Maybe Int
165− , -- | The maximum header lines per mime/multipart entry
166− prboMaxHeaderLines :: Maybe Int
167− , -- | The maximum header line length per mime/multipart entry
168− prboMaxHeaderLineLength :: Maybe Int }
169−
170−-- | Set the maximum length of a filename.
171−--
172−-- @since 3.0.16.0
173−setMaxRequestKeyLength :: Int -> ParseRequestBodyOptions -> ParseRequestBodyOptions
174−setMaxRequestKeyLength l p = p { prboKeyLength=Just l }
175−
176−-- | Do not limit the length of filenames.
177−--
178−-- @since 3.0.16.0
179−clearMaxRequestKeyLength :: ParseRequestBodyOptions -> ParseRequestBodyOptions
180−clearMaxRequestKeyLength p = p { prboKeyLength=Nothing }
181−
182−-- | Set the maximum number of files per request.
183−--
184−-- @since 3.0.16.0
185−setMaxRequestNumFiles :: Int -> ParseRequestBodyOptions -> ParseRequestBodyOptions
186−setMaxRequestNumFiles l p = p { prboMaxNumFiles=Just l }
187−
188−-- | Do not limit the maximum number of files per request.
189−--
190−-- @since 3.0.16.0
191−clearMaxRequestNumFiles :: ParseRequestBodyOptions -> ParseRequestBodyOptions
192−clearMaxRequestNumFiles p = p { prboMaxNumFiles=Nothing }
193−
194−-- | Set the maximum filesize per file (in bytes).
195−--
196−-- @since 3.0.16.0
197−setMaxRequestFileSize :: Int64 -> ParseRequestBodyOptions -> ParseRequestBodyOptions
198−setMaxRequestFileSize l p = p { prboMaxFileSize=Just l }
199−
200−-- | Do not limit the maximum filesize per file.
201−--
202−-- @since 3.0.16.0
203−clearMaxRequestFileSize :: ParseRequestBodyOptions -> ParseRequestBodyOptions
204−clearMaxRequestFileSize p = p { prboMaxFileSize=Nothing }
205−
206−-- | Set the maximum size of all files per request.
207−--
208−-- @since 3.0.16.0
209−setMaxRequestFilesSize :: Int64 -> ParseRequestBodyOptions -> ParseRequestBodyOptions
210−setMaxRequestFilesSize l p = p { prboMaxFilesSize=Just l }
211−
212−-- | Do not limit the maximum size of all files per request.
213−--
214−-- @since 3.0.16.0
215−clearMaxRequestFilesSize :: ParseRequestBodyOptions -> ParseRequestBodyOptions
216−clearMaxRequestFilesSize p = p { prboMaxFilesSize=Nothing }
217−
218−-- | Set the maximum size of the sum of all parameters.
219−--
220−-- @since 3.0.16.0
221−setMaxRequestParmsSize :: Int -> ParseRequestBodyOptions -> ParseRequestBodyOptions
222−setMaxRequestParmsSize l p = p { prboMaxParmsSize=Just l }
223−
224−-- | Do not limit the maximum size of the sum of all parameters.
225−--
226−-- @since 3.0.16.0
227−clearMaxRequestParmsSize :: ParseRequestBodyOptions -> ParseRequestBodyOptions
228−clearMaxRequestParmsSize p = p { prboMaxParmsSize=Nothing }
229−
230−-- | Set the maximum header lines per mime/multipart entry.
231−--
232−-- @since 3.0.16.0
233−setMaxHeaderLines :: Int -> ParseRequestBodyOptions -> ParseRequestBodyOptions
234−setMaxHeaderLines l p = p { prboMaxHeaderLines=Just l }
235−
236−-- | Do not limit the maximum header lines per mime/multipart entry.
237−--
238−-- @since 3.0.16.0
239−clearMaxHeaderLines:: ParseRequestBodyOptions -> ParseRequestBodyOptions
240−clearMaxHeaderLines p = p { prboMaxHeaderLines=Nothing }
241−
242−-- | Set the maximum header line length per mime/multipart entry.
243−--
244−-- @since 3.0.16.0
245−setMaxHeaderLineLength :: Int -> ParseRequestBodyOptions -> ParseRequestBodyOptions
246−setMaxHeaderLineLength l p = p { prboMaxHeaderLineLength=Just l }
247−
248−-- | Do not limit the maximum header lines per mime/multipart entry.
249−--
250−-- @since 3.0.16.0
251−clearMaxHeaderLineLength :: ParseRequestBodyOptions -> ParseRequestBodyOptions
252−clearMaxHeaderLineLength p = p { prboMaxHeaderLineLength=Nothing }
253−
254−-- | A reasonable default set of parsing options.
255−-- Maximum key/filename length: 32 bytes;
256−-- maximum files: 10; filesize unlimited; maximum
257−-- size for parameters: 64kbytes; maximum number of header
258−-- lines: 32 bytes (applies only to headers of a mime/multipart message);
259−-- maximum header line length: Apache's default for that is 8190 bytes
260−-- (http://httpd.apache.org/docs/2.2/mod/core.html#limitrequestline)
261−-- so we're using that here as well.
262−--
263−-- @since 3.0.16.0
264−defaultParseRequestBodyOptions :: ParseRequestBodyOptions
265−defaultParseRequestBodyOptions = ParseRequestBodyOptions
266− { prboKeyLength=Just 32
267− , prboMaxNumFiles=Just 10
268− , prboMaxFileSize=Nothing
269− , prboMaxFilesSize=Nothing
270− , prboMaxParmsSize=Just 65336
271− , prboMaxHeaderLines=Just 32
272− , prboMaxHeaderLineLength=Just 8190 }
273−
274−-- | Do not impose any memory limits.
275−--
276−-- @since 3.0.21.0
277−noLimitParseRequestBodyOptions :: ParseRequestBodyOptions
278−noLimitParseRequestBodyOptions = ParseRequestBodyOptions
279− { prboKeyLength=Nothing
280− , prboMaxNumFiles=Nothing
281− , prboMaxFileSize=Nothing
282− , prboMaxFilesSize=Nothing
283− , prboMaxParmsSize=Nothing
284− , prboMaxHeaderLines=Nothing
285− , prboMaxHeaderLineLength=Nothing }
137+ , -- | The maximum size of the sum of all parameters values
138+ prboMaxParmsValueSize :: Int
139+ , -- | The maximum header lines per entry
140+ prboMaxHeaderLines :: Int }
141+
142+instance Default ParseRequestBodyOptions where
143+ def = ParseRequestBodyOptions
144+ { prboKeyLength=32
145+ , prboMaxNumFiles=10
146+ , prboMaxFileSize=Nothing
147+ , prboMaxFilesSize=Nothing
148+ , prboMaxParmsValueSize=65336
149+ , prboMaxHeaderLines=32 }
286150
287151-- | Information on an uploaded file.
288152data FileInfo c = FileInfo
@@ -327,7 +191,7 @@ getRequestBodyType req = do
327191-- | Parse a content type value, turning a single @ByteString@ into the actual
328192-- content type and a list of pairs of attributes.
329193--
330−-- @since 1.3.2
194+-- Since 1.3.2
331195parseContentType :: S.ByteString -> (S.ByteString, [(S.ByteString, S.ByteString)])
332196parseContentType a = do
333197 let (ctype, b) = S.break (== semicolon) a
@@ -337,9 +201,6 @@ parseContentType a = do
337201 semicolon = 59
338202 equals = 61
339203 space = 32
340− dq s = if S.length s > 2 && S.head s == 34 && S.last s == 34 -- quote
341− then S.tail $ S.init s
342− else s
343204 goAttrs front bs
344205 | S.null bs = front []
345206 | otherwise =
@@ -348,7 +209,7 @@ parseContentType a = do
348209 goAttr bs =
349210 let (k, v') = S.break (== equals) bs
350211 v = S.drop 1 v'
351− in (strip k, dq $ strip v)
212+ in (strip k, strip v)
352213 strip = S.dropWhile (== space) . fst . S.breakEnd (/= space)
353214
354215-- | Parse the body of an HTTP request.
@@ -356,11 +217,14 @@ parseContentType a = do
356217-- Note: This function does not limit the memory it allocates.
357218-- When dealing with untrusted data (as is usually the case when
358219-- receiving input from the internet), it is recommended to
359−-- use the 'parseRequestBodyEx' function instead.
220+-- use the parseRequestBodyEx function instead.
360221parseRequestBody :: BackEnd y
361222 -> Request
362223 -> IO ([Param], [File y])
363−parseRequestBody = parseRequestBodyEx noLimitParseRequestBodyOptions
224+parseRequestBody s r =
225+ case getRequestBodyType r of
226+ Nothing -> return ([], [])
227+ Just rbt -> sinkRequestBody s rbt (requestBody r)
364228
365229-- | Parse the body of an HTTP request, limit resource usage.
366230-- The HTTP body can contain both parameters and files.
@@ -381,11 +245,16 @@ sinkRequestBody :: BackEnd y
381245 -> RequestBodyType
382246 -> IO S.ByteString
383247 -> IO ([Param], [File y])
384−sinkRequestBody = sinkRequestBodyEx noLimitParseRequestBodyOptions
248+sinkRequestBody s r body = do
249+ ref <- newIORef (id, id)
250+ let add x = atomicModifyIORef ref $ \(y, z) ->
251+ case x of
252+ Left y' -> ((y . (y':), z), ())
253+ Right z' -> ((y, z . (z':)), ())
254+ conduitRequestBody s r body add
255+ (x, y) <- readIORef ref
256+ return (x [], y [])
385257
386−-- |
387−--
388−-- @since 3.0.16.0
389258sinkRequestBodyEx :: ParseRequestBodyOptions
390259 -> BackEnd y
391260 -> RequestBodyType
@@ -398,7 +267,26 @@ sinkRequestBodyEx o s r body = do
398267 Left y' -> ((y':y, z), ())
399268 Right z' -> ((y, z':z), ())
400269 conduitRequestBodyEx o s r body add
401− (\(a, b) -> (reverse a, reverse b)) <$> readIORef ref
270+ readIORef ref
271+
272+conduitRequestBody :: BackEnd y
273+ -> RequestBodyType
274+ -> IO S.ByteString
275+ -> (Either Param (File y) -> IO ())
276+ -> IO ()
277+conduitRequestBody _ UrlEncoded rbody add = do
278+ -- NOTE: in general, url-encoded data will be in a single chunk.
279+ -- Therefore, I'm optimizing for the usual case by sticking with
280+ -- strict byte strings here.
281+ let loop front = do
282+ bs <- rbody
283+ if S.null bs
284+ then return $ S.concat $ front []
285+ else loop $ front . (bs:)
286+ bs <- loop id
287+ mapM_ (add . Left) $ H.parseSimpleQuery bs
288+conduitRequestBody backend (Multipart bound) rbody add =
289+ parsePieces backend (S8.pack "--" `S.append` bound) rbody add
402290
403291conduitRequestBodyEx :: ParseRequestBodyOptions
404292 -> BackEnd y
@@ -410,37 +298,34 @@ conduitRequestBodyEx o _ UrlEncoded rbody add = do
410298 -- NOTE: in general, url-encoded data will be in a single chunk.
411299 -- Therefore, I'm optimizing for the usual case by sticking with
412300 -- strict byte strings here.
413− let loop size front = do
301+ size <- newIORef 0
302+ let loop front = do
414303 bs <- rbody
415304 if S.null bs
416305 then return $ S.concat $ front []
417306 else do
418− let newsize = size + S.length bs
419− case prboMaxParmsSize o of
420− Just maxSize -> when (newsize > maxSize) $
421− error "Maximum size of parameters exceeded"
422− Nothing -> return ()
423− loop newsize $ front . (bs:)
424− bs <- loop 0 id
307+ newsize <- atomicModifyIORef size $
308+ \cursize -> let newsize = cursize + S.length bs in (newsize, newsize)
309+ when (newsize > prboMaxParmsValueSize o) $
310+ error "Maximum size of parameters exceeded"
311+ loop $ front . (bs:)
312+ bs <- loop id
425313 mapM_ (add . Left) $ H.parseSimpleQuery bs
426314conduitRequestBodyEx o backend (Multipart bound) rbody add =
427315 parsePiecesEx o backend (S8.pack "--" `S.append` bound) rbody add
428316
429317
430318-- | Take one header or subheader line.
431−-- Since: 3.0.26
432−-- Throw 431 if headers too large.
433−takeLine :: Maybe Int -> Source -> IO (Maybe S.ByteString)
434−takeLine maxlen src =
319+-- It makes sense to limit the maximum line length.
320+-- Apache's default is 8190 (http://httpd.apache.org/docs/2.2/mod/core.html#limitrequestline)
321+-- so we're using that here as well.
322+takeLine :: Source -> IO (Maybe S.ByteString)
323+takeLine src =
435324 go ""
436325 where
437326 go front = do
438327 bs <- readSource src
439− case maxlen of
440− Just maxlen' -> when (S.length front > maxlen') $
441− E.throwIO $ ConnectionError (UnknownErrorCode 431)
442− "Request Header Fields Too Large"
443− Nothing -> return ()
328+ when (S.length front + S.length bs > 8190) $ error "Header line length exceeds allowed maximum."
444329 if S.null bs
445330 then close front
446331 else push front bs
@@ -452,36 +337,32 @@ takeLine maxlen src =
452337 then go $ front `S.append` x
453338 else do
454339 when (S.length y > 1) $ leftover src $ S.drop 1 y
455− let res = front `S.append` x
456− case maxlen of
457− Just maxlen' -> when (S.length res > maxlen') $
458− E.throwIO $ ConnectionError (UnknownErrorCode 431)
459− "Request Header Fields Too Large"
460− Nothing -> return ()
461− return $ Just $ killCR $ res
462−
463−takeLines' :: Maybe Int -> Maybe Int -> Source -> IO [S.ByteString]
464−takeLines' lineLength maxLines source =
465− reverse <$> takeLines'' [] lineLength maxLines source
466−
467−takeLines''
468− :: [S.ByteString]
469− -> Maybe Int
470− -> Maybe Int
471− -> Source
472− -> IO [S.ByteString]
473−takeLines'' lines lineLength maxLines src = do
474− case maxLines of
475− Just maxLines' ->
476− when (length lines > maxLines') $
477− error "Too many lines in mime/multipart header"
478− Nothing -> return ()
479− res <- takeLine lineLength src
340+ return $ Just $ killCR $ front `S.append` x
341+
342+takeLines :: Source -> IO [S.ByteString]
343+takeLines src = do
344+ res <- takeLine src
480345 case res of
481− Nothing -> return lines
346+ Nothing -> return []
482347 Just l
483− | S.null l -> return lines
484− | otherwise -> takeLines'' (l:lines) lineLength maxLines src
348+ | S.null l -> return []
349+ | otherwise -> do
350+ ls <- takeLines src
351+ return $ l : ls
352+
353+takeLines' :: Int -> Source -> IO [S.ByteString]
354+takeLines' a b = reverse <$> takeLines'' [] a b
355+
356+takeLines'' :: [S.ByteString] -> Int -> Source -> IO [S.ByteString]
357+takeLines'' lines maxLines src
358+ | length lines > maxLines = error "Too many lines in mime/multipart header"
359+ | otherwise = do
360+ res <- takeLine src
361+ case res of
362+ Nothing -> return lines
363+ Just l
364+ | S.null l -> return lines
365+ | otherwise -> takeLines'' (l:lines) maxLines src
485366
486367data Source = Source (IO S.ByteString) (IORef S.ByteString)
487368
@@ -500,6 +381,53 @@ readSource (Source f ref) = do
500381leftover :: Source -> S.ByteString -> IO ()
501382leftover (Source _ ref) bs = writeIORef ref bs
502383
384+parsePieces :: BackEnd y
385+ -> S.ByteString
386+ -> IO S.ByteString
387+ -> (Either Param (File y) -> IO ())
388+ -> IO ()
389+parsePieces sink bound rbody add =
390+ mkSource rbody >>= loop
391+ where
392+ loop src = do
393+ _boundLine <- takeLine src
394+ res' <- takeLines src
395+ unless (null res') $ do
396+ let ls' = map parsePair res'
397+ let x = do
398+ cd <- lookup contDisp ls'
399+ let ct = lookup contType ls'
400+ let attrs = parseAttrs cd
401+ name <- lookup "name" attrs
402+ return (ct, name, lookup "filename" attrs)
403+ case x of
404+ Just (mct, name, Just filename) -> do
405+ let ct = fromMaybe "application/octet-stream" mct
406+ fi0 = FileInfo filename ct ()
407+ ((wasFound, _fileSize), y) <- sinkTillBound' bound name fi0 sink src Nothing
408+ add $ Right (name, fi0 { fileContent = y })
409+ when wasFound (loop src)
410+ Just (_ct, name, Nothing) -> do
411+ let seed = id
412+ let iter front bs = return $ front . (:) bs
413+ ((wasFound, _fileSize), front) <- sinkTillBound bound iter seed src Nothing
414+ let bs = S.concat $ front []
415+ let x' = (name, bs)
416+ add $ Left x'
417+ when wasFound (loop src)
418+ _ -> do
419+ -- ignore this part
420+ let seed = ()
421+ iter () _ = return ()
422+ ((wasFound, _fileSize), ()) <- sinkTillBound bound iter seed src Nothing
423+ when wasFound (loop src)
424+ where
425+ contDisp = mk $ S8.pack "Content-Disposition"
426+ contType = mk $ S8.pack "Content-Type"
427+ parsePair s =
428+ let (x, y) = breakDiscard 58 s -- colon
429+ in (mk $ x, S.dropWhile (== 32) y) -- space
430+
503431parsePiecesEx :: ParseRequestBodyOptions
504432 -> BackEnd y
505433 -> S.ByteString
@@ -511,9 +439,8 @@ parsePiecesEx o sink bound rbody add =
511439 where
512440 loop :: Int -> Int -> Int -> Int64 -> Source -> IO ()
513441 loop numParms numFiles parmSize filesSize src = do
514− _boundLine <- takeLine (prboMaxHeaderLineLength o) src
515− res' <- takeLines' (prboMaxHeaderLineLength o)
516− (prboMaxHeaderLines o) src
442+ _boundLine <- takeLine src
443+ res' <- takeLines' (prboMaxHeaderLines o) src
517444 unless (null res') $ do
518445 let ls' = map parsePair res'
519446 let x = do
@@ -524,15 +451,10 @@ parsePiecesEx o sink bound rbody add =
524451 return (ct, name, lookup "filename" attrs)
525452 case x of
526453 Just (mct, name, Just filename) -> do
527− case prboKeyLength o of
528− Just maxKeyLength ->
529− when (S.length name > maxKeyLength) $
530− error "Filename is too long"
531− Nothing -> return ()
532− case prboMaxNumFiles o of
533− Just maxFiles -> when (numFiles >= maxFiles) $
534− error "Maximum number of files exceeded"
535− Nothing -> return ()
454+ when (S.length name > prboKeyLength o) $
455+ error "Filename is too long"
456+ when (numFiles >= prboMaxNumFiles o) $
457+ error "Maximum number of files exceeded"
536458 let ct = fromMaybe "application/octet-stream" mct
537459 fi0 = FileInfo filename ct ()
538460 fs = catMaybes [ prboMaxFileSize o
@@ -543,22 +465,17 @@ parsePiecesEx o sink bound rbody add =
543465 add $ Right (name, fi0 { fileContent = y })
544466 when wasFound $ loop numParms (numFiles + 1) parmSize newFilesSize src
545467 Just (_ct, name, Nothing) -> do
546− case prboKeyLength o of
547− Just maxKeyLength ->
548− when (S.length name > maxKeyLength) $
549− error "Parameter name is too long"
550− Nothing -> return ()
468+ when (S.length name > prboKeyLength o) $
469+ error "Parameter name is too long"
551470 let seed = id
552471 let iter front bs = return $ front . (:) bs
553− ((wasFound, _fileSize), front) <- sinkTillBound bound iter seed src
554− (fromIntegral <$> prboMaxParmsSize o)
472+ ((wasFound, _fileSize), front) <- sinkTillBound bound iter seed src $
473+ Just . fromIntegral . prboMaxParmsValueSize $ o
555474 let bs = S.concat $ front []
556475 let x' = (name, bs)
557476 let newParmSize = parmSize + S.length name + S.length bs
558− case prboMaxParmsSize o of
559− Just maxParmSize -> when (newParmSize > maxParmSize) $
560− error "Maximum size of parameters exceeded"
561− Nothing -> return ()
477+ when (newParmSize > prboMaxParmsValueSize o) $
478+ error "Maximum size of parameters exceeded"
562479 add $ Left x'
563480 when wasFound $ loop (numParms + 1) numFiles
564481 newParmSize filesSize src
@@ -582,7 +499,7 @@ data Bound = FoundBound S.ByteString S.ByteString
582499 deriving (Eq, Show)
583500
584501findBound :: S.ByteString -> S.ByteString -> Bound
585−findBound b bs = handleBreak $ S.breakSubstring b bs
502+findBound b bs = handleBreak $ Search.breakOn b bs
586503 where
587504 handleBreak (h, t)
588505 | S.null t = go [lowBound..S.length bs - 1]
@@ -611,8 +528,8 @@ sinkTillBound' :: S.ByteString
611528 -> Source
612529 -> Maybe Int64
613530 -> IO ((Bool, Int64), y)
614−sinkTillBound' bound name fi sink src max' = do
615− (next, final) <- wrapTillBound bound src max'
531+sinkTillBound' bound name fi sink src max = do
532+ (next, final) <- wrapTillBound bound src max
616533 y <- sink name fi next
617534 b <- final
618535 return (b, y)
@@ -623,7 +540,7 @@ wrapTillBound :: S.ByteString -- ^ bound
623540 -> Source
624541 -> Maybe Int64
625542 -> IO (IO S.ByteString, IO (Bool, Int64)) -- ^ Bool indicates if the bound was found
626−wrapTillBound bound src max' = do
543+wrapTillBound bound src max = do
627544 ref <- newIORef $ WTBWorking id
628545 sref <- newIORef (0 :: Int64)
629546 return (go ref sref, final ref sref)
@@ -642,19 +559,18 @@ wrapTillBound bound src max' = do
642559 WTBDone _ -> return S.empty
643560 WTBWorking front -> do
644561 bs <- readSource src
645− cur <- atomicModifyIORef' sref $ \ cur ->
562+ cur <- atomicModifyIORef sref $ \ cur ->
646563 let new = cur + fromIntegral (S.length bs) in (new, new)
647− case max' of
648− Just max'' | cur > max'' ->
649− E.throwIO $ ConnectionError (UnknownErrorCode 413) "Payload Too Large"
650− _ -> return ()
564+ case max of
565+ Just max' | cur > max' -> error "Maximum size exceeded"
566+ _ -> return ()
651567 if S.null bs
652568 then do
653569 writeIORef ref $ WTBDone False
654570 return $ front bs
655571 else push $ front bs
656572 where
657− push bs = do
573+ push bs =
658574 case findBound bound bs of
659575 FoundBound before after -> do
660576 let before' = killCRLF before
@@ -682,8 +598,8 @@ sinkTillBound :: S.ByteString
682598 -> Source
683599 -> Maybe Int64
684600 -> IO ((Bool, Int64), x)
685−sinkTillBound bound iter seed0 src max' = do
686− (next, final) <- wrapTillBound bound src max'
601+sinkTillBound bound iter seed0 src max = do
602+ (next, final) <- wrapTillBound bound src max
687603 let loop seed = do
688604 bs <- next
689605 if S.null bs