[SOLVED: See solution below.]

I am getting an issue writing a RewriteMap program (using Python). I've got a RewriteMap directive pointing to some Python script which determines when the asked for URL must be rerouted elsewhere.

Once the script results a string ended with a linebreak, Apache redirects accordingly. However, once the script results NULL (without any linebreak), Apache dangles and subsequent HTTP demands are effectively overlooked.

The mistake log shows no errors. The rewrite log only shows a pass through then a redirect when effective, then only pass through when NULL is came back through the script. Subsequent demands also only show pass through.

Furthermore, changing stdout with os.fdopen(sys.stdout.fileno(), 'w', 0) to create buffer length to zero didn't help.

Any help could be greatly appreciated. Thanks ahead of time.

/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()

You need to return just one newline, not 'NULL'.

Apache waits for any newline to understand once the Hyperlink to be rewrite to finishes. In case your script transmits no newline, Apache waits forever.

So just change return ('NULL') to return ('NULL\n'), this can then redirect to /. If you do not want this to occur, possess the program to come back the URL you would like when there is no match within the map.

If you would like to not redirect when there is no match I'd:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond (${remap:$1}) !NULL
RewriteRule (.*_.*) /%1 [R=301]

Make use of a match within the RewriteCond (this could use NULL too, obviously). But given your condition, this appears like the correct solution.

The very best solution I have develop so far is to achieve the RewriteMap script return the brand new url or '__NULL__\n' if no redirect is preferred and store this value inside a ENV variable. Then, look into the ENV variable for !__NULL__ and redirect. See .htaccess file below.

Also, if anybody is thinking about doing something such as this, within the Python script I wrapped a reasonable quantity of it in try/except blocks to avoid the script from dying (during my situation, because of unsuccessful file/database reads) and subsequent queries being overlooked.

/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 certainly assisted me figure that one out. Basically had more knowledge about stackoverflow, you'd have obtained ^ from me. Thanks.

I really hope this publish helps someone handling a similar problem later on.

Cheers, Andrew