// // HttpContent.cs // // Authors: // Marek Safar // // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System.Net.Http.Headers; using System.IO; using System.Threading.Tasks; using System.Text; namespace System.Net.Http { public abstract class HttpContent : IDisposable { sealed class FixedMemoryStream : MemoryStream { readonly long maxSize; public FixedMemoryStream (long maxSize) : base () { this.maxSize = maxSize; } void CheckOverflow (int count) { if (Length + count > maxSize) throw new HttpRequestException (string.Format ("Cannot write more bytes to the buffer than the configured maximum buffer size: {0}", maxSize)); } public override void WriteByte (byte value) { CheckOverflow (1); base.WriteByte (value); } public override void Write (byte[] buffer, int offset, int count) { CheckOverflow (count); base.Write (buffer, offset, count); } } FixedMemoryStream buffer; Stream stream; bool disposed; HttpContentHeaders headers; public HttpContentHeaders Headers { get { return headers ?? (headers = new HttpContentHeaders (this)); } } public Task CopyToAsync (Stream stream) { return CopyToAsync (stream, null); } public Task CopyToAsync (Stream stream, TransportContext context) { if (stream == null) throw new ArgumentNullException ("stream"); return SerializeToStreamAsync (stream, context); } protected async virtual Task CreateContentReadStreamAsync () { await LoadIntoBufferAsync ().ConfigureAwait (false); return buffer; } static FixedMemoryStream CreateFixedMemoryStream (long maxBufferSize) { return new FixedMemoryStream (maxBufferSize); } public void Dispose () { Dispose (true); } protected virtual void Dispose (bool disposing) { if (disposing && !disposed) { disposed = true; if (buffer != null) buffer.Dispose (); } } public Task LoadIntoBufferAsync () { return LoadIntoBufferAsync (65536); } public async Task LoadIntoBufferAsync (long maxBufferSize) { if (disposed) throw new ObjectDisposedException (GetType ().ToString ()); if (buffer != null) return; buffer = CreateFixedMemoryStream (maxBufferSize); await SerializeToStreamAsync (buffer, null).ConfigureAwait (false); buffer.Seek (0, SeekOrigin.Begin); } public async Task ReadAsStreamAsync () { if (disposed) throw new ObjectDisposedException (GetType ().ToString ()); if (stream == null) stream = await CreateContentReadStreamAsync ().ConfigureAwait (false); return stream; } public async Task ReadAsByteArrayAsync () { await LoadIntoBufferAsync ().ConfigureAwait (false); return buffer.ToArray (); } public async Task ReadAsStringAsync () { await LoadIntoBufferAsync ().ConfigureAwait (false); if (buffer.Length == 0) return string.Empty; Encoding encoding; if (headers != null && headers.ContentType != null && headers.ContentType.CharSet != null) { encoding = Encoding.GetEncoding (headers.ContentType.CharSet); } else { encoding = Encoding.UTF8; } return encoding.GetString (buffer.GetBuffer (), 0, (int) buffer.Length); } protected internal abstract Task SerializeToStreamAsync (Stream stream, TransportContext context); protected internal abstract bool TryComputeLength (out long length); } }