Skip to content

Commit

Permalink
don't leave included files open after closing XIncludeReader
Browse files Browse the repository at this point in the history
  • Loading branch information
epithet authored and kzu committed Feb 7, 2025
1 parent 42ab1cd commit eeeaa17
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 50 deletions.
150 changes: 117 additions & 33 deletions src/Mvp.Xml.Tests/XInclude/XIncludeReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}

/// <summary>
Expand All @@ -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);
}
}

/// <summary>
Expand All @@ -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())
{
Expand Down Expand Up @@ -364,7 +372,7 @@ public void NoBaseURITest()

Assert.Throws<FatalResourceException>(() =>
{
var xir = new XIncludingReader(new StringReader(xml));
using var xir = new XIncludingReader(new StringReader(xml));
var w = XmlWriter.Create(Console.Out);
while (xir.Read()) ;
});
Expand All @@ -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")
Expand All @@ -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())
{
Expand All @@ -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")
Expand All @@ -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())
{
Expand Down Expand Up @@ -470,7 +478,7 @@ public void SerializerTest()
public void EncodingTest()
{
var r = new XmlTextReader(new StringReader("<foo/>"));
var xir = new XIncludingReader(r);
using var xir = new XIncludingReader(r);
xir.ExposeTextInclusionsAsCDATA = true;
xir.MoveToContent();
Assert.True(xir.Encoding == UnicodeEncoding.Unicode);
Expand All @@ -480,7 +488,7 @@ public void EncodingTest()
public void ShouldPreserveCDATA()
{
var xml = "<HTML><![CDATA[<img src=\"/_layouts/images/\">]]></HTML>";
var xir = new XIncludingReader(new StringReader(xml));
using var xir = new XIncludingReader(new StringReader(xml));
xir.Read();
Assert.Equal("<HTML><![CDATA[<img src=\"/_layouts/images/\">]]></HTML>", xir.ReadOuterXml());
}
Expand All @@ -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);
Expand All @@ -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();
Expand Down Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions src/Mvp.Xml/Common/XmlBaseAwareXmlReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ public XmlBaseAwareXmlReader(string uri, Stream stream, XmlNameTable nt) : base(
/// <summary>
/// Creates XmlBaseAwareXmlReader instance for given uri and <see cref="XmlReaderSettings"/>.
/// </summary>
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);

/// <summary>
/// Creates XmlBaseAwareXmlReader instance for given <see cref="TextReader"/> and <see cref="XmlReaderSettings"/>.
Expand All @@ -136,14 +137,16 @@ public XmlBaseAwareXmlReader(XmlReader reader, XmlReaderSettings settings) : bas
/// <see cref="TextReader"/>, <see cref="XmlReaderSettings"/>
/// and base uri.
/// </summary>
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);

/// <summary>
/// Creates XmlBaseAwareXmlReader instance for given
/// <see cref="Stream"/>, <see cref="XmlReaderSettings"/>
/// and base uri.
/// </summary>
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);

/// <summary>
/// See <see cref="XmlTextReader.BaseURI"/>.
Expand Down
22 changes: 8 additions & 14 deletions src/Mvp.Xml/XInclude/XIncludingReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -1295,7 +1287,7 @@ string CreateAcquiredInfoset(Uri includeLocation)
/// <param name="sourceReader">Source reader</param>
/// <param name="includeLocation">Base URI</param>
string CreateAcquiredInfoset(Uri includeLocation, TextReader sourceReader) => CreateAcquiredInfoset(
new XmlBaseAwareXmlReader(includeLocation.AbsoluteUri, sourceReader, nameTable));
new XmlBaseAwareXmlReader(sourceReader, CreateReaderSettings(), includeLocation.AbsoluteUri));

/// <summary>
/// Creates acquired infoset.
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -1491,4 +1483,6 @@ string GetBaseUri()

return reader.BaseURI;
}

XmlReaderSettings CreateReaderSettings() => new() { DtdProcessing = DtdProcessing.Parse, NameTable = nameTable, CloseInput = true };
}

0 comments on commit eeeaa17

Please sign in to comment.