iosswiftsslnsurlconnectionnsurlconnectiondelegate

Using NSURLConnection with a valid SSL certificate in Swift


I am relatively new to IOS development. So please bear with me and forgive anything noddy!

I am trying to get data back from a SOAP web service using NSURLConnection, and it's working fine.

However, as soon as I change the URL from http to https then I do not get any data back anymore and I do not get an error or anything like I would expect.

The https certificate is a valid certificate from godaddy and it setup correctly and views correctly on all browsers etc fine, so basically can anyone point me in the right direction as to why nothing happens when changing from http to https......

The code is in Swift and is as follows:

    // Create the SOAP Message to send
    var soapMessage = "<?xml version='1.0' encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' xmlns:ns1='http://tempuri.org/'><SOAP-ENV:Body><ns1:get_Test/></SOAP-ENV:Body></SOAP-ENV:Envelope>"

    NSLog("soapMessage generated is: %@", soapMessage)

    // Soap URL Works
    var urlString = "http://api.domain.com/testservice.svc"

    //Below https URL does not work
    //var urlString = "https://api.domain.com/testservice.svc"

    var url = NSURL(string: urlString)
    var theRequest = NSMutableURLRequest(URL: url!)

    //Get Length of request
    var msgLength = String(countElements(soapMessage))

    // POST Header values
    theRequest.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
    theRequest.addValue(msgLength, forHTTPHeaderField: "Content-Length")
    theRequest.addValue("http://tempuri.org/IService/get_Test", forHTTPHeaderField: "SoapAction")
    theRequest.HTTPMethod = "POST"
    theRequest.HTTPBody = soapMessage.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
    NSLog("Request is: %@", theRequest.allHTTPHeaderFields!)

    var connection = NSURLConnection(request: theRequest, delegate: self, startImmediately: true)
    connection?.start()

    if (connection == true) {
        var mutableData : Void = NSMutableData.initialize()
    }

Further NSURLConnection code is:

// NSURLConnectionDelegate
func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
    mutableData.length = 0;
}

func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
    mutableData.appendData(data)
}


func connection(connection: NSURLConnection, didFailWithError error: NSError) {
    NSLog("Error with Soap call: %@", error)
}

func connectionDidFinishLoading(connection: NSURLConnection!) {
    var xmlParser = NSXMLParser(data: mutableData)
    xmlParser.delegate = self
    xmlParser.parse()
    xmlParser.shouldResolveExternalEntities = true
}
// NSURLConnectionDelegate

Then I have my parser stuff, like didStartElement, didEndElement, foundCharacters, parserDidEndDocument etc.

I have also added some further delegates of NSURLConnection as below, but nothing has changed. They are being called as the logging is showing up.

 func connection(connection: NSURLConnection, canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace?) -> Bool
{
     NSLog("am here")
    return protectionSpace?.authenticationMethod == NSURLAuthenticationMethodServerTrust
}

func connection(connection: NSURLConnection, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge?)
{
     NSLog("am here 2")
    if challenge?.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
    {
        if challenge?.protectionSpace.host == "api.domain.com"
        {
            NSLog("yep")
            let credentials = NSURLCredential(forTrust: challenge!.protectionSpace.serverTrust)
            challenge!.sender.useCredential(credentials, forAuthenticationChallenge: challenge!)
        }
    }
    challenge?.sender.continueWithoutCredentialForAuthenticationChallenge(challenge!)
}

it runs through the code gets to the "yep" and so from what I understand should trust the certificate, but still nothing displays when I use the https url.

So there is no difference between any of the code apart from the https, and the certificate is properly valid, so how can I get data back using https rather than http?

Many thanks - and sorry if this is a dumb question!

Dave

Additional:

ok I have changed the connection now to:

    var connection = NSURLConnection(request: theRequest, delegate: self, startImmediately: false)
    connection?.start()

    if (connection == true) {
        var mutableData : Void = NSMutableData.initialize()
    } else {
        NSLog("Error with connection, details: %@", connection!)
    }

So this now logs "Error with connection" when I run it with SSL!

So then I have changed didreceiveresponse to:

func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
    mutableData.length = 0;
    var httpresponse = response as? NSHTTPURLResponse
    println("status \(httpresponse?.statusCode)")
    println("headers \(httpresponse?.allHeaderFields)")
}

and I see that the statuscode back is a 404 - which I just don't understand as the web service is clearly there, and can be parsed using online parsers!

So still stuck but at least it's pointing to the issue. Anyone have any thoughts to help me further?


Solution

  • If anyone else gets stuck on this, then the web config for the SVC web service was changed to:

         <bindings>
            <basicHttpBinding>
                <binding>
                    <security mode="Transport">
                        <transport clientCredentialType="None"/>
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <services>
            <service name="Service.Service">
                <endpoint address="" binding="basicHttpBinding" contract="Service.IService" />
            </service>
        </services>
    

    This fixed it so the above swift code now works fine! Phew that was a tough one!