Fix HTTP body framing and eliminate request over-read
This commit is contained in:
165
lib/http.tri
165
lib/http.tri
@@ -159,7 +159,7 @@ responseForMethod = (method resp :
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
recvUntilMax_ = (y (self sock pattern maxBytes acc accLen :
|
||||
onResult_ (recv sock 4096)
|
||||
onResult_ (recv sock 1)
|
||||
(err :
|
||||
pure (err 400 acc))
|
||||
(chunk :
|
||||
@@ -518,63 +518,130 @@ contentLength = (headers :
|
||||
-- Body reading
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
consumeAvailable_ = (y (self bytes remaining acc :
|
||||
lazyList
|
||||
(_ : pair (reverse acc) (pair remaining t))
|
||||
(h r :
|
||||
lazyBool
|
||||
(_ : pair (reverse acc) (pair 0 r))
|
||||
(_ : self r (pred remaining) (pair h acc))
|
||||
(isZero? remaining))
|
||||
bytes))
|
||||
bodyReadState = (remaining accRev rest :
|
||||
pair remaining (pair accRev rest))
|
||||
|
||||
consumeAvailable = (bytes n :
|
||||
consumeAvailable_ bytes n t)
|
||||
bodyReadRemaining = (state :
|
||||
fst state)
|
||||
|
||||
readBodyN_ = (y (self sock remaining acc :
|
||||
bodyReadAccRev = (state :
|
||||
fst (snd state))
|
||||
|
||||
bodyReadRest = (state :
|
||||
snd (snd state))
|
||||
|
||||
takeBodyBytes_ = (self bytes remaining accRev :
|
||||
lazyBool
|
||||
(_ : pure (ok acc t))
|
||||
(_ : bodyReadState 0 accRev bytes)
|
||||
(_ :
|
||||
onResult_ (recv sock remaining)
|
||||
(err :
|
||||
pure (err 400 acc))
|
||||
(chunk :
|
||||
((got :
|
||||
lazyBool
|
||||
(_ : pure (err 400 acc))
|
||||
(_ : self sock (sub remaining got) (append acc chunk))
|
||||
(equal? got 0))
|
||||
(length chunk))))
|
||||
(isZero? remaining)))
|
||||
lazyList
|
||||
(_ : bodyReadState remaining accRev t)
|
||||
(h r :
|
||||
self r (pred remaining) (pair h accRev))
|
||||
bytes)
|
||||
(isZero? remaining))
|
||||
|
||||
readBodyN = (sock n acc :
|
||||
readBodyN_ sock n acc)
|
||||
takeBodyBytes = (bytes remaining accRev :
|
||||
y takeBodyBytes_ bytes remaining accRev)
|
||||
|
||||
readBodyRecv = (self sock remaining accRev recvBytes :
|
||||
onResult_ (recv sock recvBytes)
|
||||
(errMsg :
|
||||
pure
|
||||
(err
|
||||
400
|
||||
(append "recv failed while reading body: " errMsg)))
|
||||
(chunk :
|
||||
((state :
|
||||
((nextRemaining :
|
||||
((nextAccRev :
|
||||
lazyBool
|
||||
(_ : pure (ok (reverse nextAccRev) (bodyReadRest state)))
|
||||
(_ : self sock nextRemaining nextAccRev)
|
||||
(isZero? nextRemaining))
|
||||
(bodyReadAccRev state)))
|
||||
(bodyReadRemaining state)))
|
||||
(takeBodyBytes chunk remaining accRev))))
|
||||
|
||||
readBodyMore_ = (self sock remaining accRev :
|
||||
lazyBool
|
||||
(_ : pure (ok (reverse accRev) t))
|
||||
(_ :
|
||||
lazyBool
|
||||
(_ : readBodyRecv self sock remaining accRev 4096)
|
||||
(_ :
|
||||
lazyBool
|
||||
(_ : readBodyRecv self sock remaining accRev 1024)
|
||||
(_ :
|
||||
lazyBool
|
||||
(_ : readBodyRecv self sock remaining accRev 256)
|
||||
(_ :
|
||||
lazyBool
|
||||
(_ : readBodyRecv self sock remaining accRev 64)
|
||||
(_ :
|
||||
lazyBool
|
||||
(_ : readBodyRecv self sock remaining accRev 16)
|
||||
(_ : readBodyRecv self sock remaining accRev 1)
|
||||
(lte? 16 remaining))
|
||||
(lte? 64 remaining))
|
||||
(lte? 256 remaining))
|
||||
(lte? 1024 remaining))
|
||||
(lte? 4096 remaining))
|
||||
(isZero? remaining))
|
||||
|
||||
readBodyMore = (sock remaining accRev :
|
||||
y readBodyMore_ sock remaining accRev)
|
||||
|
||||
readBodyExact = (sock expected initialBytes :
|
||||
((state :
|
||||
((remaining :
|
||||
((accRev :
|
||||
lazyBool
|
||||
(_ : pure (ok (reverse accRev) (bodyReadRest state)))
|
||||
(_ : readBodyMore sock remaining accRev)
|
||||
(isZero? remaining))
|
||||
(bodyReadAccRev state)))
|
||||
(bodyReadRemaining state)))
|
||||
(takeBodyBytes initialBytes expected t)))
|
||||
|
||||
validateBodyLength = (expected body rest :
|
||||
((actual :
|
||||
lazyBool
|
||||
(_ : pure (ok body rest))
|
||||
(_ :
|
||||
pure
|
||||
(err
|
||||
400
|
||||
(append
|
||||
"body length mismatch expected="
|
||||
(append
|
||||
(showNumber expected)
|
||||
(append
|
||||
" actual="
|
||||
(showNumber actual))))))
|
||||
(equal? actual expected))
|
||||
(length body)))
|
||||
|
||||
readBody = (sock headers initialBytes :
|
||||
matchResult
|
||||
(status msg :
|
||||
pure (err status "Bad Request\n"))
|
||||
pure (err status msg))
|
||||
(maybeLen rest :
|
||||
lazyMaybe
|
||||
(_ : pure (ok t initialBytes))
|
||||
(n :
|
||||
((consumed :
|
||||
((body0 :
|
||||
((remaining :
|
||||
lazyBool
|
||||
(_ : pure (ok body0 t))
|
||||
(_ :
|
||||
onOk (readBodyN sock remaining body0)
|
||||
(body rest : pure (ok body t)))
|
||||
(isZero? remaining))
|
||||
(fst (snd consumed))))
|
||||
(fst consumed)))
|
||||
(consumeAvailable initialBytes n)))
|
||||
lazyBool
|
||||
(_ :
|
||||
onOk (readBodyExact sock n initialBytes)
|
||||
(body rest :
|
||||
validateBodyLength n body rest))
|
||||
(_ : pure (err 400 "Request body too large\n"))
|
||||
(lte? n maxBodyBytes))
|
||||
maybeLen)
|
||||
(contentLength headers))
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 10. Request validation
|
||||
-- Request validation
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
validMethod? = (method :
|
||||
@@ -629,12 +696,12 @@ respondAndClose = (sock resp :
|
||||
pure (ok t t)))
|
||||
|
||||
handleReadableRequest = (router client method target headers rest3 :
|
||||
onResult_ (readBody client headers rest3)
|
||||
(status :
|
||||
onResult (readBody client headers rest3)
|
||||
(status msg :
|
||||
respondAndClose client
|
||||
(responseForMethod method
|
||||
(badRequestResponse "Bad Request\n")))
|
||||
(body :
|
||||
(errorResponse status msg)))
|
||||
(body rest :
|
||||
respondAndClose client
|
||||
(responseForMethod method
|
||||
(router (routerMethod method) target headers body))))
|
||||
@@ -680,12 +747,12 @@ httpHandler = (router client peer :
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
handleReadableRequestIO = (routerIO client method target headers rest3 :
|
||||
onResult_ (readBody client headers rest3)
|
||||
(status :
|
||||
onResult (readBody client headers rest3)
|
||||
(status msg :
|
||||
respondAndClose client
|
||||
(responseForMethod method
|
||||
(badRequestResponse "Bad Request\n")))
|
||||
(body :
|
||||
(errorResponse status msg)))
|
||||
(body rest :
|
||||
bind (routerIO (routerMethod method) target headers body) (resp :
|
||||
respondAndClose client (responseForMethod method resp))))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user