Skip to content

Commit 206ffa3

Browse files
committed
feat: tests and small changes
1 parent 3009358 commit 206ffa3

File tree

8 files changed

+709
-85
lines changed

8 files changed

+709
-85
lines changed

src/Std/Internal/Http/Data/Status.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ inductive Status where
337337
511 Network Authentication Required
338338
-/
339339
| networkAuthenticationRequired
340-
deriving Repr, Inhabited
340+
deriving Repr, Inhabited, BEq
341341

342342
instance : ToString Status where
343343
toString

src/Std/Internal/Http/Protocol/H1.lean

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ structure Config where
4343
maxHeaderSize : Nat := 8192
4444

4545
/--
46-
Connection timeout in seconds.
46+
Connection timeout in milliseconds.
4747
-/
48-
timeoutSeconds : Time.Second.Offset := 10
48+
timeoutMilliseconds : Time.Millisecond.Offset := 1000
4949

5050
/--
5151
Whether to enable keep-alive connections by default.
@@ -117,6 +117,9 @@ inductive Error
117117
| other (message : String)
118118
deriving Repr, BEq
119119

120+
instance : Repr ByteSlice where
121+
reprPrec x := reprPrec x.toByteArray.data
122+
120123
/--
121124
Events that can occur during HTTP message processing.
122125
-/
@@ -156,7 +159,7 @@ inductive Event
156159
Awaiting the next request
157160
-/
158161
| next
159-
deriving Inhabited
162+
deriving Inhabited, Repr
160163

161164
inductive Reader.State : Type
162165
/--
@@ -502,6 +505,14 @@ structure Machine where
502505

503506
namespace Machine
504507

