cannot read data from Json hosted on GitHub - swift

when try to read data from a json on my GitHub space, I get an error
nw_protocol_get_quic_image_block_invoke dlopen libquic failed
Invalid response from the server. Please try again.
am I using wrong url or there is an issue in the way I'm parsing data?
my repo url
https://github.com/stark226/stark226.github.io.git
where there is a simple json file at this url
https://github.com/stark226/stark226.github.io/blob/3b2bebb4a3d85524732c7e7ec302b24f8d3e66ae/testjson.json
in my viewDidload
getDataFromJsonOnGithub(completed: { [weak self] result in
guard let self = self else {return}
switch result {
case .success(let expected):
print(expected)
case .failure(let error):
print(error.rawValue)
}
})
my struct
struct RemoteData: Codable, Hashable {
var tokenDuration: Int
}
my func
func getDataFromJsonOnGithub(completed: #escaping (Result<RemoteData, ListOfErrors>) -> Void) {
let endpoint = "https://github.com/stark226/stark226.github.io/stark226/testjson.json"
guard let url = URL(string: endpoint) else {
completed(.failure(.invalidUsername))
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let _ = error {
completed(.failure(.unableToComplete))
return
}
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
completed(.failure(.invalidResponse))
return
}
guard let data = data else {
completed(.failure(.invalidData))
return
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let expectedRrsult = try decoder.decode(RemoteData.self, from: data)
completed(.success(expectedRrsult))
} catch {
completed(.failure(.invalidData))
}
}
task.resume()
}
enum ListOfErrors: String, Error {
case invalidUsername = "This username created an invalid request. Please try again."
case unableToComplete = "Unable to complete your request. Please check your internet connection"
case invalidResponse = "Invalid response from the server. Please try again."
case invalidData = "The data received from the server was invalid. Please try again."
case unableToFavorite = "There was an error favoriting this user. Please try again."
case alreadyInFavorites = "You've already favorited this user. You must REALLY like them!"
}

You have to access the raw file. The URL you are accessing renders an HTML page. Try the following url (click on "Raw" button in GitHub):
https://raw.githubusercontent.com/stark226/stark226.github.io/3b2bebb4a3d85524732c7e7ec302b24f8d3e66ae/testjson.json

Related

URLSession with URLCredential

I would like to get data from server, but credential (username, password. Not Basi Authentification) is necessary to get it. Therefore, I try to use URLSession with URLCredential as following:
https://developer.apple.com/documentation/foundation/url_loading_system/handling_an_authentication_challenge
However, I could not understand this document...
So could you tell me how to use URLSession with URLCredential?
I tried URLSession like:
func startLoad() {
let url = URL(string: "https://www.abcde-test-url.com/")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
print("client error: \(error.localizedDescription) \n")
return
}
guard let data = data, let response = response as? HTTPURLResponse else {
print("no data or no response")
return
}
if response.statusCode == 200 {
print(data)
} else {
print("error status code: \(response.statusCode)\n")
}
}
task.resume()
}
But I couldn't understand the usage with URLCredential.

Not getting Firebase token id when calling getIdToken in Swift 5 iOS

