Routing to a directory with a leading period? - url-routing

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

Related

Use a path (with "/") as a param in a URL

I'm using React Router v6 (Beta) and have a requirement to allow a path as a param, eg.
"some-url/:folderPath" -> "some-url/some/path/to/a/folder"
This is proving trickier than I expected, though I recognize the obvious confusion caused by slashes being URL delimiters. I found this answer that suggests that at some point React Router allowed for a "+" that would allow the URL param to include everything following that point in the URL, though it no longer appears supported.
Is there an explicit way to approach this problem using the React APIs?
You can encode any character using URL encoding. The encoding for forward slash is %2F. If you replace all the slashes with %2F it should work. You can also call a function that will URL-encode a string.
See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
EDIT:
That being said, the comment by #Linda Paiste is a superior solution.

How to use $header in routes

I'm creating a route using the Java DSL in Camel.
I'd like to perform a text substitution without creating a new processor or bean.
I have this:
.setHeader(MY_THING,
constant(my_template.replace("{id1}", simple("${header.subs_val}").getText())))
If I don't add 'constant' I get type mismatch errors. If I don't put getText() on the simple() part, I get text mismatch answers. When I run my route, it replaces {id} with the literal ${header.subs_val} instead of fetching my value from the header. Yet if I take the quotes off, I get compile errors; Java doesn't know the ${...} syntax of course.
Deployment takes a few minutes, so experiments are expensive.
So, how can I just do a simple substitution. Nothing I am finding on the web actually seems to work.
EDIT - what is the template? Specifically, a string (it's a URL)
http://this/that/{id1}/another/thing
I've inherited some code, so I am unable to simply to(...) the URL and apply the special .tof() (??) formatting.
Interesting case!
If you place my_template in a header you could use a nested simple expression(Camel 2.9 onwards) like in the example below. I am also setting a value to subs_val for the example, but I suppose your header has already a value in the route.
.setHeader("my_template", constant("http://this/that/{id1}/another/thing"))
.setHeader("subs_val",constant("22"))
.setHeader("MY_THING",simple("${in.header.my_template.replaceAll(\"\\{id1.?\",${in.header.subs_val.toString()})}"))
After this step header MY_THING has the value http://this/that/22/another/thing.
1)In this example I could skip to_String() but I do not know what's the type of your header "subs_val" .
2) I tried first with replaceAll(\"\{id1\"}\") but it didn't work with } Probably this is a bug...Will look at it again. That's why in my regex I used .?
3) When you debug your application inside a processor, where the exchange is available you can use SimpleBuilder to evaluate a simple expression easily in your IDE, without having to restart your app
SimpleBuilder.simple("${in.header.url.replaceAll(\"\\{id1.?\",${in.header.subs_val.toString()})}").evaluate(exchange, String.class);
Hope it helped :)

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.

AngularJS resource with explicit file type extension and POST

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

Do not allow ".xml"/".html"/"index" in URI?

I'm going through Lift's basics in Section 3.2 SiteMap of Simply Lift and one thing struck me.
Using the default SiteMap code, you can ask for, say, info view in three ways:
GET /info,
GET /info.html,
GET /info.xml (why?).
What is more, you can request index view in four different ways:
GET /,
GET /index,
GET /index.html,
GET /index.xml.
How can I limit this behaviour to GET / for directories and GET /info for files?
P.S. All of these return 200 OK:
foursquare.com/,
foursquare.com/index,
foursquare.com/index.html,
foursquare.com/index.xml.
Shouldn't one resource have one URL only?
There are actually more than four ways that it can be parsed. The full list of known suffixes (any of which can be used to access the page) can be found here.
I think the reason for that is that lift can be used to serve any resource, so most are explicitly added by default.
I think you could disable Lift's processing of all extensions by adding this to Boot.scala:
LiftRules.explicitlyParsedSuffixes = Nil
However, I wouldn't recommend that as there may be some side-effects.
Using Req with RestHelper you can specify the suffix explicitly, but I don't know if there is such a construct to do so with Sitemap.
Actually, the code to determine whether Lift should handle the request or not is here. You can see the default extensions in the liftHandled method directly above, but they can all be overridden with LiftRules.liftRequest. Something like:
LiftRules.liftRequest append {
case r => Full(r.path.suffix.trim == "")
}
Should do the trick.
As far as why it works that way, Jason is right that Lift is designed to handle multiple types of dynamic resource.

Resources