AFNetworking 2.2.1 loading an image from Amazon S3 server - ios

I'm running into a problem trying to download an image on an Amazon S3 server.
I get the following error:
Error Domain=AFNetworkingErrorDomain Code=-1016 "Request failed: unacceptable content-type: binary/octet-stream"
Anyone has an idea?

This error is generated by
- (BOOL)validateResponse:(NSHTTPURLResponse *)response
data:(NSData *)data
error:(NSError * __autoreleasing *)error
method of AFHTTPResponseSerializer in case of unexpectable MIME type of response.
You can fix it by adding required MIME type to response serializer
// In this sample self is inherited from AFHTTPSessionManager
self.responseSerializer = [AFImageResponseSerializer serializer];
NSSet *set = self.responseSerializer.acceptableContentTypes;
self.responseSerializer.acceptableContentTypes = [set setByAddingObject:#"binary/octet-stream"];
Or you can modify AFImageResponseSerializer :
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
self.acceptableContentTypes = [[NSSet alloc] initWithObjects:#"image/tiff", #"image/jpeg", #"image/gif", #"image/png", #"image/ico", #"image/x-icon", #"image/bmp", #"image/x-bmp", #"image/x-xbitmap", #"image/x-win-bitmap", #"binary/octet-stream", nil];
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
self.imageScale = [[UIScreen mainScreen] scale];
self.automaticallyInflatesResponseImage = YES;
#endif
return self;
}
But root of the problem is probably that you save your images to Amazon with wrong MIME type or without type at all. In my code I save images to Amazon with following code
S3PutObjectRequest *putObjectRequest = [ [ S3PutObjectRequest alloc ] initWithKey:keyImage inBucket:self.s3BucketName ];
putObjectRequest.contentType = #"image/jpeg";
putObjectRequest.data = UIImageJPEGRepresentation( [ image fixOrientation ], 0.5f );
putObjectRequest.cannedACL = [ S3CannedACL publicRead ];

Updated for Boto 3
You can check what MIME type it is through your S3 web interface. First select the file you are having problems with, then select the Properties view. In this view open the Metadata section.
If your Content-Type is binary/octet-stream it is unset. Setting it in Boto 3, is different than the above answer for Boto 2. Here is how I do it:
filename = "/home/me/image42.jpeg" #the file I want to upload
bucketname = "myNewBucket" #name of my S3 bucket
key = "myImages/image42.jpeg" #desired name in S3 bucket
s3.Object(bucketname, key).put(Body=open(filename, 'rb'), ACL='public-read',ContentType='image/jpeg')

AFNetworking 3.1.0
You should just modify the acceptableContentTypes property on an existing image response serializer. You can use AFHTTPSessionManager do it.
NSURL *url = [NSURL URLWithString:#"http://..."];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
AFHTTPResponseSerializer *serializer = [AFHTTPResponseSerializer serializer];
serializer.acceptableContentTypes = [NSSet setWithObject:#"binary/octet-stream"];
manager.responseSerializer = serializer;
Then you can use manager to get the content of URL:
[manager GET:[url absoluteString] parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// ...
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// ...
}];
or use setImageWithURLRequest:placeholderImage:success:^failure:^ for get image:
UIImageView *imageView = [UIImageView new];
[[UIImageView sharedImageDownloader] setSessionManager:manager];
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://..."]];
[imageView setImageWithURLRequest:urlRequest placeholderImage:[UIImage new] success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull image) {
// but image can be NSData instead of UIImage
} failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
// ...
}];
But the response can be NSData instead of UIImage.
I hope that it helps you.

Related

Pass custom Header for download image in SDWebImage iOS sdk

