Swift 4: Errors When Loading Web Page Content in iOS app

The app I'm creating in Xcode 9 needs to load web page content, so I followed the code suggested in https://www.hackingwithswift.com/example-code/strings/how-to-load-a-string-from-a-website-url


    if let url = URL(string: "https://flightplanning.navcanada.ca/cgi-bin/Fore-obs/notam.cgi?ni_FIR=on&Stations=CZEG") {
    do {
        let contents = try String(contentsOf: url)
        print(contents)
    } catch {
        // contents could not be loaded
    }
} else {
    // the URL was bad!
}


From various other threads, it seemed to be a problem with the info.plist file, so following these suggestions I added the following entries in the info.plist:

https://i.stack.imgur.com/LYuv4.png


<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <false/>
  <key>NSExceptionDomains</key>
  <dict>
  <key>flightplanning.navcanada.ca</key>
  <dict/>
  <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
  <true/>
  <key>NSIncludesSubdomains</key>
  <true/>
  </dict>
</dict>


The errors returned:

SSL_ERROR_SSL(1): operation failed within the library

SSLV3_ALERT_HANDSHAKE_FAILURE:/BuildRoot/Library/Caches/com.apple.xbs/Sources/boringssl_Sim/boringssl-109.50.14/ssl/tls_record.c:547:SSL alert number 40

HANDSHAKE_FAILURE_ON_CLIENT_HELLO

Function boringssl_context_get_os_status: line 4268 SSL_AD_HANDSHAKE_FAILURE

TIC TCP Conn Failed

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9824)

Task <AB92C36B-6E8A-42E5-9C3E-73AF6E258F43>.<0> HTTP load failed (error code: -1200 [3:-9824])

NSURLConnection finished with error - code -1200


Any corrective suggestions would be greatly appreciated.


Note when I use the same code to load web content from other web sites it seems to work ok.

When I access this website, https://flightplanning.navcanada.ca/cgi-bin/Fore-obs/notam.cgi?ni_FIR=on&Stations=CZEG, on Safari, it loads the web site with no problems.

Replies

Can anybody help?

Isn't it NSExceptionAllowsInsecureHTTPLoads (not NSTemporaryException...)?


Does it work with the blanket NSAllowsArbitraryLoads set (and your exception domain removed / commented out)?


Edit: Also, your syntax looks funky... line 8 should just be <dict> I think, to start the dictionary that contains the two keys (includes subdomains and allows arbitrary loads) for the exception domain. You should have three nested dictionaries: NSAppTransportSecurity, NSExceptionDomains, and the one for your exception domain.

No. Doesn’t work either. Same errors. Other web pages load ok and this specific web page loads on safari with no issues.

While this server supports HTTPS that support is quite out of date. Specifically:

  • It doesn’t support TLS 1.2.

  • It doesn’t support forward secrecy.

I recommend that you work with the server folks to update it to support best practice security.

If that’s not possible then you will need to disable App Transport Security’s enforcement of best practice security by adding this to your

Info.plist
.
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>flightplanning.navcanada.ca</key>
        <dict>
            <key>NSExceptionMinimumTLSVersion</key>
            <string>TLSv1.0</string>
            <key>NSExceptionRequiresForwardSecrecy</key>
            <false/>
        </dict>
    </dict>
</dict>

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hello,

Thank you for your reply. I was really eager to try this out but unfortunately, have been on the road.


I tried it today. But still get errors upon attempting to load the web page contents:

