Reputation: 17132
I'm trying to use my Proxy for an API request that needs a specified IP. To debug my issue, I'm requesting the IP from a webservice.
This is my current code:
import UIKit
import Alamofire
class ViewController: UIViewController {
var requestManager = Alamofire.SessionManager.default
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
var proxyConfiguration = [NSObject: AnyObject]()
proxyConfiguration[kCFNetworkProxiesHTTPProxy] = "http://[email protected]" as AnyObject?
proxyConfiguration[kCFNetworkProxiesHTTPPort] = "9293" as AnyObject?
proxyConfiguration[kCFNetworkProxiesHTTPEnable] = 1 as AnyObject?
let cfg = Alamofire.SessionManager.default.session.configuration
cfg.connectionProxyDictionary = proxyConfiguration
let ip = URL(string: "https://api.ipify.org?format=json")
requestManager = Alamofire.SessionManager(configuration: cfg)
requestManager.request(ip!).response { response in
print("Request: \(response.request)")
print("Response: \(response.response)")
print("Error: \(response.error)")
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)")
}
}
}
}
The problem: the responded IP is the same with or without the proxyConfiguration
.
PS: physical device used.
Upvotes: 16
Views: 4555
Reputation: 25294
Base on Fraser answer and How can I get my external IP address in a shell script? question
NetworkService.swift
import Foundation
import Alamofire
struct Proxy {
let host: String
let port: Int
}
class NetworkService {
// Pick free some proxies from here https://free-proxy-list.net if current do not work
private let listOfProxies = [
Proxy(host: "67.43.224.131", port: 3128), // Canada
Proxy(host: "167.172.180.40", port: 44129), // Germany
Proxy(host: "185.236.202.205", port: 3128), // Austria
]
private(set) var session: Session!
private var proxy: Proxy?
init () { resetSessionManager() }
func setRandomProxy() {
self.proxy = listOfProxies.randomElement()
resetSessionManager()
}
private
func resetSessionManager() {
let config = Session.default.session.configuration
if let proxy = proxy {
config.connectionProxyDictionary = [
"HTTPEnable": 1,
"HTTPProxy": proxy.host ,
"HTTPPort": proxy.port,
"HTTPSEnable": true,
"HTTPSProxy": proxy.host,
"HTTPSPort": proxy.port
]
} else {
config.connectionProxyDictionary = [:]
}
self.session = Session(configuration: config)
}
func request(url: URLConvertible,
method: Alamofire.HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil,
completion: @escaping (Result<Data, Error>) -> Void) {
let request = session.request(url, method: method,
parameters: parameters,
encoding: encoding,
headers: headers)
request.response { respionse in
if let error = respionse.error {
completion(.failure(error))
} else if let data = respionse.data {
completion(.success(data))
}
}
}
func request<T: Decodable>(url: URLConvertible,
method: Alamofire.HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil,
completion: @escaping (Result<T, Error>) -> Void) {
request(url: url, method: method,
parameters: parameters,
encoding: encoding,
headers: headers) { result in
switch result {
case .failure(let error): completion(.failure(error))
case .success(let data):
do {
let object = try JSONDecoder().decode(T.self, from: data)
completion(.success(object))
} catch let error {
completion(.failure(error))
}
}
}
}
}
GeoIP.swift
import Foundation
struct GeoIP: Codable {
let lat: Double
let lon: Double
let zip: String
let query: String
let city: String
let regionName: String
let country: String
let timezone: String
}
extension GeoIP: CustomStringConvertible {
var description: String {
"\(city), \(regionName), \(country), \(zip)\nIP:\(query)\nCoordinates:(\(lat),\(lon))\nTimezone: \(timezone)"
}
}
ViewController.swift
class ViewController: UIViewController {
private let networkService = NetworkService()
private weak var button: UIButton!
private weak var activityIndicatorView: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: view.frame)
button.setTitleColor(.blue, for: .normal)
button.setTitle("Pick random proxy and get my ip", for: .normal)
button.addTarget(self, action: #selector(buttonTouchedUpInside(source:)), for: .touchUpInside)
view.addSubview(button)
self.button = button
let activityIndicatorView = UIActivityIndicatorView(frame: view.frame)
view.addSubview(activityIndicatorView)
self.activityIndicatorView = activityIndicatorView
}
@objc func buttonTouchedUpInside(source: UIButton) {
source.isHidden = true
activityIndicatorView.startAnimating()
networkService.setRandomProxy()
showMyGeoIpInfo()
}
}
extension ViewController {
private func showMyGeoIpInfo() {
let group = DispatchGroup()
group.enter()
group.enter()
group.enter()
var httpIP: String?
var httpsIP: String?
var geoIp: GeoIP?
group.notify(queue: .main) { [weak self] in
guard let self = self else { return }
let _httpIP = httpIP ?? "nil"
let _httpsIP = httpsIP ?? "nil"
let geoIpDescription = geoIp?.description ?? "nil"
let message = "HTTP request IP: \(_httpIP)\nHTTPS request IP: \(_httpsIP)\n GeoIP: \(geoIpDescription)"
self.showAlert(title: "GeoIP", message: message)
self.button.isHidden = false
self.activityIndicatorView.stopAnimating()
}
// Get my IP on http request
getSimpleText(from: "http://ipecho.net/plain") { text in
httpIP = text
group.leave()
}
// Get my IP on https request
getSimpleText(from: "https://icanhazip.com") { text in
httpsIP = text
group.leave()
}
// Get my GeoIp info
networkService.request(url: "http://ip-api.com/json/",
encoding: JSONEncoding.default) { (response: Result<GeoIP, Error>) in
defer { group.leave() }
switch response {
case .failure(let error): print("Error: \(error)")
case .success(let value): geoIp = value
}
}
}
private func getSimpleText(from url: String, completion: @escaping (String?) -> Void) {
networkService.request(url: "https://icanhazip.com") { result in
switch result {
case .failure(let error):
print("Error: \(error)")
completion(nil)
case .success(let data):
let text = String(decoding: data, as: UTF8.self).trimmingCharacters(in: .whitespacesAndNewlines)
completion(text)
}
}
}
private func showAlert(title: String?, message: String?) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
present(alertController, animated: true, completion: nil)
}
}
Upvotes: 0
Reputation: 998
Based off Manishg's answer I use the following to avoid warnings
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
var proxyConfiguration = [String: AnyObject]()
proxyConfiguration.updateValue(1 as AnyObject, forKey: "HTTPEnable")
proxyConfiguration.updateValue("eu-west-static-01.quotaguard.com" as AnyObject, forKey: "HTTPProxy")
proxyConfiguration.updateValue(9293 as AnyObject, forKey: "HTTPPort")
proxyConfiguration.updateValue(1 as AnyObject, forKey: "HTTPSEnable")
proxyConfiguration.updateValue("eu-west-static-01.quotaguard.com" as AnyObject, forKey: "HTTPSProxy")
proxyConfiguration.updateValue(9293 as AnyObject, forKey: "HTTPSPort")
configuration.connectionProxyDictionary = proxyConfiguration
sharedManager = Alamofire.SessionManager(configuration: configuration)
The https constants have been deprecated and could be removed at anytime. By using the string values, the code might break but it won't crash
Upvotes: 5
Reputation: 9828
I think the working (supposed to be deprecated) keys are:
kCFStreamPropertyHTTPSProxyHost
kCFStreamPropertyHTTPSProxyPort
Could you try this code?
import UIKit
import Alamofire
class ViewController: UIViewController {
var requestManager = Alamofire.SessionManager.default
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
var proxyConfiguration = [NSObject: AnyObject]()
proxyConfiguration[kCFNetworkProxiesHTTPProxy] = "eu-west-static-01.quotaguard.com" as AnyObject?
proxyConfiguration[kCFNetworkProxiesHTTPPort] = "9293" as AnyObject?
proxyConfiguration[kCFNetworkProxiesHTTPEnable] = 1 as AnyObject?
proxyConfiguration[kCFStreamPropertyHTTPSProxyHost as String] = "eu-west-static-01.quotaguard.com"
proxyConfiguration[kCFStreamPropertyHTTPSProxyPort as String] = 9293
proxyConfiguration[kCFProxyUsernameKey as String] = xxx
//proxyConfiguration[kCFProxyPasswordKey as String] = "pwd if any"
let cfg = Alamofire.SessionManager.default.session.configuration
cfg.connectionProxyDictionary = proxyConfiguration
let ip = URL(string: "https://api.ipify.org?format=json")
requestManager = Alamofire.SessionManager(configuration: cfg)
requestManager.request(ip!).response { response in
print("Request: \(response.request)")
print("Response: \(response.response)")
print("Error: \(response.error)")
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)")
}
}
}
}
Also please make sure your proxy server is configured to handle https requests.
Note: It might give deprecated
warning for those keys but keys are still working (see https://forums.developer.apple.com/thread/19356#131446)
Note: I posted the same answer here. Posting the same here as it was applicable here as well. Alamofire is using same URLSessionConfiguration
.
Upvotes: 15