Would it be possible to have rewrites based on the status code? Eg. when something isn't found, a rewrite should try to find it somewhere else. Eg. a typical .htaccess rewrite looks like this:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?id=$1 [QSA,L]
Basically, if you can't find it on the filesystem pass it on to the main PHP script.
I just had an idea to use a custom error page, but that doesn't work either:
errors {
404 /index.php?id={path}&{query}
}
That's possible -- I like your second idea more, since it's more "idiomatic" way to configure Caddy. That change should be fairly easy; just need to make error page paths support placeholders.
If we make errors support placeholders, is it gonna do a redirect or rewrite ? If redirect, that's pretty straightforward. But for rewrite, it will be easier to go with the former suggestion of having rewrite based on status code.
@abiosoft Good point. Dang. I hate it when error pages redirect -- IMO that should never happen.
Right now, the errors middleware just loads the file from disk and serves it up instead of the missing page. It doesn't know that it needs to send the request to the fastcgi middleware for handling.
Will need to think about a good way to handle this.
What makes this a bit tricky is that you only get status code after request has been processed. So it looks more ideal to have it built into error. However, having it inside error is like duplicating work.
Maybe middlewares should be able to use components of (or call) one another.
Those conditions though are based on file or dir existence.. couldn't we have something similiar in rewrite ?
Right now, I need custom things like
...
rewrite /wp-admin /wp-admin/index.php
rewrite /wp-admin/ /wp-admin/index.php
rewrite {
regexp .*
ext /
to /index.php?{query}
}
fastcgi / unix:/var/run/php5-fpm.sock php
for WordPress to truly work, otherwise admin isn't available. (I also needed to copy /etc/php5/apache2/php.ini over /etc/php5/pfm/php.ini .. but that's another story).
I'm not sure how it could look like... just brainstorming here:
rewrite {
regexp .*
ext /
to /index.php?{query}
exclude +files, +dirs, some/path
}
An update is in the works for rewrite that is gonna allow you specify multiple rewrite conditions.
The syntax will look as follows and you can have multiple lines of cond.
rewrite {
...
cond condition value
}
condition and value will both support placehoders; and value will include the ability to check for file/directory existence.
Stay tuned :blush:
Cool. I wonder if cond should be if - reads more naturally that way. Will be interested to see how this plays out ;)
Good point. I'm adopting if.
With "cond" you can define a semantics, with "if", programmers will expect
"if" semantics, which might be hard to implement in the end.
Your call.
Le mar. 22 déc. 2015 10:42, Abiola Ibrahim [email protected] a
écrit :
Good point. I'm adopting if.
—
Reply to this email directly or view it on GitHub
https://github.com/mholt/caddy/issues/289#issuecomment-166650553.
Recent updates to rewrite has provided this feature.
Don't see how the recent updates permit to check for file/directory existence.
me neither, could you clarify on how to use it now?
I'm also wondering how to rewrite unless the request path is for a file/directory that exists.
i could not find a suitable rewrite for it. on my case, using extension based does not help, since my backend generates files likes routes: aka thumnail/{slug}.jpg
What exactly do you wanna achieve ? I am sure there is a way out.
My situation is similar to the one @hernandev has. The backend API has a route for downloading backups as a tar file. Those endpoints are routed through a PHP script, but the endpoint URLs end with a file extension .tar instead of .jpg in my case. The rewrite rule cant seem to capture these without also having to include file extensions using ext option within a rewrite rule.
/backups/001.tar - actual file on file system, 403 denied all good.
/api/backups/001.tar - file doesn't exist, it's a PHP script that serves a download.
For example:
postleaf.dev:7755 {
root ./app
tls off
fastcgi / 127.0.0.1:9000 php
rewrite {
regexp ^/backups
status 403
}
rewrite {
ext / .tar
to {uri} {uri}/ /index.php
}
}
What we're looking for is a way to always apply the rewrite rule (second one in my example above) unless the request is explicitly for a file or directory that exists on the file system. Basically the caddy equivalent to the directives used by an apache web server:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
So, while my example above works for my specific use case, it would need to be adjusted if the application added a route that handled images dynamically like what @hernandev describes. Ideally, we could capture regardless of the URI.
Does it make senses?
if the file exists, serve the file
if the file does not exists, send it to the handler.
@calmdev explanation is right, on my case, I do serve .jpg via normal files and via php, so the extension rule wont help.
@hernandev
rewrite {
...
/file_path /handler_path
}
@abiosoft considering it supports a parter like /path/*.jpg, that would imply changing the configuration whenever i need a new route on the app.
despite that, another problem is: whenever a file is not found, the application will never get to know it, since it fits a file pattern and the backend will not be notified.
Can we implement a nginx's try_files alike?
Checks the existence of files in the specified order and uses the first found file for request processing...
Here is a example of desired behavior there:
try_files $uri /index.php =404;
So if $uri not found, index.php is called.
other configs are in place to ensure the original uri/query string will be passed along.
Not sure on how hard would it be to code that, not that good in golang but it can try to help building it
As additional information, this is a more valid case for PHP and alikes that does not handle http requests directly, so a reverse proxy on the backend is not a real option (php has a http request handling but it is single threaded)
Maybe I am not getting you but it does exactly what try_files does. Have you checked the docs ?
@abiosoft
Checks the existence of files in the specified order and uses the first found file for request processing; the processing is performed in the current context.
so here is the case.
request /article/image.jpg
having a try files like :
try_files $uri /index.php =404;
will first try to match URI with a file on the directory, if found, serves it without passing to the backend
that's what the $uri part is for, they are multiple handles, trying the first to the least, from left to right
after not finding the file, it will serve /index.php passing the query parameters as specified on other lines on the .php location.
so for caddy it would be something like
to /{query} /index.php?{query}
it meanst, it should try to serve {query} first, if the file does not exists, try the second option, index.php?{query} but i could not make this example match the file existing or not.
P.S. on the example case,
$uri will look for /article/image.jpg on the files, if not found, them php will handle that request, regardingless the extension or pattern.
Another more complex example would be the following:
request /articles/123
if you have a .txt without extension named 123 inside a articles folder, it should be served right away, so that bypass the backend (php or other handling it)
if that file does not exists, them index.php?{query} where query would be articles/123
@taylorotwell did a workaround for at https://github.com/laravel/valet/blob/master/server.php#L90
but that's not really suited for production environments, since it's not a good idea to pass the static file serving responsability to php (it was not designed for that)
After playing around. found a solution, Caddy already supports it!
rewrite {
to {path} {path}/ /index.php?{query}
}
Please @abiosoft help is figuring out the {path} vs {string} naming, is that fixed or it would be any other names? what other options are avaible?
But, it solves my problem, should solve @calmdev too
thanks @hernandev it appears to work for me too.
@hernandev it takes in any string. That is just a placeholder .
Check destination in rewrite docs. Though it needs a minor formatting fix.
It quite amazed me on your insistence that this is not supported which is why I am asking if you've checked the docs.
Also, what was done in here in Valet https://github.com/laravel/valet/blob/master/server.php#L90 can be achieved with rewrite.
@abiosoft havent saw that option, my bad, works like a charm now! thanks for the patience
Most helpful comment
After playing around. found a solution, Caddy already supports it!
Please @abiosoft help is figuring out the {path} vs {string} naming, is that fixed or it would be any other names? what other options are avaible?
But, it solves my problem, should solve @calmdev too