123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- #if canImport(zlib)
- import Foundation
- import zlib
- @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
- public struct DeflateRequestCompressor: RequestInterceptor {
-
- public enum DuplicateHeaderBehavior {
-
- case error
-
- case replace
-
- case skip
- }
-
-
- public struct DuplicateHeaderError: Error {}
-
- public let duplicateHeaderBehavior: DuplicateHeaderBehavior
-
- public let shouldCompressBodyData: (_ bodyData: Data) -> Bool
-
-
-
-
-
- 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) {
-
- 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:
-
- 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])
- 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 {
-
- public static var deflateCompressor: DeflateRequestCompressor {
- DeflateRequestCompressor()
- }
-
-
-
-
-
-
-
-
- public static func deflateCompressor(
- duplicateHeaderBehavior: DeflateRequestCompressor.DuplicateHeaderBehavior = .error,
- shouldCompressBodyData: @escaping (_ bodyData: Data) -> Bool = { _ in true }
- ) -> DeflateRequestCompressor {
- DeflateRequestCompressor(duplicateHeaderBehavior: duplicateHeaderBehavior,
- shouldCompressBodyData: shouldCompressBodyData)
- }
- }
- #endif
|