Unable to remove empty parameters in url using context path in Location tag in apache http server - mod-rewrite

Unable to remove empty parameters in url using context path in Location tag in apache http server
Without context path setting, empty parameters are being removed correctly as expected,
Below is the example with context path, where empty parameters are not removed (Problem statement)
<Location /reports/>
LogLevel alert rewrite:trace8
RewriteEngine On
RewriteBase /
ProxyPass http://1.2.3.4:3000/
ProxyPassReverse http://1.2.3.4:3000/
RewriteCond %{QUERY_STRING} ^(.+?&)?[^=]+=(?:&(.*))?$
RewriteRule ^/reports$ /reports/?%1%2 [R=302,NE,L]
</Location>
Below is the example without context path, where empty parameters are removed as expected (But the final solution needs to work with a context path)
<Location />
ProxyPass http://1.2.3.4:3000/
ProxyPassReverse http://1.2.3.4:3000/
RewriteEngine On
AllowOverride All
RewriteCond %{QUERY_STRING} ^(.+?&)?[^=]+=(?:&(.*))?$
RewriteRule ^ %{REQUEST_URI}?%1%2 [R=302,NE,L]
</Location>
How do I remove the empty parameters from the URL with the context path setting in the location?

<Location /reports/>
:
RewriteEngine On
RewriteBase /
:
RewriteCond %{QUERY_STRING} ^(.+?&)?[^=]+=(?:&(.*))?$
RewriteRule ^/reports$ /reports/?%1%2 [R=302,NE,L]
</Location>
There are several issues here...
Your <Location> block matches /reports/ (with a trailing slash), but your RewriteRule pattern ^/reports$ omits the trailing slash, so it will never match.
<Location> blocks are merged very late and in this context the RewriteRule pattern matches against the absolute filesystem path, not the root-relative URL-path.
So in order to match the request, the RewriteRule pattern should be like /reports/$ instead to allow for the absolute filesystem path, eg. /path/to/document-root/reports/. In other words:
RewriteRule /reports/$ /reports/?%1%2 [R=302,NE,L]
Or, omit the path component of the RewriteRule pattern altogether (eg. simply ^), unless you must only match /reports/ and not /reports/<anything>.
HOWEVER, you shouldn't use mod_rewrite directives inside a <Location> block to begin with. From the Apache 2.4 docs on the RewriteRule directive:
Although rewrite rules are syntactically permitted in <Location> and <Files> sections (including their regular expression counterparts), this should never be necessary and is unsupported. A likely feature to break in these contexts is relative substitutions.
The RewriteBase directive is not being used here. (But it is not supported/not required outside of a directory context.)
The RewriteRule pattern and the <Location> directive are performing the same check. Move these mod_rewrite directives outside of the <Location> container and have them directly in the <VirtualHost> container (or server context). For example:
LogLevel alert rewrite:trace8
RewriteEngine On
RewriteCond %{QUERY_STRING} ^(.+?&)?[^=]+=(?:&(.*))?$
RewriteRule ^/reports/$ /reports/?%1%2 [R=302,NE,L]
<Location /reports/>
ProxyPass http://1.2.3.4:3000/
ProxyPassReverse http://1.2.3.4:3000/
</Location>

Related

RewriteRule includding only last part of REQUESTI_URI

