changeset 2023:8300781142e5

make contenttype values pass the validator (add charset for text), fix namespace and name validators mimetype string generation: remove blank after semicolon
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sun, 03 Mar 2013 01:41:14 +0100
parents 2bab30fa0309
children 2d11470eb41b
files MoinMoin/_tests/test_test_environ.py MoinMoin/apps/frontend/_tests/test_frontend.py MoinMoin/converter/_tests/test_include.py MoinMoin/items/_tests/test_Blog.py MoinMoin/items/_tests/test_Content.py MoinMoin/items/_tests/test_Item.py MoinMoin/storage/middleware/_tests/test_indexing.py MoinMoin/storage/middleware/_tests/test_protecting.py MoinMoin/storage/middleware/_tests/test_serialization.py MoinMoin/storage/middleware/validation.py MoinMoin/util/_tests/test_mimetype.py MoinMoin/util/mimetype.py
diffstat 12 files changed, 87 insertions(+), 84 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/_tests/test_test_environ.py	Sat Mar 02 23:40:17 2013 +0100
+++ b/MoinMoin/_tests/test_test_environ.py	Sun Mar 03 01:41:14 2013 +0100
@@ -30,7 +30,7 @@
         itemname = u"this item shouldn't exist yet"
         assert not storage.has_item(itemname)
         item = storage[itemname]
-        new_rev = item.store_revision({NAME: [itemname, ], CONTENTTYPE: u'text/plain'}, StringIO(''))
+        new_rev = item.store_revision({NAME: [itemname, ], CONTENTTYPE: u'text/plain;charset=utf-8'}, StringIO(''))
         assert storage.has_item(itemname)
 
 
--- a/MoinMoin/apps/frontend/_tests/test_frontend.py	Sat Mar 02 23:40:17 2013 +0100
+++ b/MoinMoin/apps/frontend/_tests/test_frontend.py	Sun Mar 03 01:41:14 2013 +0100
@@ -77,7 +77,7 @@
 
     def test_jfu_server(self):
         self._test_view_post('frontend.jfu_server', status='200 OK', data=['{', '}'], form=dict(
-            data_file=FileStorage(StringIO("Hello, world"), filename='C:\\fakepath\\DoesntExist.txt', content_type='text/plain'),
+            data_file=FileStorage(StringIO("Hello, world"), filename='C:\\fakepath\\DoesntExist.txt', content_type='text/plain; charset=utf-8'),
         ), viewopts=dict(item_name='WillBeCreated'), content_types=['application/json', ])
 
     def test_show_item(self):
--- a/MoinMoin/converter/_tests/test_include.py	Sat Mar 02 23:40:17 2013 +0100
+++ b/MoinMoin/converter/_tests/test_include.py	Sun Mar 03 01:41:14 2013 +0100
@@ -64,10 +64,10 @@
 
     def test_IncludeHandlesCircularRecursion(self):
         # detect circular recursion and create error message
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'{{page2}}')
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u'{{page3}}')
-        update_item(u'page3', {CONTENTTYPE: u'text/x.moin.wiki'}, u'{{page4}}')
-        update_item(u'page4', {CONTENTTYPE: u'text/x.moin.wiki'}, u'{{page2}}')
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'{{page2}}')
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'{{page3}}')
+        update_item(u'page3', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'{{page4}}')
+        update_item(u'page4', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'{{page2}}')
         page1 = Item.create(u'page1')
         rendered = page1.content._render_data()
         # an error message will follow strong tag