I need to pass custom HTTPHeader for fetch image but getting error 401. Same token is working for other api.
Header is passed in sdwebimage requesturl:
I am passing custom headers like below code.
SDWebImageDownloader *manager = [SDWebImageManager sharedManager].imageDownloader;
[manager setValue:[DefaultsValues getStringValueFromUserDefaults_ForKey:kTokenKey] forHTTPHeaderField:#"authToken"];
[manager setValue:[DefaultsValues getStringValueFromUserDefaults_ForKey:kUserEmail] forHTTPHeaderField:#"email"];
[manager downloadImageWithURL:[NSURL URLWithString:#"URL STRING"] options:SDWebImageDownloaderUseNSURLCache progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
NSLog(#"%tu",receivedSize);
} completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
if (error == nil) {
cell.profileImage.image = image;
}
}];

How we can upload image or photos to ejabberd XMPP web server?

Here i am using iOS XMPP library (https://github.com/processone/demo-xmpp-ios) for my chat application, can any one help me out for uploading image from this library.thanks
I would recommend uploading images to a third party server and then sending the URL via XMPP.
Here's an example using Backendless which offer 20GB of free file uploads. You would have to also follow the Backendless docs to install their SDK and setup the API keys:
[backendless.fileService.permissions grantForAllRoles:fileName operation:FILE_READ];
[backendless.fileService saveFile:fileName content:file response:^(BackendlessFile * file) {
// We have the url so we can send the message
} error:^(Fault * fault) {
}];
Or to a PHP server using AFNetworking:
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:#"POST" URLString:_url parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:file name:#"upfile" fileName:name mimeType:mimeType];
} error:nil];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionUploadTask *uploadTask;
uploadTask = [manager
uploadTaskWithStreamedRequest:request
progress:^(NSProgress * _Nonnull uploadProgress) {
// This is not called back on the main queue.
// You are responsible for dispatching to the main queue for UI updates
dispatch_async(dispatch_get_main_queue(), ^{
//Update the progress view
[progressView setProgress:uploadProgress.fractionCompleted];
});
}
completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
if (error) {
} else {
NSString *filePath = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
// Send message here
}
}];
[uploadTask resume];
Then you can add the image and thumbnail URLs and the image dimensions to the XMPP message:
[xmppMessage addBody:imageURL];
[xmppMessage addAttributeWithName:bMessageImageURL stringValue:imageURL];
[xmppMessage addAttributeWithName:bMessageThumbnailURL stringValue:thumbnailURL];
[xmppMessage addAttributeWithName:bMessageImageWidth floatValue:width.floatValue];
[xmppMessage addAttributeWithName:bMessageImageHeight floatValue:height.floatValue];
I'd recommend setting the body to the imageURL so that the image could be opened from a standard XMPP client.
When the message is received, you can access the details again as follows:
NSString * imageURL = [[message attributeForName:bMessageImageURL] stringValue];
NSString * thumbnailURL = [[message attributeForName:bMessageThumbnailURL] stringValue];
float width = [[[message attributeForName:bMessageImageWidth] stringValue] floatValue];
float height = [[[message attributeForName:bMessageImageHeight] stringValue] floatValue];
You could then display the image using SDWebImage.
I'd also recommend this ChatSDK which is a full front end messaging interface for iOS. It contains UITableView cells to display image messages. I used it to build an XMPP messenger using XMPPFramework.

Implement custom cache for AFNetworking 3.x