<LocationMatch /foo/>
ProxyPreserveHost On
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule .* "ws://192.168.0.101:1234%{REQUEST_URI}" [P]
when client connects to
ws://www.example.com/foo/whatever_arbitrary_random
this works great, but the outcome is
ws://192.168.0.101:1234/foo/whatever_arbitrary_random
how can i get rid of the /foo/ so the outcome would be
ws://192.168.0.101:1234/whatever_arbitrary_random
client must still need to connect to /foo/ to trigger this
EDIT: I found how to do it, replace last line with
RewriteRule ([^/]+)/?$ ws://192.168.0.101:1234/$1 [P,L]
But please read the first answer suggesting not to do this in a Location
You shouldn't use mod_rewrite directives inside <Location> (and <LocationMatch>) containers.
UPDATE: As stated in the Apache docs for the RewriteRule directive:
Although rewrite rules are syntactically permitted in <Location> and <Files> sections (including their regular expression counterparts), this should never be necessary and is unsupported. A likely feature to break in these contexts is relative substitutions.
<Location> sections are merged very late. When used inside a <Location> section, the RewriteRule directive matches the absolute filesystem-path, not the URL-path as would ordinarily be expected.
If .htaccess overrides are disabled then you can do it like this instead inside the appropriate <Directory> container:
<Directory /path/to/foo>
# Disable .htaccess overrides if not already
AllowOverride None
ProxyPreserveHost On
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule .* ws://192.168.0.101:1234/$0 [P]
</Directory>
The backreference $0 naturally excludes /foo/.
UPDATE:
RewriteRule ([^/]+)/?$ ws://192.168.0.101:1234/$1 [P,L]
This only matches the last path segment, it doesn't strictly match everything after /foo/. This may or may not be OK, depending on your requests. eg. It will redirect a request for /foo/bar/baz to /baz only, not /bar/baz.
The regex should really be anchored. However, you've probably written it this way because the directive is inside a <Location> section and matches the absolute file-path, rather than the requested URL-path.
Incidentally, you don't need the L flag when used with P - it is implied.
An alternative to the above... you don't need to use these directvies in a directory context (ie. inside a <Directory> or <Location> section). You can instead place these rules directly in the <VirtualHost> container (a virtualhost context), in which case they should be written like this instead:
ProxyPreserveHost On
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/foo/(.*) ws://192.168.0.101:1234/$1 [P]

Helicon isapi rewrite 3 redirectcondition fails

We have a url that makes use of a rewritemap to retrieve a parameter for the querystring in order to get the right themepage. This works wel and it shows the right themepage in the default language.
If a user wants to change the language of this thempage he will perform a redirect to the same url but a language parameter will be added to the url.
The problem is that it does not rewrite to the themepage but it gets rewritten to our homepage instead of the themepage.
A url like www.mysite.co.uk/theme/cars will be rewritten to www.mysite.co.uk/themepages/themepage.aspx?pgid=1
adding the language parameter : www.mysite.co.uk/theme/cars?lng=2 should redirect to www.mysite.co.uk/themepages/themepage.aspx?pgid=1&lng2 instead it is rewritten to the homepage. The url in the address bar is correct. So the rewriterule has to be incorrect.
This is part of my httpd.conf
<VirtualHost www.mysite.co.uk>
RewriteEngine on
AllowOverride all
RewriteBase /
RewriteMap thememap txt:C:\rewritemaps/redirectmap.txt [NC]
RewriteCond %{QUERY_STRING} ^$ [OR]
RewriteCond %{QUERY_STRING} ^lng=(.*)$ [NC]
RewriteRule ^theme/([^?/]+)\.* /themepages/themepage.aspx?pgid=${thememap:$1} [NC,QSA,L]
</VirtualHost>
Does somebody have a clue why this happens ?

mod_rewrite don't match on RewriteCond target - URL not found

I am trying to rewrite all URIs inside directory /docs to /docs/index.php, using apaches mod_rewrite module.
The URI doesn't exist as a directory structure, which I don't think is necessary when you are rewriting the URI to something that exit.
I am getting the error:
"The requested URL /docs/view/my_doc was not found on this server."
These are my rewrite rules:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^docs/([a-z]+)/([A-Za-z0-9_-]+)/?$
RewriteRule ^(.*)$ http://%{HTTP_HOST}/docs/index.php?action=$1&target=$2 [QSA,L]
I am doing the configuration in httpd.conf. Also, I am using a multi v-host setup.
What's my problem and how do I fix it?
I'm using Apache/httpd on CentOS 6.2
UPDATE
Including my VirtualHost as well:
NameVirtualHost *:80
<VirtualHost *:80>
ServerName www.smicloud.org
ServerAlias *.smicloud.org
VirtualDocumentRoot /var/www/html/www.smicloud.org
ExpiresActive On
ExpiresDefault "access plus 14 days"
# insert logging config, anything else you need..
#Define FileEtag so it doesnt use node
FileETag MTime Size
<Directory /var/www/html/>
Order Allow,Deny
Allow from all
# Get rid of this if you need to allow htaccess files:
AllowOverride None
</Directory>
RewriteEngine On
RewriteRule ^docs/([a-z]+)/([A-Za-z0-9_-]+)/$ /docs/index.php?action=$1&target=$2 [QSA,L]
</VirtualHost>
This should work
RewriteEngine On
RewriteRule ^docs/([a-z]+)/([A-Za-z0-9_-]+)/$ /docs/index.php?action=$1&target=$2 [QSA,L]
Ok, there were a couple of things that I had to do in order to fix it, using #donalds suggestion (which I actually tried before):
1 - I had to have a '?' at the end of the regex of RewriteRule:
^/docs/([a-z]+)/([A-Za-z0-9_-]+)/?$
Then I can chose whether to have a '/' or not at the end of the address.
2 - I had to add a '/' to the beginning of the regex of my RewriteRule. I.e.:
^/docs/([a-z]+)/([A-Za-z0-9_-]+)$
3 - I also had to add the 'http://%{HTTP_HOST}/' part to the new URI:
http://%{HTTP_HOST}/docs/index.php?action=$1&target=$2 [QSA,L]
This is what I ended up with:
RewriteRule ^/docs/([a-z]+)/([A-Za-z0-9_-]+)$
http://%{HTTP_HOST}/docs/index.php?action=$1&target=$2 [QSA,L]
Perhaps why I needed to add the %{HTTP:HOST} was because it's a multi virtual host setup.

