Skip to content

Commit 1e38825

Browse files
authored
Strict concurrency checking for ObliviousHTTP and ObliviousX (#33)
Motivation: To increase concurrency safety the ObliviousHTTP and ObliviousX modules should compile without warning under strict concurrency checking. Modifications: - Add explicit Sendable annotations - Add `@preconcurrency` to the `Crpto` import as it's not yet concurrency clean. Result: No concurrency warnings.
1 parent e42a0a4 commit 1e38825

File tree

4 files changed

+42
-18
lines changed

4 files changed

+42
-18
lines changed

Package.swift

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,24 @@
1515

1616
import PackageDescription
1717

18+
let strictConcurrencyDevelopment = false
19+
20+
let strictConcurrencySettings: [SwiftSetting] = {
21+
var initialSettings: [SwiftSetting] = []
22+
initialSettings.append(contentsOf: [
23+
.enableUpcomingFeature("StrictConcurrency"),
24+
.enableUpcomingFeature("InferSendableFromCaptures"),
25+
])
26+
27+
if strictConcurrencyDevelopment {
28+
// -warnings-as-errors here is a workaround so that IDE-based development can
29+
// get tripped up on -require-explicit-sendable.
30+
initialSettings.append(.unsafeFlags(["-require-explicit-sendable", "-warnings-as-errors"]))
31+
}
32+
33+
return initialSettings
34+
}()
35+
1836
let package = Package(
1937
name: "swift-nio-oblivious-http",
2038
platforms: [
@@ -34,7 +52,7 @@ let package = Package(
3452
),
3553
],
3654
dependencies: [
37-
.package(url: "https://github.com/apple/swift-nio.git", from: "2.54.0"),
55+
.package(url: "https://github.com/apple/swift-nio.git", from: "2.81.0"),
3856
.package(url: "https://github.com/apple/swift-crypto.git", from: "3.0.0"),
3957
],
4058
targets: [
@@ -43,13 +61,15 @@ let package = Package(
4361
dependencies: [
4462
.product(name: "NIOCore", package: "swift-nio"),
4563
.product(name: "NIOHTTP1", package: "swift-nio"),
46-
]
64+
],
65+
swiftSettings: strictConcurrencySettings
4766
),
4867
.target(
4968
name: "ObliviousX",
5069
dependencies: [
5170
.product(name: "Crypto", package: "swift-crypto")
52-
]
71+
],
72+
swiftSettings: strictConcurrencySettings
5373
),
5474
.testTarget(
5575
name: "ObliviousHTTPTests",
@@ -58,14 +78,16 @@ let package = Package(
5878
.product(name: "Crypto", package: "swift-crypto"),
5979
.product(name: "NIOCore", package: "swift-nio"),
6080
.product(name: "NIOHTTP1", package: "swift-nio"),
61-
]
81+
],
82+
swiftSettings: strictConcurrencySettings
6283
),
6384
.testTarget(
6485
name: "ObliviousXTests",
6586
dependencies: [
6687
"ObliviousX",
6788
.product(name: "Crypto", package: "swift-crypto"),
68-
]
89+
],
90+
swiftSettings: strictConcurrencySettings
6991
),
7092
]
7193
)

Sources/ObliviousHTTP/BHTTPParser.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import NIOCore
1515
import NIOHTTP1
1616

