iOS POST doesn't work on HTTPS - ios

I have some code that works fine with HTTP, but fails with (null) value returned from the NSJSONObjectserialization-thing on HTTPS.
I tried converting the received data to string, and it comes out to log as valid JSON. I validated it also to be sure. All good. The HTTPS certificate is valid, but I did try implementing the callbacks for invalid certs also, no change.
The EXACT same configuration works perfectly on HTTP, and if I go to the browser and input the same POST (I even tried removing the POST and just have the server return JSON no matter what you input) I get valid JSON also.
I tried converting the received data to an array and grab the first object in the array - didn't work either. I tried changing http headers in different configurations (application/json) etc. No dice.
Error code is Cocoa 3840. This error means, as far as I can tell, invalid JSON. HOW is this possible? It says character 3 is bad?
Any suggestions? I Googled the best I could but all I can find is "https and http should work in the same way" more or less.
Certificate is validated by RapidSSL.
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:_responseDataNews options:kNilOptions error:&error];
_responseDataNews is the object that gets filled by didReceiveData delegate - and this exact config works on HTTP. What the #€%*# am I doing wrong here? It's driving me insane.
Exact error is:
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0xbb2cde0 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
If I enable fragment option:
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Invalid value around character 3.) UserInfo=0xb939ab0 {NSDebugDescription=Invalid value around character 3.}
JSON looks like: {"r":1,"n":"Text here"}
And no, "text" contains no funky characters. This is the actual JSON value I'm testing.
Edit: NSLog of the data object reveals:
efbbbfef bbbfefbb bfefbbbf efbbbf7b 22687322 3a5b7b22 75736572 223a2254
65737465 73656e22 2c227363 6f726522 3a223233 3032227d 5d7d
(with JSON: {"hs":[{"user":"Testesen","score":"2302"}]} )
Edit: ... Okay, as it turns out, now it doesn't work on HTTP either, so it must be after changing the SSL setup or something on the server that it broke!? HTTP returns the exact same (invalid) data object :(

You report that the NSData for your string is:
<efbbbfef bbbfefbb bfefbbbf efbbbf7b 22687322 3a5b7b22 75736572 223a2254
65737465 73656e22 2c227363 6f726522 3a223233 3032227d 5d7d>
The ef bb bf is a byte order mark for a UTF-8 string. But if you have a BOM, you should have only one, and you have five of them.
If you're creating this response programmatically, you may have some server function that is called multiple times that is adding this BOM repeatedly. The BOM should appear only once (if at all), and the fact that it's appearing multiple times indicates a problem in your server code.
If you created this file manually, you might want to edit the hex data. Use whatever hex editor you want to fix this. For example, if you want to edit this file with Xcode, you can add it to your Xcode project and then right click on the file and choose "Open as..." - "Hex".

Okay - it turns out this had nothing to do with HTTPS anyway.
For some reason I cannot really understand, my php script was prefixing invalid characters after I restructured it to use only 1 .php file that responds to POST, includes all other .php files and returns the appropriate function depending on what you POST - of course I tried to just make it call one of the functions without POSTing anything, so that I could exclude POST errors from troubleshooting.
After I changed it so I request the specific file depending on what I want to do on the server - get news, get users, get score, whatever, like server.com/getscore.php instead of just server.com + POST data to get score, it works without issue and the JSON response is valid.
I don't really know how .php messes this up, but SOMETHING goes wrong. I tried enabling "Show all characters" in Notepad++, but I don't see anything funky anywhere. I made sure all .php files are encoded in UTF-8 also.

Related

IOS JSON parsing

I am an iOS beginner. I want to test open source application UBER prototype . When I have launched successfully the application on my Mac I have got the problem (signing up for this ) . I guess there is a problem with data base settings .
Error :
Failed to run command eventually with error: Error
Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with
array or object and option to allow fragments not set."
UserInfo={NSDebugDescription=JSON text did not start with array or
object and option to allow fragments not set.}
Could you give me advice how to fix it? The link for the project is here.
I think you have to set option value to NSJSONReadingAllowFragments. Maybe you have set something else!
Try to look something similar like this in your code:
id json = [NSJSONSerialization JSONObjectWithData:contentOfLocalFile options:NSJSONReadingAllowFragments error:&deserializingError];
And please update the question with the JSON format you are getting?

When I am update any field in parse database, I'm getting following error from parse database

