I'm sending a base64 encoded image to a server as part of a post request using NSMutableURLRequest. What I log as the post body and what the server receives are not the same thing. The server seems to get a truncated version, as though the connection aborts midway. See the code below:
NSString *dataStr = [NSString stringWithFormat:#"request_data=%#",reqStr];
NSLog(#"datastr is %#",dataStr);
NSData *dataForUrl = [dataStr dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"nsdata length is: %i",[dataForUrl length]);
[urlRequest setHTTPBody:dataForUrl];
[urlRequest setValue:[NSString stringWithFormat:#"%d", [dataForUrl length]] forHTTPHeaderField:#"Content-Length"];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *res, NSData *data, NSError *err) {
// ...
}
The first log statement shows the correct data. I even took the base64 part of the string to http://www.motobit.com/util/base64-decoder-encoder.asp, decoded it as a jpg, and it is the correct image. The second log statement shows that the length is the right size (422624 when the picture was 422480, for example).
I can't find anything wrong with the connection details or the data. The phone makes the connection, sends some data, then either the phone stops sending or the server stops receiving. What could cause that?
Edit: link to sample data http://pastebin.com/BS9HjKhg
Edit2: The server or iOS is converting the +'s from the image to spaces. I'll post an answer when I figure out the right way to send it.
I was able to compare a full sample from the server vs what xcode logged, and found the + converted to [space]. Since that was the only character having a problem and url encoding is buggy in iOS, I just did
NSString *dataStr = [NSString stringWithFormat:#"request_data=%#",[reqStr stringByReplacingOccurrencesOfString:#"+" withString:#"%2B"]];
The server is accepting them again. I'm still not sure whether the server was the problem or it was iOS. The other OS's that connect use the same application/x-www-form-urlencoded as their content type with no problems.
I would suggest doing the conversion from Base64 string into NSData through Nick Lockwood's Base64 class.
That
NSData *dataForUrl = [dataStr dataUsingEncoding:NSUTF8StringEncoding];
worries me a bit (even more after looking at how Base64 is implements the conversion)...
Related
The NSURLRequest is adding %0 in request. I created the string and converted it into base 64 then send to url, but NSURLRequest is automatically adding %0 in it. Below is the code i am using.
This is how converted to base 64.
NSData *plainTextData = [totalStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64String = [plainTextData base64EncodedString];
NSLog(#"encoded url:%#",base64String);
When Api called.
NSString *urlStr = [NSString stringWithFormat:#"http://mabct.co/api/checkin/%#", [code valueForKey:#"code"]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:
[NSURL URLWithString:urlStr]];
// [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
NSString *responseString = [MyEventApi sendRequest:request];
NSError *error;
NSData *jsonData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *results = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
NSLog(#"dict in API-------------%#",results);
return results;
This is the converted string in to base 64
eyJldmVudElkIjoiNDAiLCJzZWF0IjoiMTBfS2FyYW4gU3VraGlqYV8yNC0wNC0yMDEzIDE3OjE3IiwidXNlcklkIjoiMTAifQ==
This is what NSURLRequest is sending.
eyJldmVudElkIjoiNDAiLCJzZWF0IjoiMTBfS2FyYW4gU3VraGlqYV8yNC0wNC0y%0D%0AMDEzIDE3OjE3IiwidXNlcklkIjoiMTAifQ==
This is what i am sending in encoding
"{"eventId":"47","seat":"10_Karan Makhija_24-04-2013 10:06","userId":"10"}"
I am not getting what is wrong, please guide for the above.
Thanks in advance.
I see that %0D%0A is being added to your original string. I googled it and found that:
%0D%0A is the encoded ASCII non-printable characters of ,
which on Microsoft platforms is a NewLine So:
Consider if you accidentally could have replaced some HTML by hitting the return key while editing your files.
2a. Be aware of what
encoding your editor uses for saving the files (typically either
ASCII, ANSI, or Unicode)
2b. Your webserver (an IIS6, likely running
on a Windows 2003 Server) serves the files as UTF-8 encoded, which is
fine - But you may want to verify that it actually reads the files
using same encoding as you've used for saving the files.
Here, is the SOURCE if you want to check.
EDIT
Make sure that your webserver and client uses the same encoding (i.e. NSUTF8StringEncoding or any other, but same)
Also, IF base 64 encoding is there on web server. Follow this link, for implementing category for such encoding/decoding. I hope this will help you.
I have an object with the following members:
NSString *reqStr = "param1=val1¶m2=val2¶m3=val3&..";
NSData *imageData = [NSJPEGRepresentation (myimage)];
NSData *fileContents = [NSData initWithFileContents(myfile.txt)];
How can I send this out to Windows WCF? Do I send it as stream of bytes, and attach to httprequest? Or, will this be sockets? I am not sure how to pack these things as one thing as in one stream of bytes or whatever it may be the way to format such an object.
Any help?
Since you said that you already know how to send imageData which is NSData. Why not convert regStr to NSData and combine all three together as a single data and send.
To convert NSString to NSData:
NSData* strData=[regStr dataUsingEncoding:NSUTF8StringEncoding];
And use NSMutableData's appendData method to combine all three.
NSMutableData *combineData = [[NSMutableData alloc]initWithData:strData];
[combineData appendData:imageData];
[combineData appendData:fileData];
This S/O question might help:
File Upload to HTTP server in iphone programming
If the WCF endpoint is configured as HTTP then the same principles should apply regarding the multipart/formencoding of the image in question.
Edit:
Is this answer more helpful ?
HTTP "POST" request in iOS
I am experiencing an issue on iOS 4.3+ with ASIHTTPRequest where a request is fired but no data (Request methed, url, headers, etc) reaches the server. The connection times out because it never hears back.
The server hears the empty request (after some delay), then hears a valid request which is of course never reported to higher level code because the connection has timed out. This is all kind of strange because the request was not configured to resend data.
Often this happens after the app has been pushed to the background for some time (15 min or more) and the phone has been allowed to sleep.
My configuration of the request is as follows:
NSMutableData *postData = nil;
NSString *urlString = [NSString stringWithFormat:#"%#%#",[self baseURL],requestPath];
OTSHTTPRequest *request = [OTSHTTPRequest requestWithURL:[NSURL URLWithString:urlString]];
[request setCachePolicy:ASIFallbackToCacheIfLoadFailsCachePolicy];
[request setTimeOutSeconds:45];
//Set up body
NSString *queryString = [self _RPcreateQueryString:query];
if ([queryString length]>0) {
if(method == RPAsyncServerMethodPost || method == RPAsyncServerMethodPut){
postData = [[[queryString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES] mutableCopy] autorelease];
}else{
NSURL *url = [NSURL URLWithString:[urlString stringByAppendingFormat:#"?%#",queryString]];
[request setURL:url];
if (!url) return nil; //url String malformed.
}
}
// ... ///
// method setting stripped for brevity
[request addRequestHeader:#"Content-Type" value:#"application/x-www-form-urlencoded"];
if(headers){
for (NSString* head in headers) {
if ([[headers valueForKey:head] isKindOfClass:[NSString class]])
[request addRequestHeader:head value:[headers valueForKey:head]];
}
}
[request addRequestHeader:#"Content-Length" value:postLength];
[request setPostBody:postData];
OTSHTTPRequest is simply a subclass of ASIHTTPRequest that contains properties for a string tag, a pretty description, and other bling for use by consuming objects and does not override any ASI stuff.
Can anyone shed a light on why/how ASI could open a connection and then send absolutely nothing for minutes at a time?
Edit: Just to clarify. The connections DO make contact with the server, it just never sends any data through the connection from what my server logs can tell. This seems to always happen on app wake and effects all connections including NSURLConnections spawned by MapKit. the whole app just seems to loose its marbles.
I also see a bunch of background tasks ending badly right before this, but i can never catch them while in the debugger.
It doesn't look like you are starting your request based on the code that you have provided. Try call the -[startSynchronous] or -[startAsynchronous] methods of your OTSHTTPRequest object after you are done setting its various properties.
Are you setting the delegate, either I overlooked it or you stripped it out.
I didnt want to say anything till a few days passed with out the issue. The solution in this case was very obscure.
It appears the version of TestFlight i was using has a bug in it that may have contributed to this issue. Since its removal i have not experienced the issue.
I have a problem using setHTTPBodyStream instead of setHTTPBody with a NSMutableURLRequest.
I'm working on code to send large file to a server through http post. With the following portion code, everything works perfectly :
NSData * mydata = [NSData dataWithContentsOfFile:self.tmpFileLocationToUpload];
[request setHTTPBody:mydata];
If I change it to :
NSData * mydata = [NSData dataWithContentsOfFile:self.tmpFileLocationToUpload];
self.tmpInputStream = [NSInputStream inputStreamWithData:mydata];
[request setHTTPBodyStream: self.tmpInputStream];
Then I always end with a network error : Error - The operation couldn’t be completed. (kCFErrorDomainCFNetwork error 303.)
The goal is at the end to create inputStrem directly from the file to be able to send large file without to load them in memory.
Did I miss something with setHTTPBodyStream use ?
Thanks for your help.
Regards.
SĂ©bastien.
Try setting the HTTP method (if you're not already). I was able to fix a "kCFErrorDomainCFNetwork error 303" error by adding:
[request setHTTPMethod:#"POST"];
When you use setHTTPBody, it automatically sets the Content-length header of the request, but when you use setHTTPBodyStream, it doesn't, but rather sets Transfer-encoding of chunked. A chunked transfer encoding is used when the length of the stream cannot be determined in advance. (See Chunked transfer encoding.)
When using NSURLConnection in conjunction with setHTTPBodyStream, you can manually set Content-length and it will prevent the Transfer-encoding of chunked (assuming you know the length in advance):
NSString *contentLength = [NSString stringWithFormat:#"%d", [mydata length]];
[request setValue:contentLength forHTTPHeaderField:#"Content-length"];
When using NSURLSession, attempts to manually set Content-length in conjunction with a chunked request may not prevent it from being a chunked request.
I am downloading images using the NSURLConnection sendSynchronousRequest method and that works fine. However, occasionally I run into an issue where the image URL points to something other than an image file. For example, I found this non-image URL was causing issues: http://www.100plusposters.com/images/ExoticFlowers.jpg The URL returns a Web page, which I assume occurs because the image is missing from the site.
One nice thing about Objective-C is that the invalid image doesn't cause a crash. It simply and quietly continues along and just doesn't display any image, but that is still a problem.
How can I validate the data returned to ensure it is a valid image file before displaying it?
Thanks!
My relevant code, in case that helps...
NSError *error = nil;
NSURLResponse *response;
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(data != nil && [error localizedDescription] == nil)
{
//Create UIImage object using initWithData method
//Display UIImage
}
Looks like NSURLResponse object contains a MIMEType property. That should give you a pretty good idea what the type of the returned data is.
Could we take this question one step further? What if the image data is incomplete or corrupt from the server? The complete transport works, the MIME type is image/jpeg, the UIImage is constructed and non-nil but the renderer discovers inconsistencies in the data and the log may show "Bad Huffman code" or "premature end of data segment"
How would I capture this error before tossing the UIImage into the view context and thereby getting a not-pretty image on the screen?
I think by crosschecking the content length obtained from the header of the Http Request and finally recieved data would give you, whether the data downloaded was complete or not.
About the corrupt i dont have much info.