forked from apple/swift-http-api-proposal
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHTTPServerRequestHandlerMiddleware.swift
More file actions
99 lines (91 loc) · 4.19 KB
/
Copy pathHTTPServerRequestHandlerMiddleware.swift
File metadata and controls
99 lines (91 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift HTTP API Proposal open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift HTTP API Proposal project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
public import HTTPAPIs
public import Middleware
/// A terminal middleware that echoes HTTP request bodies back as responses.
///
/// ``HTTPServerRequestHandlerMiddleware`` serves as an example terminal middleware that reads
/// the entire request body and writes it back as the response body with a 200 OK status.
/// This middleware has `Never` as its `NextInput` type, indicating it's the end of the chain.
@available(anyAppleOS 26.0, *)
public struct HTTPServerRequestHandlerMiddleware<
RequestConcludingAsyncReader: ConcludingAsyncReader & ~Copyable,
ResponseConcludingAsyncWriter: ConcludingAsyncWriter & ~Copyable,
>: Middleware, Sendable
where
RequestConcludingAsyncReader.Underlying: ~Copyable,
RequestConcludingAsyncReader.Underlying.ReadElement == UInt8,
RequestConcludingAsyncReader.FinalElement == HTTPFields?,
ResponseConcludingAsyncWriter.Underlying: ~Copyable,
ResponseConcludingAsyncWriter.Underlying.WriteElement == UInt8,
ResponseConcludingAsyncWriter.FinalElement == HTTPFields?
{
public typealias Input = HTTPServerMiddlewareInput<RequestConcludingAsyncReader, ResponseConcludingAsyncWriter>
public typealias NextInput = Void
/// Creates a new request handler middleware.
public init() {}
public func intercept<Return: ~Copyable>(
input: consuming Input,
next: (consuming NextInput) async throws -> Return
) async throws -> Return {
try await input.withContents { request, _, requestBodyAndTrailers, responseSender in
// Needed since we are lacking call-once closures
var responseSender: HTTPResponseSender<ResponseConcludingAsyncWriter>? = consume responseSender
_ = try await requestBodyAndTrailers.consumeAndConclude { reader in
// Needed since we are lacking call-once closures
var reader: RequestConcludingAsyncReader.Underlying? = consume reader
let responseBodyAndTrailers = try await responseSender.take()!.send(.init(status: .ok))
try await responseBodyAndTrailers.produceAndConclude { responseBody in
var responseBody = responseBody
try await responseBody.write(reader.take()!)
return nil
}
}
}
return try await next(())
}
}
@available(anyAppleOS 26.0, *)
extension Middleware where Input: ~Copyable, NextInput: ~Copyable {
/// Creates a request handler middleware that echoes the request body back as the response.
///
/// This is a simple example middleware that reads the entire request body and writes it
/// back as the response with a 200 OK status. This middleware is the terminal middleware
/// in the chain and has `Never` as its `NextInput` type.
///
/// - Returns: A middleware that handles HTTP requests by echoing the body.
///
/// ## Example
///
/// ```swift
/// @MiddlewareBuilder
/// func buildMiddleware() -> some Middleware<...> {
/// .logging(logger: Logger(label: "HTTPServer"))
/// .requestHandler()
/// }
/// ```
public func requestHandler<RequestReader, ResponseWriter>() -> HTTPServerRequestHandlerMiddleware<RequestReader, ResponseWriter>
where
Input == HTTPServerMiddlewareInput<RequestReader, ResponseWriter>,
RequestReader: ConcludingAsyncReader & ~Copyable,
RequestReader.Underlying: ~Copyable,
RequestReader.Underlying.ReadElement == UInt8,
RequestReader.FinalElement == HTTPFields?,
ResponseWriter: ConcludingAsyncWriter & ~Copyable,
ResponseWriter.Underlying: ~Copyable,
ResponseWriter.Underlying.WriteElement == UInt8,
ResponseWriter.FinalElement == HTTPFields?
{
HTTPServerRequestHandlerMiddleware()
}
}