spring mvc decoding + is being replaced with space - iphone

I have problem in Spring MVC pattern. When i call the web service form iPhone app with encoded value, The decoding is not happening properly. Not sure about what the issue is.
the + sign is getting replaced with a space " ".
Below is my web.xml
<?xml version="1.0" encoding="UTF-8"?><br>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br>
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"<br>
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"<br>
id="WebApp_ID" version="3.0"><br>
<display-name>APPLICATIONNAME</display-name><br>
<filter><br>
<filter-name>encoding-filter</filter-name><br>
<filter-class>org.springframework.web.filter.CharacterEnco dingFilter</filter-class><br>
<init-param><br>
<param-name>encoding</param-name><br>
<param-value>UTF-8</param-value><br>
</init-param><br>
<init-param><br>
<param-name>forceEncoding</param-name><br>
<param-value>true</param-value><br>
</init-param><br>
</filter><br>
<filter-mapping><br>
<filter-name>encoding-filter</filter-name><br>
<url-pattern>/rest/*</url-pattern><br>
</filter-mapping><br>
<servlet><br>
<servlet-name>spring</servlet-name><br>
<servlet-class>org.springframework.web.servlet.DispatcherSe rvlet</servlet-class><br>
<load-on-startup>1</load-on-startup><br>
</servlet><br>
<servlet-mapping><br>
<servlet-name>spring</servlet-name><br>
<url-pattern>/rest/*</url-pattern><br>
</servlet-mapping><br>
<welcome-file-list><br>
<welcome-file>index.jsp</welcome-file><br>
</welcome-file-list><br>
</web-app><br>
My controller class
#Controller
public class LoginController {
#Autowired
private LoginServiceImpl loginService;
#RequestMapping(value = "/getUserDetails", method = RequestMethod.POST)
public #ResponseBody
LoginData getUserDetails(#ModelAttribute LoginDetails loginDetails) {
LOGGER.debug("Session ID = " + loginDetails.getSessionID());
}
Sample input request from iPhone APP
NSURLResponse *response = nil;
NSError *error = nil;
NSString *urlString = #"http://localhost:8080/rest/getUserDetails";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
NSURLConnection *connection= [[NSURLConnection alloc] initWithRequest:urlRequest
delegate:self];
[urlRequest setHTTPMethod:#"POST"];
NSString *postString = [NSString stringWithFormat:#"sessionID=%#",#"ABCD+/EFGH"];
NSData *a=[postString dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"encoded %#",a);
[urlRequest setHTTPBody:a];
[connection start];
NSString *returnString = [[NSString alloc] initWithData:[NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error] encoding:NSUTF8StringEncoding];
NSLog(#" %# ",returnString);
NSLog(#"%#",error);
On the server side instead of "ABCD+/EFGH" i am getting "ABCD /EFGH". SO the plus (+) is not getting decoded.
What needs to be done to get the plus (+) on the server? Any help is appreciated.

It's an expected behavour.
In application/x-www-form-urlencoded form (used for sending form data in POST) space is encoded as +, and real + should be represented in percent-encoded form (%2B).
I think it would be better to use some kind of built-in application/x-www-form-urlencoded encoding routine, if available on iPhone, instead of manual replacement.

Related

cachedResponseForRequest method not being accessed

I am trying to set up a cache, however the method I am using 'as below' is not being accessed by the thread.
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
I am initializing the connection like this, and connectionDidFinishLoading is accessed so I am not sure what I am missing.
- (IBAction)searchRequest:(NSData *)postBodyData
{
//Set database address
NSMutableString *databaseURL = [[NSMutableString alloc] initWithString:#"https://127.0.0.1:88"];
NSURL *url = [NSURL URLWithString:databaseURL];
NSString *postLength = [NSString stringWithFormat:#"%d", [postBodyData length]];
//SynchronousRequest to grab the data, also setting up the cachePolicy
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0]; //if request dose not finish happen within 60 second timeout.
// NSInputStream *fileStream = [NSInputStream inputStreamWithData:postBodyData];
[request setHTTPMethod: #"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/octet-stream" forHTTPHeaderField:#"content-type"];
[request setHTTPBody:postBodyData];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [NSMutableData data];
} else {
// Inform the user that the connection failed from the connection:didFailWithError method
}
}
any help would be appreciated.
connection:willCacheResponse: is only called in cases when the response will be cached. POST requests are not cacheable in most cases. (More details: Is it possible to cache POST methods in HTTP?)
You should probably look at something like MKNetworkKit which handles a lot of this kind of caching, particularly for REST protocols.
You can also look at Drop-in offline caching for UIWebView. You'd have to modify it significantly, but NSURLProtocol can be used to solve this kind of problem. AFCache is currently working to integrate this approach, and is another toolkit to consider. (Read through the comments in the blog post for more background on the issues.)

adding + before using %2b using url encoding in iphone

I have an application where on a button click i am passing my server api method which calls the JSON post method and saves data to server database.Here i am saving my mobile number and emergency no to server database.My mobile number is in string format.In my mobile number string variable, my mobile number is getting saved which is in this format '+90-9491491411'.I am entering + and then code and then- and then number but when i send to the server database i am removing the - and sending the no to database but problem is in my server database + of mobile is not getting entered which i am entering .What may be the problem .I am using POST method to send the request .This is my code
-(void)sendRequest
{
NSString *newstring = txtMobile.text;
mobileValue = [newstring stringByReplacingOccurrencesOfString:#"-" withString:#""];
NSLog(#"%#",mobileValue);
NSString *newString1 = txtemergencyprovider.text;
emergencyNumber = [newString1 stringByReplacingOccurrencesOfString:#"-" withString:#""];
NSLog(#"%#",emergencyNumber);
if ([txtEmail.text isEqualToString:#""])
{
post = [NSString stringWithFormat:#"CommandType=new&ApplicationType=%d&FullName=%#&Mobile=%#&EmergencymobileNumber=%#&Latitude=%f&Longitude=%f&City=%#&MobileModel=Apple",applicationtype,txtFullname.text,mobileValue,emergencyNumber,latitude,longitude,txtCity.text];
NSLog(#"%#",post);
}
else {
post = [NSString stringWithFormat:#"CommandType=new&ApplicationType=%d&FullName=%#&Mobile=%#&EmergencymobileNumber=%#&Latitude=%f&Longitude=%f&City=%#&EmailAddress=%#&MobileModel=Apple",applicationtype,txtFullname.text,mobileValue,emergencyNumber,latitude,longitude,txtCity.text,txtEmail.text];
NSLog(#"%#",post);
}
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSLog(#"%#",postLength);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://myapi?RequestType=NEW"]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (theConnection) {
webData = [[NSMutableData data] retain];
NSLog(#"%#",webData);
}
else
{
}
}
//In my mobile number and emrgency number variable my no is in this format '+91986444711' but when the value is entered in server database + gets removed off .What may be the prob.
Unfortunately, NSString's -stringByAddingPercentEscapesUsingEncoding: will not convert the plus (+) sign into %2B because the plus sign is a valid URL character that is used to separate query parameters. What this usually means is that it gets converted to a space character by the web server.
The easiest way to replace the plus sign would be using NSString's stringByReplacingOccurrencesOfString:withString: to replace the + with %2B. For example:
mobileValue = [mobileValue stringByReplacingOccurrencesOfString:#"+" withString:#"%2B"];
The plus sign ("+") in URL means an encoded space (" ") and most likely your server will interpret it as a space. Change the plus character to %2B in the string before posting it. For a complete solution on URL encoding see this post: http://madebymany.com/blog/url-encoding-an-nsstring-on-ios
The plus sign means space in a post request. You need to convert the plus to a percent escape character. The easiest way to do this is as follows:
NSString* escapedMobileValue = [mobileValue stringByReplacingOccurencesOfString: #"+" withString: #"%2b"];
This will turn the + into %2b. Probably the server will automatically reverse the encoding for you.
(Edited in line with mttrb's comment)

youtube inbox problem

I'm trying to programmatically (using gdata api) retrieve incoming messages from youtube account.
My request:
NSURL *url = [NSURL URLWithString:#"http://gdata.youtube.com/feeds/api/users/my_nick/inbox"];
NSMutableURLRequest *inboxRequest = [NSMutableURLRequest requestWithURL:url];
NSString *authStr = [NSString stringWithFormat:#"GoogleLogin auth=%#", authMarker];
[inboxRequest setValue:authStr forHTTPHeaderField:#"Authorization"];
[inboxRequest addValue:#"Content-Type" forHTTPHeaderField:#"application/x-www-form-urlencoded"];
[inboxRequest setHTTPMethod:#"GET"];
NSHTTPURLResponse *response = NULL;
NSData *responseData = [NSURLConnection sendSynchronousRequest:inboxRequest returningResponse:&response error:nil];
NSString *responseDataString = [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding];
NSLog(#"\n%#\n", responseDataString);
NSLog(#"\n%#\n", [inboxRequest ]);
return feed without entries... (although I can see incoming messages on the site)
here response from nslog:
<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'><id>http://gdata.youtube.com/feeds/api/users/thisistestnick/inbox</id><updated>2011-06-16T14:45:00.475Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://gdata.youtube.com/schemas/2007#videoMessage'/><title type='text'>Inbox of thisistestnick</title><logo>http://www.youtube.com/img/pic_youtubelogo_123x63.gif</logo><link rel='alternate' type='text/html' href='http://www.youtube.com/my_messages?folder=inbox&filter=videos'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/users/thisistestnick/inbox'/><link rel='http://schemas.google.com/g/2005#batch' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/users/thisistestnick/inbox/batch'/><link rel='self' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/users/thisistestnick/inbox?start-index=1&max-results=25'/><author><name>thisistestnick</name><uri>http://gdata.youtube.com/feeds/api/users/thisistestnick</uri></author><generator version='2.0' uri='http://gdata.youtube.com/'>YouTube data API</generator><openSearch:totalResults>0</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage></feed>
what is wrong? pls help.
Why cant you use, gdata-objectivec lib api's rather doing your own parsing ? I havent tried retrieving 'inbox' but was fairly successful in getting the info i want. Advantages of using it are:
a) You get the info in native formats (Strings and Dictionaries), lib does the job of parsing feeds for you.
b) mainly, there wont be any parsing/api understanding errors (which i suppose is the reason for your problem).

How do I send XML POST data from an iOS app to a Django app?

I am attempting to implement an online leaderboard in a game app for iOS, using Django to process POST requests from the iDevice and store the scores. I have figured out how to get Django to serialize the objects to XML, and my iPhone can read and display the scores. However, I can't for the life of me get my iPhone to POST XML to my Django server.
Below is the function I am using to post the scores...
iOS (Objective-C) Controller:
- (void) submitHighScore {
NSLog(#"Submitting high score...");
NSString *urlString = HIGH_SCORES_URL;
NSURL *url = [NSURL URLWithString: urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: url];
[request setHTTPMethod: #"POST"];
[request setValue: #"text/xml" forHTTPHeaderField: #"Content-Type"];
NSMutableData *highScoreData = [NSMutableData data];
[highScoreData appendData: [[NSString stringWithFormat: #"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"] dataUsingEncoding: NSUTF8StringEncoding]];
[highScoreData appendData: [[NSString stringWithFormat: #"<player_name>%#</player_name", #"test"] dataUsingEncoding: NSUTF8StringEncoding]];
[highScoreData appendData: [[NSString stringWithFormat: #"<score>%d</score>", 0] dataUsingEncoding: NSUTF8StringEncoding]];
[highScoreData appendData: [[NSString stringWithFormat: #"</xml>"] dataUsingEncoding: NSUTF8StringEncoding]];
[request setHTTPBody: highScoreData];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible: YES];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest: request
delegate: self];
if (!connection) {
NSLog(#"Request to send high scores appears to be invalid.");
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible: NO];
}
}
The above method succeeds in sending the request, and interprets it correctly as CONTENT_TYPE: text/xml, but the Django view that processes the request can't seem to make any sense of it, interpreting it almost as if it was merely plain text. Below is my Django view...
Django (Python) view:
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.core import serializers
from django.core.exceptions import ValidationError
from django.views.decorators.csrf import csrf_exempt
from modologger.taptap.models import HighScore
#csrf_exempt
def leaderboard( request, xml = False, template_name = 'apps/taptap/leaderboard.html' ):
"""Returns leaderboard."""
if xml == True: # xml is set as True or False in the URLConf, based on the URL requested
if request.method == 'POST':
postdata = request.POST.copy()
print postdata
# here, postdata is evaluated as:
# <QueryDict: {u'<?xml version': [u'"1.0" encoding="UTF-8" ?><player_name>test</player_name<score>0</score></xml>']}>
for deserialized_object in serializers.deserialize('xml', postdata): # this fails, returning a 500 error
try:
deserialized_object.object.full_clean()
except ValidationError, e:
return HttpResponseBadRequest
deserialized_object.save()
else:
high_score_data = serializers.serialize( 'xml', HighScore.objects.all() )
return HttpResponse( high_score_data, mimetype = 'text/xml' )
else:
high_scores = HighScore.objects.all()
return render_to_response( template_name, locals(), context_instance = RequestContext( request ) )
To be honest, I'm not sure whether the problem lies in the Objective-C or in the Django code. Is the Objective-C not sending the XML in the right format? Or is the Django server not processing that XML correctly?
Any insight would be much appreciated. Thanks in advance.
Update:
I got it to work, by editing the iOS Controller to set the HTTPBody of the request like so:
NSMutableData *highScoreData = [NSMutableData data];
[highScoreData appendData: [[NSString stringWithFormat: #"player_name=%#;", #"test"] dataUsingEncoding: NSUTF8StringEncoding]];
[highScoreData appendData: [[NSString stringWithFormat: #"score=%d", 0] dataUsingEncoding: NSUTF8StringEncoding]];
[request setHTTPBody: highScoreData];
For some reason putting a semicolon in there got Django to recognize it, assign the values to a new instance of a HighScore class, and save it. The logging on the test server indicates request.POST is <QueryDict: {u'score': [u'9'], u'player_name': [u'test']}>.
Still not quite sure what to make of all this.
As per Radu's suggestion, I took a look at highScoreData with NSLog, right after appending it to request.HTTPBody, and the result is <706c6179 65725f6e 616d653d 74657374 3b73636f 72653d39>.
I'm a huge Obj-C noob, so again, any help is appreciated! Thanks again.
Since you control both sides, I'd drop the complexity of xml encoding the data and use RestKit or some other framework that makes it easy to communicate with Django.

iPhone posting xml to ASP.net MVC webservices

Is it possible to POST XMLData to the webservices from iPhone OS. The webservices are developed in ASP.net MVC 3.0 with RESTFul url and we would like iPhone developers to send input data in XML format as POST variable..
The webservice actionresult looks like the following where sightings is the parameter that is expected to pass as POST variable
public ActionResult Update(XDocument sightings)
{
try
{
XMLHelper xmlHelper = new XMLHelper();
}
}
That's definitely applicable all you need to do is to use NSMutableURLRequest as the following:
NSString* sXMLToPost = #"<?xml version=\"1.0\"?><Name>user</Name>";
NSData* data = [sXMLToPost dataUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:#"http://myurl.com/RequestHandler.ashx"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[sXMLToPost dataUsingEncoding:NSUTF8StringEncoding]];
NSURLResponse *response;
NSError *error;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
if (error) {
//handle the error
}
And Now in your ASHX file parse the InputStream to read the posted XML:
System.IO.Stream str; String strmContents;
Int32 counter, strLen, strRead;
str = Request.InputStream;
strLen = Convert.ToInt32(str.Length);
byte[] strArr = new byte[strLen];
strRead = str.Read(strArr, 0, strLen);
// Convert byte array to a text string.
strmContents = "";
for (counter = 0; counter < strLen; counter++)
{
strmContents = strmContents + strArr[counter].ToString();
}
Remember you can always check the request type using:
if (context.Request.RequestType == "POST")
MSDN HttpRequest.InputStream