*Summary:*
The HTTPClient will cause a crash on iOS when given a URL containing invalid characters such as:
* Space ' ' character.
* Percent '%' sign not followed by a hex digit.
* Unicode character.
*Steps to reproduce:*
Set up a Titanium project to use the attached JavaScript file.
Build and run for iOS.
Tap the "Send HTTP Request" button.
*Result:*
Crashes due to invalid characters in the URL.
*Expected Result:*
Should not crash. Should log a warning and/or invoke the onerror callback.
Even better, we should add "autoEncodeUrl" support to iOS for feature parity with Android and Windows Phone. By default, this property is set true. This way, invalid URLs will be automatically %-encoded.
http://docs.appcelerator.com/platform/latest/#!/api/Titanium.Network.HTTPClient-property-autoEncodeUrl
*Notes:*
* The attached project does not crash on Android. Invalid URLs are automatically encoded.
* Percent signs are the only characters that should not be automatically encoded. This is in case the given URL already contains %-encoded characters. If there is a lone percent sign without a hex value, then it should produce an invalid URL.
Good catch! It returns a
nil
values from [here](https://github.com/appcelerator/titanium_mobile/blob/master/iphone/Classes/TiUtils.m#L926), causing the APSHTTPClient URL to be nil as well, the assertion then fails and the crash is produced. What's interesting is that the fix (like in [this line](https://github.com/appcelerator/titanium_mobile/blob/master/iphone/Classes/TiUtils.m#L933)) is already there, but not honored for URL's beginning with http/https. Not sure why that was done and what the best approach would be. *EDIT*: The way it was implemented was because of TIMOB-18765 - probably because the remote-URL case was not recognized. So we could: a) Add the encoding for both local and remote URL's (now: only local) b) Support theautoEncodeUrl
property on iOS and check that one. Problem: We auto-encode it by default for local URL's already, how to handle that?Hmm... I just noticed that iOS already auto-encodes http/https URL parameters. So, as long as the URL part to the left of the '?' are valid, it works fine. I tested it with the following URL...
http://localhost:40404/path?test=Hello World&percent=50%
...and the above gave me the following encoded URL path and parameter in my test code.../path?test=hello%20world&percent=50%25
So, it seems like our Objective-C "toURL" method was already intended to auto-encode by default. I can see that we call CFURLCreateStringByAddingPercentEscapes() [here](https://github.com/appcelerator/titanium_mobile/blob/master/iphone/Classes/TiUtils.m#L917) for an http/https URL's path part, which would include the parameters. The toURL method just has the above mentioned bug and doesn't support disabling auto-encoding. So, I suppose if we were to add the ability to disable auto-encoding in the future, we could create another "toURL" method with an extra argument to enable/disable auto-encoding. Also, I noticed an issue with my URL parameter test above. We're not supposed to encode a space to %20 in URL parameters. We're supposed to encode them to '+' characters instead. That is, URL query parameters are supposed to use the "application/x-www-form-urlencoded" MIME format and the rest of the URL is supposed to follow the "RFC 2373" specification. https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax I'm currently fixing URL auto-encoding issues on Android now and I'm finding the tricky things to handle are: * The username part of the URL (the part to the left of the@hostname
) can be an e-mail account name. Which means it'll have an additional@
character in the URL that'll have to be %-escaped. For example,http://john@domain.com@host.com
would have to be escaped tohttp://john%40domain.com@host.com
. (This currently work on iOS now.) * The:
and@
characters don't have to be encoded in the URL's path, query parameters, or#
fragment/anchor-tag. They only get special treatment in the authority part of the URL. * The?
and/
characters don't have to be encoded in the URL's query parameters or#
fragment/anchor-tag. * Spaces should be encoded as+
in the query parameters and as%20
in all other places. Note that the URL#
fragment/anchor-tag comes after the query parameters. For example,http://host.com/my path?test=hello world#my anchor
should be encoded tohttp://host.com/my%20path?test=hello+world#my%20anchor
. * The existing %-encoded characters in the URL string should be preserved. A simple solution to this is to %-encode the given URL string, then replace all%25
substrings with%
. For example, a string such as100%25
(intended to be decoded as100%
) would be encoded as100%2525
and then the substring substitution would turn it back to100%25
. The only limitation is that standalone%
characters without hex values would not get encoded, making the URL invalid... but I think this is the 1 ambiguous case we can't handle and it's fine. Is there a simple Objective-C function/method to auto-encode URLs? I hope so. I ask because the CFURLCreateStringByAddingPercentEscapes() function can create invalid URLs if applied to the entire URL string, which is probably why we don't do it. (On Android, there is no single magic Java function either and I have to do this myself.) Starting off, we may just want to fix the crash and let the URL be invalid. We can punt on the auto-encoding for now if we feel like it's a riskier change.