RewriteRule causes page to reload twice - apache

I shaped two different RewriteRules for my page:
# Enable URL Rewriting
RewriteEngine on
# exclude followed stuff
RewriteRule ^(js|img|css|favicon\.ico|image\.php|anprobe|content|libs|flash\.php|securimage)/ - [L,QSA,S=2]
# conditions (REQUEST dont point # file|dir|link)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-F
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
# rules
RewriteRule ^(?!index\.php)brillen/(.*(brillen)|360|neu)/(.*)([a-zA-Z0-9]{5}-[a-zA-Z0-9]{5}(?!\.))(.*)$ /index.php/brillen/$1?art_id=$4&$5&%{QUERY_STRING} [NS,QSA,L]
RewriteRule ^(?!index\.php)(.*)$ /index.php/$1 [NS,QSA,L]
... and I'm encountering a strange problem, which lies in every request causing the page internally to load twice, which leads to the problem that db actions and email dispatching are also executed twice.
Does anyone have an idea concerning that?
Thanks in advance!
Note 1: All requested resources are valid and available according to the browser's resource tracking.
Note 2: May the problem originate in retaining and post-processing the PATH_INFO? (/index.php/$1 => /index.php/foo/bar/...)

The rewrite Engine cannot make a single HTTP request run twice. It routes the HTTP request for Apache to either a static file, a proxy function, or a module (like PHP) with alteration in the request. But it cannot clone the request and give it 2 times to apache.
When you have any "run twice" problem chances are that you are hit by the empty image url bug. In fact it's not really a bug it's a feature of HTML (at least before HTML5) and a feature of url-parsing.
If you get somewhere an empty GET url, HTML states that the browser should re-send the same query (the one that gave him the current page) with same parameters. This can make a POST request happen 2 times (if the requested 1st page were a POST). So where are these empty GET url? Most of the time you get either :
<IMG SRC="" ...> (in the HTML)
or:
url() (in the css)
or:
<script type="text/javascript" src=""></script>
<link rel="stylesheet" type="text/css" href=""> (in the HTML headers)
Read also #Jon answer about the favicon query. You should always test the result without browsers behaviours by using wget or telnet 80 queries.
Update: detailled explanations and followups available on this blog with HTML5 additions which should remove this behavior for modern browsers.

I had the same issue (or so I thought). It was caused by the request for favicon.ico, which I hadn't considered in my rewrite rule.

I had the same problem, caused because I did some url rewriting, and the script was being loaded twice, due to the fact that i did not add this:
RewriteRule ^(js|img|css|favicon\.ico)/ - [L,QSA,S=2]
This will stop the script from being loaded twice; it solved my problem.

Related

POST information getting lost in .htaccess redirect