I have been trying to make this work for 3 days now, and I can't see where I am going. When trying to get firebase tokenId using the - (void)getIDTokenWithCompletion: (nullable void (^)(NSString *_Nullable __strong, NSError *_Nullable __strong))completion; function provided by firebase I am getting nothing in return.
I have created a separate class to get the Id using a completion handler. Below is the code I am using
import Foundation
import FirebaseAuth
class FirebaseToken {
static var shared = FirebaseToken.init()
func getIdToken(token completion: #escaping(String?,Error?) -> Void){
Auth.auth().currentUser?.getIDToken(completion:{ idToken, error in
guard let error = error else {return }
print(error)
completion(nil, error)
guard let token = idToken else {return}
completion(token, nil)
print(token)
})
}
}
This is the class I am using to call the func getIdToken function to get the Id, which is inside the func makeAPICall<T:Codable>(urlPath: String, apiMethod: HTTPMethod, expectedReturnType: T.Type,user completionHandler: #escaping ([T]?,Error?) function.
import Foundation
import Alamofire
import Firebase
class ApiService {
static var shared = ApiService.init()
let session: Session = {
let manager = ServerTrustManager(allHostsMustBeEvaluated: false,evaluators: ["localhost": DisabledTrustEvaluator()])
let configuration = URLSessionConfiguration.af.default
return Session(configuration: configuration, serverTrustManager: manager)
}()
//MARK:- GET
func makeAPICall<T:Codable>(urlPath: String, apiMethod: HTTPMethod, expectedReturnType: T.Type,user completionHandler: #escaping ([T]?,Error?) -> Void) {
var urlComponent = URLComponents()
urlComponent.scheme = "https"
urlComponent.host = "localhost"
urlComponent.port = 5001
urlComponent.path = "/api/" + urlPath
print(urlComponent.url!)
guard let url = urlComponent.url else {
return
}
var headers: HTTPHeaders?
FirebaseToken.shared.getIdToken(token: {tokenId, error in
guard let errors = error else {return}
print(errors)
guard let tokens = tokenId else {return}
headers = [
.authorization(bearerToken: tokens),
.accept("application/json")
]
})
guard let headerAuth = headers else {
print("not getting firebase token")
return
}
print(headerAuth)
session.request(url, method: apiMethod).validate().responseDecodable(of: [T].self) {(response) in
switch response.result{
case .success:
guard let users = response.value else {
return
}
//print(header)
completionHandler(users, nil)
case .failure(let error):
completionHandler(nil, error)
}
}
}
}
the variable var headers: HTTPHeaders?, which inside the function
guard let headerAuth = headers else {
print("not getting firebase token")
return
}
should be printing out the token yet, for some reason the token isn't being added. Can someone let me know where I am going wrong as I have been stuck for 3 days and I am still very new to firebase?
The printing result should be within print(headerAuth), however; I keep on getting the result within print("not getting firebase token")
The getIdToken method is an asynchronous call. Any code that needs the resulting token, needs to be inside the completion handler.
So something like:
FirebaseToken.shared.getIdToken(token: {tokenId, error in
guard let tokens = tokenId else {return}
headers = [
.authorization(bearerToken: tokens),
.accept("application/json")
]
guard let headerAuth = headers else {
print("not getting firebase token")
return
}
session.request(url, method: apiMethod).validate().responseDecodable(of: [T].self) {(response) in
switch response.result{
case .success:
guard let users = response.value else {
return
}
completionHandler(users, nil)
case .failure(let error):
completionHandler(nil, error)
}
}
})
I also removed this line:
guard let errors = error else {return}
As I'm pretty sure this returns out of the block when there is no error.

Swift: How to use HTTPS proxy

I have a paid proxy (HTTP/HTTPS/SOCKS).
I can make requests with HTTP scheme, but can't with HTTPS.
I always get en error:
Error Domain=kCFErrorDomainCFNetwork Code=311 "(null)" UserInfo={_NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <69F444DF-8C0E-4F4B-B723-C7BCD72B6C02>.<1>, _kCFStreamErrorDomainKey=4, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <69F444DF-8C0E-4F4B-B723-C7BCD72B6C02>.<1>"
), _kCFStreamErrorCodeKey=-2097}
I need to get and parse a few web pages from one concrete domain. I'm trying to use HTTP scheme, but it also fails (i guess due to redirect to HTTPS)
So, my goal is make HTTPS request via proxy server.
My code below:
Session configuration:
private func getProxySessionConfigration() -> URLSessionConfiguration {
let login = ConfigurationData.proxy.login
let password = ConfigurationData.proxy.password
let sessionConfiguration = URLSessionConfiguration.default
let userPasswordString = "\(login):\(password)"
let userPasswordData = userPasswordString.data(using: String.Encoding.utf8)
let base64EncodedCredential = userPasswordData!.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0))
let authString = "Basic \(base64EncodedCredential)"
sessionConfiguration.httpAdditionalHeaders = ["Authorization" : authString]
sessionConfiguration.connectionProxyDictionary = [
"HTTPEnable": true,
"HTTPPort": ConfigurationData.proxy.port,
"HTTPProxy": ConfigurationData.proxy.host,
"HTTPSEnable": true,
"HTTPSPort": ConfigurationData.proxy.port,
"HTTPSProxy": ConfigurationData.proxy.host
]
return sessionConfiguration
}
Request function:
public func getPage(_ url: URL, completion: #escaping (String?, RequestError?) -> Void) {
let session = URLSession(configuration: getProxySessionConfigration())
let task = session.dataTask(with: url) { (data, response, error) in
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
if let error = error {
completion(nil, .requestFailed(error))
} else {
completion(nil, .unknown(response))
}
return
}
if let data = data {
print(httpResponse)
if let urlContent = NSString(data: data, encoding: String.Encoding.utf8.self.rawValue) {
completion(urlContent as String, nil)
} else {
completion(nil, .dataDecodeFailed(data))
}
} else {
completion(nil, .noData)
}
}
task.resume()
}
Function call:
let requestAvito = AvitoProjectPlaygroud_Sources.RequestAvito()
let url = URL(string: "https://www.avito.ru/krasnodar/vakansii/voditel_v_yandeks_taksi_zarabotok_ot_1388074044")!
requestAvito.getPage(url) { (htmlString, error) in
if let error = error {
switch error {
case .noData: print("ERROR: no data")
case .unknown(let response):
print("ERROR: unknown error")
if let response = response { print(response) }
case .urlFailed: print("ERROR: url generating failed")
case .requestFailed(let returnedError): print("ERROR: \(returnedError)")
case .dataDecodeFailed(let data):
print("ERROR: data decoding failed")
print(data!)
}
return
}
if let htmlString = htmlString {
// print(htmlString)
print(String(htmlEncodedString: htmlString))
} else {
print("NO DATA")
}
}
For your issue first of all (Before ANYTHING else, make sure your proxy handle HTTPS proxying), if no then does not matter the code you put in.
To handle HTTPS Proxying there is 2 keys to use that it seems you are using it. One thing I can see is that you are using true as boolean, etc.
As per my experience I always used value such numeric or string lateral.
Make sure that data is passed as String / Int (true -> 1) etc. That could help.
Sometimes it can make some issues with those assumptions that true "will" be converted as 1.
Here below an example on how I use it:
let request = URLRequest(url: URL(string: url)!)
let config = URLSessionConfiguration.default
config.requestCachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
config.connectionProxyDictionary = [AnyHashable: Any]()
config.connectionProxyDictionary?[kCFNetworkProxiesHTTPEnable as String] = 1
config.connectionProxyDictionary?[kCFNetworkProxiesHTTPProxy as String] = "xxx.yyy.zzz.bbb"
config.connectionProxyDictionary?[kCFNetworkProxiesHTTPPort as String] = 8888
config.connectionProxyDictionary?[kCFStreamPropertyHTTPSProxyHost as String] = "xxx.yyy.zzz.bbb"
config.connectionProxyDictionary?[kCFStreamPropertyHTTPSProxyPort as String] = 8888
So in short :
Verify first your proxy (making sure https proxying is handled)
and then pass data as above
it may solve your issue hopefully.

