Commits

Andriy Kornatskyy committed fd28029

Fixed issue #1: Segmentation fault on escape_html

Comments (0)

Files changed (4)

 	fi
 
 test:
+	$(PYTHON) setup.py -q build ; \
+	$(PYTHON) setup.py -q develop ; \
 	$(PYTEST) -q -x --pep8 --doctest-modules \
-		src/wheezy/html
+		src/wheezy/html/tests
 
 doctest-cover:
 	$(NOSE) --stop --with-doctest --detailed-errors \

src/wheezy/html/boost.c

 typedef int Py_ssize_t;
 #endif
 
+#if PY_VERSION_HEX < 0x02060000
+#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+#endif
 
 static PyObject*
 escape_html_unicode(PyUnicodeObject *s)
         return NULL;
     }
 
-    if (PyUnicode_Check(s))
+    if (PyUnicode_CheckExact(s))
     {
         return escape_html_unicode((PyUnicodeObject*)s);
     }
-    else
+
+#if PY_MAJOR_VERSION < 3
+    if (PyString_CheckExact(s))
+#else
+    if (PyBytes_CheckExact(s))
+#endif
     {
         return escape_html_string(s);
     }
+
+    if (s == Py_None) {
+#if PY_MAJOR_VERSION < 3
+        return PyString_FromStringAndSize(NULL, 0);
+#else
+        return PyUnicode_FromStringAndSize(NULL, 0);
+#endif
+    }
+
+    PyErr_Format(PyExc_TypeError,
+                 "expected string or unicode object, %s found",
+                 Py_TYPE(s)->tp_name);
+    return NULL;
 }
 
 

src/wheezy/html/tests/test_utils.py

+
+""" Unit tests for ``wheezy.html.utils``.
+"""
+
+import unittest
+
+
+class EscapeHTMLMixin:
+
+    def test_none(self):
+        assert "" == self.escape(None)
+
+    def test_empty(self):
+        assert "" == self.escape("")
+
+    def test_no_changes(self):
+        assert "abc" == self.escape("abc")
+
+    def test_escape(self):
+        assert "&amp;&lt;&gt;&quot;\'" == self.escape('&<>"\'')
+
+    def test_type_error(self):
+        self.assertRaises(TypeError, lambda: self.escape(1))
+
+
+class NativeEscapeHTMLTestCase(unittest.TestCase, EscapeHTMLMixin):
+
+    def setUp(self):
+        from wheezy.html.utils import escape_html_native
+        self.escape = escape_html_native
+
+try:
+    from wheezy.html.boost import escape_html
+
+    class BoostEscapeHTMLTestCase(unittest.TestCase, EscapeHTMLMixin):
+        def setUp(self):
+            self.escape = escape_html
+except ImportError:
+    pass

src/wheezy/html/utils.py

 from wheezy.html.comp import str_type
 
 
+def escape_html(s):
+    """ Escapes a string so it is valid within HTML. Converts `None`
+        to an empty string. Raises TypeError is `s` is not a string
+        or unicode object.
+
+        >>> html_escape(None)
+        ''
+
+        >>> escape_html('&<>"\\'')
+        "&amp;&lt;&gt;&quot;\'"
+    """
+    if s is None:
+        return ''
+    try:
+        return s.replace('&', '&amp;').replace('<', '&lt;').replace(
+            '>', '&gt;').replace('"', '&quot;')
+    except AttributeError:
+        raise TypeError("expected string or unicode object, "
+                        "%s found" % s.__class__.__name__)
+escape_html_native = escape_html
+
 try:
     from wheezy.html.boost import escape_html
     html_escape = escape_html
 except ImportError:
-    def escape_html(s):
-        """ Escapes a string so it is valid within HTML.
-
-            >>> html_escape('abc')
-            'abc'
-            >>> escape_html('&<>"\\'')
-            "&amp;&lt;&gt;&quot;\'"
-        """
-        return s.replace('&', '&amp;').replace('<', '&lt;').replace(
-            '>', '&gt;').replace('"', '&quot;')
     html_escape = escape_html