I am using a NSMutableURLRequest to send a (synchronous) POST request to a web service.
The request body contains a combination of XML and JSON. Something like :
<element>
<element 2>
<![CDATA[
{"jsondata1":{"datafield1":"data1"},
"jsondata2":"some data"
}
]]>
</element 2>
</element>
the JSON string has been escaped (Using escape() in Javascript)
When I receive the request at the other end I notice that all escaped characters have been unescaped!!
Can anyone tell me why this is happening? And how can I prevent this?
Here is the code that I'm using to send the request:
NSURL *url = [NSURL URLWithString:#"https://my-webservice.com/something.do"];
NSData *xmlResponseDataSave;
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
NSString *msgLength = [NSString stringWithFormat:#"%d",[xmlRequestString length]];
[req addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[req addValue:msgLength forHTTPHeaderField:#"Content-Length"];
[req setHTTPMethod:#"POST"];
NSData *saveData=[xmlRequestString dataUsingEncoding:NSUTF8StringEncoding];
[req setHTTPBody:saveData];
NSError *error=nil;
NSURLResponse *resp=[[NSURLResponse alloc] init];
xmlResponseData=[NSURLConnection sendSynchronousRequest:req returningResponse:&resp error:&error];
NSString *xmlResponseString=[[NSString alloc] initWithData:xmlResponseData encoding:NSUTF8StringEncoding];
Please note: I cannot make any change to the xml or the web service. I can only change the objective c code.
After a lot of trial and error the only solution that I could come up with is to string used in the request body before sending it (Since it's gonna get unescaped while being sent):
xmlRequestString=[xmlRequestString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *saveData=[xmlRequestString dataUsingEncoding:NSUTF8StringEncoding];
Though this is not a fix in the truest sense, just a work around. But it works for me (So far).
I'm still clue less about the root cause of the problem and I am still looking for a more elegant solution.
Related
I'm writing some with server API. I'm using RestKit but this question I wrote without. I don't understand why console request is working and my is not. Please help me with this.
-(void)uploadFile {
NSString *URLPath = [NSString stringWithFormat:#"https://api.interlabs.pro/v1/texts/23041/content"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:URLPath]];
[request setHTTPMethod:#"PUT"];
[request addValue: #"Bearer ewogICAgInR5cCI6ICJKV1QiLAogICAgImFsZyI6ICJIUzI1NiIKfQ.ewogICAgImlzcyI6ICJhcGkuaW50ZXJsYWJzLnBybyIsCiAgICAiaWF0IjogMTQ2MzY3ODg2NCwKICAgICJleHAiOiAxNDYzNjgyNDY0LAogICAgInN1YiI6IDgzCn0.SuvGXfsDDzpA5-qJtRUZi7uw98IqA8_axfTGcMVjZdw" forHTTPHeaderField: #"Authorization"];
NSError *err;
NSURLResponse *response;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
NSString *resSrt = [[NSString alloc]initWithData:responseData encoding:NSASCIIStringEncoding];
NSLog(resSrt);
}
And it's still doesn't not work, but console work perfectly
But enter link description here
update token link
The code works fine and result is that token is expired.
But you should not use deprecated methods like "NSURLConnection sendSynchronousRequest", then you should check error, when handling results from internet it is utf8 most of the time and not ascii. Then when logging strings use NSLog(#"%#", theString) to avoid problems if the content of theString contains formating specifiers.
I am trying to send information to a login web service but certain characters are giving me trouble.
For example, if the password is something like h+4hfP, the web service rejects it because the plus sign ('+') is not properly encoded to %2B.
The web service uses UTF-8 encoding so I have been building an NSData object with this NSString method, - (NSData *)dataUsingEncoding:(NSStringEncoding)encoding; choosing NSUTF8StringEncoding as the encoding.
This doesn't seem to be enough though.
The problem could also be with how I'm building an NSMutableURLRequest:
NSData *postData = [#"h+4hfP" dataUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:contentLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:postData];
How can I ensure the encoding is done properly?
Use
[theRequest setValue:#"application/json; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
You could percent encode the string before representing it as NSData:
NSString *password = [#"h+4hfP" stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]];
NSData *postData = [password dataUsingEncoding:NSUTF8StringEncoding];
...
This can be a solution:
I was facing this problem. After some hours and search, I discovered this:
http://madebymany.com/blog/url-encoding-an-nsstring-on-ios
Solution:
1st: You must create a method or class with content:
-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding withString:(NSString *) str{
return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)str,
NULL,
(CFStringRef)#"!*'\"();:#&=+$,/?%#[]% ",
CFStringConvertNSStringEncodingToEncoding(encoding)));
}
2nd: Use:
NSString *stringToSend = [self urlEncodeUsingEncoding:NSUTF8StringEncoding withString:stringToBeVerifyed];
Then
NSData *postData = [stringToSend dataUsingEncoding:NSUTF8StringEncoding];
[...]
Getting following error while consuming SOAP webservice in iOS App
"No Action header was found with namespace 'http://www.w3.org/2005/08/addressing' for the given message."
The same webservice working fine in SOAP UI Tool.
Following is the request format
NSString *data = #"<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:tem=\"http://tempuri.org/\">
<soap:Header></soap:Header>
<soap:Body><tem:GetEvaluators></tem:GetEvaluators></soap:Body>
</soap:Envelope>";
NSString *url = #"webservice url";
NSData *postData = [data dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:postData];
[request setTimeoutInterval:20.0];
[request setValue:#"application/soap+xml;charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"http://tempuri.org/IATCService/GetEvaluators" forHTTPHeaderField:#"SOAPAction"];
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
Complete error response received from webservice
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/fault</a:Action>
</s:Header>
<s:Body>
<s:Fault>
<s:Code>
<s:Value>s:Sender</s:Value>
<s:Subcode>
<s:Value>a:MessageAddressingHeaderRequired</s:Value>
</s:Subcode>
</s:Code>
<s:Reason>
<s:Text xml:lang="en-US">No Action header was found with namespace 'http://www.w3.org/2005/08/addressing' for the given message.</s:Text>
</s:Reason>
<s:Detail>
<a:ProblemHeaderQName>a:Action</a:ProblemHeaderQName>
</s:Detail>
</s:Fault>
</s:Body>
Any help really appreciated.
We had the same problem with an ASP.NET-based server (error message when using python/suds, same query worked in SoapUi); after a lot of digging, we found that we need to add a SOAP header (as XML element) which contains the action; having the action in the Content-Type or SOAPAction headers was not enough (but does not hurt either). Here's an example of a successful query (from SoapUi):
<SOAP-ENV:Envelope xmlns:ns0="..." xmlns:ns1="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope">
<SOAP-ENV:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:Action>http://www.foo.com/.../SomeJob/getParameters</wsa:Action></SOAP-ENV:Header>
<ns1:Body>
<ns0:getParameters>...</ns0:getParameters>
</ns1:Body>
</SOAP-ENV:Envelope>
With Python and SUDS, this is how we did it:
from suds.sax.element import Element
wsans = ('wsa', "http://www.w3.org/2005/08/addressing")
client.set_options(soapheaders = Element('Action', ns=wsans).setText(action))
The action can be queried from the method, i.e. if you want to call a method client.service.foo, use
action = client.service.foo.method.soap.action
We found this by looking at the SoapUi HTTP log. (We also tried Wireshark, but that would not work because we're trying to use an https server which we don't own.)
Include
[request setValue:#"application/xml" forHTTPHeaderField:#"Content-Type"];
Finally i able to solve this problem, the content-type and request format are totally different than what i am passing with request
Content-Type: application/soap+xml;charset=UTF-8;action="http://tempuri.org/IATCService/GetEvaluators"
So difference is i have to pass action with content type.
Also the request Soap Envelop is totally different with different namespaces
<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:a=\"http://www.w3.org/2005/08/addressing\">
**<s:Header>
<a:Action s:mustUnderstand=\"1\">http://tempuri.org/IATCService/GetEvaluators</a:Action> </s:Header>**
<s:Body>
<GetEvaluators xmlns=\"http://tempuri.org/\"/></s:Body>
</s:Envelope>
As the header information is also totally different we have to specify action over there.
Hope it will be helpful to someone, who is facing same problem.
From my iPhone app, I'm making a call to an ASP.NET web service. Below is my code
NSString *urlString = #"http://tbtesting/teambinder5/KEY9XXXXXX-cXXe-49XX2-acca-2XXXXXXXa9/Dashboard/DashboardWidgets.asmx/GetAnnouncement";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:#"*/*" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"en-us" forHTTPHeaderField:#"Accept-Language"];
[request setValue:#"gzip, deflate" forHTTPHeaderField:#"Accept-Encoding"];
[request setValue:#"20" forHTTPHeaderField:#"Content-Length"];
//[request setValue:#"3" forHTTPHeaderField:#"announceIntKey"];
NSError *error = nil;
NSURLResponse *response = [[NSURLResponse alloc] init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error) {
NSLog(#"Following error occured: %#", error.localizedDescription);
}
else {
NSString *returnValue = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"message: %#", returnValue);
}
Here is the header taken from fiddler.
POST http://tbtesting/teambinder5/KEY9XXXXXX-cXXe-49XX2-acca-2XXXXXXXa9/Dashboard/DashboardWidgets.asmx/GetAnnouncement HTTP/1.1
Accept: */*
Accept-Language: en-us
Content-Type: application/json; charset=utf-8
Accept-Encoding: gzip, deflate
Content-Length: 20
{"announceIntKey":3}
I'm getting the following error message.
"Message":"Invalid web service call, missing value for parameter: \u0027announceIntKey\u0027."
After a little bit of searching here on SO I found out the cause for this error. It is because I'm not passing the announceIntKey and its value.
Although I know the reason, I'm kinda clueless on how to correct it. Since it looks like an object literal, you can't pass it like any other header value. All the example code I came across here on SO is for jQuery or some other language.
My question is how can I pass this value in Objective C?
Thank you.
It looks like you're sending the content-type of application/json, so it would stand to reason that you need to pass the value as part of a POST containing a JSON body.
You will need to add that to the body of your request. You don't need to set the content-length as the NSMutableURLRequest will manage this for you.
NSString *body = "{\"announceIntKey\" : VALUE}";
[request setHTTPBody:[body dataUsingEncoding:NSASCIIStringEncoding]];
You'll need to replace VALUE with what actually goes into the announceIntKey.
I do not want to use asihttp methods so is there a way to download a file from the server without having to use a get request? How to use a post request to download the file from the server?
Since the OP wants the answer regardless, I will use PHP for this.
iOS client side:
NSString *phpURLString = [NSString stringWithFormat:#"%#/getFile.php", serverAddress];
NSURL *phpURL = [NSURL URLWithString:phpURLString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:phpURL];
NSString *post = [NSString stringWithFormat:#"filePath=%#", filePath];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding];
NSString *postLength = [NSString stringWithFormat:#"%d", [post length]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:postData];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]:
For the PHP side:
<?php
$filePath = htmlspecialchars($_POST['filePath']);
$fileData = file_get_contents($filePath);
echo $fileData;
?>
This is very basic. Also for the iOS side you would want to wrap that entire request in a code block that is run asynchronously in the background. You could use GCD for that. Once you have the file as responseData in iOS you can save the file to the local container and then do many things with it.