Updating any field in parse database I'm getting below error very randomly,
My configuration in the AppDelegate looks like:
[Parse initializeWithConfiguration:[ParseClientConfiguration configurationWithBlock:^(id<ParseMutableClientConfiguration> configuration) {
configuration.applicationId = #"wrWJqA47ZvZA27X26HsJzDxc5xxxxxxx";
configuration.clientKey = #"hOhqpoIVK17joL6GiBGD54XIxxxxxx";
configuration.server = #"https://parse.nightlifexp.com/parse";
}]];
You can see my code for updating parse database in the following link:-https://dpaste.de/Fhrk
The interesting thing is Parse.Cloud.beforeSave function works as expected.Only when I requested data back, this issue appears very randomly.
Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
No proper solution found for this parse database error.Anyone can help me how to solve this problem?
Thanks in advance.
The problem is that your JSON is not an array it has nothing to do with your Objective-c code , but the input from your server is wrong.
I think your solution should be on parse.com .

Error in iOS: "you don't have permission"

I'm working on an iOS project in Swift which uses the Dropbox API to upload text files to Dropbox as well as load and read them from Dropbox. However, when I try to load a file using my DBRestClient using the following line:
restClient.loadFile("/data/" + yearStr + "/" + yearMonthStr + "/" + fullStr + ".txt", atRev: nil, intoPath: "temp2.txt")
I see the following error message in the console:
DropboxSDK: error making request to /1/files/sandbox/data/15/15_12/15_12_10.txt - (404) Path is a directory`
I'm not really sure what this means, since neither path involved in the call looks like a directory to me. I've searched for this error message but I can't seem to find it anywhere online, and I'm not sure what else might have caused it since commenting out this line prevents the error fro showing up and the same filepath works fine in other calls that don't involve loading files. Am I missing something about how loadFile() works?
UPDATE: I fixed the previous error by deleting a directory with the that filepath, making it choose the correct file. However, I am now getting the following error instead:
DropboxSDK: error making request to /1/files/sandbox/data/15/15_12/15_12_10.txt - (513) Error Domain=NSCocoaErrorDomain Code=513 "The file couldn’t be saved because you don’t have permission." UserInfo={path=/data/15/15_12/15_12_10.txt, destinationPath=temp2.txt}
I'm not sure what it means-- do I not have permission for the destination on my phone, or for the file on dropbox? I'm looking up this error message but I'm not finding anything yet, so help would be much appreciated.
According to the documentation, code 513 corresponds to:
NSFileWriteNoPermissionError = 513,
That seems to match the error message you get, and should be referring to the local destination path, which in your case is:
temp2.txt
You should check that you have access to write to that local path, and that it's a valid path, e.g., should it start with a '/'?. (Or moreover, perhaps you should be writing to NSTemporaryDirectory or something like that.)

iOS NSJSONSerialization of JPG image encoded binary data from mongodb

I think I need some assistance in figuring out the correct NSJSONSerialization option to make my problem go away.
On my app I allow the user to select an image from the gallery - the image undergoes the following:
NSData *imageData = UIImageJPEGRepresentation(self.profileImageView.image, 0.0);
then
NSString *stringOfImageData = [imageData base64EncodedStringWithOptions:0];
before it is serialized like this:
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:postDict
options:NSJSONWritingPrettyPrinted
error:&error];
and then sent to my REST API. I then decode it in python using base64 like so:
profileImageData = base64.b64decode(request.json['image'])
It is then loaded in GridFS (mongodb). On extracting the data to send back to the app I first encode in base to base64 before using dumps() to send it back:
dumps(base64.b64encode(fs.get_last_version(request.json['userID']).read()))
Within iOS after receiving the data it goes through the below de-serialization:
[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves error:&error]
I have narrowed by problem to the last NSJSONSerialization command. After the data is received by the app it is able to print to screen. After the Serialization I get a 'nil' :(
The Serialization and De-Serialization has been working great for strings, integers etc - it just doesn't work when I'm trying to move image data.
Thanks
EDIT: I am able to run a curl request against the API and then using an online base64 to image converter I can see my image. So it definitely means the issues is with the iOS side of decoding a json encoded base64 string.
EDIT: When I repeatedly run the deserialization - every 20th time or so the data is correctly converted. I think the solution might have to be to break up the data coming in.
EDIT: Error:
parsed error:Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Unterminated string around character 17.) UserInfo=0x109c08790 {NSDebugDescription=Unterminated string around character 17.}
What you don't say is how you are receiving the data. My guess is you are trying to decode the data before you receive all of it, but since I don't know how it's a guess.
To better understand what's going on, try logging the size and hash of the data, to see if the length varies. You can also save each received data object to the file system - put them in the Documents folder and you can access them from your Mac. If the size never varies you will then have to compare a good data object to a bad one.
In fact you can write a little code to save an image as data and a base64 string, upload it, then pull it back, and save it. Now compare the data and strings. Once you find a difference, then look at. What is its offset from the start? How is it different?
When you understand this all you will be able to fix it.

Enqueueing into NSInputStream?

I would like to add three "parts" to an NSInputStream: an NSString, an output from another stream and then another NSString. The idea is the following:
The first and last NSStrings represent the beginning and end of a SOAP request while the output from the stream is a result of loading a very large file and encoding it as Base64 string. So, in the end I would have the final NSInputStream hold the whole SOAP request like this:
< soap beginning > < Base64 encoded data > < soap ending >
The reason I want the whole request to be held in NSInputStream is two-fold:
I don't what to load the very large data file into memory
I think that this is the only way to enforce sending the final request in HTTP 1.1 chunks (which I need because otherwise, if the request becomes too big, the server won't accept it). So, I know that doing this:
NSInputStream *dataStream = ....;
[request setHTTPBodyStream:dataStream];
ensures that the request will be sent as HTTP 1.1 chunks and not as one huge raw SOAP request.
So, I wonder how this can be achieved - namely, how do I "enqueue" things into an NSInputStream? Can it be even done? Is there an alternative way?
Just for reference, in Java this can be done as follows
Vector<InputStream> streamVec = new Vector<InputStream>();
BufferedInputStream fStream = new BufferedInputStream(fileData.getInputStream());
Base64InputStream b64stream = new Base64InputStream(fStream, true);
String[] SOAPBody = GenerateSOAPBody(fileInfo).split("CUT_HERE");
streamVec.add(new ByteArrayInputStream(SOAPBody[0].getBytes()));
streamVec.add(b64stream);
streamVec.add(new ByteArrayInputStream(SOAPBody[1].getBytes()));
SequenceInputStream seqStream = new SequenceInputStream(streamVec.elements());
because Java has these objects available, but NSStreams in objective-c look like very low level objects and are very hard to work with.
Note: I completely re-wrote the original question as I asked it 2 days ago, since I think the new edit explains more clearly what the problem is. I hope it would help it be easier comprehended and maybe answered
UPDATE 2
Here is what I've been able to achieve so far: Instead of trying to enqueue into a stream, I am using a temp file to first write the < soap beginning >, then I set up an input stream to read from the file in chunks, encode each chunk as a Base64 string and write this to the same temp file, finally, when my stream closes, I write the < soap ending > to the temp file. Then I set up another input stream with the contents of this file which I pass to the NSMutableURLRequest:
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
...
NSInputStream *dataStream = [NSInputStream inputStreamWithFileAtPath:_tempFilePath];
[request setHTTPBodyStream:dataStream];
This ensures HTTP 1.1 chunked transfer of the contents of the file. After the connection finishes, delete the temp file.
This seems to work fine but of course this is an annoying work-about. I don't want to be writing to a temp file when it all could have been handled by streams (ideally.) If anybody still has better suggestions, let me know :)
UPDATE 3
OK, another update is in order. While my writing to file seems to work, I am now hitting an unexpected issue with some of my requests failing to upload to the server. Specifically, everything is going according to the plan, I am reading the contents of the temp file into a stream and set HTTP body of my request to be this stream and it starts transmitting the HTTP 1.1 chunks as I want it to - but for some reason some packets get dropped and the final request - this is my guess - gets malformed and thus fails. I think the issue of dropped packets is random, because I observe it on larger requests - that is, the issue just has more chance to show up - while my smaller requests usually go thru just fine. This is of course a separate issue from the original in this question. If anybody has a good idea what might be causing this, I asked about the problem here: Packets dropped during chunked HTTP 1.1 request sent by NSURLConnection
Your solution is an ok option, but you can do it with a stream. It means subclassing NSInputStream, and that isn't trivial because there are a bunch of methods you need to implement.
Basically your subclass would initially return the header bytes, then it would return bytes from the 'internal' stream to the file content, then when that's used up it returns the footer bytes. It means maintaining a record of how big the header and footer are and how much has been processed so far, but that isn't a big issue.
There's an example of creating a subclass here which shows the tricky hidden methods you need to implement to get the stream subclass to work properly without throwing exceptions.

Resources