@@ -75,61 +75,61 @@
 
     def test_ExternalInclude(self):
         # external include
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'{{http://moinmo.in}}')
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'{{http://moinmo.in}}')
         rendered = Item.create(u'page1').content._render_data()
         assert '<object class="moin-http moin-transclusion" data="http://moinmo.in" data-href="http://moinmo.in">http://moinmo.in</object>' in rendered
         # external include embedded within text (object is an inline tag)
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'before {{http://moinmo.in}} after')
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'before {{http://moinmo.in}} after')
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>before <object class="moin-http moin-transclusion" data="http://moinmo.in" data-href="http://moinmo.in">http://moinmo.in</object> after</p>' in rendered
         # external include embedded within text italic and bold markup (object is an inline tag)
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u"before ''italic '''bold {{http://moinmo.in}} bold''' italic'' normal")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"before ''italic '''bold {{http://moinmo.in}} bold''' italic'' normal")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>before <em>italic <strong>bold <object class="moin-http moin-transclusion" data="http://moinmo.in" data-href="http://moinmo.in">http://moinmo.in</object> bold</strong> italic</em> normal</p>' in rendered
 
     def test_InlineInclude(self):
 
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'before {{page2}} after')
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'before {{page2}} after')
         # transclude single paragraph as inline
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Single line')
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'Single line')
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>before <span class="moin-transclusion" data-href="/page2">Single line</span> after</p>' in rendered
         # transclude multiple paragraphs as block
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Two\n\nParagraphs')
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'Two\n\nParagraphs')
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>before </p><div class="moin-transclusion" data-href="/page2"><p>Two</p><p>Paragraphs</p></div><p> after</p></div>' in rendered
         # transclude single paragraph with internal markup as inline
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"this text contains ''italic'' string")
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"this text contains ''italic'' string")
         rendered = Item.create(u'page1').content._render_data()
         assert 'before <span class="moin-transclusion" data-href="/page2">this text contains <em>italic</em>' in rendered
         # transclude single paragraph as only content within a paragraph
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Content of page2 is\n\n{{page2}}')
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"Single Line")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'Content of page2 is\n\n{{page2}}')
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"Single Line")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>Content of page2 is</p><p><span class="moin-transclusion" data-href="/page2">Single Line</span></p>' in rendered
         # transclude single row table within a paragraph, block element forces paragraph to be split into 2 parts
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'before {{page2}} after')
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"|| table || cell ||")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'before {{page2}} after')
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"|| table || cell ||")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>before </p><div class="moin-transclusion" data-href="/page2"><table' in rendered
         assert '</table></div><p> after</p>' in rendered
         assert rendered.count('<table>') == 1
         # transclude two row table within a paragraph, block element forces paragraph to be split into 2 parts
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'before {{page2}} after')
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"|| this || has ||\n|| two || rows ||")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'before {{page2}} after')
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"|| this || has ||\n|| two || rows ||")
         rendered = Item.create(u'page1').content._render_data()
         # inclusion of block item within a paragraph results in a before and after p
         assert '<p>before </p><div class="moin-transclusion" data-href="/page2"><table' in rendered
         assert '</table></div><p> after</p>' in rendered
         assert rendered.count('<table>') == 1
         # transclude nonexistent item
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'before {{nonexistent}} after')
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'before {{nonexistent}} after')
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>before <span class="moin-transclusion" data-href="/nonexistent"><a href="/+modify/nonexistent">' in rendered
         assert '</a></span> after</p>' in rendered
         # transclude empty item
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'text {{page2}} text')
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'text {{page2}} text')
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>text <span class="moin-transclusion" data-href="/page2"></span> text</p>' in rendered
 
@@ -142,23 +142,23 @@
 
     def test_InlineIncludeWithinMarkup(self):
         # transclude single line item within italic and bold markup
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u"Normal ''italic '''bold {{page2}} bold''' italic'' normal")
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"Single Line")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"Normal ''italic '''bold {{page2}} bold''' italic'' normal")
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"Single Line")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>Normal <em>italic <strong>bold <span class="moin-transclusion" data-href="/page2">Single Line</span> bold</strong> italic</em> normal</p>' in rendered
         # transclude double line item within italic and bold markup
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u"Normal ''italic '''bold {{page2}} bold''' italic'' normal")
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"Double\n\nLine")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"Normal ''italic '''bold {{page2}} bold''' italic'' normal")
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"Double\n\nLine")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>Normal <em>italic <strong>bold </strong></em></p><div class="moin-transclusion" data-href="/page2"><p>Double</p><p>Line</p></div><p><em><strong> bold</strong> italic</em> normal</p>' in rendered
         # transclude single line item within comment
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u"comment /* before {{page2}} after */")
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"Single Line")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"comment /* before {{page2}} after */")
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"Single Line")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>comment <span class="comment">before <span class="moin-transclusion" data-href="/page2">Single Line</span> after</span></p>' in rendered
         # transclude double line item within comment
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u"comment /* before {{page2}} after */")
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"Double\n\nLine")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"comment /* before {{page2}} after */")
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"Double\n\nLine")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>comment <span class="comment">before </span></p><div class="comment moin-transclusion" data-href="/page2"><p>Double</p><p>Line</p></div><p><span class="comment"> after</span></p>' in rendered
 
