[mod_python] changing req.proxyreq on the fly

Graham Dumpleton grahamd at dscpl.com.au
Fri Mar 3 04:41:23 EST 2006


>> FWIW, if req.proxyreq is made writable, it would be good at the same
>> time to make req.uri writable as well. This would allow for example a
>> PythonTransHandler which did something like the following:
>>
>> def transhandler(req):
>>     if req.proxyreq:
>>         return apache.DECLINED
>>
>>     if req.uri.find('/search/') == 0:
>>         req.proxyreq = apache.PROXYREQ_PROXY
>>         req.uri = 'http://www.google.com/' + req.uri[len('/search/'):]
>>         req.filename= "proxy:%s' % req.uri
>>         req.handler= 'proxy-server'
>>         return apache.OK
>>
>>     return apache.DECLINED
>>
>> That is, you could from within a mod_python handler when detecting
>> a certain URL prefix, dynamically cause Apache to proxy the request to
>> another location.
>>
>> This example is based on a mod_perl example which does something
>> similar. See:
>>
>>   http://162.105.203.19/apache-doc/88.htm#BIN194
>>
>> I'll definitely create a JIRA issue for this, as can see a use for 
>> this
>> in some stuff I have to do. I was going to create a static snippet of
>> Apache configuration with lots of proxy stuff, but this would be more
>> interesting.
>
> Hmm, interesting idea. It would be great to see something like that. I
> can think of all kinds of stuff I've done with mod_rewrite and
> horrible PHP hackery that would have been a lot better and simpler
> with mod_python and something similar to what you mentioned.

Well, if you want to play further, patch for making both req.proxyreq
and req.uri modifiable is at end of this email. An example to play with
is as follows. Doesn't even need to be a transhandler. This example
does it as a fixuphandler which is possibly easier as it can be in
.htaccess file for a specific directory. The example will take any part
of the URL mapping below the directory and map it onto the remote site
instead. Of course, the site has to be proxy friendly and relocatable
within the URL namespace in as much as always using relative URLs and
not absolute URLs.

# ProxyPassReverse equivalent.

import posixpath

from mod_python import apache

def fixuphandler(req):

   if req.proxyreq:
     return apache.DECLINED

   normalised_uri = posixpath.normpath(req.uri)

   if normalised_uri:
     if normalised_uri != '/' and req.uri[-1] == '/':
       normalised_uri += '/'

   length = len(req.filename)
   length -= len(req.hlist.directory) - 1
   length += len(req.path_info or '')

   baseurl = normalised_uri[:-length]
   path = normalised_uri[len(baseurl):]

   req.proxyreq = apache.PROXYREQ_REVERSE
   req.uri = 'http://www.dscpl.com.au' + path
   req.filename = 'proxy:%s' % req.uri
   req.handler = 'proxy-server'

   return apache.OK

# Actual patches.

Index: src/requestobject.c
===================================================================
--- src/requestobject.c (revision 382636)
+++ src/requestobject.c (working copy)
@@ -1515,6 +1515,15 @@
              apr_pstrdup(self->request_rec->pool, 
PyString_AsString(val));
          return 0;
      }
+    else if (strcmp(name, "uri") == 0) {
+        if (! PyString_Check(val)) {
+            PyErr_SetString(PyExc_TypeError, "uri must be a string");
+            return -1;
+        }
+        self->request_rec->uri =
+            apr_pstrdup(self->request_rec->pool, 
PyString_AsString(val));
+        return 0;
+    }

      return PyMember_SetOne((char*)self->request_rec,
                             find_memberdef(request_rec_mbrs, 
(char*)name),
@@ -1675,7 +1684,7 @@
      {"main",       (getter)getmakeobj, NULL, "If subrequest, pointer 
to the main request", "main"},
      {"the_request", (getter)getreq_recmbr, NULL, "First line of 
request", "the_request"},
      {"assbackwards", (getter)getreq_recmbr, (setter)setreq_recmbr, 
"HTTP/0.9 \"simple\" request", "assbackwards"},
-    {"proxyreq",     (getter)getreq_recmbr, NULL, "A proxy request: 
one of apache.PROXYREQ_* values", "proxyreq"},
+    {"proxyreq",     (getter)getreq_recmbr, (setter)setreq_recmbr, "A 
proxy request: one of apache.PROXYREQ_* values", "proxyreq"},
      {"header_only",  (getter)getreq_recmbr, NULL, "HEAD request, as 
oppsed to GET", "header_only"},
      {"protocol",     (getter)getreq_recmbr, NULL, "Protocol as given 
to us, or HTTP/0.9", "protocol"},
      {"proto_num",    (getter)getreq_recmbr, NULL, "Protocol version. 
1.1 = 1001", "proto_num"},
@@ -1709,7 +1718,7 @@
      {"no_cache",      (getter)getreq_recmbr, NULL, "This response in 
non-cacheable", "no_cache"},
      {"no_local_copy", (getter)getreq_recmbr, NULL, "There is no local 
copy of the response", "no_local_copy"},
      {"unparsed_uri",  (getter)getreq_recmbr, NULL, "The URI without 
any parsing performed", "unparsed_uri"},
-    {"uri",           (getter)getreq_recmbr, NULL, "The path portion 
of URI", "uri"},
+    {"uri",           (getter)getreq_recmbr, (setter)setreq_recmbr, 
"The path portion of URI", "uri"},
      {"filename",      (getter)getreq_recmbr, (setter)setreq_recmbr, 
"The file name on disk that this request corresponds to", "filename"},
      {"canonical_filename", (getter)getreq_recmbr, NULL, "The true 
filename (req.filename is canonicalized if they dont match)", 
"canonical_filename"},
      {"path_info",     (getter)getreq_recmbr, (setter)setreq_recmbr, 
"Path_info, if any", "path_info"},


Graham



More information about the Mod_python mailing list