0

I am trying to use a proxy with auth in Swift. I finally got it working using NWConnection. And I can see from my proxy server that it's actually getting the request from my iOS app when I call this function. However I get the error response below. I am assuming something about my request to httpbin.org is wrong but I have not been able to figure it out. The proxy in the array is working and feel free to use it if you want to test.

Connected to proxy: resi.wealthproxies.com
Response from proxy resi.wealthproxies.com: HTTP/1.1 400 Bad Request

Server: awselb/2.0

Date: Thu, 13 Feb 2025 21:31:28 GMT

Content-Type: text/html

Content-Length: 122

Connection: close

<html>

<head><title>400 Bad Request</title></head>

<body>

<center><h1>400 Bad Request</h1></center>

</body>

</html>
func averageProxyGroupSpeed(proxies: [String], completion: @escaping (Int, String) -> Void) {
    let numProxies = proxies.count
    if numProxies == 0 {
        completion(0, "No proxies")
        return
    }

    var totalTime: Int64 = 0
    var successCount = 0
    let group = DispatchGroup()
    let queue = DispatchQueue(label: "proxyQueue", attributes: .concurrent)
    let lock = NSLock()

    let shuffledProxies = proxies.shuffled()
    let selectedProxies = ["resi.wealthproxies.com:8000:akzaidan:x0if46jo-country-US-session-niwtz2y7-duration-60"]

    for proxy in selectedProxies {
        group.enter()
        queue.async {
            let proxyDetails = proxy.split(separator: ":").map(String.init)
            guard proxyDetails.count == 4,
                  let port = UInt16(proxyDetails[1]) else {
                completion(0, "Invalid proxy format")
                group.leave()
                return
            }

            let proxyEndpoint = NWEndpoint.hostPort(host: .init(proxyDetails[0]), port: NWEndpoint.Port(integerLiteral: port))
            let proxyConfig = ProxyConfiguration(httpCONNECTProxy: proxyEndpoint, tlsOptions: nil)
            proxyConfig.applyCredential(username: proxyDetails[2], password: proxyDetails[3])

            let parameters = NWParameters.tcp
            let privacyContext = NWParameters.PrivacyContext(description: "ProxyConfig")
            privacyContext.proxyConfigurations = [proxyConfig]
            parameters.setPrivacyContext(privacyContext)

            let connection = NWConnection(to: .hostPort(host: "httpbin.org", port: 80), using: parameters)

            let start = Date()
            
            connection.stateUpdateHandler = { state in
                switch state {
                case .ready:
                    print("Connected to proxy: \(proxyDetails[0])")
                                        
                    let httpRequest = """
                    GET http://httpbin.org/get HTTP/1.1\r\n
                    Host: httpbin.org\r\n
                    Connection: close\r\n
                    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
                    Accept-Encoding: gzip, deflate\r\n
                    Accept-Language: en-US,en;q=0.9\r\n
                    Upgrade-Insecure-Requests: 1\r\n
                    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0.1 Safari/605.1.15\r\n
                    \r\n
                    """
                    
                    connection.send(content: httpRequest.data(using: .utf8), completion: .contentProcessed({ error in
                        if let error = error {
                            print("Failed to send request: \(error)")
                            group.leave()
                        } else {
                            // Receive the response
                            connection.receive(minimumIncompleteLength: 1, maximumLength: 4096) { data, _, isComplete, error in
                                defer { group.leave() }
                                
                                if let error = error {
                                    print("Failed to receive response: \(error)")
                                } else if isComplete {
                                    print("complete")
                                    
                                    if let data {
                                        let responseString = String(data: data, encoding: .utf8) ?? ""
                                        print("Response from proxy \(proxyDetails[0]): \(responseString)")
                                    } else {
                                        print("data len is \(data?.count ?? -6)")
                                    }
                                    
                                    let duration = Date().timeIntervalSince(start) * 1000 // Convert to milliseconds
                                    
                                    lock.lock()
                                    totalTime += Int64(duration)
                                    successCount += 1
                                    lock.unlock()
                                } else if let data {
                                    let responseString = String(data: data, encoding: .utf8) ?? ""
                                    print("Response from proxy \(proxyDetails[0]): \(responseString)")
                                } else {
                                    print("Not complete")
                                }
                            }
                        }
                    }))
                case .failed(let error):
                    print("Connection failed for proxy \(proxyDetails[0]): \(error)")
                    group.leave()
                case .cancelled:
                    print("Connection cancelled for proxy \(proxyDetails[0])")
                    group.leave()
                case .waiting(let error):
                    print("Connection waiting for proxy \(proxyDetails[0]): \(error)")
                    group.leave()
                default:
                    break
                }
            }

            connection.start(queue: queue)
        }
    }

    group.notify(queue: DispatchQueue.main) {
        if successCount == 0 {
            completion(0, "Proxies Failed")
        } else {
            let averageTime = Int(Double(totalTime) / Double(successCount))
            completion(averageTime, "")
        }
    }
}
4
  • What type of proxies do you use? Regular HTTP, Socks5 or a reverse proxy? Commented Feb 13 at 21:44
  • Apple requires https, unless you have set the "NSAppTransportSecurity" in your Info.plist to allow http connection. Commented Feb 13 at 22:54
  • @workingdogsupportUkraine yes I have already set the NSAppTransportSecurity -> NSAllowsArbitraryLoads -> YES entry in my info.plist Commented Feb 13 at 23:11
  • regular HTTP proxies require to use the proxy protocol which encapsulates the HTTP protocol. This protocol starts with CONNECT <hostname or IP address]. You should better use a HTTP client library which already implements the HTTP and proxy protocol instead of faking your own HTTP requests. Commented Feb 14 at 7:56