@@ -166,22 +166,22 @@
         # the 3rd parameter, u'',  should be a binary string defining a png image, but it is not needed for this simple test
         update_item(u'logo.png', {CONTENTTYPE: u'image/png'}, u'')
         # simple transclusion
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'{{logo.png}}')
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'{{logo.png}}')
         rendered = Item.create(u'page1').content._render_data()
         assert '<p><span class="moin-transclusion" data-href="/logo.png"><img alt="logo.png" src=' in rendered
         assert '/logo.png" /></span></p>' in rendered
         # within paragraph
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'text {{logo.png}} text')
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'text {{logo.png}} text')
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>text <span class="moin-transclusion" data-href="/logo.png"><img alt="logo.png" src=' in rendered
         assert '/logo.png" /></span> text</p>' in rendered
         # within markup
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u"Normal ''italic '''bold {{logo.png}} bold''' italic'' normal")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"Normal ''italic '''bold {{logo.png}} bold''' italic'' normal")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>Normal <em>italic <strong>bold <span class="moin-transclusion" data-href="/logo.png"><img alt="logo.png" src=' in rendered
         assert '/logo.png" /></span> bold</strong> italic</em> normal</p>' in rendered
         # multiple transclusions
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'{{logo.png}}{{logo.png}}')
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'{{logo.png}}{{logo.png}}')
         rendered = Item.create(u'page1').content._render_data()
         assert '<p><span class="moin-transclusion" data-href="/logo.png"><img alt="logo.png" src=' in rendered
         assert '/logo.png" /></span><span class="moin-transclusion" data-href="/logo.png"><img alt="logo.png" src=' in rendered
@@ -191,41 +191,41 @@
 
     def test_IncludeAsLinkAlternate(self):
         # image as link alternate
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u"text [[page2|{{logo.png}}]] text")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"text [[page2|{{logo.png}}]] text")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>text <a href="/page2"><span class="moin-transclusion" data-href="/logo.png"><img alt="logo.png" src="' in rendered
         assert '/logo.png" /></span></a> text</p>' in rendered
         # link alternate with image embedded in markup
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u"text [[page2|plain '''bold {{logo.png}} bold''' plain]] text")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"text [[page2|plain '''bold {{logo.png}} bold''' plain]] text")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>text <a href="/page2">plain <strong>bold <span class="moin-transclusion" data-href="/logo.png"><img alt="logo.png" src="' in rendered
         assert '/logo.png" /></span> bold</strong> plain</a> text</p>' in rendered
         # nonexistent image used in link alternate
         # XXX html validation errora: A inside A - the image alternate turns into an A-tag to create the non-existant image.  Error is easily seen.
         # IE9, Firefox, Chrome, Safari, and Opera display this OK;  the only usable hyperlink is to create the missing image.
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u"text [[page2|{{logoxxx.png}}]] text")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"text [[page2|{{logoxxx.png}}]] text")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>text <a href="/page2"><span class="moin-transclusion" data-href="/logoxxx.png"><a href="/+modify/logoxxx.png">' in rendered
         assert '</a></span></a> text</p>' in rendered
         # image used as alternate to nonexistent page
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u"text [[page2xxx|{{logo.png}}]] text")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"text [[page2xxx|{{logo.png}}]] text")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>text <a class="moin-nonexistent" href="/page2xxx"><span class="moin-transclusion" data-href="/logo.png"><img alt="logo.png" src="' in rendered
         assert '/logo.png" /></span></a> text</p>' in rendered
         # transclude block elem as link alternate to nonexistent page
         # XXX html validation errors, block element inside A.
         # IE9, Firefox, Chrome, Safari, and Opera display this OK;  the hyperlink is the entire div enclosing the block elem
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'text [[MyPage|{{page2}}]] text')
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"Double\n\nLine")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'text [[MyPage|{{page2}}]] text')
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"Double\n\nLine")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>text <a class="moin-nonexistent" href="/MyPage"><div class="moin-transclusion" data-href="/page2"><p>Double</p><p>Line</p></div></a> text</p>' in rendered
         # transclude empty item as link alternate to nonexistent page
         # hyperlink will be empty span and invisible
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'text [[MyPage|{{page2}}]] text')
-        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"")
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'text [[MyPage|{{page2}}]] text')
+        update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u"")
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>text <a class="moin-nonexistent" href="/MyPage"><span class="moin-transclusion" data-href="/page2"></span></a> text</p>' in rendered
         # transclude external page as link alternate to nonexistent page
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'text [[MyPage|{{http://moinmo.in}}]] text')
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'text [[MyPage|{{http://moinmo.in}}]] text')
         rendered = Item.create(u'page1').content._render_data()
         assert '<p>text <a class="moin-nonexistent" href="/MyPage"><object class="moin-http moin-transclusion" data="http://moinmo.in" data-href="http://moinmo.in">http://moinmo.in</object></a> text</p>' in rendered
