[Zope3-checkins] CVS: Zope3/src/zope/pagetemplate - pagetemplatefile.py:1.3

Fred L. Drake, Jr. fred@zope.com
Fri, 21 Mar 2003 13:02:22 -0500


Update of /cvs-repository/Zope3/src/zope/pagetemplate
In directory cvs.zope.org:/tmp/cvs-serv1637

Modified Files:
	pagetemplatefile.py 
Log Message:
_cook_check():  When loading a template from a file, actually "sniff"
    the content to see if the document should be parsed in XML mode.

document_src():  Before setting the Content-Type header, make sure
    we've sniffed the file content to see what the right Content-Type
    is.

sniff_type():  New function:  Examine some text to see if it's likely
    to be XML.


=== Zope3/src/zope/pagetemplate/pagetemplatefile.py 1.2 => 1.3 ===
--- Zope3/src/zope/pagetemplate/pagetemplatefile.py:1.2	Wed Dec 25 09:15:13 2002
+++ Zope3/src/zope/pagetemplate/pagetemplatefile.py	Fri Mar 21 13:02:21 2003
@@ -52,7 +52,12 @@
             mtime = 0
         if self._v_program is not None and mtime == self._v_last_read:
             return
-        self.pt_edit(open(self.filename), None)
+        f = open(self.filename, "rb")
+        try:
+            text = f.read()
+        finally:
+            f.close()
+        self.pt_edit(text, sniff_type(text))
         self._cook()
         if self._v_errors:
             logging.error('PageTemplateFile: Error in template: %s',
@@ -64,6 +69,10 @@
         """Return expanded document source."""
 
         if REQUEST is not None:
+            # Since _cook_check() can cause self.content_type to change,
+            # we have to make sure we call it before setting the
+            # Content-Type header.
+            self._cook_check()
             REQUEST.response.setHeader('Content-Type', self.content_type)
         return self.read()
 
@@ -72,3 +81,20 @@
 
     def __getstate__(self):
         raise TypeError("non-picklable object")
+
+
+XML_PREFIXES = [
+    "<?xml",                      # ascii, utf-8
+    "\xef\xbb\xbf<?xml",          # utf-8 w/ byte order mark
+    "\0<\0?\0x\0m\0l",            # utf-16 big endian
+    "<\0?\0x\0m\0l\0",            # utf-16 little endian
+    "\xfe\xff\0<\0?\0x\0m\0l",    # utf-16 big endian w/ byte order mark
+    "\xff\xfe<\0?\0x\0m\0l\0",    # utf-16 little endian w/ byte order mark
+    ]
+
+def sniff_type(text):
+    """Return 'text/xml' if text appears to be XML, otherwise return None."""
+    for prefix in XML_PREFIXES:
+        if text.startswith(prefix):
+            return "text/xml"
+    return None