-
Notifications
You must be signed in to change notification settings - Fork 713
feat: adds a simple Http library to Std
#10478
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
algebraic-dev
wants to merge
130
commits into
sofia/async-context
Choose a base branch
from
sofia/async-http
base: sofia/async-context
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
130 commits
Select commit
Hold shift + click to select a range
3f4baab
feat: async type classes
algebraic-dev 437fb04
feat: remove outparams
algebraic-dev 0bad6ae
fix: remove useless function
algebraic-dev 992b946
fix: stream can only return one type
algebraic-dev 9dbca20
feat: async traits
algebraic-dev 9337835
fix: small fixes
algebraic-dev 1170afb
fix: wrong function
algebraic-dev f8e4ca4
fix: channel
algebraic-dev 8a61ba5
feat: basics stream map
algebraic-dev b4165be
fix: stream map
algebraic-dev 46b1352
fix: channel
algebraic-dev 1ad1eaf
fix: async stream
algebraic-dev 9ed922e
fix: streammap
algebraic-dev 39a3086
fix: async
algebraic-dev 1f0e383
fix: small comments
algebraic-dev cf67727
fix: async
algebraic-dev 6ddd405
fix: simplify
algebraic-dev 527a5d3
feat: cancellation
algebraic-dev 0fe4086
fix: streammap
algebraic-dev f4d67f4
fix: async
algebraic-dev 78f2f96
feat: http
algebraic-dev 1bf975b
fix: copyright notice
algebraic-dev 284825c
fix: coe option
algebraic-dev 73aa8e7
fix: imports
algebraic-dev 4b4e4dc
fix: remove orphaned module
algebraic-dev cc3776a
fix: funnel imports
algebraic-dev 66a9dfa
fix: imports
algebraic-dev 505f986
feat: tests and small changes
algebraic-dev 1fe5b21
fix: bytestream
algebraic-dev 7cfd285
fix: remove useless coe
algebraic-dev de91f32
feat: add header value validation
algebraic-dev 6ce62bb
fix: merge
algebraic-dev 1922fda
fix: test and small comments
algebraic-dev 594e713
feat: small changes
algebraic-dev 58b4f98
fix: url parser
algebraic-dev 9205242
fix: comment and bytebuffer
algebraic-dev 3df4884
fix: comments
algebraic-dev 87c960d
fix: bytestream comments
algebraic-dev 4019179
fix: comments
algebraic-dev 10d58c5
fix: style changes
algebraic-dev ac80739
feat: improve comment of serveConnection
algebraic-dev 4df0c69
fix: small changes
algebraic-dev 0912602
feat: small changes
algebraic-dev 71b83c0
fix: update to master
algebraic-dev 51d8cfc
fix: timeout
algebraic-dev 2e03c22
fix: test
algebraic-dev 957fe41
feat: rename
algebraic-dev 761b703
refactor: http
algebraic-dev 974c9ec
feat: http client
algebraic-dev a31a891
feat: async type classes
algebraic-dev c446ecf
feat: remove outparams
algebraic-dev aacbe82
fix: remove useless function
algebraic-dev d590af5
fix: stream can only return one type
algebraic-dev 883bf66
feat: async traits
algebraic-dev 586c171
fix: small fixes
algebraic-dev 4dc56a4
fix: wrong function
algebraic-dev d63e682
fix: channel
algebraic-dev 510707f
feat: basics stream map
algebraic-dev b6fb42c
fix: stream map
algebraic-dev 1cde50a
fix: channel
algebraic-dev 78daa21
fix: async stream
algebraic-dev f46367a
fix: streammap
algebraic-dev 131b53f
fix: async
algebraic-dev 01a0aae
fix: small comments
algebraic-dev f0fcdff
fix: async
algebraic-dev 3288469
fix: simplify
algebraic-dev ee9bd54
feat: cancellation
algebraic-dev ae003a9
fix: streammap
algebraic-dev a7ae09d
fix: async
algebraic-dev e4b5ca9
feat: http
algebraic-dev 4660d4a
fix: remove orphaned module
algebraic-dev eeb47fc
fix: funnel imports
algebraic-dev 37fc80f
feat: tests and small changes
algebraic-dev a666d29
fix: bytestream
algebraic-dev 1bc8051
feat: add header value validation
algebraic-dev f380b3b
feat: small changes
algebraic-dev 28a3cfd
fix: comment and bytebuffer
algebraic-dev 082ac99
fix: comments
algebraic-dev 424fb96
fix: comments
algebraic-dev 9355655
fix: style changes
algebraic-dev 8af48ff
feat: small changes
algebraic-dev 45395fc
fix: update to master
algebraic-dev cdaed1f
fix: http
algebraic-dev d73e211
fix: remove orphaned modules
algebraic-dev aea10b7
fix: selectors
algebraic-dev 9074763
feat: small changes
algebraic-dev 56dd8f4
feat: closePeerConnection
algebraic-dev da1d565
fix: behavior of the client
algebraic-dev 232fc85
fix: copyright header
algebraic-dev ef8c989
fix: remove macro
algebraic-dev 78df363
fix: comment
algebraic-dev 2f91b3c
feat: improve chunk extensions and handling of shutdown
algebraic-dev 9ab5445
fix: remove log
algebraic-dev f612eca
feat: big refactor
algebraic-dev ce0c271
refactor: part of the connection API
algebraic-dev 75b24dd
fix: headers
algebraic-dev f00b88d
fix: protocol
algebraic-dev bbc7a19
fix: small issues with chunks and comments
algebraic-dev 5afc6c6
feat: remove useless variable
algebraic-dev e88e84d
fix: remove small useless things
algebraic-dev 562f504
fix: loop
algebraic-dev 6052b2a
feat: header detection and duplication
algebraic-dev 9c10bc5
feat: limits and tests
algebraic-dev 7391d81
fix: copyright header
algebraic-dev 47d71cd
fix: test
algebraic-dev e36bb26
fix: import structure
algebraic-dev 87fe876
feat: small improvements in tests and client
algebraic-dev 59c617b
feat: header changes
algebraic-dev 59a0171
fix: test
algebraic-dev 7b7d49e
fix: bug fixes and improvement in performance
algebraic-dev 148f83f
fix: tests
algebraic-dev edd9759
fix: remove client related
algebraic-dev a389f93
fix: details of connection: close
algebraic-dev ce85f65
fix: test
algebraic-dev fd36c96
fix: weird behaviro when message as not sent :)
algebraic-dev 942c044
fix: multiple small problems
algebraic-dev 9e7d485
fix: string changes
algebraic-dev beaa1e6
fix: trailers parsing
algebraic-dev ba27d70
feat: parse chunk
algebraic-dev a0c9b3a
fix: trailer
algebraic-dev 709fea1
fix: parser
algebraic-dev 1c590b5
fix: grammatical issues
algebraic-dev b9d0c50
fix: gramatic issues
algebraic-dev 99bc6ce
fix: ext chunk
algebraic-dev 912025d
fix: context
algebraic-dev dfdb3b5
feat: contextual fixes
algebraic-dev 6c3e392
feat: add more tests
algebraic-dev aa5a6d3
fix: docs
algebraic-dev 0489523
fix: comments
algebraic-dev db6975c
feat: cancellation backwards
algebraic-dev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| /- | ||
| Copyright (c) 2025 Lean FRO, LLC. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Sofia Rodrigues | ||
| -/ | ||
| module | ||
|
|
||
| prelude | ||
| public import Std.Internal.Http.Server | ||
|
|
||
| public section | ||
|
|
||
| /-! | ||
| # Http | ||
|
|
||
| A "low-level" HTTP 1.1 Server implementation for Lean. It is designed to be used with or without the | ||
| `Async` library if you want to implement a custom `Connection`. | ||
|
|
||
| # Overview | ||
|
|
||
| This module of the standard library defines many concepts related to the HTTP protocol and its semantics | ||
| in a sans I/O format. | ||
|
|
||
| **sans I/O** means that the core logic of the library doesn’t perform any actual input/output itself, | ||
| it just defines how data *should* be processed. This separation allows the protocol implementation | ||
| to remain pure and testable, while different transports (like TCP sockets or mocks) can handle | ||
| the actual reading and writing of bytes. | ||
|
|
||
| The main function of this library is `Std.Http.Server.serve`, | ||
| located in the module `Std.Internal.Http.Server`. It starts a simple HTTP/1.1 server that | ||
| handles all requests and sends them to a simple handler function. It uses the default `Std.Internal.Async` | ||
| library, but it can be customized to use whatever IO library you want, as the protocol implementation | ||
| is pure. | ||
|
|
||
| If you want to customize how your server handles sockets, you can use `Std.Http.Server.serveConnection`, | ||
| which is a simple function to bind a handler to a `Transport`. | ||
|
|
||
| # Minimal Example | ||
|
|
||
| ```lean | ||
| import Std.Internal.Http | ||
| import Std.Internal.Async | ||
|
|
||
| open Std.Internal.IO.Async | ||
| open Std Http | ||
|
|
||
| def handler (req : Request Body) : ContextAsync (Response Body) := do | ||
| let some data ← req.body.collectString | ||
| | return Response.badRequest "expected a utf8 body" | ||
|
|
||
| return Response.ok ("hi, " ++ data) | ||
|
|
||
| def mainAsync : Async Unit := do | ||
| let address := .v4 (.mk (.ofParts 0 0 0 0) 8080) | ||
| let server ← Server.serve address handler | ||
| server.waitShutdown | ||
|
|
||
| def main := mainAsync.block | ||
| ``` | ||
|
|
||
| # Main Concepts | ||
|
|
||
| ## Transport | ||
|
|
||
| `Std.Http.Server.Transport` is a type class that defines how communication occurs between a `Connection` | ||
| and the outside world. It can be implemented by, for example, a `Mock.Client`, which sends and receives | ||
| byte arrays for deterministic HTTP connection testing, or by a `TCP.Socket.Client`, which is the | ||
| standard way to communicate over the internet in HTTP/1.1. | ||
|
|
||
| ## Connection | ||
|
|
||
| `Std.Http.Server.Connection` is a structure that holds both a `Transport` and a `Machine`. The machine is | ||
| a `Protocol.H1.Machine`, which implements the state machine responsible for parsing HTTP/1.1 requests and responses. | ||
| It can change in the future if some other protocols are implemented | ||
|
|
||
| If you want to customize how your server handles sockets, you can use `Std.Http.Server.serveConnection`, | ||
| a simple function that binds a handler to a `ClientConnection`. | ||
|
|
||
| # Minimal Example | ||
|
|
||
| ```lean | ||
| import Std.Internal.Http | ||
| import Std.Internal.Async | ||
|
|
||
| open Std.Internal.IO.Async | ||
| open Std Http | ||
|
|
||
| def handler (req : Request Body) : ContextAsync (Response Body) := do | ||
| let some data ← req.body.collectString | ||
| | return Response.badRequest "expected a utf8 body" | ||
|
|
||
| return Response.ok ("hi, " ++ data) | ||
|
|
||
| def mainAsync : Async Unit := do | ||
| let server ← Server.serve (.v4 (.mk (.ofParts 0 0 0 0) 8080)) handler | ||
| server.waitShutdown | ||
|
|
||
| def main := mainAsync.block | ||
| ``` | ||
| -/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| /- | ||
| Copyright (c) 2025 Lean FRO, LLC. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Sofia Rodrigues | ||
| -/ | ||
| module | ||
|
|
||
| prelude | ||
| public import Std.Internal.Http.Data.Body | ||
| public import Std.Internal.Http.Data.Headers | ||
| public import Std.Internal.Http.Data.Method | ||
| public import Std.Internal.Http.Data.Version | ||
| public import Std.Internal.Http.Data.Request | ||
| public import Std.Internal.Http.Data.Response | ||
| public import Std.Internal.Http.Data.URI | ||
| public import Std.Internal.Http.Data.Status | ||
| public import Std.Internal.Http.Data.Version |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| /- | ||
| Copyright (c) 2025 Lean FRO, LLC. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Sofia Rodrigues | ||
| -/ | ||
| module | ||
|
|
||
| prelude | ||
| public import Std.Internal.Async.Context | ||
| public import Std.Internal.Http.Data.Body.Length | ||
| public import Std.Internal.Http.Data.Body.ByteStream | ||
|
|
||
| public section | ||
|
|
||
| /-! | ||
| # Body | ||
|
|
||
| This module defines the `Body` type, which represents the body of an HTTP request or response. | ||
| -/ | ||
|
|
||
| namespace Std.Http | ||
|
|
||
| open Std Internal IO Async | ||
|
|
||
| /-- | ||
| Type that represents the body of a request or response with streams of byte arrays or byte arrays of fixed | ||
| size. | ||
| -/ | ||
| inductive Body where | ||
| /-- | ||
| Empty body with no content | ||
| -/ | ||
| | zero | ||
|
|
||
| /-- | ||
| Body containing raw byte data stored in memory | ||
| -/ | ||
| | bytes (data : ByteArray) | ||
|
|
||
| /-- | ||
| Body containing streaming data from a byte stream channel | ||
| -/ | ||
| | stream (channel : Body.ByteStream) | ||
| deriving Inhabited | ||
|
|
||
| namespace Body | ||
|
|
||
| /-- | ||
| Get content length of a body (if known). | ||
| -/ | ||
| def getContentLength (body : Body) : Length := | ||
| match body with | ||
| | zero => .fixed 0 | ||
| | .bytes data => .fixed data.size | ||
| | .stream _ => .chunked | ||
|
|
||
| /-- | ||
| Close the body and release any associated resources. For streaming bodies, this closes the underlying | ||
| channel. For other body types, this is a no-op. | ||
| -/ | ||
| def close (body : Body) : Async Unit := | ||
| match body with | ||
| | .stream channel => channel.close | ||
| | _ => pure () | ||
|
|
||
| instance : Coe String Body where | ||
| coe := .bytes ∘ String.toUTF8 | ||
|
|
||
| instance : Coe ByteArray Body where | ||
| coe := .bytes | ||
|
|
||
| instance : Coe Body.ByteStream Body where | ||
| coe := .stream | ||
|
|
||
| instance : EmptyCollection Body where | ||
| emptyCollection := Body.zero | ||
|
|
||
| instance : ForIn Async Body Chunk where | ||
| forIn body acc step := | ||
| match body with | ||
| | .zero => pure acc | ||
| | .bytes data => return (← step (Chunk.mk data #[]) acc).value | ||
| | .stream stream' => ByteStream.forIn stream' acc step | ||
|
|
||
| instance : ForIn ContextAsync Body Chunk where | ||
| forIn body acc step := | ||
| match body with | ||
| | .zero => pure acc | ||
| | .bytes data => return (← step (Chunk.mk data #[]) acc).value | ||
| | .stream stream' => ByteStream.forIn' stream' acc step | ||
|
|
||
| /-- | ||
| Collect all data from the body into a single `ByteArray`. This reads the entire body content into memory | ||
| and consumes significant memory for large bodies. | ||
| -/ | ||
| def collectByteArray (body : Body) : Async ByteArray := do | ||
| let mut result := .empty | ||
| for x in body do result := result ++ x.data | ||
| return result | ||
|
|
||
| /-- | ||
| Collect all data from the body into a single `String`. This reads the entire body content into memory | ||
| and consumes significant memory for large bodies. Returns `some` if the data is valid UTF-8, otherwise | ||
| `none`. | ||
| -/ | ||
| def collectString (body : Body) : Async (Option String) := do | ||
| let mut result := .empty | ||
| for x in body do result := result ++ x.data | ||
| return String.fromUTF8? result |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.