--- a/MoinMoin/items/_tests/test_Blog.py	Sat Mar 02 23:40:17 2013 +0100
+++ b/MoinMoin/items/_tests/test_Blog.py	Sun Mar 03 01:41:14 2013 +0100
@@ -33,7 +33,7 @@
     NO_ENTRIES_MSG = u"There are no entries"
 
     name = u'NewBlogItem'
-    contenttype = u'text/x.moin.wiki'
+    contenttype = u'text/x.moin.wiki;charset=utf-8'
     data = u"This is the header item of this blog"
     meta = {CONTENTTYPE: contenttype, ITEMTYPE: ITEMTYPE_BLOG}
     comment = u'saved it'
@@ -138,7 +138,7 @@
 
 class TestBlogEntry(TestView):
     blog_name = u'NewBlogItem'
-    contenttype = u'text/x.moin.wiki'
+    contenttype = u'text/x.moin.wiki;charset=utf-8'
     blog_data = u"This is the header item of this blog"
     blog_meta = {CONTENTTYPE: contenttype, ITEMTYPE: ITEMTYPE_BLOG}
     comment = u'saved it'
--- a/MoinMoin/items/_tests/test_Content.py	Sat Mar 02 23:40:17 2013 +0100
+++ b/MoinMoin/items/_tests/test_Content.py	Sun Mar 03 01:41:14 2013 +0100
@@ -39,14 +39,14 @@
     def test_get_templates(self):
         item_name1 = u'Template_Item1'
         item1 = Item.create(item_name1)
-        contenttype1 = u'text/plain'
+        contenttype1 = u'text/plain;charset=utf-8'
         meta = {CONTENTTYPE: contenttype1, TAGS: ['template']}
         item1._save(meta)
         item1 = Item.create(item_name1)
 
         item_name2 = u'Template_Item2'
         item2 = Item.create(item_name2)
-        contenttype1 = u'text/plain'
+        contenttype1 = u'text/plain;charset=utf-8'
         meta = {CONTENTTYPE: contenttype1, TAGS: ['template']}
         item2._save(meta)
         item2 = Item.create(item_name2)
@@ -179,7 +179,7 @@
 
     def test_data_conversion(self):
         item_name = u'Text_Item'
-        item = Item.create(item_name, ITEMTYPE_DEFAULT, u'text/plain')
+        item = Item.create(item_name, ITEMTYPE_DEFAULT, u'text/plain;charset=utf-8')
         test_text = u'This \n is \n a \n Test'
         # test for data_internal_to_form
         result = Text.data_internal_to_form(item.content, test_text)
@@ -230,7 +230,7 @@
     def test__render_data_diff_text(self):
         item_name = u'Text_Item'
         item = Item.create(item_name)
-        contenttype = u'text/plain'
+        contenttype = u'text/plain;charset=utf-8'
         meta = {CONTENTTYPE: contenttype}
         item._save(meta)
         item1 = Item.create(item_name)
@@ -246,7 +246,7 @@
     def test__render_data_highlight(self):
         item_name = u'Text_Item'
         item = Item.create(item_name)
-        contenttype = u'text/plain'
+        contenttype = u'text/plain;charset=utf-8'
         meta = {CONTENTTYPE: contenttype}
         item._save(meta)
         item1 = Item.create(item_name)
--- a/MoinMoin/items/_tests/test_Item.py	Sat Mar 02 23:40:17 2013 +0100
+++ b/MoinMoin/items/_tests/test_Item.py	Sun Mar 03 01:41:14 2013 +0100
@@ -160,16 +160,16 @@
                     {NAME: [u'Page',
                             u'Another name',
                             ],
-                     CONTENTTYPE: u'text/x.moin.wiki'}, content)
+                     CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, content)
 
         item1 = Item.create(u'Page')
         assert item1.name == u'Page'
