obj-c AFNetworking 2.0 POST request does not work obj-c AFNetworking 2.0 POST request does not work objective-c objective-c

obj-c AFNetworking 2.0 POST request does not work


Finally it works. Was a hassle but now I am really happy... During my testing I had some problems with 'request body stream exhausted' within Wifi, what was strange.

Below the code that did the trick for me.

- (void)upload {    // !!! only JPG, PNG not covered! Have to cover PNG as well    NSString *fileName = [NSString stringWithFormat:@"%ld%c%c.jpg", (long)[[NSDate date] timeIntervalSince1970], arc4random_uniform(26) + 'a', arc4random_uniform(26) + 'a'];    // NSLog(@"FileName == %@", fileName);    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];    NSDictionary *parameters = @{@"lat": @"8.444444",                                 @"lng": @"50.44444",                                 @"location": @"New York",                                 @"type": @"2",                                 @"claim": @"NYC",                                 @"flag": @"0"};     // BASIC AUTH (if you need):    manager.securityPolicy.allowInvalidCertificates = YES;    manager.requestSerializer = [AFHTTPRequestSerializer serializer];    [manager.requestSerializer setAuthorizationHeaderFieldWithUsername:@"foo" password:@"bar"];    // BASIC AUTH END    NSString *URLString = @"http://192.168.1.157/tapp/laravel/public/foobar/upload";    /// !!! only jpg, have to cover png as well    NSData *imageData = UIImageJPEGRepresentation(self.imageView.image, 0.5); // image size ca. 50 KB    [manager POST:URLString parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {        [formData appendPartWithFileData:imageData name:@"file" fileName:fileName mimeType:@"image/jpeg"];    } success:^(AFHTTPRequestOperation *operation, id responseObject) {        NSLog(@"Success %@", responseObject);    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {        NSLog(@"Failure %@, %@", error, operation.responseString);    }];    [self dismissViewControllerAnimated:NO completion:nil];}


Thanks @NobleK , a category may be the best way to fix this issue. Here is a sample code:

@interface AFURLConnectionOperation (AuthenticationChallengeUploadFix)@end@implementation AFURLConnectionOperation (AuthenticationChallengeUploadFix)- (NSInputStream *)connection:(NSURLConnection __unused *)connection needNewBodyStream:(NSURLRequest *)request {    if ([request.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) {        return [request.HTTPBodyStream copy];    }    return nil;}@end


I have been looking for good answer for this one hell of a problem more than 10 hours and finally get hold of something what would work! according to Apple Doc

NSURLErrorRequestBodyStreamExhausted (-1021) Returned when a body stream is needed but the client does not provide one. This impacts clients on iOS that send a POST request using a body stream but do not implement the NSURLConnection delegate method connection:needNewBodyStream.

so what I had to do is subclass AFHTTPRequestOperation and implement all the delegate methods for NSURLConnection//.h

    @interface CGHTTPRequestOperation : AFHTTPRequestOperation    @end

//.m

    @implementation CGHTTPRequestOperation    #pragma mark NSURLConnection delegate methods    - (NSInputStream *)connection:(NSURLConnection __unused *)connection needNewBodyStream:(NSURLRequest *)request {        if ([request.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) {            return [request.HTTPBodyStream copy];        }        return nil;    }    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {        [super connection:connection didReceiveResponse:response];    }    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {        [super connection:connection didReceiveData:data];    }    - (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {        [super connection:connection didSendBodyData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];    }    - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse{        return [super connection:connection willCacheResponse:cachedResponse];    }    - (void)connectionDidFinishLoading:(NSURLConnection *)connection{        [super connectionDidFinishLoading:connection];    }    - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {        [super connection:connection didFailWithError:error];    }    - (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection {        return YES;    }    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {        [super connection:connection willSendRequestForAuthenticationChallenge:challenge];    }    @end

If you wonder how to use this extended classes in regards to upload the multi-part image data here is the example//.h

    typedef enum {        CGFileUploadStatusError = 0,        CGFileUploadStatusSuccess = 1,    } CGFileUploadStatus;    typedef void(^CGNetworkingFileUploadCBlock) (CGFileUploadStatus status,NSString *responseString);

//.m

    + (void) uploadImageAtPath:(NSString *) imagePath cBlock:(CGNetworkingFileUploadCBlock) cBlock {        AFHTTPRequestSerializer *r = [AFHTTPRequestSerializer serializer];        NSDictionary *param = @{@"param1":@"",@"param2":@""};        NSData *d = [NSData dataWithContentsOfFile:imagePath];        __block NSString *paramNameForImage = [imagePath pathComponents].lastObject;        NSError *error = nil;        NSMutableURLRequest *urlRequest = [r multipartFormRequestWithMethod:@"POST" URLString:@"http://url_to_up_load_image" parameters:param constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {                [formData appendPartWithFileData:d name:@"FileUploadControl" fileName:paramNameForImage mimeType:@"image/jpeg"];            } error:&error];            if (error) {                NSLog(@"Some error:%@",error);            }        CGHTTPRequestOperation *requestOperation = [[CGHTTPRequestOperation alloc] initWithRequest:urlRequest];        //[requestOperation setCredential:nil]; //set cred here        //[requestOperation setSecurityPolicy:nil]; //set security policy here if you are using one        [requestOperation setResponseSerializer:[AFHTTPResponseSerializer serializer]];        [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {            NSLog(@"Success: %@ ***** %@", operation.responseString, operation.response.allHeaderFields);            cBlock(CGFileUploadStatusSuccess,operation.responseString);        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {            NSLog(@"Error: %@ ***** %@", operation, error);            cBlock(CGFileUploadStatusError,operation.responseString);        }];        [requestOperation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {        }];        [requestOperation start];        [requestOperation waitUntilFinished];    }

Hope this helps those who is suffering this problem :)