Could not cast value of type 'Swift.String' (0x10fef45c0) to 'Swift.Error' (0x10ff2bd10). (lldb)

Below line of code is producing the error,
DispatchQueue.main.async {
completion(.success(jsonData), Error as! Error)
}
When print jsonData This code returns perfect result of array but getting this error,
Could not cast value of type 'Swift.String' (0x10fef45c0) to 'Swift.Error' (0x10ff2bd10). (lldb)
As the error says I understand its a cast exception, but I'm not able to modify the code to make it work. I'm kinda new to Swift, so any help would be appreciated. Below is my
import Foundation
class APIService {
private var dataTask: URLSessionDataTask?
func getPopularPosts(completion: #escaping (Result<Any, Error>, Error) -> Void) {
let popularURL = "URL Here"
guard let url = URL(string: popularURL) else {return}
// Create URL Session - work on the background
dataTask = URLSession.shared.dataTask(with: url) { (data, response, error) in
// Handle Error
if let error = error {
completion(.failure(error), Error.self as! Error)
print("DataTask error: \(error.localizedDescription)")
return
}
guard let response = response as? HTTPURLResponse else {
// Handle Empty Response
print("Empty Response")
return
}
print("Response status code: \(response.statusCode)")
guard let data = data else {
// Handle Empty Data
print("Empty Data")
return
}
do {
// Parse the data
let decoder = JSONDecoder()
let jsonData = try decoder.decode(APIService.self, from: data)
// print(jsonData)
// Back to the main thread
DispatchQueue.main.async {
completion(.success(jsonData), Error as! Error)
}
} catch let error {
completion(.failure(error),error)
}
}
dataTask?.resume()
}
}
Modify the completion block parameters, you already are returning the error inside the Result's .failure(Error) block so no need to repeat it again as another parameter in the completion parameter. Here's how you fix this:
Declaration:
class APIService {
private var dataTask: URLSessionDataTask?
func getPopularPosts(completion: #escaping (Result<CategoriesNewsData, Error>) -> Void) {
let popularURL = "URL Here"
guard let url = URL(string: popularURL) else {return}
// Create URL Session - work on the background
dataTask = URLSession.shared.dataTask(with: url) { (data, response, error) in
// Handle Error
if let error = error {
completion(.failure(error))
print("DataTask error: \(error.localizedDescription)")
return
}
guard let response = response as? HTTPURLResponse else {
// Handle Empty Response
print("Empty Response") // Throw a custom error here too.
return
}
print("Response status code: \(response.statusCode)")
guard let data = data else {
// Handle Empty Data
print("Empty Data") // Throw a custom error here too.
return
}
do {
let decoder = JSONDecoder()
let jsonData = try decoder.decode(CategoriesNewsData.self, from: data)
DispatchQueue.main.async {
completion(.success(jsonData))
}
} catch let error {
completion(.failure(error))
}
}
dataTask?.resume()
}
}
Calling:
service.getPopularPosts { result in
switch result {
case .success(let categoriesNewsData):
print(categoriesNewsData)
case .failure(let error):
print(error)
}
}