-        assert item1.meta[CONTENTTYPE] == 'text/x.moin.wiki'
+        assert item1.meta[CONTENTTYPE] == 'text/x.moin.wiki;charset=utf-8'
         assert item1.content.data == content
 
         item2 = Item.create(u'Another name')
         assert item2.name == u'Another name'
-        assert item2.meta[CONTENTTYPE] == 'text/x.moin.wiki'
+        assert item2.meta[CONTENTTYPE] == 'text/x.moin.wiki;charset=utf-8'
         assert item2.content.data == content
 
         assert item1.rev.revid == item2.rev.revid
@@ -208,24 +208,24 @@
                             u'Second',
                             u'Third',
                             ],
-                     CONTENTTYPE: u'text/x.moin.wiki'}, content)
+                     CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, content)
 
         item = Item.create(u'Second')
         item.rename(u'New name', comment=u'renamed')
 
         item1 = Item.create(u'First')
         assert item1.name == u'First'
-        assert item1.meta[CONTENTTYPE] == 'text/x.moin.wiki'
+        assert item1.meta[CONTENTTYPE] == 'text/x.moin.wiki;charset=utf-8'
         assert item1.content.data == content
 
         item2 = Item.create(u'New name')
         assert item2.name == u'New name'
-        assert item2.meta[CONTENTTYPE] == 'text/x.moin.wiki'
+        assert item2.meta[CONTENTTYPE] == 'text/x.moin.wiki;charset=utf-8'
         assert item2.content.data == content
 
         item3 = Item.create(u'Third')
         assert item3.name == u'Third'
-        assert item3.meta[CONTENTTYPE] == 'text/x.moin.wiki'
+        assert item3.meta[CONTENTTYPE] == 'text/x.moin.wiki;charset=utf-8'
         assert item3.content.data == content
 
         assert item1.rev.revid == item2.rev.revid == item3.rev.revid
@@ -234,9 +234,9 @@
         assert item4.meta[CONTENTTYPE] == CONTENTTYPE_NONEXISTENT
 
     def test_rename_recursion(self):