1 Answer 1

0

The issue was the formatting of the HTTP request within the string. The correct format is:

let httpRequest = "GET /get HTTP/1.1\r\nHost: httpbin.org\r\nConnection: close\r\nAccept: */*\r\nUser-Agent: MySwiftApp/1.0\r\n\r\n"

This code enables requests in Swift to utilize a Proxy with Auth. The only way I found to Authenticate a proxy in swift was with NWConnection. All the other native methods didn't work.

import Foundation
import Network

func averageProxyGroupSpeed() {
    var successCount = 0
    let group = DispatchGroup()
    let queue = DispatchQueue(label: "proxyQueue", attributes: .concurrent)
    let lock = NSLock()

    let selectedProxies = ["107.180.132.32:3128:slgayamo:xxeeikxt"]

    for proxy in selectedProxies {
        group.enter()
        queue.async {
            let proxyDetails = proxy.split(separator: ":").map(String.init)
            guard proxyDetails.count == 4,
                  let port = UInt16(proxyDetails[1]) else {
                group.leave()
                return
            }

            let proxyEndpoint = NWEndpoint.hostPort(host: .init(proxyDetails[0]), port: NWEndpoint.Port(integerLiteral: port))
            let proxyConfig = ProxyConfiguration(httpCONNECTProxy: proxyEndpoint, tlsOptions: nil)
            proxyConfig.applyCredential(username: proxyDetails[2], password: proxyDetails[3])

            let parameters = NWParameters.tcp
            let privacyContext = NWParameters.PrivacyContext(description: "ProxyConfig")
            privacyContext.proxyConfigurations = [proxyConfig]
            parameters.setPrivacyContext(privacyContext)

            let connection = NWConnection(to: .hostPort(host: "httpbin.org", port: 80), using: parameters)
            
            let start = Date()
            
            connection.stateUpdateHandler = { state in
                switch state {
                case .ready:
                    print("Connected to proxy: \(proxyDetails[0])")
                                        
                    let httpRequest = "GET /get HTTP/1.1\r\nHost: httpbin.org\r\nConnection: close\r\nAccept: */*\r\nUser-Agent: MySwiftApp/1.0\r\n\r\n"
                                        
                    
                    connection.send(content: httpRequest.data(using: .utf8), completion: .contentProcessed({ error in
                        if let error = error {
                            print("Failed to send request: \(error)")
                            group.leave()
                        } else {
                            connection.receive(minimumIncompleteLength: 1, maximumLength: 4096) { data, _, isComplete, error in
                                defer { group.leave() }
                                
                                if let error = error {
                                    print("Failed to receive response: \(error)")
                                } else if isComplete {
                                    print("complete")
                                    
                                    if let data {
                                        let responseString = String(data: data, encoding: .utf8) ?? ""
                                        print("Response from proxy \(proxyDetails[0]): \(responseString)")
                                    } else {
                                        print("data len is \(data?.count ?? -6)")
                                    }
                                    
                                    let duration = Date().timeIntervalSince(start) * 1000 // Convert to milliseconds
                                    
                                } else if let data {
                                    let responseString = String(data: data, encoding: .utf8) ?? ""
                                    print("Response from proxy \(proxyDetails[0]): \(responseString)")
                                } else {
                                    print("Not complete")
                                }
                            }
                        }
                    }))
                case .failed(let error):
                    print("Connection failed for proxy \(proxyDetails[0]): \(error)")
                    group.leave()
                case .cancelled:
                    print("Connection cancelled for proxy \(proxyDetails[0])")
                    group.leave()
                case .waiting(let error):
                    print("Connection waiting for proxy \(proxyDetails[0]): \(error)")
                    group.leave()
                default:
                    break
                }
            }

            connection.start(queue: queue)
        }
    }

    group.notify(queue: DispatchQueue.main) {
        // Handle completion if needed
    }
}

averageProxyGroupSpeed()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.