From ff90b2b6bbb25fb216d32048195499af9977564c Mon Sep 17 00:00:00 2001 From: Daniel Renninghoff Date: Fri, 9 Feb 2024 12:31:32 +0100 Subject: [PATCH] Do not use chunked transfer encoding on ASP.NET Core 2.1 Setting the Content-Length header explicitly will disable chunked transfer-encoding. However this was only done for one of the two WriteMessageAsync methods in SoapMessageEncoder. I have changed the other method to also set the Content-Length header. To do this I have used a MemoryStream. The other implementation used a StringWriter, which is not ideal, because it will convert to and from different encodings. We only want to find out the length of the stream, so a MemoryStream is faster and sufficient. Also changed the other WriteMessageAsync implementation to use a MemoryStream and removed the CustomStringWriter class. Fixes #1015 --- src/SoapCore.Tests/Wsdl/WsdlTests.cs | 2 +- src/SoapCore/CustomStringWriter.cs | 23 ------ .../MessageEncoder/SoapMessageEncoder.cs | 77 ++++++++++--------- src/SoapCore/SoapEndpointMiddleware.cs | 4 +- 4 files changed, 44 insertions(+), 62 deletions(-) delete mode 100644 src/SoapCore/CustomStringWriter.cs diff --git a/src/SoapCore.Tests/Wsdl/WsdlTests.cs b/src/SoapCore.Tests/Wsdl/WsdlTests.cs index fb3f734b..537c7b3a 100644 --- a/src/SoapCore.Tests/Wsdl/WsdlTests.cs +++ b/src/SoapCore.Tests/Wsdl/WsdlTests.cs @@ -1169,7 +1169,7 @@ private async Task GetWsdlFromMetaBodyWriter(SoapSerializer serialize using (var memoryStream = new MemoryStream()) { - await encoder.WriteMessageAsync(responseMessage, memoryStream, true); + await encoder.WriteMessageAsync(responseMessage, null, memoryStream, true); memoryStream.Position = 0; using (var streamReader = new StreamReader(memoryStream)) diff --git a/src/SoapCore/CustomStringWriter.cs b/src/SoapCore/CustomStringWriter.cs deleted file mode 100644 index 4294579d..00000000 --- a/src/SoapCore/CustomStringWriter.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.IO; -using System.Text; - -namespace SoapCore -{ - public class CustomStringWriter : StringWriter - { - private readonly Encoding _encoding; - - public CustomStringWriter(Encoding encoding) - { - _encoding = encoding; - } - - public override Encoding Encoding - { - get - { - return _encoding; - } - } - } -} \ No newline at end of file diff --git a/src/SoapCore/MessageEncoder/SoapMessageEncoder.cs b/src/SoapCore/MessageEncoder/SoapMessageEncoder.cs index ce96f0a5..95b94bf4 100644 --- a/src/SoapCore/MessageEncoder/SoapMessageEncoder.cs +++ b/src/SoapCore/MessageEncoder/SoapMessageEncoder.cs @@ -181,41 +181,36 @@ public virtual async Task WriteMessageAsync(Message message, HttpContext httpCon ThrowIfMismatchedMessageVersion(message); - //Custom string writer with custom encoding support - using (var stringWriter = new CustomStringWriter(_writeEncoding)) + using var memoryStream = new MemoryStream(); + using (var xmlTextWriter = XmlWriter.Create(memoryStream, new XmlWriterSettings { - using (var xmlTextWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings - { - OmitXmlDeclaration = _optimizeWriteForUtf8 && _omitXmlDeclaration, //can only omit if utf-8 - Indent = indentXml, - Encoding = _writeEncoding, - CloseOutput = true, - CheckCharacters = _checkXmlCharacters - })) - { - using var xmlWriter = XmlDictionaryWriter.CreateDictionaryWriter(xmlTextWriter); - message.WriteMessage(xmlWriter); - xmlWriter.WriteEndDocument(); - xmlWriter.Flush(); - } - - var data = stringWriter.ToString(); - var soapMessage = _writeEncoding.GetBytes(data); - - //Set Content-length in Response - httpContext.Response.ContentLength = soapMessage.Length; + OmitXmlDeclaration = _optimizeWriteForUtf8 && _omitXmlDeclaration, //can only omit if utf-8 + Indent = indentXml, + Encoding = _writeEncoding, + CloseOutput = false, + CheckCharacters = _checkXmlCharacters + })) + { + using var xmlWriter = XmlDictionaryWriter.CreateDictionaryWriter(xmlTextWriter); + message.WriteMessage(xmlWriter); + xmlWriter.WriteEndDocument(); + xmlWriter.Flush(); + } - if (_overwriteResponseContentType) - { - httpContext.Response.ContentType = ContentType; - } + //Set Content-length in Response + httpContext.Response.ContentLength = memoryStream.Length; - await pipeWriter.WriteAsync(soapMessage); - await pipeWriter.FlushAsync(); + if (_overwriteResponseContentType) + { + httpContext.Response.ContentType = ContentType; } + + memoryStream.Seek(0, SeekOrigin.Begin); + await memoryStream.CopyToAsync(pipeWriter); + await pipeWriter.FlushAsync(); } - public virtual Task WriteMessageAsync(Message message, Stream stream, bool indentXml) + public virtual async Task WriteMessageAsync(Message message, HttpContext httpContext, Stream stream, bool indentXml) { if (message == null) { @@ -229,21 +224,31 @@ public virtual Task WriteMessageAsync(Message message, Stream stream, bool inden ThrowIfMismatchedMessageVersion(message); - using var xmlTextWriter = XmlWriter.Create(stream, new XmlWriterSettings + using var memoryStream = new MemoryStream(); + using (var xmlTextWriter = XmlWriter.Create(memoryStream, new XmlWriterSettings { OmitXmlDeclaration = _optimizeWriteForUtf8 && _omitXmlDeclaration, //can only omit if utf-8, Indent = indentXml, Encoding = _writeEncoding, CloseOutput = false, CheckCharacters = _checkXmlCharacters - }); + })) + { + using var xmlWriter = XmlDictionaryWriter.CreateDictionaryWriter(xmlTextWriter); + message.WriteMessage(xmlWriter); + xmlWriter.WriteEndDocument(); + xmlWriter.Flush(); + } - using var xmlWriter = XmlDictionaryWriter.CreateDictionaryWriter(xmlTextWriter); - message.WriteMessage(xmlWriter); - xmlWriter.WriteEndDocument(); - xmlWriter.Flush(); + if (httpContext != null) // HttpContext is null in unit tests + { + // Set Content-Length in response. This will disable chunked transfer-encoding. + httpContext.Response.ContentLength = memoryStream.Length; + } - return Task.CompletedTask; + memoryStream.Seek(0, SeekOrigin.Begin); + await memoryStream.CopyToAsync(stream); + await stream.FlushAsync(); } internal static string GetMediaType(MessageVersion version) diff --git a/src/SoapCore/SoapEndpointMiddleware.cs b/src/SoapCore/SoapEndpointMiddleware.cs index 0068c8e7..afa0e7d6 100644 --- a/src/SoapCore/SoapEndpointMiddleware.cs +++ b/src/SoapCore/SoapEndpointMiddleware.cs @@ -173,7 +173,7 @@ public async Task Invoke(HttpContext httpContext, IServiceProvider serviceProvid #if !NETCOREAPP3_0_OR_GREATER private static Task WriteMessageAsync(SoapMessageEncoder messageEncoder, Message responseMessage, HttpContext httpContext, bool indentXml) { - return messageEncoder.WriteMessageAsync(responseMessage, httpContext.Response.Body, indentXml); + return messageEncoder.WriteMessageAsync(responseMessage, httpContext, httpContext.Response.Body, indentXml); } #else private static Task WriteMessageAsync(SoapMessageEncoder messageEncoder, Message responseMessage, HttpContext httpContext, bool indentXml) @@ -257,7 +257,7 @@ private async Task ProcessMeta(HttpContext httpContext, bool showDocumentation) httpContext.Response.ContentType = "text/html;charset=UTF-8"; using var ms = new MemoryStream(); - await messageEncoder.WriteMessageAsync(responseMessage, ms, _options.IndentWsdl); + await messageEncoder.WriteMessageAsync(responseMessage, httpContext, ms, _options.IndentWsdl); ms.Position = 0; using var sr = new StreamReader(ms); var wsdl = await sr.ReadToEndAsync();