NSURLConnection times out when doing PUT of binary - ios

I'm trying to use NSURLConnection sendSynchronousRequest: to send a binary file (an JPEG image) to a server. The code I have is:
// url contains the URL of the remote server.
// fileURL contains the URL for the local file to be sent.
request = [NSMutableURLRequest requestWithURL:url];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setHTTPMethod:#"PUT"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"image/jpeg" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBodyStream:[NSInputStream inputStreamWithURL:fileURL]];
responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&requestError];
if (requestError != nil) {
NSLog(#"%#", requestError);
return NO;
}
This almost works. The remote server receives the request properly, and responds with an appropriate JSON object. But sendSynchronousRequest: blocks until the timeout value, and then reports a timeout.
Elsewhere, I'm able to send and receive JSON objects properly using pretty much this same code pattern, so I'm baffled why this one would be timing out.

Related

Cannot get correct return message when consuming WCF web-service via NSURLConnection

I have a WCF web-service. If I just put the URL into the browser, I will get the error message: Forbidden. But if I post data through Fetcher(a HTTP Simulator in OS X), I can get the correct return value.
Now, I tried to use NSURLConnection to post data to the web-service and fetch the return value.
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:postURL];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d", postData.length] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLResponse * response = nil;
NSError * error = [[NSError alloc] init];
receivedData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString * receivedStr = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
But all I get is just the html code of the error page I can see from the browser(that forbidden message).
Please help me figure it out. Thanks in advance.
EDIT:
I set up a PHP server and try to do the same thing. I works perfectly. Therefore, I highly doubt it is the WCF problem. Anyone has some good ideas?
if you use generated .svc service you need to :
change
[request setValue:#"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
to
[request addValue:#"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-type"];
also you need to SOAPAction field according to operation you request
What is you postData?

Timeout in NSURLConnection to WCF JSON REST server

I have a Windows based REST Server built using Microsoft-HTTPAPI (i.e. its not running under IIS)
If I send a JSON request to the service from a browser based REST tool (Firefox RESTClient) the server receives the request and processes it correctly as per the traces from the Microsoft Service Trace Viewer and the response from the service. I receive valid JSON back from the service.
I have an iOS application that uses a NSURLConnect to send the VERY SAME JSON request to the service, but it always times out. I've traced using WireShark, and the HTTP request is correctly formed and sent correctly to the server in both cases. I've traced using the MS Trace Viewer and it goes into "receive Bytes" but never returns. I get an exception when I eventually close the WCF Server.It never returns when I close the iOS app.
I have tried using NSURLConnection sendSynchronousRequest and asynchronously using the callbacks and asynchronously using completion blocks. If I make the timeout 0, the call (to sendSynchronousRequest) never returns. In all other cases, I get a timeout, and the WCF never completes the receive bytes part of the WCF invocation (a POST request)
I've checked
Here's my iOS Code:
dispatch_queue_t myQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(myQ, ^{ // First Queue the parsing
#try {
//Generate endpoint url
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/%#",appState.posPostingURL,serviceName]];
//Setup request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:10.0];
NSString *authStr = [NSString stringWithFormat:#"%#:%#", #"xxxx", #"xxxx"];
NSString *authData = [NSString base64StringFromString:authStr];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", authData];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
//Setup request headers
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"no-cache" forHTTPHeaderField:#"Cache-Control"];
[request setValue:[NSString stringWithFormat:#"%d", [dataBuffer length]] forHTTPHeaderField:#"Content-Length"];
// Put the request data in the request body
[request setHTTPBody: dataBuffer];
NSHTTPURLResponse *urlResponse = nil;
NSError *error = nil;
// and send to the server synchronously
serverData = [[NSURLConnection sendSynchronousRequest:request
returningResponse:&urlResponse
error:&error] mutableCopy];
// Now check the status and response
if (error) {
My WCF Code is as follows
namespace MyWebService{
[ServiceContract(Name = "MyServiceIntegrator", Namespace = "")]
public interface IMyIntegrator
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/Configure",
BodyStyle=WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
Result Configure(MyServerConfig config);
In the app.config file, the service endpoint is configured with
binding="webHttpBinding"
The Trace view is as follows:
Could there be any reason on either side that the server does not complete the read even though the JSON is valid.
I have also checked NSURLConnection JSON Submit to Server
and as far as I can see my code to send the request is correct.
Any ideas - Been pulling my hair out for 3 days now
What happens if you change this:
[request setValue:[NSString stringWithFormat:#"%d", [dataBuffer length]] forHTTPHeaderField:#"Content-Length"];
To this:
[request setValue:[NSString stringWithFormat:#"%i", [dataBuffer length]] forHTTPHeaderField:#"Content-Length"];
Probably won't make a difference, but the rest of your code looks fine so maybe worth a shot. (My thinking is the decimal is causing the server issues).
ferdil,I think you can try changing timeout period to 30.0 instead of 10.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:30.0];

iOS: POST where JSON is just one argument of many

I have successfully used JSON as arguments to a POST webservices in my apps by making the data representation of the JSON the HTTP body:
//Prep
NSData *requestData = [NSJSONSerialization dataWithJSONObject:<my JSON> options:0 error:nil];
NSString *apiString = <the webservice>;
//POST
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiString]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:requestData];
//Go
NSURLResponse *response = nil;
queryResultData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
Which works great.
The trouble is, this works for a webservice which is expecting a single JSON argument as the http body.
How can I include JSON as one of many arguments, the way you can use the data encoding of #"arg1=val1&arg2=val2".
For example: image you have a webservice expecting something like
http://mysite.com/api/v1/route/test?data={json:%22true%22}&other=abcdefg
Which must be submitted as a POST.
This, interestingly, has a JSON dictionary as only one argument of many, and not in the body at that. I can't figure out how to add these arguments to the post.
EDIT
Here's the same concept in php. How do you do this in Cocoa?
$data = array('x' => 1, 'name => 'fred');
$json = json_encode($data);
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, array('json_data' => $json));
-- or --
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, 'something=whatever&json_data='.$json);

Need example for Posting Core Data objects in JSON to RESTful web service

I've been reading over code samples and posts for days but I haven't found a definitive way to post JSON data from my Core Data objects to a RESTful web service. There's a TON of documentation about pulling the JSON from a web service but not so much about sending stuff back. Can anyone point me to a good example or post some code on how to do it? I'm using Core Data and I have the object I want to send back mapped to a Dictionary but I'm missing the code to send it to the service.
EDIT:
I ended up with the code below which looks right and runs without errors, but I get 0 bytes of data returned and my webservice doesn't seem to be receiving the request. The JSON data looks good, the URL is correct, and I can hit the webservice and get JSON data back from it. The NSURLConnection delegate methods also fire as expected.
Is there anything I'm missing below?
- (void)SubmitSystems
{
NSFetchRequest * allSystems = [[NSFetchRequest alloc] init];
[allSystems setEntity:[NSEntityDescription entityForName:#"System" inManagedObjectContext:self.managedObjectContext]];
NSError * error = nil;
NSArray * systems = [self.managedObjectContext executeFetchRequest:allSystems error:&error];
//error handling goes here
//for (NSManagedObject * system in systems) {
NSManagedObject *system = systems[2];
NSString *entityString = #"System";
NSString * serverString = [NSString stringWithFormat:#"%#%#", kWebServiceAddress, entityString];
NSURL *url = [NSURL URLWithString:serverString];
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:[self jsonSystemDictionary:(System *)system] options:kNilOptions error:&error];
//NSLog([[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]); //debug only
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy: NSURLRequestReloadIgnoringCacheData timeoutInterval: 30.f];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [jsonData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: jsonData];
self.urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
//}
}
You're going to need to NSMutableURLRequest. Using this, you can use setHTTPMethod and pass it the #"POST" string, and then use the attributes of your NSManagedObject to populate the URL, HTTPBody and/or HTTPHeader as needed.

HTTP Post help - iOS app

I've successfully implemented push notifications with Urban Airship in my app, but I want to make an administrative password-protected part of the app that enables one to send the push notifications from any authorized iPhone with the app installed.
I need a way so whatever i type in a text box is send via https POST to https://go.urbanairship.com/api/push/broadcast.
Can anyone recommend or tell me a way to do this?
You can use NSURLConnection to do this. Setup an NSMutableURLRequest with the post data and other information, and then use NSURLConnection to post it and get a response:
NSString * postString = [NSString stringWithFormat:#"field1=%#", myItem];
NSData * postData = [postString dataUsingEncoding:NSUTF8StringEncoding];
NSURL * myURL = [NSURL URLWithString:#"https://go.urbanairship.com/api/push/broadcast"];
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:myURL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:10];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [postData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:postData];
NSData * returnedData = [NSURLConnection sendSynchronousRequest:request
returningResponse:nil error:nil];
You can also use NSURLConnection for asynchronous requests. See the NSURLConnection Class Reference.

Resources