Webservice returning nil

I am having trouble populating a UITextField with my returnHTML data that I get from my web-service.
If I have my web-service such that:
import Foundation;
class WebSessionCredentials {
static let requestURL = URL(string:"xxxx.on.ca/getData.aspx?requestType=Tech")!
var htmlbody: String?
var instancedTask: URLSessionDataTask?
static var sharedInstance = WebSessionCredentials()
init() {
self.instancedTask = URLSession.shared.dataTask(with: WebSessionCredentials.requestURL) { [weak self] (data,response,error) in
if let error = error {
// Error
print("Client Error: \(error.localizedDescription)")
return
}
guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else {
print("Server Error!")
return
}
guard let mime = response.mimeType, mime == "text/html" else {
print("Wrong mime type!");
return
}
if let htmlData = data, let htmlBodyString = String(data: htmlData, encoding: .utf8) {
self?.htmlbody = htmlBodyString;
};
};
};
};
Through this I should be able to access the returned HTML response through WebSessionCredentials.sharedInstance.htmlbody;
Verifying this in playground I seem to be getting the correct response within the class but when calling htmlbody from outside the class I get a nil response - I am out of ideas in terms of how to send that HTML string that I get from the class to outside the function. This question is built off another question I have posted a couple days earlier -> Delegating privately declared variables to a public scope
Thanks,
Rather than implementing the dataTask in the init method add a method run with completion handler
class WebSessionCredentials {
enum WebSessionError : Error {
case badResponse(String)
}
static let requestURL = URL(string:"xxxx.on.ca/getData.aspx?requestType=Tech")!
static var sharedInstance = WebSessionCredentials()
func run(completion : #escaping (Result<String,Error>) -> Void) {
let instancedTask = URLSession.shared.dataTask(with: WebSessionCredentials.requestURL) { (data,response,error) in
if let error = error {
// Error
print("Client Error: \(error.localizedDescription)")
completion(.failure(error))
return
}
guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else {
completion(.failure(WebSessionError.badResponse("Server Error!")))
return
}
guard let mime = response.mimeType, mime == "text/html" else {
completion(.failure(WebSessionError.badResponse("Wrong mime type!")))
return
}
completion(.success(String(data: data!, encoding: .utf8)!))
}
instancedTask.resume()
}
}
And use it
WebSessionCredentials.sharedInstance.run { result in
switch result {
case .success(let htmlBody): print(htmlBody)
case .failure(let error): print(error)
}
}