private static async Task<RTIHttpContent> CreateRequestContentAsync(HttpRequestMessage request, HttpRequestHeaderCollection rtHeaderCollection)
{
HttpContent content = request.Content;
RTIHttpContent rtContent;
ArraySegment<byte> buffer;
// If we are buffered already, it is more efficient to send the data directly using the buffer with the
// WinRT HttpBufferContent class than using HttpStreamContent. This also avoids issues caused by
// a design limitation in the System.Runtime.WindowsRuntime System.IO.NetFxToWinRtStreamAdapter.
if (content.TryGetBuffer(out buffer))
{
rtContent = new RTHttpBufferContent(buffer.Array.AsBuffer(), (uint)buffer.Offset, (uint)buffer.Count);
}
else
{
Stream contentStream = await content.ReadAsStreamAsync().ConfigureAwait(false);
if (contentStream is RTIInputStream)
{
rtContent = new RTHttpStreamContent((RTIInputStream)contentStream);
}
else if (contentStream is MemoryStream)
{
var memStream = contentStream as MemoryStream;
if (memStream.TryGetBuffer(out buffer))
{
rtContent = new RTHttpBufferContent(buffer.Array.AsBuffer(), (uint)buffer.Offset, (uint)buffer.Count);
}
else
{
byte[] byteArray = memStream.ToArray();
rtContent = new RTHttpBufferContent(byteArray.AsBuffer(), 0, (uint) byteArray.Length);
}
}
else
{
rtContent = new RTHttpStreamContent(contentStream.AsInputStream());
}
}
// RTHttpBufferContent constructor automatically adds a Content-Length header. RTHttpStreamContent does not.
// Clear any 'Content-Length' header added by the RTHttp*Content objects. We need to clear that now
// and decide later whether we need 'Content-Length' or 'Transfer-Encoding: chunked' headers based on the
// .NET HttpRequestMessage and Content header collections.
rtContent.Headers.ContentLength = null;
// Deal with conflict between 'Content-Length' vs. 'Transfer-Encoding: chunked' semantics.
// Desktop System.Net allows both headers to be specified but ends up stripping out
// 'Content-Length' and using chunked semantics. The WinRT APIs throw an exception so
// we need to manually strip out the conflicting header to maintain app compatibility.
if (request.Headers.TransferEncodingChunked.HasValue && request.Headers.TransferEncodingChunked.Value)
{
content.Headers.ContentLength = null;
}
else
{
// Trigger delayed header generation via TryComputeLength. This code is needed due to an outstanding
// bug in HttpContentHeaders.ContentLength. See GitHub Issue #5523.
content.Headers.ContentLength = content.Headers.ContentLength;
}
foreach (KeyValuePair<string, IEnumerable<string>> headerPair in content.Headers)
{
foreach (string value in headerPair.Value)
{
if (!rtContent.Headers.TryAppendWithoutValidation(headerPair.Key, value))
{
// rtContent headers are restricted to a white-list of allowed headers, while System.Net.HttpClient's content headers
// will allow custom headers. If something is not successfully added to the content headers, try adding them to the standard headers.
bool success = rtHeaderCollection.TryAppendWithoutValidation(headerPair.Key, value);
Debug.Assert(success);
}
}
}
return rtContent;
}