ASIFormDataRequest - iOS Application. How do I RETRIEVE a post variable - objective-c

So I have this url that leads to a .php
So far I managed to retrieve every single thing except the actual XML that I want. the XML is stored in a variable called _xml.
if($this->outMethod=="" || $this->outMethod=="POST") //Default to POST
{
$_POST["_xml"] = $_xml;
}
So I've already set the outMethod to POST but I don't understand how to retrieve the value within _xml.
- (void)grabURLInBackground
{
NSLog(#"grab url in background");
NSURL *url = [NSURL URLWithString:#"xxxxxxxxxxx"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:#"POST" forKey:#"outMethod"];
[request setPostValue:#"1" forKey:#"Entity_ID"];
[request setDelegate:self];
[request startAsynchronous];
NSLog(#"end of grabUrlInBackgroun");
}
don't worry the URL is right I just don't want to post it.
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSLog(#"A");
// Use when fetching text data
NSString *responseString = [request responseString];
// Use when fetching binary data
NSData *responseData = [request responseData];
if(responseString)
{
NSLog(#"responseData is not null");
}
NSLog(#"response string: %#", responseString);
//NSLog(#"%#", responseString);
}
What I get back is that the request is good, but there is no response in responseString. This is because my php does not want to print out any of the XML on screen in HTML but it stores the result in the variable _xml sent via post "$_POST["_xml"] = $_xml
My question is, how do I get back that xml variable? Isn't there a method available within the ASIHTTPRequest library? I am using ASIFormDataRequest class not ASIHTTPRequest.

You have to print you variable in the php-file:
if($this->outMethod=="" || $this->outMethod=="POST") //Default to POST
{
echo $_xml;
}
A HTTPRequest (and the ASIFormDataRequest as well) isn't interested in any variables you declare in your *.php file. It only returns the string you actually print.

Related

Rails params not being constructed correctly

I have a strange issue.
I have tried a lot of different things to reproduce the issue but it has not been possible. The error shows up thanks to exception_notification.
I am sending a NSDictionary to the backend, and instead of being parsed as a dictionary, this is what I get (on the rails side):
* Parameters : {"{\"facebook_id\":\"\",\"city\":\"\",\"account_type\":\"email\",\"poll_reminder\":\"0\",\"last_name\":\"\",\"picture_url\":\"\",\"email\":\"\",
\"birthday\":\"\",\"users_value_categories_attributes\":"=>{"{\"value_category_id\":25},{\"value_category_id\":24},
{\"value_category_id\":21},{\"value_id\":24,\"priority\":14},{\"value_id\":21,\"priority\":15},
{\"value_id\":58,\"priority\":16},
{\"value_id\":8,\"priority\":17},{\"value_id\":9,\"priority\":18},{\"value_id\":41,\"priority\":19},
{\"value_id\":27,\"priority\":20}"=>{",\"first_name\":\"\"}"
=>nil}}}}}
It is dictionary where the only key is my serialized dictionary!
This is the error on the rails side:
An ActiveRecord::UnknownAttributeError occurred in #:
unknown attribute: {"facebook_id":"","city":"","account_type":"email","poll_reminder":"0","last_name":"","picture_url":"","email":"","birthday":"",":...........
app/api/v2/resources/example_business_api.rb:6:in `block in <class:ExampleBusinessApi>'
params hash is like:
{"<MY SERIALIZED DICTIONARY" => nil }
instead of being the dictionary itself.
The relevant code in iOS is:
request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[self getHTTPBodyForUser:theUser]];
getHTTPBodyForUser is the following:
+ (NSData *)getHTTPBodyForUser:(User *)user {
// Load a tmp dictionary using user variable
....
// The tmp dictionary is totally fine
NSError *error;
NSData *postdata = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];
return postdata;
}
The weird part is that just some users are having the error.....
Any help?

OCMock: Setting expectations on properties

How do I set an expectation on a property of an instance?
Let's say I have the following code:
id request = OCMClassMock([NSMutableURLRequest class]);
And I want to make sure that, in my implementation, the HTTPMethod property is set to #"Get", how would my test verify this?
Try something like this:
- (void)testNSURLConnection
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.stackoverflow.com"]];
[request setHTTPMethod:#"POST"];
id connectionMock = OCMClassMock([NSURLConnection class]);
OCMStub([connectionMock connectionWithRequest:[OCMArg checkWithBlock:^BOOL(NSMutableURLRequest *request) {
XCTAssertTrue([request.HTTPMethod isEqualToString:#"GET"]);
return YES;
}] delegate:OCMOCK_ANY]);
[NSURLConnection connectionWithRequest:request delegate:nil];
}
This test will fail until your change #"POST" to #"GET" which is, I believe, what you want.

HTTPRequest for forum login - Objective C

I am trying to implement this code in Objective C:
Public Shared Function Login(ByVal Username As String, ByVal Password As String) As Boolean
Dim str As String = Func.ConvertToHex(Username)
Http.GetResponse("http://www.website.com/forum/login.php?do=login", String.Concat(New String() { "vb_login_username=", str, "&vb_login_password=", Password, "&cookieuser=1&s=&securitytoken=guest&do=login&vb_login_md5password=&vb_login_md5password_utf=" }))
If Http.ResponseValue.Contains(("Thank you for logging in, " & Username)) Then
Http.GetResponse("http://www.website.com/forum/usercp.php")
Return True
End If
Return False
End Function
This is what I've already done:
- (IBAction)loginButton:(id)sender {
NSURL *loginURL = [NSURL URLWithString:#"http://www.website.com/forum/login.php?do=login"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:loginURL];
[request setRequestMethod:#"POST"];
[request setUseKeychainPersistence:YES];
[request addPostValue:[self.usernameField stringValue] forKey:#"vb_login_username="];
[request addPostValue:[self.passwordField stringValue] forKey:#"&vb_login_password="];
[request setDelegate:self];
[request setTimeOutSeconds:60];
[request startSynchronous];
[request setUseSessionPersistence:YES];
}
- (void)requestFailed:(ASIHTTPRequest *)request {
NSLog(#"Request failed: %#",[request error]);
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSLog(#"Submitted form successfully");
NSLog(#"Response was:");
NSLog(#"%#",[request responseString]);
}
But it does not work..
I get a reply back but not as a member.
P.S. It's about a vBulletin Forum
Sorry for my bad english..
Thanks in advance!
Hard to try to reproduce with no server to test. However two things:
lib which you use is depreciated, consider moving for other (for example AFNetworking)
in second parameter you have "&vb_login_password=" I believe there should be no '&' character. Also try to remove '=' at end.
If there is no HTTPS you can use wireshark to check packets from program which work, and from your version. Then compare both request and seek for differences.
It now works. I've added some more entries.
[request addPostValue:#"1" forKey:#"cookieuser"];
[request addPostValue:#"login" forKey:#"do"];
[request addPostValue:#"" forKey:#"s"];
[request addPostValue:#"guest" forKey:#"securitytoken"];
[request addPostValue:#"" forKey:#"vb_login_md5password"];
[request addPostValue:#"" forKey:#"vb_login_md5password_utf"];
[request addPostValue:[self.passwordField stringValue] forKey:#"vb_login_password"];
[request addPostValue:[self.usernameField stringValue] forKey:#"vb_login_username"];
I now get the HTML code from the forum back to a point where it says "Thank you for logging in, Username".

JSON Payload doesnt seem to be sending

My problem I'm pretty positive is simple, I must just be missing something.. just not sure what.
I can send GET and POST for granular elements (this=that kind of stuff), but a web service call I need to send data too, takes a raw JSON block, with no "key"
Heres the method I wrote:
-(NSData *)execute {
// Smart Chooser ?
if(PostData.count >0 || Payload != nil)
[self setMethod:UPLINK_METHOD_POST];
else
[self setMethod:UPLINK_METHOD_GET];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.connectionUrl
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:10];
if([UPLINK_METHOD_GET isEqualToString:self.connectionMethod])
[request setHTTPMethod:#"GET"];
else
[request setHTTPMethod:#"POST"];
NSString *gData = [self compileGetData];
NSString *pData = [self compilePostData];
// if we have get data, set it into the URL string
if(GetData.count > 0) {
[self setURLWithString:[[self.connectionUrl absoluteString] stringByAppendingString:[#"?" stringByAppendingString:gData]]];
[request setURL:self.connectionUrl];
}
// if we have post data, set it in the body
if(PostData.count > 0) {
const char *bytes = [[NSString stringWithString:pData] UTF8String];
[request setHTTPBody:[NSData dataWithBytes:bytes length:strlen(bytes)]];
}
// Override any post data if a payload is already defined.
if(Payload != nil) {
[request setHTTPBody:[Payload dataUsingEncoding:NSUTF8StringEncoding]];
}
NSLog(#"URL : %#", request.URL);
NSURLResponse *response;
NSError *err;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
if(err != nil)
NSLog(#"here was an error: %#", err);
return responseData;
}
-(NSDictionary *)executeAsJSON
{
NSData *responseData = [self execute];
NSError *e;
return [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&e];
}
Ok SO, the way this thing works, is that it automatically sets whether the request is POST or GET depending on the data provided in the GetData, PostData, and Payload vars.
The request is GET by default, but turns into POST if PostData or Payload have anything in them.
The compileGetData and compilePostData mostly just bring back formatted strings with arrays of information combined, nothing special there.
But thats not where the problem is.
See, "Payload" overrides anything "PostData" had in it. If you had provided PostData elements into the class, it would just be overridden by a provided Payload if that does exist.
I needed to provide this to demonstrate the "workarea" as it exists right now, its not linearly provided information.
This is the area of interest:
// Override any post data if a payload is already defined.
if(Payload != nil) {
//const char *plbytes = [[NSString stringWithString:Payload] UTF8String]; // this didn't work
[request setHTTPBody:[Payload dataUsingEncoding:NSUTF8StringEncoding]]; // inline, doesn't work either
}
When I say "doesnt work", what I mean is, im getting back an error JSON array from the webservice that basically means "hey, wheres the payload?". If the request is not POST it comes back as a general error, so thats all working, the URL is then obviously correct.
I've used RESTConsole for Chrome to test the webservice to make sure its working properly, and it does.
I've also checked through the debugger the exact payload im sending, i copy+pasted that into RESTConsole, and it works there.
I'm.. honestly at a loss here...
Try using a web proxy like Charles or Wireshark (I personally preferr Charles due to it's ease of use, it's a 30-day trial though) and monitor the request you make from RESTConsole and the one you make from your app and see if they look the same.
Check any headers, line returns and anything else that looks different.
That's the best I can think of to start with

JSON broken in Objective-C URL Request

After pounding my head all day long, I am down to StackOverflow to pull me through.
I am making a NSURLRequest in my iPhone App ...
NSURL* url = [[self serviceUrl] URLByAppendingPathComponent:[NSString stringWithFormat:#"Json"]];
NSString* json = [NSString stringWithFormat:#"{\"id\":\"%#\"}", id];
NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[urlRequest setHTTPBody:[json dataUsingEncoding:NSUTF8StringEncoding]];
this is returning to me a JSON string, which comes back to me but it is broken in the since that the string will not parse correctly.
However if I make a normal request to the same url in the Safari browser then JSON is returned correctly. I am validating this JSON here.
So whats the deal? Is there a limit to the length of data in a NSString* that a 32Kb json file would not be stored in memory correctly? Sometimes the JSON can be parsed, which leads me to believe that I am not clearing my JSON string correctly after each request.
_json = [[NSString alloc] initWithData:_dataResponse encoding:NSUTF8StringEncoding];
NSArray* retrievedData = (NSArray*)[_json JSONValue];
// removed for brevity
_json = #"";
Other information, I am using ASP.NET MVC 3 to provide the web services for this app.
EDIT
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
{
_loader.hidden = NO;
[_loadingIndicator startAnimating];
return request;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
_dataResponse = [[NSMutableData alloc] init];
[_dataResponse setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_dataResponse appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Error receiving response: %#", error);
_loader.hidden = YES;
[_loadingIndicator stopAnimating];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
_json = [[NSString alloc] initWithData:_dataResponse encoding:NSUTF8StringEncoding];
// Removed for brevity
_json = #"";
_loader.hidden = YES;
[_dataResponse release];
_dataResponse = nil;
[_loadingIndicator stopAnimating];
}
FINAL SOLUTION
I was making multiple calls to have data already stored for views in order to switch views in a tab bar controller. I wasn't checking the connection during the appending of the data, I was checking the connection when it was finished in order to store the data correctly. My final solution was to make each call sychronously after the previous one during the finished method call.
Unfortunately, nothing blatant is jumping out at me.
Some things to try that will hopefully help:
double check your NSUrlConnection pattern against this doc. The only diff I see is they're doing [[NSMutableData data] retain] instead of alloc, init. They also create NSMutableData with the connection request (not in response) and only length=0 in response. Not sure why it would matter though ...
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html
try something like Charles Proxy. It allows you to sniff the wire. You can see what's different between browser and simulator/phone access. At a minimum, you'll see what's coming over the wire in the bad cases.
add lots of logging. everytime you append data, log some details. After you convert to string and before the json call, log. Log sizes, etc... Something may offer you a hint.
the use of _json string seems a bit off. You're reallocating and then setting to empty string. You should either have an iVar that you alloc and release (not set to "") or create a #property with retain, copy.
You should definitely include charset=utf8 in you content-type header. And how do you know that the response you get is encoded as utf8? You should also set content-size header.