app.yaml : wildcard in URL with static_dir? - google-app-engine

My attempt at matching a regex as directory name in app.yaml doesn't work :
- url: /v1_.*
static_dir: static/v1
expiration: "364d"
Although this official spec says regex syntax is supported. Is there a way to make this work ?
I.e. /v1_2014-01-29/img/logo.png should match the static file /static/v1/img/logo.png.
Trivia
I use Google App Engine to serve a Go webapp.
I'd like to maximize browser cache longevity, minimize number of requests and still serve the fresh versions of my css/js/png, and I believe revving filenames is a best practice to achieve this. Also as adding a variable querystring (/v1/img/logo.png?2014-01-29) might cause proxy and cache problems, I prefer to show a variable directory name (/v1_2014-01-29/img/logo.png), pointing to the same underlying server dir.

Seems to me that whatever part of the URL that is beyond the match of the url definition (which matches from the start) is appended to the static_dir.
So the following handler should match /v1_2014-01-29/img/logo.png if the file path is static/v1/img/logo.png (tried with Python):
- url: /v1_(\d+-?)+
static_dir: static/v1

After olivierdm's answer I changed my yaml into :
- url: /v1_.*_
static_dir: static/v1
expiration: "364d"
and my html templates to produce /v1_2014-01-29_/img/logo.png.
Basically, the extra arbitrary character underscore _ forces .* to match 2014-01-29, not the empty string.
Now every time I want the visitors to reload the static files, I just change the date in the tempating (I don't touch the app.yaml anymore). Also, any accidental request to an "outdated" URL will still succeed and serve the fresh resource.

Related

Complex routing in NextJs

I'm trying to create descriptive routes in the NextJs app however I'm struggling with the nextJs file-based routing system.
Intended route in the web is: (/posts/id/mail);
How I do it in the project:
Posts
- index.js
- [id]
- mail.js
As you can see, I don't have index.js in my [id] folder hence whenever somebody decides to go to /posts/id without '/mail' it is gonna be 404.
So basically my question is: How do I turn mail.js into index.js and make the URL stay the same (/mail at the end).
If there is no way of doing it natively with nextjs I'd also be grateful if you let me know.
catch all
This might not be the way you like it, but you might use a catch all route to hande [id] and mail.js together in one file.
E.g. if you have a file [...post].jsx and call the routes /someid/mail or just /someid you would have params.post to be an array like [ 'someid', 'mail' ] or just [ 'someid' ].
redirect
Apart from that I also didn't find any way for a folder to be a route on its own without an index file (or any other file), especially for a route like www.example.com/ (i.e. without an /index appended to it). I solved it by using some "unneeded" path /main and then redirected that to /.
As a remark:
I found that the specific route /index caused an error in some cases, that's why I've choosen /main.
I don't remember exactly, it might be dependent on if you want both routes ('/index' and '/') to be valid and point to the same file (and stay visible in the addressbar), or if only one of them should be valid and redirect to the other. Also in that case my paths came from getStaticPaths, not from files.

Sylius: Only one incomplete object in RequestStack through particular route

I am a Symfony beginner and I am writing a plugin for the e-commerce system Sylius: Every route up until now gave me two objects in RequestStack, and I was able to get a very particular variable everywhere through the one I retrieve through $requestStack->getMasterRequest().
In a particular route suddenly the variable (set in yaml file where the routes are configured) is not retrievable and the $requestStack doesn't hold two objects, only one.
I apologize, I know this is very badly explained, I hope someone can make sense of it.
I tried $request = Request::createFromGlobals() and retrieving the Container instead of the RequestStack directly, but both end up with the same result.
# This is the route I am trying to overwrite because I want to give it an extra parameter from the request:
sylius_shop_product_show:
path: /products/{slug}
methods: [GET]
defaults:
_controller: sylius.controller.product:showAction
_sylius:
template: "#SyliusShop/Product/show.html.twig"
repository:
method: findOneByChannelAndSlug_andVarFromRequest
arguments:
- "expr:service('sylius.context.channel').getChannel()"
- "expr:service('sylius.context.locale').getLocaleCode()"
- $slug
- "expr:service('request_stack')"
//This is the function which should be used, it is part of a Repository
public function findOneByChannelAndSlug_andVarFromRequest(ChannelInterface $channel, string $locale, string $slug, RequestStack $requestStack): ?ProductInterface
{
I don't understand why suddenly I cannot get a hold off the variable I can access through all the other routes. Because it is a repository? Is the request not yet completely processed?
Try to enter variable name with $ symbol before its name. For example if your variable name is myVar:
sylius_shop_product_show:
path: /products/{slug}
methods: [GET]
defaults:
_controller: sylius.controller.product:showAction
_sylius:
template: "#SyliusShop/Product/show.html.twig"
repository:
method: findOneByChannelAndSlug_andVarFromRequest
arguments:
- "expr:service('sylius.context.channel').getChannel()"
- "expr:service('sylius.context.locale').getLocaleCode()"
- $slug
- $myVar
How it works under the hood: https://github.com/Sylius/SyliusResourceBundle/blob/1.4/src/Bundle/Controller/ParametersParser.php#L55 Note: $request->get() method is alias to get variable from GET, POST and Symfony attributes.
I solved this myself yesterday. The problem was that I did not declare the sylius_shop_product_show in the correct scope of the route description which also declared the variable I was trying to pass through, thereby Symfony logically was not able to parse it and make it available. Well, seeing the solution right now it makes perfect sense, but before and the fact that I am a Symfony (and thus Sylius) beginner it was hard to understand what was wrong.
So I understood the problem when I executed php bin/console debug:router which listed all the available routes and when I discovered that the route sylius_shop_product_show actually is not creating a route where the variable I was looking for was even available in the routing-path. Thanks for everyone who tried to help me!

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

Do I need base href='/'?

My understanding according to this post is that the default base href is '/'. This scotch tutorial says to include this base href:
<!-- ./index.html -->
<base href="/">
For a basic app, is this strictly necessary, or will browsers assume that '/' is the base href for relative paths anyway?
will browsers assume that '/' is the base href for relative paths anyway?
No, they will not.
The HTML spec specifies how relative URLs are resolved. It's not too hard to work through the specification and definitions to find that when a relative URL is resolved against a document that does not have a base URL specified via a <base> element, the effective ("fallback") base URL is not guaranteed to be /. There are a few alternatives, but in the usual case, the document's fallback base URL is taken as the document's own URL. Typically, that's not /.
It's not so clear whether it's a good idea to specify / as every document's base URL. It does mean that every relative URL will resolve the same way, regardless of the document in which it appears; that could be taken as a plus. On the other hand, it differs from the default behavior for resolving relative URLs, which could be a source of bugs. Certainly, if you choose to do it then you should do it consistently throughout the application.
The base is the location the page is in. Every relative URL is relative to that base. Let us suppose you are at
http://a/b/c
If you have a link inside this page with this code:
abc
Then by clicking on the link, the target will be
http://a/d
So, your base is at
http://a/b
because c is inside that. Now that you understand what base is, take a look here. You will see that besides href, you can set target as well, specifying where links should open.

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