I'm using URLSession.dataTask() but I'm getting this error in the console:
Peer disconnected during the middle of a handshake. Sending
errSSLClosedNoNotify
and:
An SSL error has occurred and a secure connection to the server cannot
be made
I open the web in my explorer and it has a valid Goddady SSL certificate recently updated.
And there is a strange detail, when I'm not running the app from xcode, sometimes it works fine.
Here is my code:
let postString = "user=\(user)&pass=\(pass)"
let url = URL(string: "https://www.<<mydomain>>.com/ws/login_ios.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print("Server Error: ", error!)
return
}
}
Related
i have a WKWebView where users can login onto my server.
i also have a site that can be called from the background to renew the session time.
However, that request needs the same session cookie as my webview.
Since the cookies are handled by HTTPCookieStorage, my first attempt was to just send the request with
var request = URLRequest(url: URL(string: DOMAIN + PAGE_KEEP_ALIVE)!)
let task = URLSession.shared.dataTask(with: request)
task.resume()
But that didn't work(i can see the invalid time of all current sessions on my server).
So, i tried adding the cookies to the request:
let cookies = HTTPCookieStorage.shared.cookies(for: URL(string: DOMAIN)!)
let headers = HTTPCookie.requestHeaderFields(with: cookies!)
var request = URLRequest(url: URL(string: DOMAIN + PAGE_KEEP_ALIVE)!)
request.allHTTPHeaderFields = headers
let task = URLSession.shared.dataTask(with: request)
task.resume()
but it still didn't work. Finally i tried request.httpShouldHandleCookies = true, but it still didn't help and i'm now out of ideas. Can anyone help me?
edit: after the comment from Larme the following worked
let store = webView.configuration.websiteDataStore.httpCookieStore
store.getAllCookies { cookies in
let domainCookies = cookies.filter { c in c.domain == DOMAIN }
let headers=HTTPCookie.requestHeaderFields(with: domainCookies)
var request = URLRequest(url: URL(string: DOMAIN + PAGE_KEEP_ALIVE)!)
request.allHTTPHeaderFields=headers
let task = URLSession.shared.webSocketTask(with: request)
task.resume()
}
I want to use the URLSession to send a json data that store the detail information to the server bought from vultr. The url is the server ip address and I already set the username and password in the postParams and set the request's httpBody property. The problem is that I can't connect the server.
I thought it should be the problem that I fail to connect to the server. I just buy a server and do nothing to it. The server has a username and a password. I don't know whether I should first setup the server or if I can use it directly after finishing the purchase.
private func sendData() {
let url = URL(string: "https://xxx.xxx.xxx.xxx")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let postParams = "username=root&password=*****"
let postData = postParams.data(using: .utf8)
request.httpBody = postData
let task = URLSession.shared.uploadTask(with: request, fromFile: AppDelegate.data.filename!) { data, response, error in
if let error = error {
print("error: \(error)")
return
}
guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else {
print("server error")
return
}
if let mimeType = response.mimeType, mimeType == "application/json", let data = data, let dataString = String(data: data, encoding: .utf8) {
print("got data: \(dataString)")
}
}
task.resume()
}
The error message is shown as followed:
2019-09-07 21:02:46.880119+0800 HeadGaze[2241:445676] Task .<1> finished with error - code: -1004
error: Error Domain=NSURLErrorDomain Code=-1004 "Could not connect to the server." UserInfo={NSUnderlyingError=0x2807e0f30 {Error Domain=kCFErrorDomainCFNetwork Code=-1004 "(null)" UserInfo={_kCFStreamErrorCodeKey=61, _kCFStreamErrorDomainKey=1}}, NSErrorFailingURLStringKey=https://155.138.243.166/, NSErrorFailingURLKey=https://155.138.243.166/, _kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=61, NSLocalizedDescription=Could not connect to the server.}
With my program I try to login and scrape the home page, however after I log in with a post request (in which the response says successful), when I try to get the home page it says my session has timed out.
I've tried using different types of session, modifying minor parts of the code, and Alamofire with no success
import Foundation
let session: URLSession = {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 30 // seconds
configuration.timeoutIntervalForResource = 30 // seconds
return URLSession(configuration: .default)
}()
let url = URL(string: "examplesite.com")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField:
"Content-Type")
request.httpMethod = "POST"
let postString = "Email=exampleemail&Password=examplepass"
request.httpBody = postString.data(using: .utf8)
//log in
session.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
// check for fundamental networking error
print("\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode
!= 200 { // check for http errors
print("\(httpStatus.statusCode)")
print("\(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("\(responseString)")
let urlnext = URL(string: "example.com/HomePage")!
//get page after loggin in
session.dataTask(with: urlnext) { datanext, responsenext, errornext in
guard let datanext = datanext, errornext == nil else {
print("\(errornext)")
return
}
let stringnext = String(data: datanext, encoding: .utf8)
//get page html
print("\(stringnext)")
}.resume()
}.resume()
// Infinitely run the main loop to wait for our request.
// Only necessary if you are testing in the command line.
RunLoop.main.run()
the results are a successful login {\"msg\":\"\",\"valid\":\"1\"}, and the html code of a time out page instead of the home page
I would like with an API -Key and authenticate user . I have the message " Session URL Task Succeeded : HTTP 200 " get in the Console . Unfortunately, I always get the message of the page " {" message " : " . Authorization has been denied for this request " } " . I spent hours looking for and found a solution . I ask for your help . Here is my code :
let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
let URL = NSURL(string: "https://api.testhomepage.com/api/contact")
let request = NSMutableURLRequest(URL: URL!)
// Headers
request.addValue("ARRAffinity=259dfjiehfs315d7249df8805c7895a98c4cbd3327ffdcb82aaa16317f2e6", forHTTPHeaderField: "Cookie")
request.addValue("Basic dWVzQGp1bGl0ZafdgfvcfgeDcyZS1hZWEyLTQzYmVmMjFhNDMxZQ==", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("api.testhomepage.com", forHTTPHeaderField: "Host")
request.addValue("//api.testhomepage.com/api/contact: POST", forHTTPHeaderField: "https")
request.HTTPMethod = "GET"
// JSON Body
/* Start a new Task */
let task = session.dataTaskWithRequest(request) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
if (error == nil) {
// Success
let statusCode = (response as! NSHTTPURLResponse).statusCode
print("URL Session Task Succeeded: HTTP \(statusCode)")
let myURLString = "https://api.testhomepage.com/api/contact"
if let myURL = NSURL(string: myURLString) {
var error: NSError?
let myhtml = try! NSString(contentsOfURL: myURL, encoding: NSUTF8StringEncoding)
if let error = error {
print("Error : \(error)")
} else {
print("HTML : \(myhtml)")
}
} else {
print("Error: \(myURLString) doesn't seem to be a valid URL")
}
}
else {
// Failure
print("URL Session Task Failed: %#", error!.localizedDescription);
}
}
task.resume()
}
This is in the console:
URL Session Task Succeeded: HTTP 200
HTML : {"Message":"Authorization has been denied for this request."}
use request.setvalue("", forHTTPHeaderField: "") instead of request.addValue("", forHTTPHeaderField: "")
You cannot populate the Authentication header yourself, period. That header is owned by the URL loading system, and is populated based on credentials in the user's keychain.
You can learn about how to do authentication by reading the authentication chapter of URL Session Programming Guide. Note that the examples are for NSURLConnection, but the rest of the text applies to both.
Alternatively, you can store the credentials in the keychain as an Internet Password item, as described in Keychain Services Programming Guide.
Problem
I would like to use the MailGun service to send emails from a pure Swift app.
Research So Far
As I understand it, there are two methods to send an email via MailGun. One is to email MailGun with the emails, and MailGun will redirect it (See Send via SMTP). That will, as I understand it, not work, as iOS cannot programatically automatically send mail, and must use methods that require user intervention. As such, I should use the API directly. As I understand it, I need to open a URL to do this, and so I should use some form of NSURLSession, as per this SO answer
Code
MailGun provides documentation for Python, which is as follows:
def send_simple_message():
return requests.post(
"https://api.mailgun.net/v3/sandbox(Personal info).mailgun.org/messages",
auth=("api", "key-(Personal info)"),
data={"from": "Excited User <(Personal info)>",
"to": ["bar#example.com", "(Personal info)"],
"subject": "Hello",
"text": "Testing some Mailgun awesomness!"})
with (Personal info) being substituted for keys/information/emails.
Question
How do I do that in Swift?
Thanks!
In python, the auth is being passed in the header.
You have to do a http post request, passing both the header and the body.
This is a working code:
func test() {
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: "https://api.mailgun.net/v3/sandbox(Personal info).mailgun.org/messages")!)
request.HTTPMethod = "POST"
let data = "from: Excited User <(Personal info)>&to: [bar#example.com,(Personal info)]&subject:Hello&text:Testinggsome Mailgun awesomness!"
request.HTTPBody = data.dataUsingEncoding(NSASCIIStringEncoding)
request.setValue("key-(Personal info)", forHTTPHeaderField: "api")
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.URL!)")
print("response = \(response)")
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}
people are getting 400 or 401 errors because none of the other answers construct the url correctly. here is some code that works in swift 5 and iOS15:
func sendEmail() {
// variablize our https path with API key, recipient and message text
let mailgunAPIPath = "https://api:YOUR_API_KEY#api.mailgun.net/v3/YOUR_DOMAIN/messages?"
let emailRecipient = "RECIPIENT#EMAIL.COM"
let emailMessage = "Testing%20email%20sender%20variables"
// Create a session and fill it with our request
let session = URLSession.shared
let request = NSMutableURLRequest(url: NSURL(string: mailgunAPIPath + "from=USER#YOUR_DOMAIN&to=\(emailRecipient)&subject=A%20New%20Test%21&text=\(emailMessage)")! as URL)
// POST and report back with any errors and response codes
request.httpMethod = "POST"
let task = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.url!)")
print("response = \(response)")
let httpResponse = response as! HTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}
requests.post sends an HTTP POST request, encoding key/value pairs as application/x-www-form-urlencoded. You need to do the same.
convert the set of key-value pairs into application/x-www-form-urlencoded as per How to escape the HTTP params in Swift
compose the request using the resulting string for data & send it as per iOS : http Post using swift
I spent hours trying to get the selected answer working, but to no avail.
Although I was finally able to get this working properly with a large HTTP response. I put the full path into Keys.plist so that I can upload my code to github and broke out some of the arguments into variables so I can have them programmatically set later down the road.
// Email the FBO with desired information
// Parse our Keys.plist so we can use our path
var keys: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("Keys", ofType: "plist") {
keys = NSDictionary(contentsOfFile: path)
}
if let dict = keys {
// variablize our https path with API key, recipient and message text
let mailgunAPIPath = dict["mailgunAPIPath"] as? String
let emailRecipient = "bar#foo.com"
let emailMessage = "Testing%20email%20sender%20variables"
// Create a session and fill it with our request
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: mailgunAPIPath! + "from=FBOGo%20Reservation%20%3Cscheduler#<my domain>.com%3E&to=reservations#<my domain>.com&to=\(emailRecipient)&subject=A%20New%20Reservation%21&text=\(emailMessage)")!)
// POST and report back with any errors and response codes
request.HTTPMethod = "POST"
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.URL!)")
print("response = \(response)")
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}
The Mailgun Path is in Keys.plist as a string called mailgunAPIPath with the value:
https://API:key-<my key>#api.mailgun.net/v3/<my domain>.com/messages?
Hope this offers a solution to anyone else having issues with MailGun and wanting to avoid a 3rd party solution!
Swift 3 answer:
func test() {
let session = URLSession.shared
var request = URLRequest(url: URL(string: "https://api.mailgun.net/v3/sandbox(Personal info).mailgun.org/messages")!)
request.httpMethod = "POST"
let data = "from: Excited User <(Personal info)>&to: [bar#example.com,(Personal info)]&subject:Hello&text:Testinggsome Mailgun awesomness!"
request.httpBody = data.data(using: .ascii)
request.setValue("key-(Personal info)", forHTTPHeaderField: "api")
let task = session.dataTask(with: request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.url!)")
print("response = \(response)")
let httpResponse = response as! HTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}