So, I have a fully working CRUD. The problem is, because of my file structure, my URLs were looking something like https://localhost/myapp/resources/views/add-product.php but that looked too ugly, so after research and another post here, I was able to use a .htaccess file to make the links look like https://localhost/myapp/add-product (removing .php extension and the directories), and I'm also using it to enforce HTTPS. Now, most of the views are working fine, but my Mass Delete view uses POST information from a form on my index. After restructuring the code now that the redirect works, the Mass Delete view is receiving an empty array. If I remove the redirect and use the "ugly URLs" it works fine. Here's how my .htaccess file is looking like:
Options +FollowSymLinks +MultiViews
RewriteEngine On
RewriteBase /myapp/
RewriteRule ^resources/views/(.+)\.php$ $1 [L,NC,R=301]
RewriteCond %{DOCUMENT_ROOT}/myapp/resources/views/$1.php -f
RewriteRule ^(.+?)/?$ resources/views/$1.php [END]
RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
I didn't actually write any of it, it's a mesh between answered questions and research. I did try to change the L flag to a P according to this post: Is it possible to redirect post data?, but that gave me the following error:
Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator at admin#example.com to inform them of the time this error occurred, and the actions you performed just before this error.
More information about this error may be available in the server error log.
Apache/2.4.52 (Win64) OpenSSL/1.1.1m PHP/8.1.2 Server at localhost Port 443
POST information getting lost in .htaccess redirect
You shouldn't be redirecting the form submission in the first place. Ideally, you should be linking directly to the "pretty" URL in your form action. If you are unable to change the form action in the HTML then include an exception in your .htaccess redirect to exclude this particular URL from being redirected.
Redirecting the form submission is not really helping anyone here. Users and search engines can still see the "ugly" URL (it's in the HTML source) and you are doubling the form submission that hits your server (and doubling the user's bandwidth).
"Redirects" like this are only for when search engines have already indexed the "ugly" URL and/or is linked to by external third parties that you have no control over. This is in order to preserve SEO, just like when you change any URL structure. All internal "ugly" URLs should have already been converted to the "pretty" version. The "ugly" URLs are then never exposed to users or search engines.
So, using a 307 (temporary) or 308 (permanent) status code to get the browser to preserve the request method across the redirect should not be necessary in the first place. For redirects like this it is common to see an exception for POST requests (because the form submission shouldn't be redirected). Or only target GET requests. For example:
RewriteCond %{REQUEST_METHOD} GET
:
Changing this redirect to a 307/8 is a workaround, not a solution. And if this redirect is for SEO (as it only should be) then this should be a 308 (permanent), not a 307 (temporary).
Aside:
RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Your HTTP to HTTPS redirect is in the wrong place. This needs to go as the first rule, or make sure you are redirecting to HTTPS in the current first rule and include this as the second rule, before the rewrite (to ensure you never get a double redirect).
By placing this rule last then any HTTP requests to /resources/views/<something>.php (or /<something>) will not be upgraded to HTTPS.

HTTPS redirect fails with .htaccess rewrite for certain URL length

I have an .htaccess file for showing a default image if the requested URL does not exist. I simplified it to this:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . default.png [L]
Using HTTPS, this suddenly stopped working if the URL exceeds a certain length (connection closed).
HTTP always works.
It used to work like this for years and it still does on other servers.
It also seems that the kind of characters matter:
not working:
https://server.abc/images/01234567890123456789012345678901234567890123456789abc.png
https://server.abc/images/012345678901234567890123456789012345678901234567890123456789.png
working:
https://server.abc/images/01234567890123456789012345678901234567890123456789.png
https://server.abc/images/01234567890123456789012345678901234567890123456789123.png
https://server.abc/images/0123456789012345678901234567890123456789012345678912345.png
The redirect works if the condition is removed (second line), so it seems like it has something to do with REQUEST_FILENAME, HTTPS and the byte size (encoding?) of the filename/URL string.
This occurs with Apache/2.4.46 and macOS/10.15.7. It might have started after one of the latest security updates.
Any idea where this is coming from or what kind of configuration could cause this?
Thanks for your help!
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . default.png [L]
It's not clear why this would "fail" for only certain requests over HTTPS only. A "security" update (particularly if it involves mod_security) is a likely cause - although an unusual one.
However, you shouldn't really be doing it this way to begin with. This will result in a request for any non-existent URL being served /default.png with a "200 OK" response and potentially risk being indexed by search engines and abused by a malicious user.
What you are doing here is essentially setting a custom 404 response to an image, which you could do with the following instead and which will also return the "correct" 404 status.
ErrorDocument 404 /default.png
Now, any request that does not map to file (or directory) will be served the image /default.png but with a 404 "Not Found" HTTP response code, so search engines/bots get the "correct" response.
This also naturally gets around the REQUEST_FILENAME issue, assuming these "not working" URLs do ultimately result in a 404 and not some other response (due to the "security" update).

Allowing relative paths only

I believe this is an Apache .htaccess issue, and yet, maybe not. Maybe I am looking at the problem from the wrong angle, and thus can't find the proper solution.
I am building a web app + hybrid mobile app. I would like to share the exact same code base, without having to tweak anything manually to deploy my app to Android or iOS, otherwise, the process of deploying will be hacky and painful. What I want is to take the web app repository, shove it into Cordova's box (you dirty man ;), and it would deploy it successfully.
Now, one issue is that Cordova requires relative paths to work properly. For example, this is how I include my require.js file :
<script data-main="library/js/dependencies.js" src="library/js/libs/require.js">
</script>
This works fine on the hybrid app. This works fine also on most of the web app's URLs, those with the following scheme :
domain.com/view_name
However, this is what happens when I load the app from a view that receives URI parameters :
domain.com/view_name/6iwO4NyJqy
The relative paths are not resolved properly anymore. I get 404 error due to unproper paths. For instance, this is how is resolved the require.js file above :
http://domain.com/view_name/library/js/libs/require.js
The view_name bit is the wrong part. It should not be there. Without it, the file would be found successfully.
This is my .htaccess file :
RewriteEngine on
RewriteBase /
# REROUTING EVERYTHING TO index.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d [OR]
RewriteCond %{REQUEST_URI} ^/$
RewriteRule .* /index.html [NC,L,QSA]
Is there a way to set my .htaccess file, so that I don't need to modify the relative paths within the app, and still can have them resolved properly ?
Any suggestion is most welcome.
It is not caused by your rewrite rule, it is due to your use of relative paths.
You can add this just below <head> section of your page's HTML:
<base href="/" />
so that every relative URL is resolved from that base URL and not from the current page's URL.

SSL script issue

I am currently using this htaccess code to force all users to use ssl :
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
However my website uses many scripts to load variety of images and i get tons off errors like this one :
Mixed Content: The page at 'https://website.com/' was loaded over HTTPS, but requested an insecure image 'http://website.com/3.jpg'. This content should also be served over HTTPS.
Is there a way of forcing scripts to load https images or i have to edit them manually ?
You would have to edit them manually. Of course, if any of those resources, i. e. other sources than yours, don't have https-alternatives, you will always get errors. With newer versions of some browsers those scripts will actually be blocked, and not loaded at all.
You can edit your script URLs to use the protocol relative format. Modern browsers understand that they should load the script using whatever protocol (https or http) you're using in the calling page.
Example:
Change <script src=”https://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js” type=”text/javascript”></script>
To <script src=”//ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js” type=”text/javascript”></script>
Article explaining:
http://blog.httpwatch.com/2010/02/10/using-protocol-relative-urls-to-switch-between-http-and-https/

Frontloading mod_rewrite rule is causing index.php to load twice

I've been working on a project that uses a frontloader to handle all requests (Routing domain.com/args/go/here to Index.php?req=args/go/here), and it's worked very well... Or I should say, I thought it did - I recently added a new logger, and to test it I placed a test log message in index.php. This message was being written to my log file twice, every time I reloaded the page, and after much debugging I found the cause to be my .htaccess file - for whatever reason, it loads index.php twice for every request.
Here's my .htaccess:
RewriteEngine On
RewriteBase /site/beta/ #I added this after I discovered the bug
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^index\.php$ #This too. Doesn't work
RewriteRule ^(.*)$ index.php?args=$1 [L]
I've also tried:
FallbackResource /site/beta/index.php
Which both doesn't work (Index.php just doesn't load if you try to go to, say, 127.0.0.1/site/beta/admin/controls/ - but it does if you just go to /index.php), and still loads twice.
Is anyone able to help me? I spent a few hours in IRC, and no one could come up with a solution that worked. (The two above are the only ones suggested)
Are you completly sure it's a mod_rewrite bug? If you enable RewriteLog file with a high rewriteLogLevel (9) do you see the same requests handled 2 times?
For me every time I see the 'same request done 2 times' I think about another strange web bug: The empty IMG src bug.
If you have somewhere in your HTML an
<IMG SRC="">
or in one of the css (harder to find) a:
url()
Then you've got it. HTTP protocol dictate that an empty GET url (and an image or url() in css is a GET implicit request) MUST be a call to the same url as the one which render the original page (and it can be a POST as well if you get your page as a POST request).
There're really few reason to have a mod_rewrite responding 2 times to one single request. Check with Firebug or LiveHTTP Requests that you're not always sending the index.php request 2 times. Or test your server with a telnet-mode HTTP request, by hand, as this will certainly send only one request.
This can also be the browser trying to load (invisibly it seems unless you check the apache access logs) favicon.ico. I had the same issue until I put one in my sites root directory. I know the issue was resolved for the initial asker, I'm putting this here for people like myself looking for an answer to the same question.