Apache2 + RewriteMap + Python - when returning "NULL" apache hangs
[SOLVED: see solution below.]
I am having a problem writing a program RewriteMap
(using Python). I have a directive RewriteMap
pointing to a Python script that determines if the required URL needs to be redirected to a different location.
When the script outputs a line terminated by a line break, Apache redirects accordingly. However, when the script outputs NULL
(no line breaks), Apache hangs and subsequent HTTP requests are effectively ignored.
There are no errors in the error log. The rewrite log shows only pass through
followed by redirect
then only pass through
when the NULL
script returns. Subsequent requests also show only pass through
.
Also, replacing stdout
with os.fdopen(sys.stdout.fileno(), 'w', 0)
to set the buffer length to zero didn't help.
Any help would be greatly appreciated. Thank you in advance.
/etc/apache2/httpd.conf
[...]
RewriteLock /tmp/apache_rewrite.lock
/ etc / apache2 / sites-available / default
<VirtualHost *:80>
[...]
RewriteEngine on
RewriteLogLevel 1
RewriteLog /var/www/logs/rewrite.log
RewriteMap remap prg:/var/www/remap.py
[...]
</VirtualHost>
/var/www/webroot/.htaccess
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*_.*) /${remap:$1} [R=301]
/var/www/remap.py
#!/usr/bin/python
import sys
def getRedirect(str):
new_url = None
# if url needs to be redirected, put this value in new_url
# otherwise new_url remains None
return new_url
while True:
request = sys.stdin.readline().strip()
response = getRedirect(request)
if response:
sys.stdout.write(response + '\n')
else:
sys.stdout.write('NULL')
sys.stdout.flush()
source to share
You should return one new line, not "NULL".
Apache waits for a new line to know when the URL has been rewritten to the end. If your script doesn't post a newline, Apache waits forever.
So, just change return ('NULL')
to return ('NULL\n')
, then redirect to /. If you don't want this to happen, ask the program to return the desired URL if there is no match on the map.
If you don't want to redirect if there is no match I would:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond (${remap:$1}) !NULL
RewriteRule (.*_.*) /%1 [R=301]
Use match in RewriteCond (this will work with NULL of course). But given your problem, this looks like the right solution.
source to share
The best solution I've come to is to return the RewriteMap script to the new url or '__NULL__\n'
if no redirect is required and store that value in the ENV variable. Then check the ENV variable for !__NULL__
and redirect. See below .htaccess
file.
Also, if anyone is planning to do something like this, inside a Python script I have wrapped it quite a bit in a try / except block to prevent the script from dying (in my case due to a file / database read failed) and subsequent requests are ignored.
/var/www/webroot/.htaccess
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ - [E=REMAP_RESULT:${remap:$1},NS]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{ENV:REMAP_RESULT} !^__NULL__$
RewriteRule ^(.+)$ /%{ENV:REMAP_RESULT} [R=301,L]
/var/www/remap.py
#!/usr/bin/python
import sys
def getRedirect(str):
try: # to prevent the script from dying on any errors
new_url = str
# if url needs to be redirected, put this value in new_url
# otherwise new_url remains None
if new_url == str: new_url = '__NULL__'
return new_url
except:
return '__NULL__'
while True:
request = sys.stdin.readline().strip()
response = getRedirect(request)
sys.stdout.write(response + '\n')
sys.stdout.flush()
Vinko, you definitely helped me figure this out. If I had more experience with stackoverflow
, you would get ^
from me. Thank.
I hope this post helps someone who is facing a similar issue in the future.
Cheers, Andrew
source to share