1717
/// Binary HTTP parser as described in [RFC9292](https://www.rfc-editor.org/rfc/rfc9292).
18-
public struct BHTTPParser {
18+
public struct BHTTPParser: Sendable {
1919
private var buffer: ByteBuffer?
2020
private var state: State
2121
private var role: Role
@@ -447,7 +447,7 @@ extension BHTTPParser {
447447
}
448448

449449
/// Role to assume when parsing binary HTTP
450-
public enum Role {
450+
public enum Role: Sendable {
451451
case client
452452
case server
453453

@@ -471,7 +471,7 @@ extension BHTTPParser {
471471
}
472472

473473
/// Part of overall HTTP request or response.
474-
public enum Message {
474+
public enum Message: Sendable {
475475
case request(HTTPServerRequestPart)
476476
case response(HTTPClientResponsePart)
477477
}

Sources/ObliviousHTTP/BHTTPSerializer.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import NIOHTTP1
2121
// Later optimizations can be made by adding more state into this type.
2222
/// Binary HTTP serialiser as described in [RFC9292](https://www.rfc-editor.org/rfc/rfc9292).
2323
/// Currently only indeterminate-length encoding is supported.
24-
public struct BHTTPSerializer {
24+
public struct BHTTPSerializer: Sendable {
2525
/// Initialise a Binary HTTP Serialiser.
2626
public init() {}
2727

@@ -96,7 +96,7 @@ public struct BHTTPSerializer {
9696

9797
extension BHTTPSerializer {
9898
/// Types of message for binary http serilaisation
99-
public enum Message {
99+
public enum Message: Sendable {
100100
/// Part of an HTTP request.
101101
case request(HTTPClientRequestPart)
102102
/// Part of an HTTP response.

Sources/ObliviousX/OHTTPEncapsulation.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
// SPDX-License-Identifier: Apache-2.0
1212
//
1313
//===----------------------------------------------------------------------===//
14-
import Crypto
14+
@preconcurrency import Crypto
1515
import Foundation
1616

1717
/// Functionality to add oblivious HTTP style encapsulation to data messages.
1818
@available(macOS 14, iOS 17, *)
19-
public enum OHTTPEncapsulation {
20-
/// Encapsulate a request messge.
19+
public enum OHTTPEncapsulation: Sendable {
20+
/// Encapsulate a request message.
2121
/// - Parameters:
2222
/// - keyID: Key Id to send.
2323
/// - publicKey: Public key for the recipient.
@@ -47,7 +47,7 @@ public enum OHTTPEncapsulation {
4747
}
4848

4949
/// Stream a request in multiple chunks.
50-
public struct StreamingRequest {
50+
public struct StreamingRequest: Sendable {
5151
/// Bytes representation of header.
5252
public let header: Data
5353
/// Sender used to seal messages.
@@ -127,7 +127,7 @@ public enum OHTTPEncapsulation {
127127
}
128128

129129
/// Encapsulated request header.
130-
public struct RequestHeader {
130+
public struct RequestHeader: Sendable {
131131
/// Key Id specified.
132132
public private(set) var keyID: UInt8
133133

@@ -148,7 +148,7 @@ public enum OHTTPEncapsulation {
148148
}
149149

150150
/// Functionality to remove oblivious encapsulation from a series of request chunks.
151-
public struct StreamingRequestDecapsulator {
151+
public struct StreamingRequestDecapsulator: Sendable {
152152
/// The request header.
153153
public private(set) var header: RequestHeader
154154

@@ -285,7 +285,7 @@ public enum OHTTPEncapsulation {
285285
}
286286

287287
/// Processor for a series of response chunks.
288-
public struct StreamingResponse {
288+
public struct StreamingResponse: Sendable {
289289
private let responseNonce: Data
290290

291291
private var aeadNonce: Data
@@ -380,7 +380,7 @@ public enum OHTTPEncapsulation {
380380
}
381381

382382
/// Decapsulator which can process a response as a series of chunks.
383-
public struct StreamingResponseDecapsulator {
383+
public struct StreamingResponseDecapsulator: Sendable {
384384
enum State {
385385
case awaitingResponseNonce(
386386
mediaType: String,
@@ -518,6 +518,8 @@ public enum OHTTPEncapsulation {
518518
}
519519
}
520520

521+
extension OHTTPEncapsulation.RequestDecapsulator: Sendable where Bytes: Sendable {}
522+
521523
extension RandomAccessCollection where Element == UInt8, Self == Self.SubSequence {
522524
mutating func popUInt8() -> UInt8? {
523525
self.popFirst()

0 commit comments

Comments
 (0)