initial
This commit is contained in:
153
Pods/Alamofire/Source/RequestCompression.swift
generated
Normal file
153
Pods/Alamofire/Source/RequestCompression.swift
generated
Normal file
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// RequestCompression.swift
|
||||
//
|
||||
// Copyright (c) 2023 Alamofire Software Foundation (http://alamofire.org/)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if canImport(zlib)
|
||||
import Foundation
|
||||
import zlib
|
||||
|
||||
/// `RequestAdapter` which compresses outgoing `URLRequest` bodies using the `deflate` `Content-Encoding` and adds the
|
||||
/// appropriate header.
|
||||
///
|
||||
/// - Note: Most requests to most APIs are small and so would only be slowed down by applying this adapter. Measure the
|
||||
/// size of your request bodies and the performance impact of using this adapter before use. Using this adapter
|
||||
/// with already compressed data, such as images, will, at best, have no effect. Additionally, body compression
|
||||
/// is a synchronous operation, so measuring the performance impact may be important to determine whether you
|
||||
/// want to use a dedicated `requestQueue` in your `Session` instance. Finally, not all servers support request
|
||||
/// compression, so test with all of your server configurations before deploying.
|
||||
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||
public struct DeflateRequestCompressor: RequestInterceptor {
|
||||
/// Type that determines the action taken when the `URLRequest` already has a `Content-Encoding` header.
|
||||
public enum DuplicateHeaderBehavior {
|
||||
/// Throws a `DuplicateHeaderError`. The default.
|
||||
case error
|
||||
/// Replaces the existing header value with `deflate`.
|
||||
case replace
|
||||
/// Silently skips compression when the header exists.
|
||||
case skip
|
||||
}
|
||||
|
||||
/// `Error` produced when the outgoing `URLRequest` already has a `Content-Encoding` header, when the instance has
|
||||
/// been configured to produce an error.
|
||||
public struct DuplicateHeaderError: Error {}
|
||||
|
||||
/// Behavior to use when the outgoing `URLRequest` already has a `Content-Encoding` header.
|
||||
public let duplicateHeaderBehavior: DuplicateHeaderBehavior
|
||||
/// Closure which determines whether the outgoing body data should be compressed.
|
||||
public let shouldCompressBodyData: (_ bodyData: Data) -> Bool
|
||||
|
||||
/// Creates an instance with the provided parameters.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - duplicateHeaderBehavior: `DuplicateHeaderBehavior` to use. `.error` by default.
|
||||
/// - shouldCompressBodyData: Closure which determines whether the outgoing body data should be compressed. `true` by default.
|
||||
public init(duplicateHeaderBehavior: DuplicateHeaderBehavior = .error,
|
||||
shouldCompressBodyData: @escaping (_ bodyData: Data) -> Bool = { _ in true }) {
|
||||
self.duplicateHeaderBehavior = duplicateHeaderBehavior
|
||||
self.shouldCompressBodyData = shouldCompressBodyData
|
||||
}
|
||||
|
||||
public func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
|
||||
// No need to compress unless we have body data. No support for compressing streams.
|
||||
guard let bodyData = urlRequest.httpBody else {
|
||||
completion(.success(urlRequest))
|
||||
return
|
||||
}
|
||||
|
||||
guard shouldCompressBodyData(bodyData) else {
|
||||
completion(.success(urlRequest))
|
||||
return
|
||||
}
|
||||
|
||||
if urlRequest.headers.value(for: "Content-Encoding") != nil {
|
||||
switch duplicateHeaderBehavior {
|
||||
case .error:
|
||||
completion(.failure(DuplicateHeaderError()))
|
||||
return
|
||||
case .replace:
|
||||
// Header will be replaced once the body data is compressed.
|
||||
break
|
||||
case .skip:
|
||||
completion(.success(urlRequest))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var compressedRequest = urlRequest
|
||||
|
||||
do {
|
||||
compressedRequest.httpBody = try deflate(bodyData)
|
||||
compressedRequest.headers.update(.contentEncoding("deflate"))
|
||||
completion(.success(compressedRequest))
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
func deflate(_ data: Data) throws -> Data {
|
||||
var output = Data([0x78, 0x5E]) // Header
|
||||
try output.append((data as NSData).compressed(using: .zlib) as Data)
|
||||
var checksum = adler32Checksum(of: data).bigEndian
|
||||
output.append(Data(bytes: &checksum, count: MemoryLayout<UInt32>.size))
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func adler32Checksum(of data: Data) -> UInt32 {
|
||||
#if swift(>=5.6)
|
||||
data.withUnsafeBytes { buffer in
|
||||
UInt32(adler32(1, buffer.baseAddress, UInt32(buffer.count)))
|
||||
}
|
||||
#else
|
||||
data.withUnsafeBytes { buffer in
|
||||
let buffer = buffer.bindMemory(to: UInt8.self)
|
||||
return UInt32(adler32(1, buffer.baseAddress, UInt32(buffer.count)))
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||
extension RequestInterceptor where Self == DeflateRequestCompressor {
|
||||
/// Create a `DeflateRequestCompressor` with default `duplicateHeaderBehavior` and `shouldCompressBodyData` values.
|
||||
public static var deflateCompressor: DeflateRequestCompressor {
|
||||
DeflateRequestCompressor()
|
||||
}
|
||||
|
||||
/// Creates a `DeflateRequestCompressor` with the provided `DuplicateHeaderBehavior` and `shouldCompressBodyData`
|
||||
/// closure.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - duplicateHeaderBehavior: `DuplicateHeaderBehavior` to use.
|
||||
/// - shouldCompressBodyData: Closure which determines whether the outgoing body data should be compressed. `true` by default.
|
||||
///
|
||||
/// - Returns: The `DeflateRequestCompressor`.
|
||||
public static func deflateCompressor(
|
||||
duplicateHeaderBehavior: DeflateRequestCompressor.DuplicateHeaderBehavior = .error,
|
||||
shouldCompressBodyData: @escaping (_ bodyData: Data) -> Bool = { _ in true }
|
||||
) -> DeflateRequestCompressor {
|
||||
DeflateRequestCompressor(duplicateHeaderBehavior: duplicateHeaderBehavior,
|
||||
shouldCompressBodyData: shouldCompressBodyData)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user