AngularJS resource with explicit file type extension and POST - angularjs

Angular $resource does a pretty good job figuring out how to handle POST and GET query with no resource ID; it intelligently removes the trailing slash:
resource('/users/:user',{user:'#id'},{})
Will give the correct:
GET /users/25 (for User.get())
POST /users (for new creation)
GET /users (for User.query())
Note that for creation and User.query() is correctly stripped the trailing slash when :user was blank.
However, if you add a file type extension, it stops stripping the trailing slash
resource('/users/:user.json',{user:'#id'},{})
Will give
GET /users/25.json (CORRECT)
POST /users/.json (BAD: should be /users.json)
GET /users/.json (BAD: should be /users.json)
Is there any way to get it to either:
intelligently strip the trailing slash even with a file type; OR
put on the '.json' extension afterwards
This is a pretty common pattern, supported as a basic format in Sinatra (RoR) and express (node), and is even part of the basic angular tutorial at http://docs.angularjs.org/tutorial/step_11
How do I get it to do the right thing?

I think it's a bug, which seems to be fixed in Version 1.1.5: https://github.com/angular/angular.js/commit/5306136

Related

Encoded slash (%2F) in query parameter causes redirection to fail in Angular Application

In my angular application, I need to make GET call to a Tomcat server. This GET call requires query parameters which could contain special characters too like "+", "/", "/+"
GET call is being made from angular controller using $window.open with target as "_blank"
Currently the redirection is getting failed without any encoding.
So, I added encoding in .js file before the GET call is being made by using encodeURIComponent.
Then I added decoding logic using URLDecode.decode in backend java code to decode query parameters.
But still it doesn't work.
It works only if I encode query parameters twice within the .js file using encodeURIComponent twice.
I am trying to find the root cause for double encoding but no luck yet. I would greatly appreciate if anyone could share any inputs.
Made it work by adding a * in path parameter in app.js. Adding a star means that the request will include multiple path parameters separated by /, and so angular will not try to encode / in the request.
Double encoding could also work but then the server side logic has to be modified to decode the request parameters twice and replace %2B2F by %2F

Routing to a directory with a leading period?

Trying to enable letsencrypt with web2py. As part of that I may need to create a route for a url like www.example.com/.well-known/acme-challenge/<some long string>
As I test this I notice that the following route works:
('/\.well-known/acme-challenge/test.html',
'/some_app/static/well-known/acme-challenge/test.html'),
While this almost identical route doesn't:
('/\.well-known/acme-challenge/test.html',
'/some_app/static/.well-known/acme-challenge/test.html'),
The only difference between these two routes is that in the latter one, in the second element of the tuple, .well-known has a leading period while the former route has well-known without a period.
Note I did try escaping the period like \.well-known but it doesn't work either.
Why does the route with the leading period not work? And how can I fix it?
Even though it is a static URL, the path segment immediately after /static/ is interpreted as the controller function and is therefore expected to be a valid Python identifier (the regular expression used to match that part of the path is \w+).
Note, rather than having web2py serve the letsencrypt response, you might consider configuring your web server to return the response directly (e.g., it is easy to configure Nginx to do this).
I haven't come across a direct solution to the leading period issue (as mentioned by Anthony web2py expects a valid python identifier)
However, to solve the specific problem of working with Let's Encrypt I did follow Anthony's suggestion to handle it in the webserver. I am using Apache, in my httpd.conf I added:
LoadModule alias_module modules/mod_alias.so
Alias "/.well-known/" "/var/www/html/somedirectory/.well-known/"
Note Alias will automatically map whatever comes after the url path. Example with the above Alias:
example.com/.well-known/something/hello
will map to
/var/www/html/somedirectory/.well-known/something/hello

Angular Routing with an encoded backslash

