Releases: swhitty/FlyingFox
Large Requests with HTTPBodySequence
Adds support for very large bodies within HTTPRequest and HTTPResponse that can be processed in Data chunks.
HTTPRequest
Requests now include a bodySequence: HTTPBodySequence which allows the request body to be iterated in small chunks as the arrive:
func saveBody(request: HTTPRequest) async throws -> HTTPResponse {
let file = URL(fileURLWithPath: "/tmp/file")
_ = FileManager.default.createFile(atPath: file.path, contents: nil)
let handle = try FileHandle(forWritingTo: file)
for try await chunk in req.bodySequence {
try handle.write(contentsOf: chunk)
}
return HTTPResponse(statusCode: .ok)
}The existing var data: Data property has been deprecated, but is still supported and synchronously returns the uploaded data for requests less than 10 MiB.
HTTPResponse
Response payloads can provide a HTTPBodySequence which allows the response body to be provided in small chunks as they are sent:
func getXcode(request: HTTPRequest) async throws -> HTTPResponse {
try HTTPResponse(
statusCode: .ok,
body: HTTPBodySequence(file: URL(fileURLWithPath: "/tmp/Xcode_14.3.xip"))
)
}Providing a Data instance for the body property is still supported.
The existing var data: Data? property has been deprecated, but is still supported and synchronously returns response payload if the response is not a web socket or HTTPBodySequence.
FileHTTPHandler
The existing FileHTTPHandler now serves all files larger than 10 MiB in small chunks, while files smaller are still served via a complete Data instance.
SocketPool kqueue / epoll
kqueue(2)/epoll(7)events are now used to suspend and resume socket usingSocketPool<EventQueue>SocketPool<EventQueue>is now the default pool used byHTTPServerPollingSocketPoolhas been replaced bySocketPool<Poll>- Windows uses
SocketPool<Poll> - Moved
HTTPLoggingtoFlyingSocks.Loggingenabling logs within sockets and pools. - Decreased compilation time
epoll Fix
Support for kqueue / epoll
- Gracefully finish existing requests then stop server with
await server.stop() - Retrieve the server listening address with
await server.listeningAddress - Use
makeEventQueuePool()to enablekqueue(2)on Darwin platforms andepoll(7)on Linux. PollingSocketPoolremains the default socket pool.- Fixes WebSocket bug where connection would not be removed after disconnection.
- Fixes for Swift 5.7 related warnings
Swift 5.7 Support
- Support for building and testing with Swift 5.7 (Xcode 14 beta).
- CancellingContinuation ensures cancellation does not escape actor isolated methods.
- Updates default
PollingSocketPoolinterval to not block the cooperative task pool at all.
0.7.0
import FlyingSocksmodule exposes the underlying async sockets that power FlyingFoxHTTPServercan be started with anyAsyncSocketPool.PollingSocketPoolcan be tuned to control the interval before and after each loop.- Improved concurrency checking support on Swift 5.6
- Experimental support for Windows 10
0.6.0
WebSocketHTTPHandlerenables support for WebSockets allowing handlers to exchange pair of AsyncStream.DirectoryHTTPHandlerto automatically share all files within a directory.- Groups
sockaddrstructures withprotocol SocketAddress - Supports UNIX-domain sockets via
sockaddr_un
0.5.0
0.4.1
0.4.0
Several enhancements have been made to HTTPRoute that enable fine grained pattern matching of requests.
Query items can now be matched:
await server.appendRoute("GET /meal?side=fish", to: .file(named: "meal-fish.json"))
await server.appendRoute("GET /meal?side=chips", to: .file(named: "meal-chips.json"))HTTP headers can also be matched:
let json = HTTPRoute("*", headers: [.contentType: "application/json"])
let xml = HTTPRoute("*", headers: [.contentType: "application/xml"])
await server.appendRoute(json, to: .file(named: "sample.json"))
await server.appendRoute(xml, to: .file(named: "sample.xml"))And request body can also be matched:
public protocol HTTPBodyPattern: Sendable {
func evaluate(_ body: Data) -> Bool
}Darwin platforms can pattern match a JSON body with an NSPredicate:
let route = HTTPRoute("POST *", body: .json(where: "food == 'fish'")){"side": "chips", "food": "fish"}