I have a NSURLConnection which is a post to the server, but I expect it to return some small data, whether it was successful or not.
-(void)submitPost:(NSString *)xml
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[service generateURL]];
NSString *result = (NSString *) CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)xml, NULL, CFSTR("?=&+"), kCFStringEncodingUTF8);
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[result dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPMethod:#"POST"];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if(theConnection)
{
NSLog(#"Connection success");
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[theConnection retain];
failed = NO;
}
else
{
NSLog(#"Connection failed");
}
}
The problem is, not only does it send a post the URL, it also sends a GET, and the GET response is returned as the data... I'm a bit confused. I checked my wireshark output, and it's definitely making both a post and a get.
What do you guys think?
Does the URL respond to a POST with redirect? You can implement the NSURLConnection delegate method connection:willSendRequest:redirectResponse: to see if that's the case (and to cancel an unwanted redirect).
Related
How can I detect if an NSURLConnection failure is due to server being inaccessible?
I checked the server's logs and there is no mention of the app's calls in these cases when the NSURLConnection failed. However, could it be that trying to initiate the NSURLConnection (see below) failed for a different reason?
I implement the call to NSURLConnection via a wrapper with the following init function:
-(id)initWithURL:(NSURL*)url
postData:(NSData*)postData
responseData:(NSMutableData*)responseData
delegate:(id)delegate
doneSelector:(SEL)doneSelector
errorSelector:(SEL)errorSelector {
if(self=[super init]) {
_url = [url retain];
_postData = [postData retain];
_responseData = [responseData retain];
_delegate = [delegate retain];
_doneSelector = doneSelector;
_errorSelector = errorSelector;
// Set up request
NSMutableURLRequest* request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:_url];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d",[_postData length]] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:_postData];
// Kick off the connection
NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
if(!connection) {
[_delegate performSelector:_errorSelector];
}
}
return self;
}
We never encountered this problem during our testing (and 99% of the time the URL connection works flawlessly for our users) so I am unable to say where exactly the NSURLConnection fails. I do know though that when it fails the errorSelector is called with an empty _responseData string.
Do you see anything in the above code that may fail on rare occasions?
Any idea how to find the cause of the connection failures?
Thanks in advance!
I am trying to parse an HTML page, but the page requires a username/password to access the data.
How do I pass the credentials to the server so I can load the webpage into my NSData object?
UPDATE for Comments Below
Normally if you are using a web browser, it will pop up a login window for you to type in the credentials. When I execute it in iOS, it doesn't give me anything.
Thanks a lot!
Alan
You can use ASIFormDataRequest. Take a look at it here
NSURL *tempUrl = [NSURL URLWithString:#"http://www.yoursitetoparse.com"];
ASIFormDataRequest *request = [[ASIFormDataRequest alloc] init];
request = [ASIFormDataRequest requestWithURL:tempUrl];
[request setDelegate:self];
[request setRequestMethod:#"POST"];
[request setUsername:#"username"]; //Username
[request setPassword:#"password"]; //Password
[request startAsynchronous];
And it's delegate methods:
-(void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"Failed %# with code %d and with userInfo %#",[error domain],[error code],[error userInfo]);
}
-(void)requestFinished:(ASIHTTPRequest *)request
{
NSLog(#"Finished : %#",[theRequest responseString]);
}
I have a bunch of URL requests that are sent out in batch and then a 'catcher' class that recieves the results. I'm doing this through facebook's graph API SDK so I don't have control of the actual NSURL. My problem is that I don't trigger the next result protocol until all requests have come back, but sometimes, especially over 3G, they don't always come back (especially when you have a few hundred). What's a good way to 'give up' on a given request? The way the actual request works, for those who aren't familiar with the FB api, is you initialize a facebook object and then request data from it, and you specify a return delegate. So, for each individual request I have a returnDelegate (the catcher), which I can initialize specific to each request.
UPDATE: Some code from FB-API
- (FBRequest*)requestWithMethodName:(NSString *)methodName
andParams:(NSMutableDictionary *)params
andHttpMethod:(NSString *)httpMethod
andDelegate:(id <FBRequestDelegate>)delegate {
NSString * fullURL = [kRestserverBaseURL stringByAppendingString:methodName];
return [self openUrl:fullURL
params:params
httpMethod:httpMethod
delegate:delegate];
}
- (FBRequest*)openUrl:(NSString *)url
params:(NSMutableDictionary *)params
httpMethod:(NSString *)httpMethod
delegate:(id<FBRequestDelegate>)delegate {
[params setValue:#"json" forKey:#"format"];
[params setValue:kSDK forKey:#"sdk"];
[params setValue:kSDKVersion forKey:#"sdk_version"];
if ([self isSessionValid]) {
[params setValue:self.accessToken forKey:#"access_token"];
}
[self extendAccessTokenIfNeeded];
FBRequest* _request = [FBRequest getRequestWithParams:params
httpMethod:httpMethod
delegate:delegate
requestURL:url];
[_requests addObject:_request];
[_request addObserver:self forKeyPath:requestFinishedKeyPath options:0 context:finishedContext];
[_request connect];
return _request;
}
- (void)connect {
if ([_delegate respondsToSelector:#selector(requestLoading:)]) {
[_delegate requestLoading:self];
}
NSString* url = [[self class] serializeURL:_url params:_params httpMethod:_httpMethod];
NSMutableURLRequest* request =
[NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:kTimeoutInterval];
[request setValue:kUserAgent forHTTPHeaderField:#"User-Agent"];
[request setHTTPMethod:self.httpMethod];
if ([self.httpMethod isEqualToString: #"POST"]) {
NSString* contentType = [NSString
stringWithFormat:#"multipart/form-data; boundary=%#", kStringBoundary];
[request setValue:contentType forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[self generatePostBody]];
}
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
self.state = kFBRequestStateLoading;
self.sessionDidExpire = NO;
}
As discussed above, you can implement your own timeout by instantiating an NSTimer which will signal a delegate object when a certain amount of time elapses.
The URL is written properly, I tested it in the browser with data and it sends properly, but when I make the request, it returns that it is successful, but it does not actually write the data. Any idea?
- (void)writeAboutMe:(NSString *)about withIcebreaker:(NSString *)icebreaker
{
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
NSString *urlString = [NSString stringWithFormat:#"http://nailorbail.net63.net/submit_about_and_icebreaker.php?username=%#&about=%#&icebreaker=%#",[SignInViewController getUsernameString] ,about,icebreaker];
NSLog(#"%#",urlString);
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Current-Type"];
NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if(conn)
NSLog(#"Connection Successful");
else
NSLog(#"Connection could not be made");
[conn release];
}
It could be an encoding issue. What kinds of characters are in getUsernameString, about, and icebreaker? As Maudicus mentioned, you need to handle special characters in the URL yourself.
Try:
urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
You have set up an asynchronous connection. Do you implement the NSURLConnection delegate protocol methods? Are any of them being called?
The creation of the connection instance doesn't say anything about it's success.
Check out some tutorials, like this one.
I am trying to write an iPhone app in Objective-C. I need to POST data using NSURLConnection. Every example I can find deals with JSON; I do not need to use JSON. All I need to do is POST the data and get a simple 1 or 0 (succeed or fail) from a PHP script. Nothing more.
I came across this code but I am not sure how to use it or modify it to not use JSON:
- (void)performRequest {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://someplace.com/"]];
[request setValue:#"Some Value" forHTTPHeaderField:#"Some-Header"];
[request setHTTPBody:#"{\"add_json\":\"here\"}"];
[request setHTTPMethod:#"POST"];
[NSURLConnection connectionWithRequest:[request autorelease] delegate:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// Fail..
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Request performed.
}
Here's how to create an ordinary post.
First create a request of the right type:
NSURL *URL = [NSURL URLWithString:#"http://example.com/somepath"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
request.HTTPMethod = #"POST";
Now format your post data as a URL-encoded string, like this:
NSString *params = #"param1=value1¶m2=value2&etc...";
Remember to encode the individual parameters using percent encoding. You can't entirely rely on the NSString stringByAddingPercentEscapesUsingEncoding method for this (google to find out why) but it's a good start.
Now we add the post data to your request:
NSData *data = [params dataUsingEncoding:NSUTF8StringEncoding];
[request addValue:#"8bit" forHTTPHeaderField:#"Content-Transfer-Encoding"];
[request addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request addValue:[NSString stringWithFormat:#"%i", [data length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:data];
And that's it, now just send your request as normal using NSURLConnection (or whatever).
To interpret the response that comes back, see Maudicus's answer.
You can use the following NSURLConnection method if you target ios 2.0 - 4.3 (It seems to be deprecated in ios 5)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSString * string = [[NSString alloc] initWithData:data encoding:
NSASCIIStringEncoding];
if (string.intValue == 1) {
} else {
}
}
I've a very similar situation to whitebreadb. I'm not disagreeing with the answers submitted and accepted but would like to post my own as the code provided here didn't work for me (my PHP script reported the submitted parameter as a zero-length string) but I did find this question that helped.
I used this to perform a posting to my PHP script:
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.myphpscriptlocation.net/index.php?userID=%#",self.userID_field.stringValue]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
request.HTTPMethod = #"POST";
NSURLConnection *c = [NSURLConnection connectionWithRequest:request delegate:self];