-        update_item(u'Page', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Page 1')
-        update_item(u'Page/Child', {CONTENTTYPE: u'text/x.moin.wiki'}, u'this is child')
-        update_item(u'Page/Child/Another', {CONTENTTYPE: u'text/x.moin.wiki'}, u'another child')
+        update_item(u'Page', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'Page 1')
+        update_item(u'Page/Child', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'this is child')
+        update_item(u'Page/Child/Another', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'another child')
 
         item = Item.create(u'Page')
         item.rename(u'Renamed_Page', comment=u'renamed')
@@ -273,17 +273,17 @@
 
     def test_rename_recursion_with_multiple_names_and_children(self):
         update_item(u'Foo', {
-            CONTENTTYPE: u'text/x.moin.wiki',
+            CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8',
             NAME: [u'Other', u'Page', u'Foo'],
         }, u'Parent')
-        update_item(u'Page/Child', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Child of Page')
-        update_item(u'Other/Child2', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Child of Other')
+        update_item(u'Page/Child', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'Child of Page')
+        update_item(u'Other/Child2', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'Child of Other')
         update_item(u'Another', {
-            CONTENTTYPE: u'text/x.moin.wiki',
+            CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8',
             NAME: [u'Another', u'Page/Second'],
         }, u'Both')
-        update_item(u'Page/Second/Child', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Child of Second')
-        update_item(u'Another/Child', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Child of Another')
+        update_item(u'Page/Second/Child', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'Child of Second')
+        update_item(u'Another/Child', {CONTENTTYPE: u'text/x.moin.wiki;charset=utf-8'}, u'Child of Another')
 
         item = Item.create(u'Page')
 
--- a/MoinMoin/storage/middleware/_tests/test_indexing.py	Sat Mar 02 23:40:17 2013 +0100
+++ b/MoinMoin/storage/middleware/_tests/test_indexing.py	Sun Mar 03 01:41:14 2013 +0100
@@ -356,7 +356,7 @@
         # TODO: this is a very simple check that assumes that data is put 1:1
         # into index' CONTENT field.
         item_name = u'foo'
-        meta = dict(name=[item_name, ], contenttype=u'text/plain')
+        meta = dict(name=[item_name, ], contenttype=u'text/plain;charset=utf-8')
         data = 'some test content\n'
         item = self.imw[item_name]
         data_file = StringIO(data)
@@ -370,11 +370,11 @@
     def test_namespaces(self):
         item_name_n = u'normal'
         item = self.imw[item_name_n]
-        rev_n = item.store_revision(dict(name=[item_name_n, ], contenttype=u'text/plain'),
+        rev_n = item.store_revision(dict(name=[item_name_n, ], contenttype=u'text/plain;charset=utf-8'),
                                     StringIO(str(item_name_n)), return_rev=True)
         item_name_u = u'%s:userprofile' % NAMESPACE_USERPROFILES
         item = self.imw[item_name_u]
-        rev_u = item.store_revision(dict(name=[item_name_u, ], contenttype=u'text/plain'),
+        rev_u = item.store_revision(dict(name=[item_name_u, ], contenttype=u'text/plain;charset=utf-8'),
                                     StringIO(str(item_name_u)), return_rev=True)
         item = self.imw[item_name_n]
         rev_n = item.get_revision(rev_n.revid)
@@ -389,7 +389,7 @@
         item_name = u'child'
         item = self.imw[item_name]
         item.store_revision(dict(name=[u'child', u'p1/a', u'p2/b', u'p2/c', u'p3/p4/d', ],
-                                 contenttype=u'text/plain'),
+                                 contenttype=u'text/plain;charset=utf-8'),
                             StringIO(''))
         item = self.imw[item_name]
         assert item.parentnames == [u'p1', u'p2', u'p3/p4', ]  # one p2 duplicate removed
--- a/MoinMoin/storage/middleware/_tests/test_protecting.py	Sat Mar 02 23:40:17 2013 +0100
+++ b/MoinMoin/storage/middleware/_tests/test_protecting.py	Sun Mar 03 01:41:14 2013 +0100
@@ -63,7 +63,7 @@
         revids = []
         for item_name, acl, content in items:
             item = self.imw[item_name]
-            r = item.store_revision(dict(name=[item_name, ], acl=acl, contenttype=u'text/plain'),
+            r = item.store_revision(dict(name=[item_name, ], acl=acl, contenttype=u'text/plain;charset=utf-8'),
                                     StringIO(content), return_rev=True)
             revids.append(r.revid)
         return revids
@@ -87,26 +87,26 @@
         revid_unprotected, revid_protected = self.make_items(u'joe:write', u'boss:write')
         # now testing:
         item = self.imw[UNPROTECTED]
-        item.store_revision(dict(name=[UNPROTECTED, ], acl=u'joe:write', contenttype=u'text/plain'), StringIO(UNPROTECTED_CONTENT))
+        item.store_revision(dict(name=[UNPROTECTED, ], acl=u'joe:write', contenttype=u'text/plain;charset=utf-8'), StringIO(UNPROTECTED_CONTENT))
         item = self.imw[PROTECTED]
         with pytest.raises(AccessDenied):
-            item.store_revision(dict(name=[PROTECTED, ], acl=u'boss:write', contenttype=u'text/plain'), StringIO(UNPROTECTED_CONTENT))
+            item.store_revision(dict(name=[PROTECTED, ], acl=u'boss:write', contenttype=u'text/plain;charset=utf-8'), StringIO(UNPROTECTED_CONTENT))
 
     def test_write_create(self):
         # now testing:
         item_name = u'newitem'
         item = self.imw[item_name]
-        item.store_revision(dict(name=[item_name, ], contenttype=u'text/plain'), StringIO('new content'))
+        item.store_revision(dict(name=[item_name, ], contenttype=u'text/plain;charset=utf-8'), StringIO('new content'))
 
     def test_overwrite_revision(self):
         revid_unprotected, revid_protected = self.make_items(u'joe:write,destroy', u'boss:write,destroy')
         # now testing:
         item = self.imw[UNPROTECTED]
-        item.store_revision(dict(name=[UNPROTECTED, ], acl=u'joe:write,destroy', contenttype=u'text/plain', revid=revid_unprotected),
+        item.store_revision(dict(name=[UNPROTECTED, ], acl=u'joe:write,destroy', contenttype=u'text/plain;charset=utf-8', revid=revid_unprotected),
                             StringIO(UNPROTECTED_CONTENT), overwrite=True)
         item = self.imw[PROTECTED]
         with pytest.raises(AccessDenied):
-            item.store_revision(dict(name=[PROTECTED, ], acl=u'boss:write,destroy', contenttype=u'text/plain', revid=revid_protected),
+            item.store_revision(dict(name=[PROTECTED, ], acl=u'boss:write,destroy', contenttype=u'text/plain;charset=utf-8', revid=revid_protected),
                                 StringIO(UNPROTECTED_CONTENT), overwrite=True)
 
     def test_destroy_revision(self):
--- a/MoinMoin/storage/middleware/_tests/test_serialization.py	Sat Mar 02 23:40:17 2013 +0100
+++ b/MoinMoin/storage/middleware/_tests/test_serialization.py	Sun Mar 03 01:41:14 2013 +0100
@@ -22,11 +22,11 @@
 
 
 contents = [
-    (u'Foo', {NAME: [u'Foo', ], CONTENTTYPE: u'text/plain'}, ''),
-    (u'Foo', {NAME: [u'Foo', ], CONTENTTYPE: u'text/plain'}, '2nd'),
-    (u'Subdir', {NAME: [u'Subdir', ], CONTENTTYPE: u'text/plain'}, ''),
-    (u'Subdir/Foo', {NAME: [u'Subdir/Foo', ], CONTENTTYPE: u'text/plain'}, ''),
-    (u'Subdir/Bar', {NAME: [u'Subdir/Bar', ], CONTENTTYPE: u'text/plain'}, ''),
+    (u'Foo', {NAME: [u'Foo', ], CONTENTTYPE: u'text/plain;charset=utf-8'}, ''),
+    (u'Foo', {NAME: [u'Foo', ], CONTENTTYPE: u'text/plain;charset=utf-8'}, '2nd'),
+    (u'Subdir', {NAME: [u'Subdir', ], CONTENTTYPE: u'text/plain;charset=utf-8'}, ''),
+    (u'Subdir/Foo', {NAME: [u'Subdir/Foo', ], CONTENTTYPE: u'text/plain;charset=utf-8'}, ''),
+    (u'Subdir/Bar', {NAME: [u'Subdir/Bar', ], CONTENTTYPE: u'text/plain;charset=utf-8'}, ''),
 ]
 
 
--- a/MoinMoin/storage/middleware/validation.py	Sat Mar 02 23:40:17 2013 +0100
+++ b/MoinMoin/storage/middleware/validation.py	Sun Mar 03 01:41:14 2013 +0100
@@ -138,6 +138,9 @@
     """
     if element.raw is Unset:
         element.set(state[keys.NAMESPACE])
+    v = element.value
+    if v is None:
+        return True  # the routing middleware can extract namespace from the name
     return name_validator(element, state)
 
 
@@ -319,7 +322,7 @@
     String.named(keys.PARENTID).validated_by(uuid_validator).using(optional=True),
     String.named(keys.WIKINAME).using(strip=False).validated_by(wikiname_validator),
     String.named(keys.NAMESPACE).using(strip=False).validated_by(namespace_validator),
-    List.named(keys.NAME).of(String.using(strip=False).validated_by(name_validator)),
+    List.named(keys.NAME).of(String.using(strip=False).validated_by(name_validator)).using(optional=True),
     List.named(keys.NAME_OLD).of(String.using(strip=False).validated_by(name_validator)).using(optional=True),
     Integer.named(keys.MTIME).validated_by(mtime_validator),
     String.named(keys.ACTION).validated_by(action_validator),
--- a/MoinMoin/util/_tests/test_mimetype.py	Sat Mar 02 23:40:17 2013 +0100
+++ b/MoinMoin/util/_tests/test_mimetype.py	Sun Mar 03 01:41:14 2013 +0100
@@ -73,7 +73,7 @@
 
         # major == 'text'
         result2 = MimeType_obj.content_type(major='text', minor='plain', charset="utf-16", params=None)
-        expected = 'text/plain; charset="utf-16"'
+        expected = 'text/plain;charset="utf-16"'
         assert result2 == expected
 
         # when all the parameters passed are None
--- a/MoinMoin/util/mimetype.py	Sat Mar 02 23:40:17 2013 +0100
+++ b/MoinMoin/util/mimetype.py	Sun Mar 03 01:41:14 2013 +0100
@@ -170,7 +170,7 @@
         mimestr = "{0}/{1}".format(major, minor)
         params = ['{0}="{1}"'.format(key.lower(), value) for key, value in params.items()]
         params.insert(0, mimestr)
-        return "; ".join(params)
+        return ";".join(params)
 
     def mime_type(self):
         """ return a string major/minor only, no params """