1. from xml.dom import minidom
    
  2. 
    
  3. from django.core import serializers
    
  4. from django.core.serializers.xml_serializer import DTDForbidden
    
  5. from django.test import TestCase, TransactionTestCase
    
  6. 
    
  7. from .tests import SerializersTestBase, SerializersTransactionTestBase
    
  8. 
    
  9. 
    
  10. class XmlSerializerTestCase(SerializersTestBase, TestCase):
    
  11.     serializer_name = "xml"
    
  12.     pkless_str = """<?xml version="1.0" encoding="utf-8"?>
    
  13. <django-objects version="1.0">
    
  14.     <object model="serializers.category">
    
  15.         <field type="CharField" name="name">Reference</field>
    
  16.     </object>
    
  17.     <object model="serializers.category">
    
  18.         <field type="CharField" name="name">Non-fiction</field>
    
  19.     </object>
    
  20. </django-objects>"""
    
  21.     mapping_ordering_str = """<?xml version="1.0" encoding="utf-8"?>
    
  22. <django-objects version="1.0">
    
  23.   <object model="serializers.article" pk="%(article_pk)s">
    
  24.     <field name="author" rel="ManyToOneRel" to="serializers.author">%(author_pk)s</field>
    
  25.     <field name="headline" type="CharField">Poker has no place on ESPN</field>
    
  26.     <field name="pub_date" type="DateTimeField">2006-06-16T11:00:00</field>
    
  27.     <field name="categories" rel="ManyToManyRel" to="serializers.category"><object pk="%(first_category_pk)s"></object><object pk="%(second_category_pk)s"></object></field>
    
  28.     <field name="meta_data" rel="ManyToManyRel" to="serializers.categorymetadata"></field>
    
  29.   </object>
    
  30. </django-objects>"""  # NOQA
    
  31. 
    
  32.     @staticmethod
    
  33.     def _validate_output(serial_str):
    
  34.         try:
    
  35.             minidom.parseString(serial_str)
    
  36.         except Exception:
    
  37.             return False
    
  38.         else:
    
  39.             return True
    
  40. 
    
  41.     @staticmethod
    
  42.     def _get_pk_values(serial_str):
    
  43.         ret_list = []
    
  44.         dom = minidom.parseString(serial_str)
    
  45.         fields = dom.getElementsByTagName("object")
    
  46.         for field in fields:
    
  47.             ret_list.append(field.getAttribute("pk"))
    
  48.         return ret_list
    
  49. 
    
  50.     @staticmethod
    
  51.     def _get_field_values(serial_str, field_name):
    
  52.         ret_list = []
    
  53.         dom = minidom.parseString(serial_str)
    
  54.         fields = dom.getElementsByTagName("field")
    
  55.         for field in fields:
    
  56.             if field.getAttribute("name") == field_name:
    
  57.                 temp = []
    
  58.                 for child in field.childNodes:
    
  59.                     temp.append(child.nodeValue)
    
  60.                 ret_list.append("".join(temp))
    
  61.         return ret_list
    
  62. 
    
  63.     def test_control_char_failure(self):
    
  64.         """
    
  65.         Serializing control characters with XML should fail as those characters
    
  66.         are not supported in the XML 1.0 standard (except HT, LF, CR).
    
  67.         """
    
  68.         self.a1.headline = "This contains \u0001 control \u0011 chars"
    
  69.         msg = "Article.headline (pk:%s) contains unserializable characters" % self.a1.pk
    
  70.         with self.assertRaisesMessage(ValueError, msg):
    
  71.             serializers.serialize(self.serializer_name, [self.a1])
    
  72.         self.a1.headline = "HT \u0009, LF \u000A, and CR \u000D are allowed"
    
  73.         self.assertIn(
    
  74.             "HT \t, LF \n, and CR \r are allowed",
    
  75.             serializers.serialize(self.serializer_name, [self.a1]),
    
  76.         )
    
  77. 
    
  78.     def test_no_dtd(self):
    
  79.         """
    
  80.         The XML deserializer shouldn't allow a DTD.
    
  81. 
    
  82.         This is the most straightforward way to prevent all entity definitions
    
  83.         and avoid both external entities and entity-expansion attacks.
    
  84.         """
    
  85.         xml = (
    
  86.             '<?xml version="1.0" standalone="no"?>'
    
  87.             '<!DOCTYPE example SYSTEM "http://example.com/example.dtd">'
    
  88.         )
    
  89.         with self.assertRaises(DTDForbidden):
    
  90.             next(serializers.deserialize("xml", xml))
    
  91. 
    
  92. 
    
  93. class XmlSerializerTransactionTestCase(
    
  94.     SerializersTransactionTestBase, TransactionTestCase
    
  95. ):
    
  96.     serializer_name = "xml"
    
  97.     fwd_ref_str = """<?xml version="1.0" encoding="utf-8"?>
    
  98. <django-objects version="1.0">
    
  99.     <object pk="1" model="serializers.article">
    
  100.         <field to="serializers.author" name="author" rel="ManyToOneRel">1</field>
    
  101.         <field type="CharField" name="headline">Forward references pose no problem</field>
    
  102.         <field type="DateTimeField" name="pub_date">2006-06-16T15:00:00</field>
    
  103.         <field to="serializers.category" name="categories" rel="ManyToManyRel">
    
  104.             <object pk="1"></object>
    
  105.         </field>
    
  106.         <field to="serializers.categorymetadata" name="meta_data" rel="ManyToManyRel"></field>
    
  107.     </object>
    
  108.     <object pk="1" model="serializers.author">
    
  109.         <field type="CharField" name="name">Agnes</field>
    
  110.     </object>
    
  111.     <object pk="1" model="serializers.category">
    
  112.         <field type="CharField" name="name">Reference</field></object>
    
  113. </django-objects>"""  # NOQA