@@ -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
@@ -305,16 +169,8 @@ type BackEnd a = S.ByteString -- ^ parameter name
305169 -> IO S.ByteString
306170 -> IO a
307171
308−-- | The mimetype of the http body.
309−-- Depending on whether just parameters or parameters and files
310−-- are passed, one or the other mimetype should be used.
311−data RequestBodyType
312− = -- | application/x-www-form-urlencoded (parameters only)
313− UrlEncoded
314− | -- | multipart/form-data (parameters and files)
315− Multipart S.ByteString
172+data RequestBodyType = UrlEncoded | Multipart S.ByteString
316173
317−-- | Get the mimetype of the body of an http request.
318174getRequestBodyType :: Request -> Maybe RequestBodyType
319175getRequestBodyType req = do
320176 ctype' <- lookup hContentType $ requestHeaders req
@@ -327,7 +183,7 @@ getRequestBodyType req = do
327183-- | Parse a content type value, turning a single @ByteString@ into the actual
328184-- content type and a list of pairs of attributes.
329185--
330−-- @since 1.3.2
186+-- Since 1.3.2
331187parseContentType :: S.ByteString -> (S.ByteString, [(S.ByteString, S.ByteString)])
332188parseContentType a = do
333189 let (ctype, b) = S.break (== semicolon) a
@@ -337,9 +193,6 @@ parseContentType a = do
337193 semicolon = 59
338194 equals = 61
339195 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
343196 goAttrs front bs
344197 | S.null bs = front []
345198 | otherwise =
@@ -348,26 +201,17 @@ parseContentType a = do
348201 goAttr bs =
349202 let (k, v') = S.break (== equals) bs
350203 v = S.drop 1 v'
351− in (strip k, dq $ strip v)
204+ in (strip k, strip v)
352205 strip = S.dropWhile (== space) . fst . S.breakEnd (/= space)
353206
354−-- | Parse the body of an HTTP request.
355−-- See parseRequestBodyEx for details.
356−-- Note: This function does not limit the memory it allocates.
357−-- When dealing with untrusted data (as is usually the case when
358−-- receiving input from the internet), it is recommended to
359−-- use the 'parseRequestBodyEx' function instead.
360207parseRequestBody :: BackEnd y
361208 -> Request
362209 -> IO ([Param], [File y])
363−parseRequestBody = parseRequestBodyEx noLimitParseRequestBodyOptions
364−
365−-- | Parse the body of an HTTP request, limit resource usage.
366−-- The HTTP body can contain both parameters and files.
367−-- This function will return a list of key,value pairs
368−-- for all parameters, and a list of key,a pairs
369−-- for filenames. The a depends on the used backend that
370−-- is responsible for storing the received files.
210+parseRequestBody s r =
211+ case getRequestBodyType r of
212+ Nothing -> return ([], [])
213+ Just rbt -> sinkRequestBody s rbt (requestBody r)
214+
371215parseRequestBodyEx :: ParseRequestBodyOptions
372216 -> BackEnd y
373217 -> Request
@@ -381,11 +225,16 @@ sinkRequestBody :: BackEnd y
381225 -> RequestBodyType
382226 -> IO S.ByteString
383227 -> IO ([Param], [File y])
384−sinkRequestBody = sinkRequestBodyEx noLimitParseRequestBodyOptions
228+sinkRequestBody s r body = do
229+ ref <- newIORef (id, id)
230+ let add x = atomicModifyIORef ref $ \(y, z) ->
231+ case x of
232+ Left y' -> ((y . (y':), z), ())
233+ Right z' -> ((y, z . (z':)), ())
234+ conduitRequestBody s r body add
235+ (x, y) <- readIORef ref
236+ return (x [], y [])
385237
386−-- |
387−--
388−-- @since 3.0.16.0
389238sinkRequestBodyEx :: ParseRequestBodyOptions
390239 -> BackEnd y
391240 -> RequestBodyType
@@ -398,7 +247,26 @@ sinkRequestBodyEx o s r body = do
398247 Left y' -> ((y':y, z), ())
399248 Right z' -> ((y, z':z), ())
400249 conduitRequestBodyEx o s r body add
401− (\(a, b) -> (reverse a, reverse b)) <$> readIORef ref
250+ readIORef ref
251+
252+conduitRequestBody :: BackEnd y
253+ -> RequestBodyType
254+ -> IO S.ByteString
255+ -> (Either Param (File y) -> IO ())
256+ -> IO ()
257+conduitRequestBody _ UrlEncoded rbody add = do
258+ -- NOTE: in general, url-encoded data will be in a single chunk.
259+ -- Therefore, I'm optimizing for the usual case by sticking with
260+ -- strict byte strings here.
261+ let loop front = do
262+ bs <- rbody
263+ if S.null bs
264+ then return $ S.concat $ front []
265+ else loop $ front . (bs:)
266+ bs <- loop id
267+ mapM_ (add . Left) $ H.parseSimpleQuery bs
268+conduitRequestBody backend (Multipart bound) rbody add =
269+ parsePieces backend (S8.pack "--" `S.append` bound) rbody add
402270
403271conduitRequestBodyEx :: ParseRequestBodyOptions
404272 -> BackEnd y
@@ -410,78 +278,60 @@ conduitRequestBodyEx o _ UrlEncoded rbody add = do
410278 -- NOTE: in general, url-encoded data will be in a single chunk.
411279 -- Therefore, I'm optimizing for the usual case by sticking with
412280 -- strict byte strings here.
413− let loop size front = do
281+ let loop front = do
414282 bs <- rbody
415283 if S.null bs
416284 then return $ S.concat $ front []
417− 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
285+ else loop $ front . (bs:)
286+ bs <- loop id
425287 mapM_ (add . Left) $ H.parseSimpleQuery bs
426288conduitRequestBodyEx o backend (Multipart bound) rbody add =
427289 parsePiecesEx o backend (S8.pack "--" `S.append` bound) rbody add
428290
429291
430−-- | 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 =
435− go ""
292+takeLine :: Source -> IO (Maybe S.ByteString)
293+takeLine src =
294+ go id
436295 where
437296 go front = do
438297 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 ()
444298 if S.null bs
445299 then close front
446300 else push front bs
447301
448− close front = leftover src front >> return Nothing
302+ close front = leftover src (front S.empty) >> return Nothing
449303 push front bs = do
450− let (x, y) = S.break (== 10) bs -- LF
304+ let (x, y) = S.break (== 10) $ front bs -- LF
451305 in if S.null y
452− then go $ front `S.append` x
306+ then go $ S.append x
453307 else do
454308 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
309+ return $ Just $ killCR x
310+
311+takeLines :: Source -> IO [S.ByteString]
312+takeLines src = do
313+ res <- takeLine src
480314 case res of
481− Nothing -> return lines
315+ Nothing -> return []
482316 Just l
483− | S.null l -> return lines
484− | otherwise -> takeLines'' (l:lines) lineLength maxLines src
317+ | S.null l -> return []
318+ | otherwise -> do
319+ ls <- takeLines src
320+ return $ l : ls
321+
322+takeLines' :: Int -> Source -> IO [S.ByteString]
323+takeLines' a b = reverse <$> takeLines'' [] a b
324+
325+takeLines'' :: [S.ByteString] -> Int -> Source -> IO [S.ByteString]
326+takeLines'' lines maxLines src
327+ | length lines > maxLines = error "Too many lines in mime/multipart header"
328+ | otherwise = do
329+ res <- takeLine src
330+ case res of
331+ Nothing -> return lines
332+ Just l
333+ | S.null l -> return lines
334+ | otherwise -> takeLines'' (l:lines) maxLines src
485335
486336data Source = Source (IO S.ByteString) (IORef S.ByteString)
487337
@@ -500,6 +350,53 @@ readSource (Source f ref) = do
500350leftover :: Source -> S.ByteString -> IO ()
501351leftover (Source _ ref) bs = writeIORef ref bs
502352
353+parsePieces :: BackEnd y
354+ -> S.ByteString
355+ -> IO S.ByteString
356+ -> (Either Param (File y) -> IO ())
357+ -> IO ()
358+parsePieces sink bound rbody add =
359+ mkSource rbody >>= loop
360+ where
361+ loop src = do
362+ _boundLine <- takeLine src
363+ res' <- takeLines src
364+ unless (null res') $ do
365+ let ls' = map parsePair res'
366+ let x = do
367+ cd <- lookup contDisp ls'
368+ let ct = lookup contType ls'
369+ let attrs = parseAttrs cd
370+ name <- lookup "name" attrs
371+ return (ct, name, lookup "filename" attrs)
372+ case x of
373+ Just (mct, name, Just filename) -> do
374+ let ct = fromMaybe "application/octet-stream" mct
375+ fi0 = FileInfo filename ct ()
376+ ((wasFound, _fileSize), y) <- sinkTillBound' bound name fi0 sink src Nothing
377+ add $ Right (name, fi0 { fileContent = y })
378+ when wasFound (loop src)
379+ Just (_ct, name, Nothing) -> do
380+ let seed = id
381+ let iter front bs = return $ front . (:) bs
382+ ((wasFound, _fileSize), front) <- sinkTillBound bound iter seed src Nothing
383+ let bs = S.concat $ front []
384+ let x' = (name, bs)
385+ add $ Left x'
386+ when wasFound (loop src)
387+ _ -> do
388+ -- ignore this part
389+ let seed = ()
390+ iter () _ = return ()
391+ ((wasFound, _fileSize), ()) <- sinkTillBound bound iter seed src Nothing
392+ when wasFound (loop src)
393+ where
394+ contDisp = mk $ S8.pack "Content-Disposition"
395+ contType = mk $ S8.pack "Content-Type"
396+ parsePair s =
397+ let (x, y) = breakDiscard 58 s -- colon
398+ in (mk $ x, S.dropWhile (== 32) y) -- space
399+
503400parsePiecesEx :: ParseRequestBodyOptions
504401 -> BackEnd y
505402 -> S.ByteString
@@ -511,9 +408,8 @@ parsePiecesEx o sink bound rbody add =
511408 where
512409 loop :: Int -> Int -> Int -> Int64 -> Source -> IO ()
513410 loop numParms numFiles parmSize filesSize src = do
514− _boundLine <- takeLine (prboMaxHeaderLineLength o) src
515− res' <- takeLines' (prboMaxHeaderLineLength o)
516− (prboMaxHeaderLines o) src
411+ _boundLine <- takeLine src
412+ res' <- takeLines' (prboMaxHeaderLines o) src
517413 unless (null res') $ do
518414 let ls' = map parsePair res'
519415 let x = do
@@ -524,41 +420,30 @@ parsePiecesEx o sink bound rbody add =
524420 return (ct, name, lookup "filename" attrs)
525421 case x of
526422 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 ()
423+ when (S.length name > prboKeyLength o) $
424+ error "Filename is too long"
425+ when (numFiles >= prboMaxNumFiles o) $
426+ error "Maximum number of files exceeded"
536427 let ct = fromMaybe "application/octet-stream" mct
537428 fi0 = FileInfo filename ct ()
538− fs = catMaybes [ prboMaxFileSize o
539− , subtract filesSize <$> prboMaxFilesSize o ]
429+ fs = catMaybes [ prboMaxFileSize o, prboMaxFilesSize o ]
540430 mfs = if fs == [] then Nothing else Just $ minimum fs
541431 ((wasFound, fileSize), y) <- sinkTillBound' bound name fi0 sink src mfs
542432 let newFilesSize = filesSize + fileSize
543433 add $ Right (name, fi0 { fileContent = y })
544434 when wasFound $ loop numParms (numFiles + 1) parmSize newFilesSize src
545435 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 ()
436+ when (S.length name > prboKeyLength o) $
437+ error "Parameter name is too long"
551438 let seed = id
552439 let iter front bs = return $ front . (:) bs
553− ((wasFound, _fileSize), front) <- sinkTillBound bound iter seed src
554− (fromIntegral <$> prboMaxParmsSize o)
440+ ((wasFound, _fileSize), front) <- sinkTillBound bound iter seed src $
441+ Just . fromIntegral . prboMaxParmsValueSize $ o
555442 let bs = S.concat $ front []
556443 let x' = (name, bs)
557444 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 ()
445+ when (newParmSize > prboMaxParmsValueSize o) $
446+ error "Maximum size of parameters exceeded"
562447 add $ Left x'
563448 when wasFound $ loop (numParms + 1) numFiles
564449 newParmSize filesSize src
@@ -582,7 +467,7 @@ data Bound = FoundBound S.ByteString S.ByteString
582467 deriving (Eq, Show)
583468
584469findBound :: S.ByteString -> S.ByteString -> Bound
585−findBound b bs = handleBreak $ S.breakSubstring b bs
470+findBound b bs = handleBreak $ Search.breakOn b bs
586471 where
587472 handleBreak (h, t)
588473 | S.null t = go [lowBound..S.length bs - 1]
@@ -611,8 +496,8 @@ sinkTillBound' :: S.ByteString
611496 -> Source
612497 -> Maybe Int64
613498 -> IO ((Bool, Int64), y)
614−sinkTillBound' bound name fi sink src max' = do
615− (next, final) <- wrapTillBound bound src max'
499+sinkTillBound' bound name fi sink src max = do
500+ (next, final) <- wrapTillBound bound src max
616501 y <- sink name fi next
617502 b <- final
618503 return (b, y)
@@ -623,7 +508,7 @@ wrapTillBound :: S.ByteString -- ^ bound
623508 -> Source
624509 -> Maybe Int64
625510 -> IO (IO S.ByteString, IO (Bool, Int64)) -- ^ Bool indicates if the bound was found
626−wrapTillBound bound src max' = do
511+wrapTillBound bound src max = do
627512 ref <- newIORef $ WTBWorking id
628513 sref <- newIORef (0 :: Int64)
629514 return (go ref sref, final ref sref)
@@ -642,19 +527,18 @@ wrapTillBound bound src max' = do
642527 WTBDone _ -> return S.empty
643528 WTBWorking front -> do
644529 bs <- readSource src
645− cur <- atomicModifyIORef' sref $ \ cur ->
530+ cur <- atomicModifyIORef sref $ \ cur ->
646531 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 ()
532+ case max of
533+ Just max' | cur > max' -> error "Maximum size exceeded"
534+ _ -> return ()
651535 if S.null bs
652536 then do
653537 writeIORef ref $ WTBDone False
654538 return $ front bs
655539 else push $ front bs
656540 where
657− push bs = do
541+ push bs =
658542 case findBound bound bs of
659543 FoundBound before after -> do
660544 let before' = killCRLF before
@@ -682,8 +566,8 @@ sinkTillBound :: S.ByteString
682566 -> Source
683567 -> Maybe Int64
684568 -> IO ((Bool, Int64), x)
685−sinkTillBound bound iter seed0 src max' = do
686− (next, final) <- wrapTillBound bound src max'
569+sinkTillBound bound iter seed0 src max = do
570+ (next, final) <- wrapTillBound bound src max
687571 let loop seed = do
688572 bs <- next
689573 if S.null bs