Hi I'm writing a IOS api to fetch data from server using AFNetworking 3.x My Server does not support caching. This this server header
Connection →Keep-Alive
Content-Length →4603
Content-Type →text/html; charset=UTF-8
Date →Wed, 10 Aug 2016 04:03:56 GMT
Keep-Alive →timeout=5, max=100
Server →Apache/2.4.18 (Unix) OpenSSL/1.0.1e-fips PHP/5.4.45
X-Powered-By →PHP/5.4.45
I want to build custom API to enable cache (for example request and response should be cache for 10 second so that if user make same request, cache data is used. If cache expired app will then re download again)
My AFNetworking Singleton
#pragma mark - Shared singleton instance
+ (ApiClient *)sharedInstance {
static ApiClient *sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sharedInstance = [[self alloc] initWithBaseURL:[NSURL URLWithString:SINGPOST_BASE_URL] sessionConfiguration:sessionConfiguration];
return sharedInstance;
}
- (id)initWithBaseURL:(NSURL *)url
{
if ((self = [super initWithBaseURL:url])) {
self.requestSerializer = [AFHTTPRequestSerializer serializer];
}
return self;
}
My JSON request
- (void)sendJSONRequest:(NSMutableURLRequest *)request
success:(void (^)(NSURLResponse *response, id responseObject))success
failure:(void (^)(NSError *error))failure {
self.responseSerializer.acceptableContentTypes = [AFHTTPResponseSerializer serializer].acceptableContentTypes;
self.requestSerializer.timeoutInterval = 5;
self.requestSerializer.cachePolicy = NSURLRequestReturnCacheDataElseLoad;
[self setDataTaskWillCacheResponseBlock:^NSCachedURLResponse * _Nonnull(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSCachedURLResponse * _Nonnull proposedResponse) {
return [[NSCachedURLResponse alloc] initWithResponse:proposedResponse.response
data:proposedResponse.data
userInfo:proposedResponse.userInfo
storagePolicy:NSURLCacheStorageAllowed];
}];
NSURLSessionDataTask *dataTask = [ApiClient.sharedInstance dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(#"Error URL: %#",request.URL.absoluteString);
NSLog(#"Error: %#", error);
failure(error);
} else {
NSDictionary *jsonDict = (NSDictionary *) responseObject;
success(response,jsonDict);
NSLog(#"Success URL: %#",request.URL.absoluteString);
NSLog(#"Success %#",jsonDict);
}
}];
[dataTask resume];
}
How to modify the bellow code to enable caching request and response (I want response to be keep like 10 sec) (Or 1 day if no internet connection) Any help is much appreciate. Thanks!
[self setDataTaskWillCacheResponseBlock:^NSCachedURLResponse * _Nonnull(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSCachedURLResponse * _Nonnull proposedResponse) {
return [[NSCachedURLResponse alloc] initWithResponse:proposedResponse.response
data:proposedResponse.data
userInfo:proposedResponse.userInfo
storagePolicy:NSURLCacheStorageAllowed];
}];
Instead of
return [[NSCachedURLResponse alloc] initWithResponse:proposedResponse.response
do
NSMutableDictionary *dictionary = [proposedResponse.response.allHeaderFields mutableCopy];
dictionary[#"Cache-Control" = ...
NSHTTPURLResponse *modifiedResponse =
[[NSHTTPURLResponse alloc initWithURL:proposedResponse.response.URL
statusCode:proposedResponse.response.statusCode
HTTPVersion:#"HTTP/1.1"
headerFields:modifiedHeaders];
[modifiedResponse
return [[NSCachedURLResponse alloc] initWithResponse:modifiedResponse
Note that it is not possible to retrieve the HTTP version from the original request. I'm pretty sure I filed a bug about that. I'm also pretty sure that it doesn't have any effect on anything, and I don't think it even gets stored in the underlying object, so it probably doesn't matter.

AFNetworking downloaded file missing

I'm using AFNetworking 3.0 to download a file, and it seems to be doing the downloading part fine, but I can't find the file afterwards.
I'm using the code below. In the download task, if I set breakpoints in the destination block, it seems as though the target path and download destination path are correct, and in fact at the point the targetPath points to a tmp file in the tmp folder which exists and contains the correctly downloaded data. However if I then hit a breakpoint in the completion handler block, the tmp file has disappeared and there is no file where my download destination path pointed.
Am I missing a step? Do I have to move this file myself, or is that something AFNetworking should be taking care of?
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
self.theRequest = [[AFHTTPRequestSerializer serializer]
requestWithMethod:self.RequestMethod //#"POST"
URLString:requestURL.absoluteString //url to my API
parameters:self.Parameters //params being sent to API
error:nil];
//headers in this example:
//"Content-Type" = "application/json"
//"X-Requested-With" = XMLHttpRequest
//token = "<API TOKEN>";
for (id key in headers) {
[self.theRequest setValue:headers[key] forHTTPHeaderField:key];
}
self.theRequest.timeoutInterval = 60 * 100;
NSURLSessionDownloadTask * downloadTask =
[manager downloadTaskWithRequest:self.theRequest
progress:^(NSProgress * _Nonnull downloadProgress) {
if(self.DownloadProgressHandler)
self.DownloadProgressHandler(downloadProgress.fractionCompleted);
}
destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
NSURL *url = [NSURL URLWithString:self.downloadDestinationPath];
NSLog(#"%#",[targetPath absoluteString]);
NSLog(#"%#",[url absoluteString]);
return url;
}
completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
[self RequestCompleteWithResponse:response responseObject:[[filePath absoluteString] dataUsingEncoding:NSUTF8StringEncoding] error:error];
}];
self.theTask = downloadTask;
[self.theTask resume];
Output from the NSLogs above:
2016-03-04 13:43:44.412 Marq[27505:154492] __23-[MarqAPI BuildRequest]_block_invoke247 line 648 $ file:///Users/aerion/Library/Developer/CoreSimulator/Devices/11594D0A-882C-4E46-9BAC-CEF7148014C7/data/Containers/Data/Application/E8C7D3EE-BB69-461F-BA2F-49EB7C2AE1CF/tmp/CFNetworkDownload_7VGArX.tmp
2016-03-04 13:43:44.425 Marq[27505:154492] __23-[MarqAPI BuildRequest]_block_invoke247 line 649 $ /Users/aerion/Library/Developer/CoreSimulator/Devices/11594D0A-882C-4E46-9BAC-CEF7148014C7/data/Containers/Data/Application/E8C7D3EE-BB69-461F-BA2F-49EB7C2AE1CF/Documents/9dfd86c2-458e-4725-a184-5fcd87f94dbd.inspect
Argh, that was silly of me. The answer is staring me in the face in those logs.
The file path for the temp file begins with file://, whereas my download destination path does not. the answer is to change
NSURL *url = [NSURL URLWithString:self.downloadDestinationPath];
to
NSURL *url = [NSURL fileURLWithPath:self.downloadDestinationPath];
This will give me a valid file path to send the downloaded file to

AFNetworking - Stream 0x96c93c0 is sending an event before being opened

I am trying to send some data to AFNetworking to my server but when I want to send the data the following error appear in the console log and the server never received the data.
Does anyone know why I am reciving this error?
2013-06-06 17:02:16.246 iGym[15255:c07] Stream 0xa267930 is sending an event before being opened
2013-06-06 17:02:17.277 iGym[15255:c07] Inside the success block (null)
The code
-(void) shareExercise {
Exercise* myExercise = [self getCurrentExercise];
if (![myExercise.author isEqualToString:#"me"] )
{
// TODO: Error you cannnot share an exercise that is not yours
}
User* myUser = [self getCurrentUser];
if (myUser.nickname == nil) {
// You need a
}
NSData *exercisePictureThumb = [[NSData alloc] init];
NSData *exerciseDesPic1 = [[NSData alloc] init];
NSData *exercisePic = [[NSData alloc] init];
// Sort the pictures out
if(myExercise.exercisePictureThumb){
UIImage* image1 = [UIImage imageNamed:myExercise.exercisePictureThumb];
exercisePictureThumb = UIImagePNGRepresentation(image1);
}
if(myExercise.exerciseDesPic1){
UIImage* image2 = [UIImage imageNamed:myExercise.exerciseDesPic1];
exerciseDesPic1 = UIImagePNGRepresentation(image2);
}
if(myExercise.exercisePic){
UIImage* image3 = [UIImage imageNamed:myExercise.exercisePic];
exercisePic = UIImagePNGRepresentation(image3);
}
NSDictionary *params = #{#"userID":(myUser.idUserExternal ? myUser.idUserExternal : #"0"),
#"interact":#{
#"action":#"add",
#"actionTarget":#"exercise"},
#"share":#{#"exercise":#{
#"exerciseType":(myExercise.exerciseType ? #"1" : #"0"),
#"exerciseName":(myExercise.exerciseName ? myExercise.exerciseName : #"0"),
#"exerciseAuthorID":(myUser.nickname ? myUser.nickname : #"0"),
#"exerciseDescription":(myExercise.exerciseDescription ? myExercise.exerciseDescription : #"0"),
#"exerciseYoutube":(myExercise.exerciseYoutube ? myExercise.exerciseYoutube : #"0"),
#"exerciseID":(myExercise.exerciseWebID ? myExercise.exerciseWebID : #"0"),
#"exercisePicture":(myExercise.exercisePic ? myExercise.exercisePic : #"0"),
#"exerciseDescriptionPic1":(myExercise.exerciseDesPic1 ? myExercise.exerciseDesPic1 : #"0"),
#"exercisePictureThumb":(myExercise.exercisePictureThumb ? myExercise.exercisePictureThumb : #"0")
}
}
};
NSLog(#"%#",params);
NSURL *url = [[NSURL alloc]initWithString:#"http://192.168.1.64/"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc]initWithBaseURL:url];
NSURLRequest *request = [httpClient multipartFormRequestWithMethod:#"POST" path:#"igym/bootstrap.php" parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
{
/*
if(myExercise.exercisePictureThumb){
[formData appendPartWithFileData:exercisePictureThumb name:#"asd" fileName:myExercise.exercisePictureThumb mimeType:#"image/png"];
}
if(myExercise.exerciseDesPic1){
[formData appendPartWithFileData:exerciseDesPic1 name:#"asd" fileName:myExercise.exerciseDesPic1 mimeType:#"image/png"];
}
if(myExercise.exercisePic){
[formData appendPartWithFileData:exercisePic name:#"asd" fileName:myExercise.exercisePic mimeType:#"image/png"];
}
*/
}];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON){
NSLog(#"Inside the success block %#",JSON);
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON){
NSLog(#"json text is: %#", JSON);
NSLog(#"Request failed with error: %#, %#", error, error.userInfo);
}];
[operation start];
}
UPDATE: Looks like this accepted pull request should resolve your issue. Update AFNetworking, and complete your constructor block.
You need to put some code in your constructor block; it appears yours is commented out.
There is an open issue related to this on the AFNetworking GitHub site (it's been around for about a month). A few patches have been applied but it doesn't look 100% resolved. You may want to make sure you are using the latest build of AFNetworking.

Resources