Until now I have found no way to use a higher level Swift native method (URlSession for example) to make a basic GET/POST request using a HTTP proxy that requires AUTH. I have this Stack OverFlow Question dedicated for that, but have had no luck solving it. The only way that works that I have found is shown below using a NWConnection
and it's not very clean. A URLSession auto manages cookies so that Set Cookies
from a previous request are present in future requests. I am trying to replicate this behavior with NWConnection
, but have had no luck.
The response data from an NWConnection includes the response headers at the top. Do I have to manually parse the string and try and extract cookies then add them into the httpRequest
string. Is there an easier way?
Also if anyone knows an answer to the question linked above then there is no need to solve this question.
func updateOrderStatusProxy(proxy: String, completion: @escaping (Bool) -> Void) {
let orderLink = ";
guard let url = URL(string: orderLink) else {
completion(true)
return
}
let proxyDetails = proxy.split(separator: ":").map(String.init)
guard proxyDetails.count == 4, let port = UInt16(proxyDetails[1]) else {
completion(false)
print("Invalid proxy format")
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.tls
let privacyContext = NWParameters.PrivacyContext(description: "ProxyConfig")
privacyContext.proxyConfigurations = [proxyConfig]
parameters.setPrivacyContext(privacyContext)
let host = url.host ?? ""
let path = url.path.isEmpty ? "/" : url.path
let query = url.query ?? ""
let fullPath = query.isEmpty ? path : "\(path)?\(query)"
let connection = NWConnection(
to: .hostPort(
host: .init(host),
port: .init(integerLiteral: UInt16(url.port ?? 443))
),
using: parameters
)
connection.stateUpdateHandler = { state in
switch state {
case .ready:
let httpRequest = "GET \(fullPath) HTTP/1.1\r\nHost: \(host)\r\nConnection: close\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nUser-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\nAccept-Language: en-US,en;q=0.9\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: none\r\nPriority: u=0, i\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)")
completion(false)
return
}
readAllData(connection: connection) { finalData, readError in
if let readError = readError {
print("Failed to receive response: \(readError)")
completion(false)
return
}
guard let data = finalData else {
print("No data received or unable to read data.")
completion(false)
return
}
if let body = String(data: data, encoding: .utf8) {
completion(true)
} else {
print("Unable to decode response body.")
completion(false)
}
}
}))
case .failed(let error):
print("Connection failed for proxy \(proxyDetails[0]): \(error)")
completion(false)
default:
break
}
}
connection.start(queue: .global())
}
func readAllData(connection: NWConnection,
accumulatedData: Data = Data(),
completion: @escaping (Data?, Error?) -> Void) {
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { data, context, isComplete, error in
if let error = error {
completion(nil, error)
return
}
let newAccumulatedData = accumulatedData + (data ?? Data())
if isComplete {
completion(newAccumulatedData, nil)
} else {
readAllData(connection: connection,
accumulatedData: newAccumulatedData,
completion: completion)
}
}
}
Until now I have found no way to use a higher level Swift native method (URlSession for example) to make a basic GET/POST request using a HTTP proxy that requires AUTH. I have this Stack OverFlow Question dedicated for that, but have had no luck solving it. The only way that works that I have found is shown below using a NWConnection
and it's not very clean. A URLSession auto manages cookies so that Set Cookies
from a previous request are present in future requests. I am trying to replicate this behavior with NWConnection
, but have had no luck.
The response data from an NWConnection includes the response headers at the top. Do I have to manually parse the string and try and extract cookies then add them into the httpRequest
string. Is there an easier way?
Also if anyone knows an answer to the question linked above then there is no need to solve this question.
func updateOrderStatusProxy(proxy: String, completion: @escaping (Bool) -> Void) {
let orderLink = "https://us.supreme/checkouts/c/79393a1d2d6098cb2477a49dfd7699bd/thank_you"
guard let url = URL(string: orderLink) else {
completion(true)
return
}
let proxyDetails = proxy.split(separator: ":").map(String.init)
guard proxyDetails.count == 4, let port = UInt16(proxyDetails[1]) else {
completion(false)
print("Invalid proxy format")
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.tls
let privacyContext = NWParameters.PrivacyContext(description: "ProxyConfig")
privacyContext.proxyConfigurations = [proxyConfig]
parameters.setPrivacyContext(privacyContext)
let host = url.host ?? ""
let path = url.path.isEmpty ? "/" : url.path
let query = url.query ?? ""
let fullPath = query.isEmpty ? path : "\(path)?\(query)"
let connection = NWConnection(
to: .hostPort(
host: .init(host),
port: .init(integerLiteral: UInt16(url.port ?? 443))
),
using: parameters
)
connection.stateUpdateHandler = { state in
switch state {
case .ready:
let httpRequest = "GET \(fullPath) HTTP/1.1\r\nHost: \(host)\r\nConnection: close\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nUser-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\nAccept-Language: en-US,en;q=0.9\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: none\r\nPriority: u=0, i\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)")
completion(false)
return
}
readAllData(connection: connection) { finalData, readError in
if let readError = readError {
print("Failed to receive response: \(readError)")
completion(false)
return
}
guard let data = finalData else {
print("No data received or unable to read data.")
completion(false)
return
}
if let body = String(data: data, encoding: .utf8) {
completion(true)
} else {
print("Unable to decode response body.")
completion(false)
}
}
}))
case .failed(let error):
print("Connection failed for proxy \(proxyDetails[0]): \(error)")
completion(false)
default:
break
}
}
connection.start(queue: .global())
}
func readAllData(connection: NWConnection,
accumulatedData: Data = Data(),
completion: @escaping (Data?, Error?) -> Void) {
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { data, context, isComplete, error in
if let error = error {
completion(nil, error)
return
}
let newAccumulatedData = accumulatedData + (data ?? Data())
if isComplete {
completion(newAccumulatedData, nil)
} else {
readAllData(connection: connection,
accumulatedData: newAccumulatedData,
completion: completion)
}
}
}
Share
asked Mar 3 at 21:27
Ahmed ZaidanAhmed Zaidan
711 gold badge9 silver badges24 bronze badges
1 Answer
Reset to default 0Made a Swift TLS Client. Please start of GitHub. Literally the only swift tls client on GitHub.
https://github/ak3zaidan/Swift-TLS-Client
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745071055a4609548.html
评论列表(0条)