send urlrequest with same session id as webview - swift

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()
}

Related

How to add followRedirect or not in Swift 3/4 in URLSession?

I am making API calls in Swift using URLSession and I want to add option in my request whether to allow redirects of a request (followRedirect) but I don't know how to accomplish it.. I think there is a way in Alamofire but I can not use external library for this task...
i.e. In NodeJS you can do
var 'https' = require('follow-redirects').'https';
//and add this in field in options of https.request allowing max 21 redirects
'maxRedirects': 21
If someone know how to do it.. Please let me know..
This is my snippet, let me know of any suggested changes.
import Foundation
var sema = DispatchSemaphore (value: 0)
var request = URLRequest(url: URL(string: "https://mockbin.org/request")!, timeoutInterval: 2000)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
return
}
print(String(data: data, encoding: .utf8)!)
sema.signal()
}
task.resume()
sema.wait()

Using facebook graph API to make HTTPS POST request in swift

When I use the url below normally on Google Chrome, I am able to create a new facebook test user, I get back a valid json with username and password, and other details back.
https://graph.facebook.com/v3.1/2232192233718728/accounts/test-users?installed=true&name=Thomasfsdks&locale=en_US&permissions=read_stream&method=post&access_token=2232192233718728|24q_TtCeh44Z0dUVm7x5pg2U5iQ
However, when I try to do it on swift, it does not seem to work correctly. I am unsure how to make it work.Below is the code in swift.
let appID = "2232192233718728"
let urlString = "https://graph.facebook.com/v3.1/" + appID + "/accounts/test-users?"
let url = URL(string: urlString)!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let name = "Thomasdasfafada"
let accessToken = "2232192233718728|24q_TtCeh44Z0dUVm7x5pg2U5iQ"
let postString = "installed=true&name=" + name + "&locale=en_US&permissions=read_stream&method=post&access_token=" + accessToken
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
let responseString = String(data: data!, encoding: .utf8)
print("here"+"responseString = \(responseString)")
}
task.resume()

Swift - How to set cookie in NSMutableURLRequest

I'm trying to set cookie in my HTTP request
and I thought that below code would work:
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "GET"
request.setValue("key=value;", forHTTPHeaderField: "Cookie")
but this code is not working.
does anyone have idea how to set it?
Updated answer for Swift 3
You want to look at HTTPCookieStorage.
// First
let jar = HTTPCookieStorage.shared
let cookieHeaderField = ["Set-Cookie": "key=value"] // Or ["Set-Cookie": "key=value, key2=value2"] for multiple cookies
let cookies = HTTPCookie.cookies(withResponseHeaderFields: cookieHeaderField, for: url)
jar.setCookies(cookies, for: url, mainDocumentURL: url)
// Then
var request = URLRequest(url: url)
Original answer for swift 2
You want to look at NSHTTPCookieStorage.
// First
let jar = NSHTTPCookieStorage.sharedHTTPCookieStorage()
let cookieHeaderField = ["Set-Cookie": "key=value"] // Or ["Set-Cookie": "key=value, key2=value2"] for multiple cookies
let cookies = NSHTTPCookie.cookiesWithResponseHeaderFields(cookieHeaderField, forURL: url)
jar.setCookies(cookies, forURL: url, mainDocumentURL: url)
// Then
let request = NSMutableURLRequest(URL: url)
Swift 5
if let cookie = HTTPCookie(properties: [
.domain: ".my.domain.name.com",
.path: "/",
.name: "myCookieNameKey",
.value: "K324klj23KLJKH223423CookieValueDSFLJ234",
.secure: "FALSE",
.discard: "TRUE"
]) {
HTTPCookieStorage.shared.setCookie(cookie)
print("Cookie inserted: \(cookie)")
}
This may be useful for some one(Swift 5).
Avoid using NSMutableURLRequest in Swift. Instead follow the below snippet:
func request(with url: URL) -> URLRequest {
var request = URLRequest(url: url)
guard let cookies = HTTPCookieStorage.shared.cookies(for: url) else {
return request
}
request.allHTTPHeaderFields = HTTPCookie.requestHeaderFields(with: cookies)
return request
}
Here is how it works in Swift 3.x after you set cookie using HTTPCookieStorage
let cookies=HTTPCookieStorage.shared.cookies(for: URL(string: cookieURL)!)
let headers=HTTPCookie.requestHeaderFields(with: cookies!)
let request = NSMutableURLRequest(url: requestURL!)
request.allHTTPHeaderFields=headers

Swift Send Email with MailGun

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()
}

Save cookie persistence

var url:NSURL=NSURL(string:"http://xxxxxxxx/index.php?s=/Public_verify.html")!
var data:NSData=NSData(contentsOfURL: url)!
var img:UIImage=UIImage(data:data)!
self.Verify.setBackgroundImage(img, forState: UIControlState.Normal)
var username=UserName.text
var password=PassWord.text
var verifycode=VerifyCode.text
let url=NSURL(string:"http://xxxxxxxx/index.php?s=/Public_doLogin.html")!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
let postString = "username=\(username)&password=\(password)&verifyCode=\(verifycode)&ajax=1"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
//cookie?
}
task.resume()
Code above, I used NSURLSession.sharedSession (). DataTaskWithRequest to POST login.
I quit APP, COOKIE disappears need to re-login
How to make cookie has been recorded, unless I log off the user?