From 15273f2e875ef4084a3d884b34518705d53f6636 Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Thu, 26 Apr 2012 13:40:26 +0100 Subject: [PATCH] More work on System.Net.Http --- .../System.Net.Http/Assembly/AssemblyInfo.cs | 2 +- .../System.Net.Http/HttpClient.cs | 11 ++- .../System.Net.Http/HttpClientHandler.cs | 3 - .../System.Net.Http/HttpContent.cs | 38 +++++++++- .../System.Net.Http/HttpRequestMessage.cs | 12 +-- .../System.Net.Http/HttpResponseMessage.cs | 3 + .../Test/System.Net.Http/HttpClientTest.cs | 75 +++++++++++++++++++ .../Test/System.Net.Http/StreamContentTest.cs | 16 ++++ mcs/class/System/Assembly/AssemblyInfo.cs | 2 +- 9 files changed, 144 insertions(+), 18 deletions(-) diff --git a/mcs/class/System.Net.Http/Assembly/AssemblyInfo.cs b/mcs/class/System.Net.Http/Assembly/AssemblyInfo.cs index 1b530078df5..869ab38bc95 100644 --- a/mcs/class/System.Net.Http/Assembly/AssemblyInfo.cs +++ b/mcs/class/System.Net.Http/Assembly/AssemblyInfo.cs @@ -53,7 +53,7 @@ using System.Runtime.InteropServices; [assembly: CLSCompliant (true)] [assembly: AssemblyDelaySign (true)] -[assembly: AssemblyKeyFile ("../ecma.pub")] +[assembly: AssemblyKeyFile ("../msfinal.pub")] [assembly: ComVisible (false)] diff --git a/mcs/class/System.Net.Http/System.Net.Http/HttpClient.cs b/mcs/class/System.Net.Http/System.Net.Http/HttpClient.cs index acfea3ef918..9a4ac95f9e3 100644 --- a/mcs/class/System.Net.Http/System.Net.Http/HttpClient.cs +++ b/mcs/class/System.Net.Http/System.Net.Http/HttpClient.cs @@ -253,10 +253,10 @@ namespace System.Net.Http request.Headers.AddHeaders (headers); } - return SendAsyncWorker (request, cancellationToken); + return SendAsyncWorker (request, completionOption, cancellationToken); } - async Task SendAsyncWorker (HttpRequestMessage request, CancellationToken cancellationToken) + async Task SendAsyncWorker (HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken) { try { if (cancellation_token == null) @@ -273,6 +273,13 @@ namespace System.Net.Http if (response == null) throw new InvalidOperationException ("Handler failed to return a response"); + // + // Read the content when default HttpCompletionOption.ResponseContentRead is set + // + if (response.Content != null && (completionOption & HttpCompletionOption.ResponseHeadersRead) == 0) { + await response.Content.LoadIntoBufferAsync (MaxResponseContentBufferSize).ConfigureAwait (false); + } + return response; } } finally { diff --git a/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs b/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs index 4d9eeafc369..6ba92066f16 100644 --- a/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs +++ b/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs @@ -200,9 +200,6 @@ namespace System.Net.Http HttpWebRequest CreateWebRequest (HttpRequestMessage request) { - //var factory = Activator.CreateInstance (typeof (IWebRequestCreate).Assembly.GetType ("System.Net.HttpRequestCreator"), true) as IWebRequestCreate; - //var wr = (HttpWebRequest) factory.Create (request.RequestUri); - var wr = new HttpWebRequest (request.RequestUri); wr.ThrowOnError = false; diff --git a/mcs/class/System.Net.Http/System.Net.Http/HttpContent.cs b/mcs/class/System.Net.Http/System.Net.Http/HttpContent.cs index 247e9c40454..84d65a637e0 100644 --- a/mcs/class/System.Net.Http/System.Net.Http/HttpContent.cs +++ b/mcs/class/System.Net.Http/System.Net.Http/HttpContent.cs @@ -35,7 +35,36 @@ namespace System.Net.Http { public abstract class HttpContent : IDisposable { - MemoryStream buffer; + sealed class FixedMemoryStream : MemoryStream + { + readonly int maxSize; + + public FixedMemoryStream (int 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; @@ -64,6 +93,11 @@ namespace System.Net.Http await LoadIntoBufferAsync ().ConfigureAwait (false); return buffer; } + + static FixedMemoryStream CreateFixedMemoryStream (int maxBufferSize) + { + return new FixedMemoryStream (maxBufferSize); + } public void Dispose () { @@ -93,7 +127,7 @@ namespace System.Net.Http if (buffer != null) return; - buffer = new MemoryStream (); + buffer = CreateFixedMemoryStream (maxBufferSize); await SerializeToStreamAsync (buffer, null).ConfigureAwait (false); buffer.Seek (0, SeekOrigin.Begin); } diff --git a/mcs/class/System.Net.Http/System.Net.Http/HttpRequestMessage.cs b/mcs/class/System.Net.Http/System.Net.Http/HttpRequestMessage.cs index 40aa64b9a28..00bee6f6646 100644 --- a/mcs/class/System.Net.Http/System.Net.Http/HttpRequestMessage.cs +++ b/mcs/class/System.Net.Http/System.Net.Http/HttpRequestMessage.cs @@ -34,7 +34,6 @@ namespace System.Net.Http { public class HttpRequestMessage : IDisposable { - HttpContent content; HttpRequestHeaders headers; HttpMethod method; Version version; @@ -59,14 +58,7 @@ namespace System.Net.Http RequestUri = requestUri; } - public HttpContent Content { - get { - return content; - } - set { - content = value; - } - } + public HttpContent Content { get; set; } public HttpRequestHeaders Headers { get { @@ -148,6 +140,8 @@ namespace System.Net.Http sb.Append ("', Version: ").Append (Version); sb.Append (", Content: ").Append (Content != null ? Content.ToString () : ""); sb.Append (", Headers:\r\n{\r\n").Append (Headers); + if (Content != null) + sb.Append (Content.Headers); sb.Append ("}"); return sb.ToString (); diff --git a/mcs/class/System.Net.Http/System.Net.Http/HttpResponseMessage.cs b/mcs/class/System.Net.Http/System.Net.Http/HttpResponseMessage.cs index d95b7984e00..bf39da68917 100644 --- a/mcs/class/System.Net.Http/System.Net.Http/HttpResponseMessage.cs +++ b/mcs/class/System.Net.Http/System.Net.Http/HttpResponseMessage.cs @@ -130,6 +130,9 @@ namespace System.Net.Http sb.Append ("', Version: ").Append (Version); sb.Append (", Content: ").Append (Content != null ? Content.ToString () : ""); sb.Append (", Headers:\r\n{\r\n").Append (Headers); + if (Content != null) + sb.Append (Content.Headers); + sb.Append ("}"); return sb.ToString (); diff --git a/mcs/class/System.Net.Http/Test/System.Net.Http/HttpClientTest.cs b/mcs/class/System.Net.Http/Test/System.Net.Http/HttpClientTest.cs index c2b6e41b736..90c8a2d54f9 100644 --- a/mcs/class/System.Net.Http/Test/System.Net.Http/HttpClientTest.cs +++ b/mcs/class/System.Net.Http/Test/System.Net.Http/HttpClientTest.cs @@ -438,6 +438,81 @@ namespace MonoTests.System.Net.Http } } + [Test] + public void Send_Complete_Content () + { + var listener = CreateListener (l => { + var request = l.Request; + l.Response.OutputStream.WriteByte (55); + l.Response.OutputStream.WriteByte (75); + }); + + try { + var client = new HttpClient (); + var request = new HttpRequestMessage (HttpMethod.Get, LocalServer); + request.Headers.AddWithoutValidation ("aa", "vv"); + var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result; + + Assert.AreEqual ("7K", response.Content.ReadAsStringAsync ().Result, "#100"); + Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101"); + + IEnumerable values; + Assert.IsTrue (response.Headers.TryGetValues ("Transfer-Encoding", out values), "#102"); + Assert.AreEqual ("chunked", values.First (), "#102a"); + Assert.AreEqual (true, response.Headers.TransferEncodingChunked, "#102b"); + } finally { + listener.Close (); + } + } + + [Test] + public void Send_Complete_Content_MaxResponseContentBufferSize () + { + var listener = CreateListener (l => { + var request = l.Request; + var b = new byte[4000]; + l.Response.OutputStream.Write (b, 0, b.Length); + }); + + try { + var client = new HttpClient (); + client.MaxResponseContentBufferSize = 1000; + var request = new HttpRequestMessage (HttpMethod.Get, LocalServer); + var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result; + + Assert.AreEqual (4000, response.Content.ReadAsStringAsync ().Result.Length, "#100"); + Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101"); + } finally { + listener.Close (); + } + } + + [Test] + public void Send_Complete_Content_MaxResponseContentBufferSize_Error () + { + var listener = CreateListener (l => { + var request = l.Request; + var b = new byte[4000]; + l.Response.OutputStream.Write (b, 0, b.Length); + }); + + try { + var client = new HttpClient (); + client.MaxResponseContentBufferSize = 1000; + var request = new HttpRequestMessage (HttpMethod.Get, LocalServer); + + try { + client.SendAsync (request, HttpCompletionOption.ResponseContentRead).Wait (); + Assert.Fail ("#2"); + } catch (AggregateException e) { + Assert.IsInstanceOfType (typeof (HttpRequestException), e.InnerException, "#3"); + } + + } finally { + listener.Close (); + } + } + [Test] public void Send_Complete_Error () { diff --git a/mcs/class/System.Net.Http/Test/System.Net.Http/StreamContentTest.cs b/mcs/class/System.Net.Http/Test/System.Net.Http/StreamContentTest.cs index 2e0975e0301..46459f0079a 100644 --- a/mcs/class/System.Net.Http/Test/System.Net.Http/StreamContentTest.cs +++ b/mcs/class/System.Net.Http/Test/System.Net.Http/StreamContentTest.cs @@ -302,6 +302,22 @@ namespace MonoTests.System.Net.Http Assert.IsTrue (sc.LoadIntoBufferAsync (400).Wait (200)); } + [Test] + public void LoadIntoBuffer_BufferOverflow () + { + var ms = new MemoryStream (); + ms.Write (new byte[10000], 0, 10000); + ms.Seek (0, SeekOrigin.Begin); + + var sc = new StreamContent (ms); + try { + Assert.IsTrue (sc.LoadIntoBufferAsync (50).Wait (200)); + Assert.Fail ("#1"); + } catch (AggregateException e) { + Assert.IsInstanceOfType (typeof (HttpRequestException), e.InnerException, "#2"); + } + } + [Test] public void ReadAsByteArrayAsync () { diff --git a/mcs/class/System/Assembly/AssemblyInfo.cs b/mcs/class/System/Assembly/AssemblyInfo.cs index a6ec552db4e..a565b594ac3 100644 --- a/mcs/class/System/Assembly/AssemblyInfo.cs +++ b/mcs/class/System/Assembly/AssemblyInfo.cs @@ -73,7 +73,7 @@ using System.Runtime.InteropServices; [assembly: InternalsVisibleTo ("System.Net, PublicKey=00240000048000009400000006020000002400005253413100040000010001008D56C76F9E8649383049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B37AB")] #else [assembly: InternalsVisibleTo ("System.ComponentModel.DataAnnotations, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] - [assembly: InternalsVisibleTo ("System.Net.Http, PublicKey=00000000000000000400000000000000")] + [assembly: InternalsVisibleTo ("System.Net.Http, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] [assembly: StringFreezing] [assembly: DefaultDependency (LoadHint.Always)] #endif -- 2.25.1