2018-07-21 18:06:21.451622-0400 Load Web Content[7033:2216088] [BoringSSL] Function boringssl_session_errorlog: line 2866 [boringssl_session_handshake_continue] SSL_ERROR_SSL(1): operation failed within the library
2018-07-21 18:06:21.451965-0400 Load Web Content[7033:2216088] [BoringSSL] Function boringssl_session_handshake_error_print: line 2805 boringssl ctx 0x7f9daf4052e0: 140315314882832:error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE:/BuildRoot/Library/Caches/com.apple.xbs/Sources/boringssl_Sim/boringssl-109.50.14/ssl/tls_record.c:547:SSL alert number 40
2018-07-21 18:06:21.452278-0400 Load Web Content[7033:2216088] [BoringSSL] Function boringssl_session_handshake_error_print: line 2805 boringssl ctx 0x7f9daf4052e0: 140315314882832:error:1000009a:SSL routines:OPENSSL_internal:HANDSHAKE_FAILURE_ON_CLIENT_HELLO:/BuildRoot/Library/Caches/com.apple.xbs/Sources/boringssl_Sim/boringssl-109.50.14/ssl/handshake_client.c:946:
2018-07-21 18:06:21.452520-0400 Load Web Content[7033:2216088] [BoringSSL] Function boringssl_context_get_os_status: line 4268 SSL_AD_HANDSHAKE_FAILURE
2018-07-21 18:06:21.460732-0400 Load Web Content[7033:2216088] TIC TCP Conn Failed [1:0x60000017d040]: 3:-9824 Err(-9824)
2018-07-21 18:06:21.461300-0400 Load Web Content[7033:2216088] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9824)
2018-07-21 18:06:21.461409-0400 Load Web Content[7033:2216088] Task <59B7AE65-5FCA-407F-BDE1-0914AD9D350D>.<0> HTTP load failed (error code: -1200 [3:-9824])
2018-07-21 18:06:21.461551-0400 Load Web Content[7033:2216091] NSURLConnection finished with error - code -1200

If you please have any other suggestions I would greatly appreciate it as I'm stuck and can't progress with my app without this.


Here is the code in my test app:

    override func viewDidLoad()
    {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        if let url = URL(string: "https://flightplanning.navcanada.ca/cgi-bin/Fore-obs/notam.cgi?ni_FIR=on&Stations=CZEG")
        {
            do
            {
                let contents = try String(contentsOf: url)
                print(contents)
            }
            catch
            {
                // contents could not be loaded
            }
        }
        else
        {
            // the URL was bad!
        }
    }


Here is the info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleDevelopmentRegion</key>
  <string>$(DEVELOPMENT_LANGUAGE)</string>
  <key>CFBundleExecutable</key>
  <string>$(EXECUTABLE_NAME)</string>
  <key>CFBundleIdentifier</key>
  <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
  <key>CFBundleInfoDictionaryVersion</key>
  <string>6.0</string>
  <key>CFBundleName</key>
  <string>$(PRODUCT_NAME)</string>
  <key>CFBundlePackageType</key>
  <string>BNDL</string>
  <key>CFBundleShortVersionString</key>
  <string>1.0</string>
  <key>CFBundleVersion</key>
  <string>1</string>


  <key>NSAppTransportSecurity</key>  
  <dict>  
     <key>NSExceptionDomains</key>  
     <dict>  
  <key>flightplanning.navcanada.ca</key>  
  <dict>  
     <key>NSExceptionMinimumTLSVersion</key>  
     <string>TLSv1.0</string>  
     <key>NSExceptionRequiresForwardSecrecy</key>  
     <false/>  
  </dict>  
     </dict>  
  </dict>  


</dict>
</plist>

I put your code into a test project here and then tweaked the

catch
clause to print the error:
NSLog("error %@", error as NSError)

Here’s what I see:

2018-07-23 10:36:18.485751+0100 xxsi[3066:315833] error Error Domain=NSCocoaErrorDomain Code=264 "The file “notam.cgi” couldn’t be opened because the text encoding of its contents can’t be determined." UserInfo={NSURL=https://flightplanning.navcanada.ca/cgi-bin/Fore-obs/notam.cgi?ni_FIR=on&Stations=CZEG}

So the problem isn’t that you can’t load the resource, it’s that the resource isn’t being parsed correctly. That’s because of a text encoding problem; you’re using

String(contentsOf:)
, whose text encoding behaviour is not well specified.

I strongly recommend that you fetch the resource using

URLSession
. For example, code like this:
let url = URL(string: "https://flightplanning.navcanada.ca/cgi-bin/Fore-obs/notam.cgi?ni_FIR=on&Stations=CZEG")!
let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60.0)
URLSession.shared.dataTask(with: request) { (data, response, error) in
    if let error = error as NSError? {
        NSLog("task transport error %@ / %d", error.domain, error.code)
        return
    }
    let response = response as! HTTPURLResponse
    let data = data!
    NSLog("task finished with status %d, bytes %d", response.statusCode, data.count)
}.resume()

prints:

2018-07-23 10:38:25.422562+0100 xxsi[3066:318977] task finished with status 200, bytes 27935

indicating that the resource was fetched correctly. Moreover, the content type (

response?.mimeType
) is
text/html
, meaning that you need to parse the data as HTML, and HTML has its own rules about how to deal with text encodings.

Now, if you only care about this specific site, and you’re OK with your code breaking if the site changes its text encoding, you can take a shortcut and interpret the data as ISO-8859-1 (aka ISO-Latin-1). For example:

if let text = String(data: data, encoding: .isoLatin1) {
    … deal with `text` …
} else {
    … `data` wasn't parseable as ISO-Latin-1 …
}

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hello,

I really apreciate your assistance. But I tried your version of the code, it seems to have the same issue:


I tried your version of the code:

    override func viewDidLoad()
    {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let url = URL(string: "https://flightplanning.navcanada.ca/cgi-bin/Fore-obs/notam.cgi?ni_FIR=on&Stations=CZEG")!
        let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60.0)
        URLSession.shared.dataTask(with: request)
        { (data, response, error) in
            if let error = error as NSError?
            {
                NSLog("--------------------------------------------------------")
                NSLog("task transport error %@ / %d", error.domain, error.code)
                NSLog("--------------------------------------------------------")

                print("--------------------------------------------------------")
                print("task transport error \(error.domain) / \(error.code)")
                print("--------------------------------------------------------")
                return
            }
            let response = response as! HTTPURLResponse
            let data = data!
            NSLog("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
            NSLog("task finished with status %d, bytes %d", response.statusCode, data.count)
            NSLog("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
            
            print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
            print("task finished with status \(response.statusCode), \(data.count) bytes")
            print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")

        }.resume()
    }


And this is what I see in the output:

2018-07-23 09:42:02.319798-0400 Load Web Content[23874:4065599] [BoringSSL] Function boringssl_session_errorlog: line 2866 [boringssl_session_handshake_continue] SSL_ERROR_SSL(1): operation failed within the library
2018-07-23 09:42:02.320099-0400 Load Web Content[23874:4065599] [BoringSSL] Function boringssl_session_handshake_error_print: line 2805 boringssl ctx 0x7f91a6602b00: 140263629523344:error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE:/BuildRoot/Library/Caches/com.apple.xbs/Sources/boringssl_Sim/boringssl-109.50.14/ssl/tls_record.c:547:SSL alert number 40
2018-07-23 09:42:02.321107-0400 Load Web Content[23874:4065599] [BoringSSL] Function boringssl_session_handshake_error_print: line 2805 boringssl ctx 0x7f91a6602b00: 140263629523344:error:1000009a:SSL routines:OPENSSL_internal:HANDSHAKE_FAILURE_ON_CLIENT_HELLO:/BuildRoot/Library/Caches/com.apple.xbs/Sources/boringssl_Sim/boringssl-109.50.14/ssl/handshake_client.c:946:
2018-07-23 09:42:02.321615-0400 Load Web Content[23874:4065599] [BoringSSL] Function boringssl_context_get_os_status: line 4268 SSL_AD_HANDSHAKE_FAILURE
2018-07-23 09:42:02.333874-0400 Load Web Content[23874:4065599] TIC TCP Conn Failed [1:0x600000173200]: 3:-9824 Err(-9824)
2018-07-23 09:42:02.336214-0400 Load Web Content[23874:4065599] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9824)
2018-07-23 09:42:02.336707-0400 Load Web Content[23874:4065599] Task .<1> HTTP load failed (error code: -1200 [3:-9824])
2018-07-23 09:42:02.337733-0400 Load Web Content[23874:4065596] Task .<1> finished with error - code: -1200
2018-07-23 09:42:02.388090-0400 Load Web Content[23874:4065599] --------------------------------------------------------
2018-07-23 09:42:02.389397-0400 Load Web Content[23874:4065599] task transport error NSURLErrorDomain / -1200
2018-07-23 09:42:02.389590-0400 Load Web Content[23874:4065599] --------------------------------------------------------
--------------------------------------------------------
task transpor error NSURLErrorDomain / -1200
--------------------------------------------------------

