diff --git a/src/Mvp.Xml.Tests/XInclude/XIncludeReaderTests.cs b/src/Mvp.Xml.Tests/XInclude/XIncludeReaderTests.cs index 0b0cd0a..7733b92 100644 --- a/src/Mvp.Xml.Tests/XInclude/XIncludeReaderTests.cs +++ b/src/Mvp.Xml.Tests/XInclude/XIncludeReaderTests.cs @@ -44,7 +44,7 @@ public static void RunAndCompare(string source, string result, bool textAsCDATA, { var doc = new XmlDocument(); doc.PreserveWhitespace = true; - var xir = new XIncludingReader(source); + using var xir = new XIncludingReader(source); if (resolver != null) xir.XmlResolver = resolver; xir.ExposeTextInclusionsAsCDATA = textAsCDATA; @@ -284,17 +284,21 @@ public void XmlLangTest() [Fact] public void OuterXmlTest() { - var xir = new XIncludingReader("../../XInclude/tests/document.xml"); - xir.MoveToContent(); - var outerXml = xir.ReadOuterXml(); - xir.Close(); - xir = new XIncludingReader("../../XInclude/tests/document.xml"); - xir.MoveToContent(); - var doc = new XmlDocument(); - doc.PreserveWhitespace = true; - doc.Load(xir); - var outerXml2 = doc.DocumentElement.OuterXml; - Assert.Equal(outerXml, outerXml2); + string outerXml; + using (var xir = new XIncludingReader("../../XInclude/tests/document.xml")) + { + xir.MoveToContent(); + outerXml = xir.ReadOuterXml(); + } + using (var xir = new XIncludingReader("../../XInclude/tests/document.xml")) + { + xir.MoveToContent(); + var doc = new XmlDocument(); + doc.PreserveWhitespace = true; + doc.Load(xir); + var outerXml2 = doc.DocumentElement.OuterXml; + Assert.Equal(outerXml, outerXml2); + } } /// @@ -303,17 +307,21 @@ public void OuterXmlTest() [Fact] public void InnerXmlTest() { - var xir = new XIncludingReader("../../XInclude/tests/document.xml"); - xir.MoveToContent(); - var innerXml = xir.ReadInnerXml(); - xir.Close(); - xir = new XIncludingReader("../../XInclude/tests/document.xml"); - xir.MoveToContent(); - var doc = new XmlDocument(); - doc.PreserveWhitespace = true; - doc.Load(xir); - var innerXml2 = doc.DocumentElement.InnerXml; - Assert.Equal(innerXml, innerXml2); + string innerXml; + using (var xir = new XIncludingReader("../../XInclude/tests/document.xml")) + { + xir.MoveToContent(); + innerXml = xir.ReadInnerXml(); + } + using (var xir = new XIncludingReader("../../XInclude/tests/document.xml")) + { + xir.MoveToContent(); + var doc = new XmlDocument(); + doc.PreserveWhitespace = true; + doc.Load(xir); + var innerXml2 = doc.DocumentElement.InnerXml; + Assert.Equal(innerXml, innerXml2); + } } /// @@ -322,7 +330,7 @@ public void InnerXmlTest() [Fact] public void DepthTest() { - var xir = new XIncludingReader("../../XInclude/tests/document.xml"); + using var xir = new XIncludingReader("../../XInclude/tests/document.xml"); var sb = new StringBuilder(); while (xir.Read()) { @@ -364,7 +372,7 @@ public void NoBaseURITest() Assert.Throws(() => { - var xir = new XIncludingReader(new StringReader(xml)); + using var xir = new XIncludingReader(new StringReader(xml)); var w = XmlWriter.Create(Console.Out); while (xir.Read()) ; }); @@ -391,7 +399,7 @@ public void LoopTest() [Fact] public void GetAttributeTest() { - var xir = new XIncludingReader("../../XInclude/tests/document.xml"); + using var xir = new XIncludingReader("../../XInclude/tests/document.xml"); while (xir.Read()) { if (xir.NodeType == XmlNodeType.Element && xir.Name == "disclaimer") @@ -406,7 +414,7 @@ public void GetAttributeTest() [Fact] public void GetAttributeTest2() { - var xir = new XIncludingReader("../../XInclude/tests/document2.xml"); + using var xir = new XIncludingReader("../../XInclude/tests/document2.xml"); xir.MakeRelativeBaseUri = false; while (xir.Read()) { @@ -422,7 +430,7 @@ public void GetAttributeTest2() [Fact] public void GetAttributeTest3() { - var xir = new XIncludingReader("../../XInclude/tests/document.xml"); + using var xir = new XIncludingReader("../../XInclude/tests/document.xml"); while (xir.Read()) { if (xir.NodeType == XmlNodeType.Element && xir.Name == "disclaimer") @@ -438,7 +446,7 @@ public void GetAttributeTest3() [Fact] public void GetAttributeTest4() { - var xir = new XIncludingReader("../../XInclude/tests/document2.xml"); + using var xir = new XIncludingReader("../../XInclude/tests/document2.xml"); xir.MakeRelativeBaseUri = false; while (xir.Read()) { @@ -470,7 +478,7 @@ public void SerializerTest() public void EncodingTest() { var r = new XmlTextReader(new StringReader("")); - var xir = new XIncludingReader(r); + using var xir = new XIncludingReader(r); xir.ExposeTextInclusionsAsCDATA = true; xir.MoveToContent(); Assert.True(xir.Encoding == UnicodeEncoding.Unicode); @@ -480,7 +488,7 @@ public void EncodingTest() public void ShouldPreserveCDATA() { var xml = "]]>"; - var xir = new XIncludingReader(new StringReader(xml)); + using var xir = new XIncludingReader(new StringReader(xml)); xir.Read(); Assert.Equal("]]>", xir.ReadOuterXml()); } @@ -496,7 +504,7 @@ public void TestXPointerIndentationBug() var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Parse }; //settings.ProhibitDtd = false; var reader = XmlReader.Create("../../XInclude/tests/Transform.xsl", settings); - var xInputReader = new XIncludingReader("../../XInclude/tests/FileA.xml"); + using var xInputReader = new XIncludingReader("../../XInclude/tests/FileA.xml"); try { var processor = new MvpXslTransform(false); @@ -521,7 +529,7 @@ public void TestXPointerIndentationBug() [Fact] public void TestLineInfo() { - var r = new XIncludingReader("../../XInclude/tests/document.xml"); + using var r = new XIncludingReader("../../XInclude/tests/document.xml"); var lineInfo = ((IXmlLineInfo)r); Assert.True(lineInfo.HasLineInfo()); r.Read(); @@ -594,6 +602,82 @@ public void TestLineInfo() Assert.Equal(6, lineInfo.LineNumber); Assert.Equal(12, lineInfo.LinePosition); } + + [Fact] + public void DisposeInternalStreams() + { + using (var xir = new XIncludingReader("../../XInclude/tests/document.xml")) + { + while (xir.Read()) ; + } + + using (var stream = new FileStream("../../XInclude/tests/document.xml", FileMode.Open, FileAccess.ReadWrite)) + { + // success! + } + + using (var stream = new FileStream("../../XInclude/tests/disclaimer.xml", FileMode.Open, FileAccess.ReadWrite)) + { + // success! + } + } + + [Fact] + public void DisposeInternalStreamsResolver() + { + using (var xir = new XIncludingReader("../../XInclude/tests/document.xml") { XmlResolver = new TestResolver() }) + { + while (xir.Read()) ; + } + + using (var stream = new FileStream("../../XInclude/tests/document.xml", FileMode.Open, FileAccess.ReadWrite)) + { + // success! + } + + using (var stream = new FileStream("../../XInclude/tests/disclaimer.xml", FileMode.Open, FileAccess.ReadWrite)) + { + // success! + } + } + + [Fact] + public void DisposeInternalStreamsXPointer() + { + using (var xir = new XIncludingReader("../../XInclude/tests/xpointer.xml")) + { + while (xir.Read()) ; + } + + using (var stream = new FileStream("../../XInclude/tests/xpointer.xml", FileMode.Open, FileAccess.ReadWrite)) + { + // success! + } + + using (var stream = new FileStream("../../XInclude/tests/test2.xml", FileMode.Open, FileAccess.ReadWrite)) + { + // success! + } + } + + [Fact] + public void DisposeInternalStreamsXPointerResolver() + { + using (var xir = new XIncludingReader("../../XInclude/tests/xpointer.xml") { XmlResolver = new TestResolver() }) + { + while (xir.Read()) ; + } + + using (var stream = new FileStream("../../XInclude/tests/xpointer.xml", FileMode.Open, FileAccess.ReadWrite)) + { + // success! + } + + using (var stream = new FileStream("../../XInclude/tests/test2.xml", FileMode.Open, FileAccess.ReadWrite)) + { + // success! + } + } } //public class XMLBase : XmlUrlResolver diff --git a/src/Mvp.Xml/Common/XmlBaseAwareXmlReader.cs b/src/Mvp.Xml/Common/XmlBaseAwareXmlReader.cs index 7b10d4a..9e9416d 100644 --- a/src/Mvp.Xml/Common/XmlBaseAwareXmlReader.cs +++ b/src/Mvp.Xml/Common/XmlBaseAwareXmlReader.cs @@ -114,7 +114,8 @@ public XmlBaseAwareXmlReader(string uri, Stream stream, XmlNameTable nt) : base( /// /// Creates XmlBaseAwareXmlReader instance for given uri and . /// - public XmlBaseAwareXmlReader(string uri, XmlReaderSettings settings) : base(Create(uri, settings)) { } + public XmlBaseAwareXmlReader(string uri, XmlReaderSettings settings) : base(Create(uri, settings)) + => state.BaseUri = new Uri(base.BaseURI); /// /// Creates XmlBaseAwareXmlReader instance for given and . @@ -136,14 +137,16 @@ public XmlBaseAwareXmlReader(XmlReader reader, XmlReaderSettings settings) : bas /// , /// and base uri. /// - public XmlBaseAwareXmlReader(TextReader reader, XmlReaderSettings settings, string baseUri) : base(Create(reader, settings, baseUri)) { } + public XmlBaseAwareXmlReader(TextReader reader, XmlReaderSettings settings, string baseUri) : base(Create(reader, settings, baseUri)) + => state.BaseUri = new Uri(base.BaseURI); /// /// Creates XmlBaseAwareXmlReader instance for given /// , /// and base uri. /// - public XmlBaseAwareXmlReader(Stream stream, XmlReaderSettings settings, string baseUri) : base(Create(stream, settings, baseUri)) { } + public XmlBaseAwareXmlReader(Stream stream, XmlReaderSettings settings, string baseUri) : base(Create(stream, settings, baseUri)) + => state.BaseUri = new Uri(base.BaseURI); /// /// See . diff --git a/src/Mvp.Xml/XInclude/XIncludingReader.cs b/src/Mvp.Xml/XInclude/XIncludingReader.cs index be29c23..1644297 100644 --- a/src/Mvp.Xml/XInclude/XIncludingReader.cs +++ b/src/Mvp.Xml/XInclude/XIncludingReader.cs @@ -1260,24 +1260,16 @@ string CreateAcquiredInfoset(Uri includeLocation) var stream = GetResource(includeLocation.AbsoluteUri, reader.GetAttribute(keywords.Accept), reader.GetAttribute(keywords.AcceptLanguage), out var wRes); - var xir = new XIncludingReader(wRes.ResponseUri.AbsoluteUri, stream, nameTable) - { - WhitespaceHandling = WhitespaceHandling - }; var sw = new StringWriter(); - var w = new XmlTextWriter(sw); - try + using (var r = new XmlBaseAwareXmlReader(stream, CreateReaderSettings(), wRes.ResponseUri.AbsoluteUri)) + using (var xir = new XIncludingReader(r) { WhitespaceHandling = WhitespaceHandling }) + using (var w = new XmlTextWriter(sw)) { while (xir.Read()) { w.WriteNode(xir, false); } } - finally - { - xir.Close(); - w.Close(); - } var content = sw.ToString(); lock (cache) { @@ -1295,7 +1287,7 @@ string CreateAcquiredInfoset(Uri includeLocation) /// Source reader /// Base URI string CreateAcquiredInfoset(Uri includeLocation, TextReader sourceReader) => CreateAcquiredInfoset( - new XmlBaseAwareXmlReader(includeLocation.AbsoluteUri, sourceReader, nameTable)); + new XmlBaseAwareXmlReader(sourceReader, CreateReaderSettings(), includeLocation.AbsoluteUri)); /// /// Creates acquired infoset. @@ -1360,7 +1352,7 @@ bool ProcessInterDocXmlInclusion(string href, string xpointer) // XmlResolver = xmlResolver, // IgnoreWhitespace = (WhitespaceHandling == WhitespaceHandling.None) //}; - XmlReader r = new XmlBaseAwareXmlReader(wRes.ResponseUri.AbsoluteUri, stream, nameTable); + XmlReader r = new XmlBaseAwareXmlReader(stream, CreateReaderSettings(), wRes.ResponseUri.AbsoluteUri); reader = r; } return Read(); @@ -1420,7 +1412,7 @@ bool ProcessInterDocXmlInclusion(string href, string xpointer) //No XPointer if (resource is TextReader tr) { - reader = new XmlBaseAwareXmlReader(includeLocation.AbsoluteUri, tr, nameTable); + reader = new XmlBaseAwareXmlReader(tr, CreateReaderSettings(), includeLocation.AbsoluteUri); } else if (resource is XmlReader xr) { @@ -1491,4 +1483,6 @@ string GetBaseUri() return reader.BaseURI; } + + XmlReaderSettings CreateReaderSettings() => new() { DtdProcessing = DtdProcessing.Parse, NameTable = nameTable, CloseInput = true }; } diff --git a/src/nuget.config b/src/nuget.config index ef2b768..930055a 100644 --- a/src/nuget.config +++ b/src/nuget.config @@ -13,6 +13,7 @@ +