Rewriting behaves differently in .htaccess vs vhost

I'm using following chunk of instructions to rewrite www to non www url:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,NC,L]
</IfModule>
If I place it in .htaccess file, it works fine.
If I place it in vhost file, after rewriting two forward slashes are added to the host, for example www.domain.com will become domain.com//
Am I missing something?
Also, is it worth placing all .htaccess content in vhost performancewise?
RewriteRule is behaving as the docs say.
There is a difference in what RewriteRule matches against when in VirtualHost context & Directory & .htaccess context.
From RewriteRule Directive Apache Docs
What is matched?
In VirtualHost context, The Pattern will initially be matched against the part of the URL after the hostname and port, and before the query string (e.g. "/app1/index.html").
In Directory and htaccess context, the Pattern will initially be matched against the filesystem path, after removing the prefix that lead the server to the current RewriteRule (e.g. "app1/index.html" or "index.html" depending on where the directives are defined).
If you wish to match against the hostname, port, or query string, use a RewriteCond with the %{HTTP_HOST}, %{SERVER_PORT}, or %{QUERY_STRING} variables respectively.
So, when in VirtualHost the server in not in a directory context so prefix / will not be removed. Also remember when matching with RewriteRule in VirtualHost context, the pattern will always begin with /.
So, your RewriteRule Should be:
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^/(.*)$ http://%1/$1 [R=301,NC,L]
in VirtualHost context.
Also, is it worth placing all .htaccess content in vhost performancewise?
Yes, Definitely. One reason is that, no file (.htaccess) will be read every time you are accessing a page.

How to configure mod_proxy to block every site except one

I'm trying to set up mod proxy to block all traffic except to a specific domain. I can configure it to block individual domains using the ProxyBlock directive, and I can block everything using ProxyBlock *. Is there a way to block everything but one domain?
Thanks,
-Andrew
On apache 2.2 you need to have 2 proxy sections.
ProxyRequests On
ProxyVia On
# block all domains except our target
<ProxyMatch ^((?!www\.proxytarget\.com).)*$>
Order deny,allow
Deny from all
</ProxyMatch>
# here goes your usual proxy configuration...
<ProxyMatch www\.proxytarget\.com >
Order deny,allow
Deny from all
Allow from 127.0.0.1
</ProxyMatch>
On apache 2.4 it would be much easier because you could use the If directive instead of that regexp to invert the match for the domain name.
Note: I got that regexp from Invert match with regexp
Try:
ProxyBlock *
ProxyPass <path> <destination>
See if that works.
EDIT: scratch that. I think you have to get creative here with mod_rewrite (the basic reference is at http://httpd.apache.org/docs/current/rewrite/proxy.html):
RewriteCond %{HTTP_HOST} =allowtoproxy.com
RewriteRule ^/(.*)$ http://proxytarget.com/$1 [P]
ProxyPassReverse / http://proxytarget.com/
Try that?
Try this code:
RewriteEngine On
# Testing URLs
RewriteCond %{HTTP_HOST} !google.co.uk [NC]
RewriteCond %{HTTP_HOST} !bbc.co.uk [NC]
RewriteCond %{HTTP_HOST} !amazon.com [NC]
RewriteCond %{HTTP_HOST} !centos.org [NC]
RewriteCond %{HTTP_HOST} !opensuse.org [NC]
# Url to redirect to if not in allowed list
RewriteRule (.*) http://example.org/notallowed.htm

Resources