On 14/03/2006, at 7:33 PM, André Malo wrote:

* Graham Dumpleton <[EMAIL PROTECTED]> wrote:

Do you have examples of SSI tag handlers that you might implement this way if such a feature were available? I ask as it all good to speculate
on such a feature, but like this generic "#python" tag, would it in
itself be used either?

Actually, I'd hardly use the the #python tag by itself, but specific
functions, provided by my application as needed (like the SSI templates
are provided by my application but designed by someone else!).

All you thus get by having an explicit registered tag is that that
Python
is used can be hidden and a user would be none the wiser.

Exactly that's the point. Separation of concerns - I'm not a friend of a
raw programming language in a template.
Therefore - if you really want to pass httpd features to mod_python, it
would be nice to consider this one :)

I would agree that excessive raw programming language code in a template
is not good either. I however don't see minimal callouts, which
effectively what a custom tag is doing anyway, as that bad.

What I am about to describe can only be done using a backdoor with the
current SSI support. This is the case because of bug described in:

  https://issues.apache.org/jira/browse/MODPYTHON-146

which means it will not work where DirectoryIndex is matching files.

When that is fixed, a notionally private variable reference just needs
to be made part of the public API and this will all work. You could use
the notionally private variable name now if you wanted to play, it just
will not work on DirectoryIndex matched files. In other words, have
simply hidden fact this can be done until that other issue is fixed.

First off, in my .htaccess file I have:

  PythonFixupHandler _dispatch

I have not turned on INCLUDES output filter in the configuration as I
do it dynamically, but you could do it in the configuration instead.

My fixup handler then contains:

  from mod_python import apache

  def header():
    return "<p>HEADER</p>"

  def footer():
    return "<p>FOOTER</p>"

  def other(filter):
    print >> filter, "<p>OTHER</p>"

  def fixuphandler(req):

    if req.content_type == "text/html":

      # Enable INCLUDES output filter for request.

      req.add_output_filter("INCLUDES")

      # Setup globals visible to INCLUDES files.

      req.ssi_globals = {}
      req.ssi_globals["header"] = header
      req.ssi_globals["footer"] = footer
      req.ssi_globals["other"] = other

    return apache.OK

In my HTML file being processed by INCLUDES output filter, I can then
use:

  <html>
    <body>
      <!--#python eval="header()" -->
      <p>TEXT</p>
      <!--#python eval="other(filter)" -->
      <p>TEXT</p>
      <!--#python eval="footer()" -->
      </pre>
    </body>
  </html>

What I am doing is using the fixup handler to enabled the INCLUDES
output filter based on type of file matched by request, but am also
creating a dictionary object preloaded with data accessible to the
code executing within context of file being processed by INCLUDES
output filter. This dictionary actual becomes the globals of the code.
That is, equivalent to saying:

  eval "header()" in req.ssi_globals

Thus one can avoid having a whole lot of excessive code in the HTML
to perform imports, setup data etc. This can all be done in the
fixup handler for all files in the directory to be processed by the
INCLUDES output filter. The result is that the HTML is quite simple
and not really that much more complicated than having custom tags.

In respect of customised tag handlers, this is more flexible, as a
customised tag handler resides in the global Apache server namespace.
That is, it is accessible to everything. With the above mechanism, what
is available and callable can be specific to a particular part of the
URL namespace, specifically, whatever context the fixup handler is
specified for. With a bit of extra work, you could even allow fixup
handlers specific to each resource and allow file level customisations
as well as directory level.

That customised tag handlers are in the global namespace presents
other issues as well. The first is that they have to be registered at
the time that mod_python is being initialised. To do this, custom
directives would need to be created and they must be used only in
main sever configuration context. That is, outside of all VirtualHost,
Location, Directory or Files directive containers. As mentioned before,
means they cant apply to a specific context and a user who only has
access to a .htaccess file cant define them.

The next issue would be coming up with a simple API on the Python side
for processing the callback when a registered tag were called. Doing
this in C code is quite fiddly and not sure how one could present a nice
API to do the same if you wanted to have the same abilities for
processing tag arguments and values etc.

What might be a better approach is to harness some other changes I have
in mind for mod_python down the track. That is, I want to export some
functions from mod_python which would be callable from other Apache
modules using the optional function API. These functions would provide
ability to get a named Python interpreter, get a Python wrapped request
object, filter object or server object and the ability to finally release
the interpreter lock.

With these, if one was really serious about having a customised tag
handler which behind the scenes was implemented using Python, one could
start by writing a custom C Apache module which registers the tag, and
when called processes arguments and sets up filter bucket chain etc,
in C code and then grabs Python interpreter and then executes a call
into actual Python code stored in an installed Python module.

I am sure you will say that this is too much work, but it becomes a
balance between having full access to Apache internals to properly
register the tag handler and process arguments, versus tolerating that
it is still Python code in the template, albeit this would allow things
to be done quicker and not require a full blown separate Apache module
to be created.

The only other option is to invest a lot of time in coming up with an
additional Python API which wraps lower level bits of Apache. This is
what mod_perl effectively does, but am not sure the effort is worth it.
You might also be able to come up with a slightly more high level API
related to just tag handlers which isn't a direct map to lower level
concepts and is more Pythonic, but it is still effort. As is, the SSI
support I did add was simple to implement and thus partly why I did it.
If was going to be too much more complicated, I wouldn't have bothered.

Graham

Reply via email to