Files
async-http-client/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientResponse.swift
T
Cory Benfield 5e3e58dafd Use Docc for documentation (#613)
Motivation

Documentation is nice, and we can help support users by providing useful
clear docs.

Modifications

Add Docc to 5.6 and later builds
Make sure symbol references work
Add overview docs

Result

Nice rendering docs
2022-08-09 16:23:14 +01:00

132 lines
4.0 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the AsyncHTTPClient open source project
//
// Copyright (c) 2021 Apple Inc. and the AsyncHTTPClient project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
#if compiler(>=5.5.2) && canImport(_Concurrency)
import NIOCore
import NIOHTTP1
/// A representation of an HTTP response for the Swift Concurrency HTTPClient API.
///
/// This object is similar to ``HTTPClient/Response``, but used for the Swift Concurrency API.
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public struct HTTPClientResponse {
/// The HTTP version on which the response was received.
public var version: HTTPVersion
/// The HTTP status for this response.
public var status: HTTPResponseStatus
/// The HTTP headers of this response.
public var headers: HTTPHeaders
/// The body of this HTTP response.
public var body: Body
/// A representation of the response body for an HTTP response.
///
/// The body is streamed as an `AsyncSequence` of `ByteBuffer`, where each `ByteBuffer` contains
/// an arbitrarily large chunk of data. The boundaries between `ByteBuffer` objects in the sequence
/// are entirely synthetic and have no semantic meaning.
public struct Body {
private let bag: Transaction
private let reference: ResponseRef
fileprivate init(_ transaction: Transaction) {
self.bag = transaction
self.reference = ResponseRef(transaction: transaction)
}
}
init(
bag: Transaction,
version: HTTPVersion,
status: HTTPResponseStatus,
headers: HTTPHeaders
) {
self.body = Body(bag)
self.version = version
self.status = status
self.headers = headers
}
}
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension HTTPClientResponse.Body: AsyncSequence {
public typealias Element = AsyncIterator.Element
public struct AsyncIterator: AsyncIteratorProtocol {
private let stream: IteratorStream
fileprivate init(stream: IteratorStream) {
self.stream = stream
}
public mutating func next() async throws -> ByteBuffer? {
try await self.stream.next()
}
}
public func makeAsyncIterator() -> AsyncIterator {
AsyncIterator(stream: IteratorStream(bag: self.bag))
}
}
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension HTTPClientResponse.Body {
/// The purpose of this object is to inform the transaction about the response body being deinitialized.
/// If the users has not called `makeAsyncIterator` on the body, before it is deinited, the http
/// request needs to be cancelled.
fileprivate class ResponseRef {
private let transaction: Transaction
init(transaction: Transaction) {
self.transaction = transaction
}
deinit {
self.transaction.responseBodyDeinited()
}
}
}
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension HTTPClientResponse.Body {
internal class IteratorStream {
struct ID: Hashable {
private let objectID: ObjectIdentifier
init(_ object: IteratorStream) {
self.objectID = ObjectIdentifier(object)
}
}
private var id: ID { ID(self) }
private let bag: Transaction
init(bag: Transaction) {
self.bag = bag
}
deinit {
self.bag.responseBodyIteratorDeinited(streamID: self.id)
}
func next() async throws -> ByteBuffer? {
try await self.bag.nextResponsePart(streamID: self.id)
}
}
}
#endif