I am building in invite/registration form for my site. The idea is that one user invites another user, which sends a code with a url to register with. The problem is that the code can have an encoded backslash in it. When that encoded backslash is processed in Angular, it seems to get decoded and ends up busting the routing.
http://localhost:54464/ang/register/owi0%2fCQCrjzBcwqEORVVHhrICIANGKxtxMJ2Kh91y%2bNhhB%2br06appZzEVPhpkP2C
becomes:
http://localhost:54464/ang/register/owi0/CQCrjzBcwqEORVVHhrICIANGKxtxMJ2Kh91y+NhhB+r06appZzEVPhpkP2C
How can I stop this behavior?
Try using a route like:
/register/*code
The code will contain the string with the slashes
source
It is typically used for path-like url arguments...but I don't see why this wouldn't work for your case.

mail clients stripping part of angular url

I am sending a signup activation email containing a signup confirmation url with a confirmation token that points to an angular front end app:
...
Activate
...
Note that the token is a JWT and is fairly long.
This works find for most users, but for some clicking on the link takes them to https://domain/com only without the confirm-signup?token=...
It seems as though the mail client may be stripping off everything after the #, but I can't find any evidence of others having this problem, nor can I reproduce it.
My best guess so far is that some mail clients are seeing the # and somehow treating the trailing part as an internal anchor and stripping it...?
Has anyone else encountered this sort of problem? If so, have you found any solution short of replacing the whole mechanism with something else?
Some clients treat the hash-link just fine. Others don't. There's a conversation about Outlook being dirty about this here: Outlook strips URL hash from email
What we did to resolve this at our company is simply create a handler on our server that redirects. Your email link would become http://domain.com/email-link?url=https%3A%2F%2Fdomain.com%2F%23%2Fconfirm-signup%3Ftoken%3D1234 and your server side script would grab the query param url and immediately trigger a redirect.
You'd need to make sure that you find all links in your emails and replace them. Here's a PHP function for that, but you could do this in whatever backend language you're using. Regex here may be helpful at least.
function replaceLinks($html,$hash) {
return preg_replace_callback('/<a [^>]*href=[\"\']{1}(.+?)[\"\\\']{1}/', function($matches) use ($hash) {
return str_replace($matches[1],"http://domain.com/email-link?url=".rawurlencode($matches[1]),$matches[0]);
}, $html);
}
Yes I have encountered this issue before because of the #, I was trying to link to a anchor on a landingpage.. My solution ended up using a short.url service to "hide" the # from the html e.g. https://goo.gl/
Looks like you need percent encoding!
A lot of times when your href gets parsed (by angular in this case) it doesn't handle the special characters right, or strips them. Find your problem characters and replace them with %3F for ?, %26 for &, and %23 for #. The rest are in a chart in the link.
Once the encoded address hits the browser the url will be decoded in your url bar.

Nginx fallback for file not found to different directory with same path

Short Version: Is there any easy way to automatically redirect a path like /templates/my_child_theme/main/sidebar/user_nav.html to /templates/default/main/sidebar/user_nav.html whenever a 404 is encountered?
Question: Is there an easy way to use something like try_files within nginx to change a filepath when not found to a different folder with the same file path at the end? I'm currently using a client-side framework (AngularJS) and dealing with checking for the existence of files can get fairly expensive as I am literally performing an AJAX call for each file and looking for a 404 before performing the logic to swap out the path in Javascript. I've seen similar solutions for fallback images but haven't gotten a good solution yet. Here's the gist of what I'm looking to do:
Look for file at /templates/$1/$2.
On HTTP 404 instead return /templates/default/$2.
This only really needs to happen in the /templates/ location for now.
It's possible that these files could be nested several layers deep so I need something like /templates/my_child_theme/main/sidebar/user_nav.html to redirect to /templates/default/main/sidebar/user_nav.html
Backstory:
I've been building a site in AngularJS that has a fairly complex templating setup. I am utilizing the awesome ui-router module from Angular UI for deeply nested views and have written a few custom functions to implement child themes similar to Magento's fallback system. Here's what currently happens:
AngularJS requests a template path using a getTemplate() function I wrote which first looks for the file at /templates/child_theme_name_here/filepath by performing an XMLHttpRequest, checking for a status code of 404 (file not found), and then either returning that path or (in the case of a 404) returning /templates/default/filepath instead.
This way I can overload modify specific templates without needing to copy the entire theme each time, making development easier (we have 3 major corporate clients which will each have their own branded child theme) by not making me keep up with each change across multiple themes.
If there is a better way to do this within AngularJS I am open to that as well, it just seemed to me that Nginx would be the most logical place to perform such an action due to to it's low-level integration with the filesystem.
Solved.
Had to teach myself a bit on regular expressions, but finally got it working.
Here's what worked:
location ~* ^\/templates\/([^\/\\\]+)(.*)$ {
try_files /templates/$1$2 /templates/default$2 =404;
}
Regex Explanation
~* means case-insensitive matching (not really regex, just nginx syntax)
^ means start of a string
\/ means match a backslash
templates means literally match the word templates
\/ means match a backslash again
( means start capturing the following match as a group for later use
[^\\\/] means match anything that's not a backslash or forward slash means the previous set of characters can be matched multiple times (i.e. keep matching anything that isn't a slash.
) means stop capturing characters for this group. We have now defined the string that represents the first folder after /templates/
(.*) means match any other character as many times as needed (match everything that isn't a line feed in other words)
$ means match the end of the string
try_files then tries each URL in order
/templates/$1$2 means try /templates/(everything in capture group 1 above, which holds the folder we captured)(then add everything from capture group which holds the backslash and anything after it until the end of the url)
/templates/default$2 is very similar, except instead of using the text from capture group 1 ($1, the folder name we matched) we use the text "default" and then add everything from the second capture group to the end like before
=404 means that if neither of those worked return a 404 error
I'm seeing a significant speed improvement by moving this fallback mechanism into the server versus all of the extraneous calls I was forced to do before on the client.

Resources