How do I get the remote user agent inside a Genshi template when using Trac, and WSGI?

1.1k views Asked by At

I'm trying to do some customization of a Trac project management website and have run into an interesting problem. The project has a set of images that are both SVG and PNG. The SVG images have numerous advantages including multiple hyperlinks and a smaller transmitted size against PNG which is bigger and can only link to a single document.

I realize that it is possible to use jQuery to sniff out the user agent after the page has been loaded and replace the PNG with the SVG version of the image, but this results in the PNG being sent to all clients. I also can have Genshi replace the PNG with SVG for all clients and then use jQuery to put the PNG back, but the same problem results. I could use jQuery to insert the appropriate images for all clients, but that just seems silly to require the client to do what the server should.

Is there a way I can get browser information inside of a Genshi template? It's a little more difficult than just calling for environment variables because of the fact that I'm running Trac using WSGI. I've looked through the output of repr(locals()) and didn't see anything that looked like it solved my problem. I'd also like to avoid modifying the Trac source code.

2

There are 2 answers

0
Pridkett On BEST ANSWER

Okay, so I did some digging on the issue, not by grepping through the source code, but by writing a custom Genshi handler that spit out the recursive repr() of every element in locals (with help provided by a previous question that addressed how to print out all variables in scope). I had originally missed the req object. It looks like it's as simple as using req.environ['HTTP_USER_AGENT']. The problem was in finding the req object in the first place. Grepping through the source code I still can't find exactly where the templates are instantiated, so this proves to be much easier and better than a patch.

For completeness, here's the bit of Genshi template I used to replace the logo only for newer versions of Gecko based browsers. It's a little hacky and probably suboptimal, but it works and it doesn't send SVG to browsers that lie and say they're "like Gecko" but can't render SVG properly -- yes, I'm looking at you Webkit.

<py:if test="'Gecko/' in req.environ['HTTP_USER_AGENT'] and [int(x.split('/')[1]) for x in req.environ['HTTP_USER_AGENT'].split() if x.startswith('Gecko')][0] &gt; 20080101">
  <div py:match="div[@id='header']">
    <object type="image/svg+xml" id="svgLogo" data="${href.chrome('site/logo.svg')}" style="width=${chrome['logo']['width']}px; height=${chrome['logo']['height']}px;"></object>
  </div>
</py:if>
3
jfs On
user_agent = environ.get('HTTP_USER_AGENT', None)

Or if environ is wrapped in some sort of Request object:

user_agent = request.user_agent

btw, You should probably look at HTTP_ACCEPT header instead of HTTP_USER_AGENT to find out what representation should be sent.