#import #import #import #import "NSURLSession+AnyPromise.h" #import #import #import #import #import #import #import #import @implementation NSURLSession (PromiseKit) - (AnyPromise *)promiseDataTaskWithRequest:(NSURLRequest *)rq { return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { [[self dataTaskWithRequest:rq completionHandler:^(NSData *data, id rsp, NSError *urlError){ assert(![NSThread isMainThread]); PMKResolver fulfiller = ^(id responseObject){ resolve(PMKManifold(responseObject, rsp, data)); }; PMKResolver rejecter = ^(NSError *error){ id userInfo = error.userInfo.mutableCopy ?: [NSMutableDictionary new]; if (data) userInfo[PMKURLErrorFailingDataKey] = data; if (rsp) userInfo[PMKURLErrorFailingURLResponseKey] = rsp; error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo]; resolve(error); }; NSStringEncoding (^stringEncoding)(void) = ^NSStringEncoding{ id encodingName = [rsp textEncodingName]; if (encodingName) { CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName); if (encoding != kCFStringEncodingInvalidId) return CFStringConvertEncodingToNSStringEncoding(encoding); } return NSUTF8StringEncoding; }; if (urlError) { rejecter(urlError); } else if (![rsp isKindOfClass:[NSHTTPURLResponse class]]) { fulfiller(data); } else if ([rsp statusCode] < 200 || [rsp statusCode] >= 300) { id info = @{ NSLocalizedDescriptionKey: @"The server returned a bad HTTP response code", NSURLErrorFailingURLStringErrorKey: rq.URL.absoluteString, NSURLErrorFailingURLErrorKey: rq.URL }; id err = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:info]; rejecter(err); } else if (PMKHTTPURLResponseIsJSON(rsp)) { // work around ever-so-common Rails workaround: https://github.com/rails/rails/issues/1742 if ([rsp expectedContentLength] == 1 && [data isEqualToData:[NSData dataWithBytes:" " length:1]]) return fulfiller(nil); NSError *err = nil; id json = [NSJSONSerialization JSONObjectWithData:data options:PMKJSONDeserializationOptions error:&err]; if (!err) { fulfiller(json); } else { id userInfo = err.userInfo.mutableCopy; if (data) { NSString *string = [[NSString alloc] initWithData:data encoding:stringEncoding()]; if (string) userInfo[PMKURLErrorFailingStringKey] = string; } long long length = [rsp expectedContentLength]; id bytes = length <= 0 ? @"" : [NSString stringWithFormat:@"%lld bytes", length]; id fmt = @"The server claimed a %@ JSON response, but decoding failed with: %@"; userInfo[NSLocalizedDescriptionKey] = [NSString stringWithFormat:fmt, bytes, userInfo[NSLocalizedDescriptionKey]]; err = [NSError errorWithDomain:err.domain code:err.code userInfo:userInfo]; rejecter(err); } #ifdef UIKIT_EXTERN } else if (PMKHTTPURLResponseIsImage(rsp)) { UIImage *image = [[UIImage alloc] initWithData:data]; image = [[UIImage alloc] initWithCGImage:[image CGImage] scale:image.scale orientation:image.imageOrientation]; if (image) fulfiller(image); else { id info = @{ NSLocalizedDescriptionKey: @"The server returned invalid image data", NSURLErrorFailingURLStringErrorKey: rq.URL.absoluteString, NSURLErrorFailingURLErrorKey: rq.URL }; id err = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:info]; rejecter(err); } #endif } else if (PMKHTTPURLResponseIsText(rsp)) { id str = [[NSString alloc] initWithData:data encoding:stringEncoding()]; if (str) fulfiller(str); else { id info = @{ NSLocalizedDescriptionKey: @"The server returned invalid string data", NSURLErrorFailingURLStringErrorKey: rq.URL.absoluteString, NSURLErrorFailingURLErrorKey: rq.URL }; id err = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:info]; rejecter(err); } } else { fulfiller(data); } }] resume]; }]; } @end