Does this code work differently on your end?


Thank you.

Hmmm, I’m not sure why this isn’t working for you. Here’s what I did:

  1. In Xcode 9.4, I created a new project from the iOS > Single View Application template.

  2. I replaced the

    viewDidLoad
    method implementation with the code you posted yesterday (23 Jul).
  3. I editing the

    Info.plist
    to add the ATS exception properties you posted on 21 Jul.
  4. I built and ran the app on an iOS 11.4 simulator.

  5. It printed:

    2018-07-24 08:59:57.056802+0100 xxsi9[2090:174383] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    2018-07-24 08:59:57.061785+0100 xxsi9[2090:174383] task finished with status 200, bytes 27625
    2018-07-24 08:59:57.061950+0100 xxsi9[2090:174383] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    task finished with status 200, 27625 bytes
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    .

Please repeat those steps to see if you can get it working. If not, I recommend you open a DTS tech support incident so I can help you on a one-on-one basis.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hello,

I really appreciate your patience and support.

I repeated steps 1 through 5 as in your last post but the problem presists.


See screenshots: https://imgur.com/a/sPLd9kU


But same type of errors persist:

2018-08-03 16:02:24.674881-0500 Load Web Data 2[14178:4237199] [BoringSSL] Function boringssl_session_errorlog: line 2866 [boringssl_session_handshake_continue] SSL_ERROR_SSL(1): operation failed within the library
2018-08-03 16:02:24.676030-0500 Load Web Data 2[14178:4237199] [BoringSSL] Function boringssl_session_handshake_error_print: line 2805 boringssl ctx 0x7ff2b7604ce0: 140680525515408:error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE:/BuildRoot/Library/Caches/com.apple.xbs/Sources/boringssl_Sim/boringssl-109.50.14/ssl/tls_record.c:547:SSL alert number 40
2018-08-03 16:02:24.676634-0500 Load Web Data 2[14178:4237199] [BoringSSL] Function boringssl_session_handshake_error_print: line 2805 boringssl ctx 0x7ff2b7604ce0: 140680525515408:error:1000009a:SSL routines:OPENSSL_internal:HANDSHAKE_FAILURE_ON_CLIENT_HELLO:/BuildRoot/Library/Caches/com.apple.xbs/Sources/boringssl_Sim/boringssl-109.50.14/ssl/handshake_client.c:946:
2018-08-03 16:02:24.677310-0500 Load Web Data 2[14178:4237199] [BoringSSL] Function boringssl_context_get_os_status: line 4268 SSL_AD_HANDSHAKE_FAILURE
2018-08-03 16:02:24.688796-0500 Load Web Data 2[14178:4237199] TIC TCP Conn Failed [1:0x60800017b540]: 3:-9824 Err(-9824)
2018-08-03 16:02:24.690940-0500 Load Web Data 2[14178:4237199] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9824)
2018-08-03 16:02:24.691086-0500 Load Web Data 2[14178:4237199] Task <9C8D168A-4E67-42CB-BDE7-BFDAD5A4DAED>.<1> HTTP load failed (error code: -1200 [3:-9824])
2018-08-03 16:02:24.692087-0500 Load Web Data 2[14178:4237212] Task <9C8D168A-4E67-42CB-BDE7-BFDAD5A4DAED>.<1> finished with error - code: -1200
2018-08-03 16:02:24.757671-0500 Load Web Data 2[14178:4237199] --------------------------------------------------------
2018-08-03 16:02:24.761062-0500 Load Web Data 2[14178:4237199] task transport error NSURLErrorDomain / -1200
2018-08-03 16:02:24.761175-0500 Load Web Data 2[14178:4237199] --------------------------------------------------------
--------------------------------------------------------
task transport error NSURLErrorDomain / -1200
--------------------------------------------------------



I'll follow the DTS Tech Support link you suggested.

Thanks.