508+
private def shouldBreakConnection (c : Status) : Bool :=
509+
match c with
510+
| .uriTooLong
511+
| .badRequest
512+
| .payloadTooLarge
513+
| .requestHeaderFieldsTooLarge => true
514+
| _ => false
515+
505516
-- Additional helper functions for writer manipulation
506517
@[inline]
507518
private def modifyWriter (machine : Machine) (fn : Writer → Writer) : Machine :=
@@ -557,7 +568,7 @@ private def parseWith (machine : Machine) (parser : Parser α) (limit : Option N
557568

558569
if let some limit := limit then
559570
if usedBytesUntilFailure ≥ limit
560-
then (machine.setError .badRequest, none)
571+
then (machine.setFailure .badRequest .badRequest, none)
561572
else (machine.addEvent (.needMoreData expect), none)
562573
else (machine.addEvent (.needMoreData expect), none)
563574
| .error _ _ =>
@@ -666,7 +677,7 @@ def setHeaders (response : Response.Head) (machine : Machine) : Machine :=
666677

667678
let headers := if let some date := machine.instant then headers.insert "Date" (date.format "EEE, dd MMM yyyy HH:mm:ss 'GMT'") else headers
668679

669-
let headers := if ¬machine.keepAlive ∨ response.status.isClientError ∨ response.status.isServerError then
680+
let headers := if ¬machine.keepAlive ∨ shouldBreakConnection response.status then
670681
headers.insert "Connection" "close"
671682
else
672683
headers
@@ -748,12 +759,14 @@ def sendResponse (machine : Machine) (response : Response.Head) : Machine :=
748759
| .waitingHeaders =>
749760
let machine := machine.modifyWriter ({ · with response, state := .waitingForFlush })
750761
let conn := response.headers.getD "Connection"
751-
if response.status.isClientError || response.status.isServerError || conn.contains "close" then
762+
763+
if conn.contains "close" then
752764
machine
753765
|>.closeConnection
754-
|>.setReaderState .complete -- Stop receiving data
766+
|>.setReaderState .complete
755767
else
756768
machine
769+
757770
| _ =>
758771
machine
759772

@@ -765,7 +778,7 @@ def isReaderComplete (machine : Machine) : Bool :=
765778
/--
766779
Advances the state of the reader.
767780
-/
768-
def processRead (machine : Machine) : Machine :=
781+
partial def processRead (machine : Machine) : Machine :=
769782
match machine.reader.state with
770783
| .needStartLine =>
771784
let (machine, result) := parseWith machine parseRequestLine (limit := some 8192)
@@ -774,6 +787,7 @@ def processRead (machine : Machine) : Machine :=
774787
machine
775788
|>.modifyReader (.setRequest head)
776789
|>.setReaderState (.needHeader 0)
790+
|>.processRead
777791
else
778792
machine
779793

@@ -788,6 +802,7 @@ def processRead (machine : Machine) : Machine :=
788802
machine
789803
|>.modifyReader (.addHeader name value)
790804
|>.setReaderState (.needHeader (headerCount + 1))
805+
|>.processRead
791806
else
792807
processHeaders machine
793808
else
@@ -804,6 +819,7 @@ def processRead (machine : Machine) : Machine :=
804819
machine
805820
|>.setReaderState (.needChunkedBody size)
806821
|>.setEvent (some ext <&> .chunkExt)
822+
|>.processRead
807823
| none =>
808824
machine
809825

@@ -817,24 +833,34 @@ def processRead (machine : Machine) : Machine :=
817833
machine
818834
|>.setReaderState .needChunkedSize
819835
|>.addEvent (.gotData false body)
836+
|>.processRead
820837
else
821838
machine
822839
|>.setReaderState .complete
823840
|>.addEvent (.gotData true .empty)
841+
|>.processRead
824842
| .incomplete body remaining => machine
825843
|>.setReaderState (.needChunkedBody remaining)
826844
|>.addEvent (.gotData false body)
827845
else
828846
machine
829847

848+
| .needFixedBody 0 =>
849+
machine
850+
|>.setReaderState .complete
851+
|>.addEvent (.gotData true .empty)
852+
|>.processRead
853+
830854
| .needFixedBody size =>
831855
let (machine, result) := parseWith machine (parseFixedSizeData size) (limit := none) (some size)
832856

833857
if let some body := result then
834858
match body with
835-
| .complete body => machine
859+
| .complete body =>
860+
machine
836861
|>.setReaderState .complete
837862
|>.addEvent (.gotData true body)
863+
|>.processRead
838864
| .incomplete body remaining =>
839865
machine
840866
|>.setReaderState (.needFixedBody remaining)
@@ -878,31 +904,32 @@ def takeOutput (machine : Machine) (highMark := 0): Option (Machine × BufferBui
878904
/--
879905
Write response data to the machine
880906
-/
881-
def processWrite (machine : Machine) : Machine :=
907+
partial def processWrite (machine : Machine) : Machine :=
882908
match machine.writer.state with
883909
| .waitingHeaders =>
884910
machine
885911

886912
| .waitingForFlush =>
887913
if machine.shouldFlush then
888-
machine.setHeaders machine.writer.response
914+
machine.setHeaders machine.writer.response |>.processWrite
889915
else
890916
machine
891917

892918
| .writingFixedData =>
893919
if machine.writer.userData.size ≥ machine.config.highMark ∨ machine.writer.closed then
894920
let machine := machine.modifyWriter Writer.writeFixedBody
895921
if machine.writer.closed then
896-
machine.setWriterState .complete
922+
machine.setWriterState .complete |>.processWrite
897923
else
898924
machine
899925
else
900926
machine
927+
901928
| .writingChunkedBody =>
902929
if machine.writer.closed then
903-
machine.modifyWriter Writer.writeFinalChunk
930+
machine.modifyWriter Writer.writeFinalChunk |>.processWrite
904931
else if machine.writer.userData.size ≥ machine.config.highMark then
905-
machine.modifyWriter Writer.writeChunkedBody
932+
machine.modifyWriter Writer.writeChunkedBody |>.processWrite
906933
else
907934
machine
908935

src/Std/Internal/Http/Server.lean

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,33 @@ module
77

88
prelude
99
public import Std.Internal.Http.Server.Connection
10+
public import Std.Internal.Http.Server.Client
11+
12+
public section
13+
14+
namespace Std
15+
namespace Http
16+
namespace Server
17+
18+
open Std Internal IO Async TCP
19+
open Time
20+
21+
/--
22+
Serve conection
23+
-/
24+
def serve
25+
(addr : Net.SocketAddress)
26+
(onRequest : Request Body → Async (Response Body))
27+
(onReady : Async Unit := pure ())
28+
(onFailure : Error → Async Unit := fun _ => pure ())
29+
(config : Config := {})
30+
(backlog : UInt32 := 128) : Async Unit := do
31+
let server ← Socket.Server.mk
32+
server.bind addr
33+
server.listen backlog
34+
35+
onReady
36+
37+
while true do
38+
let client ← server.accept
39+
background (prio := .max) <| serveConnection client onRequest onFailure config

0 commit comments

Comments
 (0)