New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS 9 AFHTTPRequestOperation failure #2779

Closed
kross50 opened this Issue Jun 10, 2015 · 5 comments

Comments

Projects
None yet
3 participants
@kross50

kross50 commented Jun 10, 2015

In iOS 8, the below code works (in Sim and Device) with the latest version of AFNetworking. In iOS 9, the below code fails with AFHTTPRequestOperation returning the following error in the failure block (in Sim and Device):

Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)"

//

__weak __typeof(self)weakSelf = self;
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
requestOperation.responseSerializer = [AFImageResponseSerializer serializer];
[requestOperation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
CGFloat progress = (CGFloat)totalBytesRead/(CGFloat)totalBytesExpectedToRead;

        self.progressLayer.strokeEnd        = progress;
        self.backgroundLayer.strokeStart    = progress;
    }];
    [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        UIImage *image = responseObject;
        [weakSelf updateWithImage:image animated:YES];
        if(self.cacheEnabled)
        {
            [self.cache setImage:responseObject forURL:URL];
        }
        if(completionBlock) completionBlock(nil);

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        if(completionBlock) completionBlock(error);
    }];
    [requestOperation start];
@kross50

This comment has been minimized.

Show comment
Hide comment
@kross50

kross50 Jun 10, 2015

Failure seems to happen right after the following is called:

  • (void)connection:(NSURLConnection *)connection
    willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    ..
    [[challenge sender] cancelAuthenticationChallenge:challenge];
    ..
    }

kross50 commented Jun 10, 2015

Failure seems to happen right after the following is called:

  • (void)connection:(NSURLConnection *)connection
    willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    ..
    [[challenge sender] cancelAuthenticationChallenge:challenge];
    ..
    }
@kross50

This comment has been minimized.

Show comment
Hide comment
@kross50

kross50 Jun 10, 2015

Found the answer:

http://stackoverflow.com/questions/30739473/ios9-nsurlsession-nsurlconnection-http-load-failed
//
In iOS9, ATS enforces best practices during network calls, including the use of HTTPS.

From Apple documentation:

ATS prevents accidental disclosure, provides secure default behavior, and is easy to adopt. You should adopt ATS as soon as possible, regardless of whether you’re creating a new app or updating an existing one. If you’re developing a new app, you should use HTTPS exclusively. If you have an existing app, you should use HTTPS as much as you can right now, and create a plan for migrating the rest of your app as soon as possible.

In beta 1, currently there is no way to define this in info.plist. Solution is to add it manually:

kross50 commented Jun 10, 2015

Found the answer:

http://stackoverflow.com/questions/30739473/ios9-nsurlsession-nsurlconnection-http-load-failed
//
In iOS9, ATS enforces best practices during network calls, including the use of HTTPS.

From Apple documentation:

ATS prevents accidental disclosure, provides secure default behavior, and is easy to adopt. You should adopt ATS as soon as possible, regardless of whether you’re creating a new app or updating an existing one. If you’re developing a new app, you should use HTTPS exclusively. If you have an existing app, you should use HTTPS as much as you can right now, and create a plan for migrating the rest of your app as soon as possible.

In beta 1, currently there is no way to define this in info.plist. Solution is to add it manually:

@macecchi

This comment has been minimized.

Show comment
Hide comment
@macecchi

macecchi Jun 14, 2015

I was able to reproduce the problem. Using @kross50's solution I was able to fix it. I just added an exception in my info.plist with the domain I was using and it worked normally.

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains</key>
  <dict>
    <key>yourserver.com</key>
    <dict>
      <!--Include to allow subdomains-->
      <key>NSIncludesSubdomains</key>
      <true/>
      <!--Include to allow HTTP requests-->
      <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
      <true/>
      <!--Include to specify minimum TLS version-->
      <key>NSTemporaryExceptionMinimumTLSVersion</key>
      <string>TLSv1.1</string>
    </dict>
  </dict>
</dict>

So, it's not a bug, just new iOS default behaviour. A better error message would've been great though, but... first beta.

(By the way, thanks a lot for posting the answer you found, @kross50!)

macecchi commented Jun 14, 2015

I was able to reproduce the problem. Using @kross50's solution I was able to fix it. I just added an exception in my info.plist with the domain I was using and it worked normally.

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains</key>
  <dict>
    <key>yourserver.com</key>
    <dict>
      <!--Include to allow subdomains-->
      <key>NSIncludesSubdomains</key>
      <true/>
      <!--Include to allow HTTP requests-->
      <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
      <true/>
      <!--Include to specify minimum TLS version-->
      <key>NSTemporaryExceptionMinimumTLSVersion</key>
      <string>TLSv1.1</string>
    </dict>
  </dict>
</dict>

So, it's not a bug, just new iOS default behaviour. A better error message would've been great though, but... first beta.

(By the way, thanks a lot for posting the answer you found, @kross50!)

@kross50

This comment has been minimized.

Show comment
Hide comment
@kross50

kross50 Jun 14, 2015

Always glad to help... in addition to the above domain-by-domain exception fix... it's also worth noting for views that devs can alternatively just put in a blanket exception with the following in their app's info.plist that covers any http call to any domain [if the first option is not viable because of not knowing up-front which domains will need exceptions]:

<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>

kross50 commented Jun 14, 2015

Always glad to help... in addition to the above domain-by-domain exception fix... it's also worth noting for views that devs can alternatively just put in a blanket exception with the following in their app's info.plist that covers any http call to any domain [if the first option is not viable because of not knowing up-front which domains will need exceptions]:

<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>

@kcharwood

This comment has been minimized.

Show comment
Hide comment
@kcharwood

kcharwood Jun 15, 2015

Contributor

I want to make sure everyone fully understands this behavior. I spent some time in the labs last week at WWDC, and got the following information.

Setting NSAllowsArbitraryLoads to true will allow it to work, but Apple was very clear in that they intend to reject apps who use this flag without a specific reason. The main reason to use NSAllowsArbitraryLoads I can think of would be user created content (link sharing, custom web browser, etc). And in this case, Apple still expects you to include exceptions that enforce the ATS for the URLs you are in control of.

If you do need access to specific URLs that are not served over TLS 1.2, you need to write specific exceptions for those domains, not use NSAllowsArbitraryLoads set to yes. You can find more info in the NSURLSesssion WWDC session.

Please be careful in sharing the NSAllowsArbitraryLoads solution. It is not the recommended fix from Apple.

Contributor

kcharwood commented Jun 15, 2015

I want to make sure everyone fully understands this behavior. I spent some time in the labs last week at WWDC, and got the following information.

Setting NSAllowsArbitraryLoads to true will allow it to work, but Apple was very clear in that they intend to reject apps who use this flag without a specific reason. The main reason to use NSAllowsArbitraryLoads I can think of would be user created content (link sharing, custom web browser, etc). And in this case, Apple still expects you to include exceptions that enforce the ATS for the URLs you are in control of.

If you do need access to specific URLs that are not served over TLS 1.2, you need to write specific exceptions for those domains, not use NSAllowsArbitraryLoads set to yes. You can find more info in the NSURLSesssion WWDC session.

Please be careful in sharing the NSAllowsArbitraryLoads solution. It is not the recommended fix from Apple.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment