2

I have a simple GET request for login. Username is Silver and password is MOto&@10
I am using SwiftHttp framework for handling requests. On hitting login request, I always get response as false.
However on hitting the login request url on browser (replaced actual domain with server) I get true :
https://server/api/check-access/by-login-pass?_key=wlyOF7TM8Y3tn19KUdlq&login=silver&pass=MOto%26@10

There is something wrong with encoding & in the password. Though I have replaced it with percent encoding. Here is my code :

do {               
   let passwordString = self.convertSpecialCharacters(string: password.text!)
   print("%@", passwordString)
   let opt = try HTTP.GET(Constants.kLoginUrl, parameters: ["login": username.text!, "pass": passwordString])
   opt.start { response in
             if let err = response.error {
                 print("error: \(err.localizedDescription)")
                 return
             }

             print("opt finished: \(response.description)")
             self.parseLoginResponse(response.data)
}
} catch _ as NSError {

}  

And this is convertSpecialCharacters :

func convertSpecialCharacters(string: String) -> String {
        var newString = string

        let arrayEncode = ["&", "<", ">", "\"", "'", "-", "..."]

        for (escaped_char) in arrayEncode {
            newString = newString.encode(escaped_char)
        }

        return newString
    } 

Extension for encoding :

extension String {
        func encode(_ chars: String) -> String
        {
            let forbidden = CharacterSet(charactersIn: chars)
            return self.addingPercentEncoding(withAllowedCharacters: forbidden.inverted) ?? self
        }
    }
Sulthan
  • 128,090
  • 22
  • 218
  • 270
Nitish
  • 13,845
  • 28
  • 135
  • 263
  • 3
    Please do not use `GET` for login purposes where you send the password along : http://stackoverflow.com/a/323286/2442804 – luk2302 Apr 01 '17 at 09:01
  • See http://stackoverflow.com/questions/24551816/swift-encode-url – Sulthan Apr 01 '17 at 10:40
  • As far as I read the latest source of SwiftHTTP, it adds percent encoding properly to the `parameters`. So, if you call `convertSpecialCharacters(string:)`, the password is double-encoded. Remove the line `let passwordString = self.convertSpecialCharacters(string: password.text!)` and create the `parameters` as `["login": username.text!, "pass": password.text!]` (assuming two `!`s are safe here.) – OOPer Apr 01 '17 at 14:47

2 Answers2

7

A suitable way is to use URLComponents which handles all percent encoding:

var urlComponents = URLComponents(string: "https://server/api/check-access/by-login-pass")!
let queryItems = [URLQueryItem(name:"_key", value:"wlyOF7TM8Y3tn19KUdlq"),
                  URLQueryItem(name:"login", value:"silver"),
                  URLQueryItem(name:"pass", value:"MOto&@10")]
urlComponents.queryItems = queryItems
let url = urlComponents.url

print(url) // "https://server/api/check-access/by-login-pass?_key=wlyOF7TM8Y3tn19KUdlq&login=silver&pass=MOto%26@10"

PS: I totally agree with luk2302's comment.

vadian
  • 274,689
  • 30
  • 353
  • 361
  • 3
    A small warning, `URLQueryItem` does not encode `+` to percent escapes correctly. It leaves it as `+` which is a bit surprising. – Sulthan Apr 01 '17 at 10:39
0

I've decided to go full custom for my GET-request, since everything else didn't want to work and got me angry. I used the request for something different though, like getting a list from our server. The login is done via POST requests which was easier.

However, to stick with GET-requests: I needed characters like "+" and "/" encoded... First I couldn't get the "+" encoded with the "stringByAddingPercentEncodingWithAllowedCharacters" method. So I have built my own extension for String:

extension String 
{
    return CFURLCreateStringByAddingPercentEscapes(
      nil,
      self as CFString,
      nil,
      "!*'();:@&=+$,/?%#[]" as CFString,
      CFStringBuiltInEncodings.UTF8.rawValue
    ) as String
}

2nd step was to add this to my url for the final request. I wanted to use URLQueryItems and add them to the url by using url.query or url.queryItems. Bad surprise: My already correctly encoded string got encoded again and every "%" inside of it became "%25" making it invalid. -.-

So now I have appended each encoded value to a string which will be added to the url. Doesn't feel very "swift" but ok..

let someUrl = "https://example.com/bla/bla.json"
var queryString = ""
var index = 0

// dicParam is of type [String: AnyObject] with all needed keys and values for the query
for (key, value) in dicParam  
{
    let encodedValue = (value as! String).encodeUrl()
    if index != 0
    {
        queryString.append("&\(key)=\(encodedValue)")
    }
    else
    {
        queryString.append("?\(key)=\(encodedValue)")
    }

    index += 1
}

let url = URLComponents(string: someUrl + queryString)!

Hope this helps someone and saves a few hours :/

Colibri
  • 713
  • 12
  • 16