Apache 2.4 RewriteMap never matches - apache

I'm using an Apache RewriteMap to permanently redirect 60 or so urls. In one development environment, the below configuration works flawlessly while in another development environment it doesn't work at all. Most notably, the last RewriteCond never passes and unfortunately the logging options I've attempted are no help. With LogLevel debug rewrite:trace8, I can see that the RewriteCond just before the map is receiving the expected input, but the map nonetheless returns no match:
[Thu Apr 19 19:35:19.109789 2018] [rewrite:trace4] [pid 11188] mod_rewrite.c(470): [client 127.0.0.1:62369] 127.0.0.1 - - [server.dev/sid#7f7719da0d50][rid#7f7719fc8000/initial] [perdir /html/path/] RewriteCond: input='/help_center/help_center.php?' pattern='^/?(.*[^\\?])\\??/?$' => matched
[Thu Apr 19 19:35:19.109793 2018] [rewrite:trace4] [pid 11188] mod_rewrite.c(470): [client 127.0.0.1:62369] 127.0.0.1 - - [server.dev/sid#7f7719da0d50][rid#7f7719fc8000/initial] [perdir /html/path/] RewriteCond: input='NOTFOUND' pattern='!NOTFOUND' [NC] => not-matched
For debugging purposes I've simplified things to pass a constant key into the map, but the map nonetheless returns no substitute value. I've also tried simplifying the map file, adding all the possible variations of a key it could receive (with and without leading/trailing slashes and ?). I've tried renaming the map file and extension, renaming the map itself, moving the map file outside of the public directory, all with no change in results. The map file is readable as is the directory it's in, Apache starts up error-free with the config and yes I've been restarting it when testing config changes.
What's left to try? Both systems run CentOS 7, Apache 2.4, one works and one doesn't. Configs below
Apache server-level config declaring map
RewriteMap help_center txt:/path/to/rewritemap/help_center.map
.htaccess
RewriteEngine on
RewriteCond %{REQUEST_URI} !(\.(js|css|less|png|swf|flv|jpg|svg|ico))$
RewriteCond %{REQUEST_URI}?%{QUERY_STRING} ^/?(.*[^\?])\??/?$
RewriteCond ${help_center:%1|NOTFOUND} !NOTFOUND [NC]
RewriteRule ^.*$ /${help_center:%1}/ [QSD,L,NC,R=301]
Abbreviated contents of help_center.map
help_center/help_center.php help-center
help_center/help_center.php?1_7_q-1 help-center/article/authorized-dealer
pages/appliance_installation help-center/article/installation-services
UPDATE
After 6 hours of debugging, I've finally been able to get the RewriteMap to match. By moving the RewriteMap directive to the <VirtualHost _default_:443> scope of /etc/conf.d/ssl.conf, urls are rewriting as expected.
Why is this the case?
The config between these two environments is very similar with the exception of virtual hosting. Both environments run SSL and redirect all requests to the SSL site. The environment that works is configured without a name based virtual host config (i.e. one site for the server) while the environment that didn't work is running name based virtual hosting. I have a single hypothesis related to this:
While I'd expect the root directive to apply to the default site and all virtual sites (including SSL), perhaps the RewriteMap directive must be virtual host scoped to be referenced by a virtual host. Not sure this makes sense, but I couldn't find any documentation to clarify. After testing, turning off NameVirtualHost nothing changes :/
Related: It seems that referencing a non-existent RewriteMap logs no error. Perhaps it was buried while I had debug logging turned on, but is there a config for logging RewriteMap reference errors? That would have help narrow my debugging much sooner.
Finally, for examining parsed Apache config run this from command line: httpd -DDUMP_CONFIG -k start or to view in vi httpd -DDUMP_CONFIG -k start | vi -. I was able to use this to confirm that my RewriteMap directive was being loaded despite it still not matching.

I'm not entirely sure this should qualify as an answer, but I THINK this is what has made it work: Remove the QSD argument and append a ? to manually discard it. This change was made because we have a server running 2.2 that would error out entirely (rather than not match) and it seems that a side effect is that our 2.4 servers are now matching. I'm sure not it's Voodoo, but unfortunately I can't explain it with confidence.
## QSD not available in apache 2.2, add a ? to the end of the rewrite to discard
RewriteRule ^.*$ /${help_center:%1}/? [L,NC,R=301]

Related

AEM Apache Dispatcher 2.4.6 client denied by server configuration

I have an AEM 6.3 instance running behind an Apache instance which version is 2.4.6, with Dispatcher module in it. All is good, but now I need to wipe out all query params for all URLs that end with ".html".
This may sound simple to accomplish, but I came across an issue I can't resolve. This is the rewrite rule I'm using to remove all the query params from URLs ending in .html:
RewriteRule ^/(.*)\.html$ /$1.html [QSD]
Technically, one could see this rewrite as not a rewrite actually, because it is sending the original request to the same URL, but the flag QSD is for dropping all query params.
The problem is, if I reload my Apache instance whit this rule included, I start getting errors like this:
[Wed Jun 10 14:53:35.698908 2020] [authz_core:error] [pid 31733] [client 54.209.162.6:61649] AH01630: client denied by server configuration: /etc/clientlibs, referer: https://my.domain.com/etc/clientlibs/mygroup/some/simple/page.html
I know some people had issues like this when migrating from Apache 2.2 to 2.4. This is not my case, and I have also checked my vhost configuration. I don't have directives from Apache 2.2 like "Order deny,allow" or "Allow from all". I'm using "Require all granted".
One weird thing in AEM logs, is that when my Rewrite rule is not in place, I can see error.log logging that "/etc/clientlibs/mygroup/some/simple/page.html" is found. But if I put the rule and reload Apache, I see this from logs:
10.06.2020 10:16:40.085 *INFO* [54.209.162.6 [1591798600081] GET /etc/clientlibs/mygroup/some/simple/page/jcr:content.json HTTP/1.1] org.apache.sling.engine.impl.SlingRequestProcessorImpl service: Resource /etc/clientlibs/mygroup/some/simple/page/jcr:content.json not found
It is like the extension .html would be ripped off from URL, and since there is no extension, AEM or rather Sling is trying to use the default content resolver which is JSON.
why donÄt you just use
RewriteRule ^ %{REQUEST_URI} [L,R,QSD]
(maybe the redirect is not needed in your case... but it makes things clear to the browser).
Or if you just want to make sure that your request is cached in the dispatcher and not passed throught to AEM each time, use:
/filter {
/0001 { /type "deny" /method "POST" /url "/etc/*" }
/0002 { /type "allow" /method "GET" /url "/etc/*" /query "a=*" }
}
in your dispatcher config (s. https://docs.adobe.com/content/help/en/experience-manager-dispatcher/using/configuring/dispatcher-configuration.html for details).
I finally was able to fix my issue. Even though I still don't understand the full picture. This is my final condition and rule:
RewriteCond %{QUERY_STRING} ^.
RewriteRule ^/(.*)\.html$ /$1.html [QSD,PT]
Adding "PT" along with "QSD" makes Apache not return the "client denied" error. The condition around QUERY_STRING it is just to make sure Apache only manipulates those requests that really have query params in the URL, or technically at least one char
What about adding a conditional to skip this rule to be applied for /etc/clientlibs just before the rewrite rule. RewriteCond %{REQUEST_URI} !^/etc/clientlibs.*

Apache 2.4 RewriteRule only working with domain name

I'm moving an old site from apache 2.2 to 2.4
I've got a vhost.conf file that contains the following rewriterule:
RewriteRule ^/news/[0-9]{4}/[A-za-z]{3}/([0-9a-zA-Z-]*)/([0-9]{4})([0-9]{6})/?$ "/news/article.cfm?article_id=$3&urltitle=$1&clk=$2" [NE,L]
So I'm trying to turn this url:
https://example.com/news/2016/Feb/Article-Title/0025012345
into this:
https://example.com/news/article.cfm?article_id=012345&urltitle=Article-Title&clk=0025
Depending on what I put in the 2nd part of the RewriteRule I get the following:
"https://example.com/news/article.cfm?article_id=$3&urltitle=$1&clk=$2" this works fine but I don't want to specify the hostname as it gets used on dev/staging/live servers, so the URLs change
"/news/article.cfm?article_id=$3&urltitle=$1&clk=$2" this throws a 404 which shows up in the access_log
"news/article.cfm?article_id=$3&urltitle=$1&clk=$2" this throws a 503 which shows up in the access_log
So I know I'm correctly identifying the URL in the first part of the rule and grabbing the correct components with my regex, as specifying the full domain name shows the correct URL manipulation.
I'm completely failing to do a relative redirect though, and I'm certain this rule works in Apache 2.2
I'm using the following software:
CentOS Linux release 7.7.1908 (Core)
Server version: Apache/2.4.6 (CentOS)
Server built: Aug 8 2019 11:41:18
Obviosuly, the answer is in the manual... which I should have read in more detail:
https://httpd.apache.org/docs/2.4/rewrite/remapping.html#old-to-new
Assume we have recently renamed the page foo.html to bar.html and now want to provide the old URL for backward compatibility. However, we want that users of the old URL even not recognize that the pages was renamed - that is, we don't want the address to change in their browser.
RewriteEngine on
RewriteRule "^/foo\.html$" "/bar.html" [PT]
The key thing here being the [PT], that fixed it for me:
RewriteRule ^/news/[0-9]{4}/[A-za-z]{3}/([0-9a-zA-Z-]*)/([0-9]{4})([0-9]{6})/?$ "/news/article.cfm?article_id=$3&urltitle=$1&clk=$2" [PT,NE,L]

Apache %{REQUEST_URI} not working correctly

I am not using Virtual Hosts or anything fancy though I have some .htaccess files setup. Following is my rewrite rule in httpd.conf:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/app/smsapi [NC]
RewriteRule (.*) https://www.example.com/uri=%{REQUEST_URI} [R,L]
This rule basically says that if the uri does not begin with /app/smsapi then fire the rewrite. But when I restart the server and try it I get some weird results.
When I request the URL https://www.example.com/app/smsapi/index.php, I get a 200 Success code which is as expected. But, when I request the URL http://www.example.com/app/smsapi/index.php, it redirects to https://www.example.com/uri=/app/smsapi/index.php. So it actually fires the rule even though the request URI does not satisfy the condition.
So, then I decided to turn off the rewrite rules and give it a go. Now, both those URL give me a 200 Success code.
Now, I know this problem cannot be solved easily by other people who do not have access to the server, but am I right in saying that this is certainly a problem with REQUEST_URI not firing correctly? I have shown that without the rewrite rule, everything works normally, but with the rewrite rule, the second URL is redirected. Therefore, the redirection must be caused by the rewrite rule? Additionally, the condition for redirect rule is not satisfied. Doesn't this prove that there is something wrong with the functioning of the rewrite rule?
Is there any other possibility?
UPDATE
Something very weird is happening here. I setup a local server and tried the same rule and what I got for the URL http://192.168.0.112/app/ is
http://192.168.0.112/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/app/
which is correct because as long as the URL is not like /app/smsapi, it should redirect it. Wonder why this is not happening on the real server. Also, where you insert these rules seems to make a difference. (I am only including these rules after the LoadModule command).
On localhost, if I put these rules either above or below the Directory section, it won't work. But, if I include it inside the Directory section it will.
On server, if I include the rules inside the Directory section, they won't work. But, if I include them either above or below the Directory section, they start working.
This seems to me to be due to a difference in the versions. My localhost is an Ubuntu Desktop 16.04 running Apache 2.4.18. While the server is CentOS 6.8 running Apache 2.2.15.
But, i think the mystery as to why on the server redirect happens only once (though it is configured to go upto 20 times) has something to do with https. Which is also related to the original problem in which https is redirected even on a non-matching rule.
Clues anyone?
UPDATE
I updated the httpd.conf file with the same rules but I used http:// instead of https:// and it gave me the correct result with 20 redirects. That means I have isolated the problem to https.
You are reporting the exact issue in the first phrase: "I am not using Virtual Hosts or anything fancy though I have some .htaccess files setup"
.htaccess is "fancy" and overcomplicated, not virtualhosts.
If you had defined that RewriteCond in virtualhost in the first place it would work, but .htaccess is per-dir context (aka a nightmare) and the regex ^/ will never match in that context.
If you want to match REQUEST_URI in per-dir context (directory or .htaccess) you need to drop the initial slash, that is:
RewriteCond %{REQUEST_URI} !^app/smsapi [NC]
Extra, also consider you MAY NOT need to add a RewriteCond for this:
RewriteRule ^(?!app/smsapi)(.*) https://www.example.com/uri=$1 [R,L]

How to configure apache (ubuntu) such that www.mysite.com will direct to www.mysite.com/drupal6/?

I am a newbie to ubuntu and apache. Can someone tell me how I could direct to
www.mysite.com/drupal6
when user address www.mysite.com?
Thanks a lot.
Cheers.
If you are running Apache and Ubuntu, there is actually a really easy way to force this redirect using a simple php script.
Create an index.php file in the root of your server and paste the following code into it
<?php header("location: drupal6/") ?>
This will cause the site to auto-redirect to the drupal6 folder whenever it is visited.
This should work. Create a file in the root folder of your server called .htaccess - the dot at the beginning is very important as this helps the server identify the file as a hidden / system config file.
Open the file and paste the following lines of code in :
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ www.mysite.com/drupal6/$1 [R,L]
This should force all traffic to the server to redirect to your custom folder.
A brief explanation of the .htaccess code
If you want rewrites to work, you have to enable the Rewrite Engine and tell the server to follow symlinks.
The second section establishes the rule - specifically applying it to all traffic on the standard web port of 80.
The final line tells the server to grab everything after the URL and append it to the new address (mysite.com/drupal6).
There's a lot more you can do with .htaccess files but you really need to Google for good examples to test out.
Look at Apache's mod_rewrite documentation. You will need a RewriteRule in your apache configuration at the minimum, you may also need RewriteCond's to define when the RewriteRule is used.
Your rewrite pattern will be rewriting the REQUEST_URI with something from: ^/$ to: /drupal6. The ^ and $ are essential to prevent Apache getting into an infinite loop while rewriting the base URI by only matching "/" and not "/anything-else".
I assume you're on a recent version of Ubuntu and Apache? If so, see the Apache 2.2 documentation on mod_rewrite.

Mod rewrite issue

As many others I am having issues with doing some very simple mod_rewriting in apache.
I have the following in my .htaccess:
Options +FollowSymLinks
RewriteEngine on
RewriteBase /
RewriteRule ^view/([0-9]+)/([0-9]+)$ view.php?advertId=$1&publisherId=$2 [NC,QSA,L]
Which is supposed to translate /view/4093/203?qs=val -> /view.php?advertId=4093&publisherId=203?qs=val
Now, it works when calling it with /View..., but when doing lowercase /view, it redirects to the right file, but advertId and publisherId is not set within my PHP script as it is with the first-letter-uppercase View and I simply put have no clue whatsoever with what is going on on that front (I have been testing and watching that behavior simply by doing a on my view.php).
Anyone know why this is happening?
I may want to add, my server info is as follows:
Apache/2.2.9 (Debian) PHP/5.2.6-1+lenny2 with Suhosin-Patch mod_python/3.3.1 Python/2.5.2 mod_perl/2.0.4 Perl/v5.10.0
IE. a stock brand new debian install with default debian packages + php-mssql.
MultiViews might cause this behavior, that is trying to map the request to a siminar existing file before passing the request to mod_rewrite. Try to disable it:
Options -MultiViews