Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
signalapp
GitHub Repository: signalapp/Signal-iOS
Path: blob/main/SignalServiceKit/Calls/CallHTTPClient.swift
1 views
//
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import Foundation
public import SignalRingRTC

public class CallHTTPClient {
    public let ringRtcHttpClient: SignalRingRTC.HTTPClient

    public init() {
        self.ringRtcHttpClient = SignalRingRTC.HTTPClient()
        self.ringRtcHttpClient.delegate = self
    }
}

// MARK: - HTTPDelegate

extension CallHTTPClient: HTTPDelegate {
    /**
     * A HTTP request should be sent to the given url.
     * Invoked on the main thread, asychronously.
     * The result of the call should be indicated by calling the receivedHttpResponse() function.
     */
    public func sendRequest(requestId: UInt32, request: HTTPRequest) {
        AssertIsOnMainThread()

        let session = OWSURLSession(
            securityPolicy: OWSURLSession.signalServiceSecurityPolicy,
            configuration: OWSURLSession.defaultConfigurationWithoutCaching,
            canUseSignalProxy: true,
        )
        session.require2xxOr3xx = false
        session.allowRedirects = true
        session.customRedirectHandler = { redirectedRequest in
            var redirectedRequest = redirectedRequest
            if
                let authHeader = request.headers.first(where: {
                    $0.key.caseInsensitiveCompare("Authorization") == .orderedSame
                })
            {
                redirectedRequest.setValue(authHeader.value, forHTTPHeaderField: authHeader.key)
            }
            return redirectedRequest
        }

        Task { @MainActor in
            do {
                var headers = HttpHeaders()
                headers.addHeaderMap(request.headers, overwriteOnConflict: true)

                let response = try await session.performRequest(
                    request.url,
                    method: request.method.httpMethod,
                    headers: headers,
                    body: request.body,
                )
                self.ringRtcHttpClient.receivedResponse(
                    requestId: requestId,
                    response: response.asRingRTCResponse,
                )
            } catch {
                if error.isNetworkFailureOrTimeout {
                    Logger.warn("Peek client HTTP request had network error: \(error)")
                } else {
                    owsFailDebug("Peek client HTTP request failed \(error)")
                }
                self.ringRtcHttpClient.httpRequestFailed(requestId: requestId)
            }
        }
    }
}

extension SignalRingRTC.HTTPMethod {
    var httpMethod: SignalServiceKit.HTTPMethod {
        switch self {
        case .get: return .get
        case .post: return .post
        case .put: return .put
        case .delete: return .delete
        }
    }
}

extension SignalServiceKit.HTTPResponse {
    var asRingRTCResponse: SignalRingRTC.HTTPResponse {
        return SignalRingRTC.HTTPResponse(
            statusCode: UInt16(responseStatusCode),
            body: responseBodyData,
        )
    }
}