RE: [cherrypy-users] Variable filters

1 view
Skip to first unread message

Robert Brewer

unread,
Aug 7, 2005, 1:32:43 AM8/7/05
to cherryp...@googlegroups.com
paron wrote:
> I'd like to provide a service where users can send requests
> and specify the response type (for example: html, xml, or
> json.) The URL would look like http:www.example.com/products/
> 123/?_format=xml.
>
> Can I change filters on the fly like that? Or is there a
> better way?

The 'Accept' HTTP request header was designed for that.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1


Robert Brewer
System Architect
Amor Ministries
fuma...@amor.org

paron

unread,
Aug 9, 2005, 7:03:54 AM8/9/05
to cherrypy-users
Thanks! I was really thinking more in terms of browser-users. Should
have been more specific.

Anyway, the CherryPy filter I worked out does the trick -- if a user
requests a representation in some flavor of xml that I am supporting,
CP sets the Content-type to 'text/xml', and if they request it in some
flavor of text, CP sets it to 'text/plain', etc.

However, I really need to support the 'Accept' header content as well.
I'll have to review the spec. Thanks for the reminder.

Ron

paron

unread,
Aug 19, 2005, 7:25:27 AM8/19/05
to cherrypy-users
OK, for those who come along later, here's what I added to my page:

#Check the 'Accept' header to see what formats work
if cpg.request.headerMap.has_key('Accept'):
theStr = cpg.request.headerMap['Accept']
if 'text/xml' in theStr or 'text/*' in theStr or '*/*' in
theStr:
#they'll accept xml(default, so do nothing)
pass
elif theStr=='text/html' or theStr=='text/xhtml':
#they'll only accept html
theFormat='XHTML'
else:
cpg.response.headerMap['Status']= '406 Not acceptable'
return """<h1>406 Not acceptable</h1><br />
'Accept': %s was requested<br />
No acceptable formats available --
'txt/xml' is default, 'txt/html' or 'txt/xhtml'
provided"""%theStr

Robert Brewer

unread,
Aug 19, 2005, 1:18:01 PM8/19/05
to cherryp...@googlegroups.com
paron wrote:
> OK, for those who come along later, here's what I added to my page:
>
> #Check the 'Accept' header to see what formats work
> if cpg.request.headerMap.has_key('Accept'):
> theStr = cpg.request.headerMap['Accept']
> if 'text/xml' in theStr or 'text/*' in theStr or '*/*' in
> theStr:
> #they'll accept xml(default, so do nothing)
> pass

Excellent! Glad you decided to inspect the Accept header, after all.

> elif theStr=='text/html' or theStr=='text/xhtml':
> #they'll only accept html
> theFormat='XHTML'

Note that the Accept header can take multiple values (e.g. "Accept:
text/*, text/html, */*"), so you should probably check if 'text.html' is
in theStr (as you did in the first block), instead of checking equality.

> else:
> cpg.response.headerMap['Status']= '406 Not acceptable'
> return """<h1>406 Not acceptable</h1><br />
> 'Accept': %s was requested<br />
> No acceptable formats available --
> 'txt/xml' is default, 'txt/html' or 'txt/xhtml'
> provided"""%theStr

Nice. Perhaps we could write a generic AcceptHeaderFilter, which also
handles Accept-Charset, -Encoding, and -Language? Maybe that could be
expanded to include User-Agent, and then be called
ContentNegotiationFilter? And output an appropriate Vary header? Maybe.

paron

unread,
Aug 25, 2005, 7:18:08 AM8/25/05
to cherrypy-users
> Nice. Perhaps we could write a generic AcceptHeaderFilter, which also
> handles Accept-Charset, -Encoding, and -Language? Maybe that could be
> expanded to include User-Agent, and then be called
> ContentNegotiationFilter? And output an appropriate Vary header? Maybe.

I didn't "not think" about this, it just took longer than I thought to
think what I thought :)

Yes, I think we could -- the Accept information comes in a logical
structure, but it's sure not one that's employed anywhere else. How
about if it were exposed as a dictionary, similar to the way CherryPy
"pythonizes" the HeaderMap? Something like:

AcceptHeaderMap={'text':[{'xml':{'q':50}},{'html':{'q':30}},{'*':{'q':10}}]}

or something?

There's a lot of good data in the Accept header, and it comes in a
structured way, so it should be possible -- but is it simpler for the
developer just to parse it for what the application needs? OTOH, if it
were written as a "generic AcceptHeaderFilter," it would provide a way
to handle the ever-expanding list of filetypes, encodings, languages,
etc. gracefully.

So, assuming we could, then should we? Eventually?

Ron

Reply all
Reply to author
Forward
0 new messages