用 Python WSGI 混和并匹配 Web 组件
2010-09-22 11:13:19 来源:WEB开发网清单 1(safexhtml.py). WSGI 中间件为不能处理 XHTML 的浏览器把 XHTML 翻译成 HTML
import cStringIO
from xml import sax
from Ft.Xml import CreateInputSource
from Ft.Xml.Sax import SaxPrinter
from Ft.Xml.Lib.HtmlPrinter import HtmlPrinter
XHTML_IMT = "application/xhtml+xml"
HTML_CONTENT_TYPE = 'text/html; charset=UTF-8'
class safexhtml(object):
"""
Middleware that checks for XHTML capability in the client and translates
XHTML to HTML if the client can't handle it
"""
def __init__(self, app):
#Set-up phase
self.wrapped_app = app
return
def __call__(self, environ, start_response):
#Handling a client request phase.
#Called for each client request routed through this middleware
#Does the client specifically say it supports XHTML?
#Note saying it accepts */* or application/* will not be enough
xhtml_ok = XHTML_IMT in environ.get('HTTP_ACCEPT', '')
#Specialized start_response function for this middleware
def start_response_wrapper(status, response_headers, exc_info=None):
#Assume response is not XHTML; do not activate transformation
environ['safexhtml.active'] = False
#Check for response content type to see whether it is XHTML
#That needs to be transformed
for name, value in response_headers:
#content-type value is a media type, defined as
#media-type = type "/" subtype *( ";" parameter )
if ( name.lower() == 'content-type'
and value.split(';')[0] == XHTML_IMT ):
#Strip content-length if present (needs to be
#recalculated by server)
#Also strip content-type, which will be replaced below
response_headers = [ (name, value)
for name, value in response_headers
if ( name.lower()
not in ['content-length', 'content-type'])
]
#Put in the updated content type
response_headers.append(('content-type', HTML_CONTENT_TYPE))
#Response is XHTML, so activate transformation
environ['safexhtml.active'] = True
break
#We ignore the return value from start_response
start_response(status, response_headers, exc_info)
#Replace any write() callable with a dummy that gives an error
#The idea is to refuse support for apps that use write()
def dummy_write(data):
raise RuntimeError('safexhtml does not support the deprecated
write() callable in WSGI clients')
return dummy_write
if xhtml_ok:
#The client can handle XHTML, so nothing for this middleware to do
#Notice that the original start_response function is passed
#On, not this middleware's start_response_wrapper
for data in self.wrapped_app(environ, start_response):
yield data
else:
response_blocks = [] #Gather output strings for concatenation
for data in self.wrapped_app(environ, start_response_wrapper):
if environ['safexhtml.active']:
response_blocks.append(data)
yield '' #Obey buffering rules for WSGI
else:
yield data
if environ['safexhtml.active']:
#Need to convert response from XHTML to HTML
xhtmlstr = ''.join(response_blocks) #First concatenate response
#Now use 4Suite to transform XHTML to HTML
htmlstr = cStringIO.StringIO() #Will hold the HTML result
parser = sax.make_parser(['Ft.Xml.Sax'])
handler = SaxPrinter(HtmlPrinter(htmlstr, 'UTF-8'))
parser.setContentHandler(handler)
#Don't load the XHTML DTDs from the Internet
parser.setFeature(sax.handler.feature_external_pes, False)
parser.parse(CreateInputSource(xhtmlstr))
yield htmlstr.getvalue()
return
更多精彩
赞助商链接