diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/jaegertracing/thrift/lib/swift/Sources/THTTPSessionTransport.swift | |
parent | Initial commit. (diff) | |
download | ceph-upstream.tar.xz ceph-upstream.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/jaegertracing/thrift/lib/swift/Sources/THTTPSessionTransport.swift')
-rw-r--r-- | src/jaegertracing/thrift/lib/swift/Sources/THTTPSessionTransport.swift | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/src/jaegertracing/thrift/lib/swift/Sources/THTTPSessionTransport.swift b/src/jaegertracing/thrift/lib/swift/Sources/THTTPSessionTransport.swift new file mode 100644 index 000000000..3c0af8eb8 --- /dev/null +++ b/src/jaegertracing/thrift/lib/swift/Sources/THTTPSessionTransport.swift @@ -0,0 +1,184 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import Foundation +import Dispatch + + +public class THTTPSessionTransport: TAsyncTransport { + public class Factory : TAsyncTransportFactory { + public var responseValidate: ((HTTPURLResponse?, Data?) throws -> Void)? + + var session: URLSession + var url: URL + + public class func setupDefaultsForSessionConfiguration(_ config: URLSessionConfiguration, withProtocolName protocolName: String?) { + var thriftContentType = "application/x-thrift" + + if let protocolName = protocolName { + thriftContentType += "; p=\(protocolName)" + } + + config.requestCachePolicy = .reloadIgnoringLocalCacheData + config.urlCache = nil + + config.httpShouldUsePipelining = true + config.httpShouldSetCookies = true + config.httpAdditionalHeaders = ["Content-Type": thriftContentType, + "Accept": thriftContentType, + "User-Agent": "Thrift/Swift (Session)"] + + + } + + public init(session: URLSession, url: URL) { + self.session = session + self.url = url + } + + public func newTransport() -> THTTPSessionTransport { + return THTTPSessionTransport(factory: self) + } + + func validateResponse(_ response: HTTPURLResponse?, data: Data?) throws { + try responseValidate?(response, data) + } + + func taskWithRequest(_ request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> ()) throws -> URLSessionTask { + + let newTask: URLSessionTask? = session.dataTask(with: request, completionHandler: completionHandler) + if let newTask = newTask { + return newTask + } else { + throw TTransportError(error: .unknown, message: "Failed to create session data task") + } + } + } + + var factory: Factory + var requestData = Data() + var responseData = Data() + var responseDataOffset: Int = 0 + + init(factory: Factory) { + self.factory = factory + } + + public func readAll(size: Int) throws -> Data { + let read = try self.read(size: size) + if read.count != size { + throw TTransportError(error: .endOfFile) + } + return read + } + + public func read(size: Int) throws -> Data { + let avail = responseData.count - responseDataOffset + let (start, stop) = (responseDataOffset, responseDataOffset + min(size, avail)) + let read = responseData.subdata(in: start..<stop) + responseDataOffset += read.count + return read + } + + public func write(data: Data) throws { + requestData.append(data) + } + + public func flush(_ completed: @escaping (TAsyncTransport, Error?) -> Void) { + var error: Error? + var task: URLSessionTask? + + var request = URLRequest(url: factory.url) + request.httpMethod = "POST" + request.httpBody = requestData + + requestData = Data() + + do { + task = try factory.taskWithRequest(request, completionHandler: { (data, response, taskError) in + + // Check if there was an error with the network + if taskError != nil { + error = TTransportError(error: .timedOut) + completed(self, error) + return + } + + // Check response type + if taskError == nil && !(response is HTTPURLResponse) { + error = THTTPTransportError(error: .invalidResponse) + completed(self, error) + return + } + + // Check status code + if let httpResponse = response as? HTTPURLResponse { + if taskError == nil && httpResponse.statusCode != 200 { + if httpResponse.statusCode == 401 { + error = THTTPTransportError(error: .authentication) + } else { + error = THTTPTransportError(error: .invalidStatus(statusCode: httpResponse.statusCode)) + } + } + + // Allow factory to check + if error != nil { + do { + try self.factory.validateResponse(httpResponse, data: data) + } catch let validateError { + error = validateError + } + } + + self.responseDataOffset = 0 + if error != nil { + self.responseData = Data() + } else { + self.responseData = data ?? Data() + } + completed(self, error) + } + }) + + } catch let taskError { + error = taskError + } + + if let error = error, task == nil { + completed(self, error) + } + task?.resume() + } + + public func flush() throws { + let completed = DispatchSemaphore(value: 0) + var internalError: Error? + + flush() { _, error in + internalError = error + completed.signal() + } + + _ = completed.wait(timeout: DispatchTime.distantFuture) + + if let error = internalError { + throw error + } + } +} |