Implement more of System.Net.Http
authorMarek Safar <marek.safar@gmail.com>
Fri, 13 Apr 2012 15:09:50 +0000 (16:09 +0100)
committerMarek Safar <marek.safar@gmail.com>
Fri, 13 Apr 2012 16:09:52 +0000 (17:09 +0100)
13 files changed:
mcs/class/System.Net.Http/System.Net.Http.dll.sources
mcs/class/System.Net.Http/System.Net.Http/ByteArrayContent.cs
mcs/class/System.Net.Http/System.Net.Http/DelegatingHandler.cs
mcs/class/System.Net.Http/System.Net.Http/FormUrlEncodedContent.cs [new file with mode: 0644]
mcs/class/System.Net.Http/System.Net.Http/HttpClient.cs
mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs
mcs/class/System.Net.Http/System.Net.Http/HttpContent.cs
mcs/class/System.Net.Http/System.Net.Http/MessageProcessingHandler.cs [new file with mode: 0644]
mcs/class/System.Net.Http/System.Net.Http/StreamContent.cs
mcs/class/System.Net.Http/System.Net.Http_test.dll.sources
mcs/class/System.Net.Http/Test/System.Net.Http/HttpClientHandlerTest.cs
mcs/class/System.Net.Http/Test/System.Net.Http/HttpClientTest.cs
mcs/class/System.Net.Http/Test/System.Net.Http/StreamContentTest.cs

index daee130501b38b3f08d1ce2c1b3ed8a49de8de4e..7d522af878cd22ff599b37ba545981734dbb9d4e 100644 (file)
@@ -3,6 +3,7 @@ Assembly/AssemblyInfo.cs
 System.Net.Http/ByteArrayContent.cs
 System.Net.Http/ClientCertificateOption.cs
 System.Net.Http/DelegatingHandler.cs
+System.Net.Http/FormUrlEncodedContent.cs
 System.Net.Http/HttpClient.cs
 System.Net.Http/HttpClientHandler.cs
 System.Net.Http/HttpCompletionOption.cs
@@ -12,6 +13,7 @@ System.Net.Http/HttpMethod.cs
 System.Net.Http/HttpRequestException.cs
 System.Net.Http/HttpRequestMessage.cs
 System.Net.Http/HttpResponseMessage.cs
+System.Net.Http/MessageProcessingHandler.cs
 System.Net.Http/StreamContent.cs
 System.Net.Http/StringContent.cs
 System.Net.Http.Headers/AuthenticationHeaderValue.cs
index 13d5c8de7b99055515b280e9921490c2c79d9c00..46a92e38cd2279340ca717f686ef2b3fb83e261c 100644 (file)
@@ -58,6 +58,11 @@ namespace System.Net.Http
                        this.count = count;
                }
 
+               protected override Task<Stream> CreateContentReadStreamAsync ()
+               {
+                       return Task.FromResult<Stream> (new MemoryStream (content, offset, count));
+               }
+
                protected override Task SerializeToStreamAsync (Stream stream, TransportContext context)
                {
                        return stream.WriteAsync (content, offset, count);
index 5bc1aa855ac23d16445a074fcce56c097d16df74..2458975d687bdf829f78a8a325d8ea2d0ae11233 100644 (file)
@@ -61,7 +61,7 @@ namespace System.Net.Http
 
                protected internal override Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken)
                {
-                       throw new NotImplementedException ();
+                       return InnerHandler.SendAsync (request, cancellationToken);
                }
        }
 }
diff --git a/mcs/class/System.Net.Http/System.Net.Http/FormUrlEncodedContent.cs b/mcs/class/System.Net.Http/System.Net.Http/FormUrlEncodedContent.cs
new file mode 100644 (file)
index 0000000..967b89f
--- /dev/null
@@ -0,0 +1,89 @@
+//
+// FormUrlEncodedContent.cs
+//
+// Authors:
+//     Marek Safar  <marek.safar@gmail.com>
+//
+// Copyright (C) 2012 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.Collections.Generic;
+using System.Net.Http.Headers;
+using System.Text;
+
+namespace System.Net.Http
+{
+       public class FormUrlEncodedContent : ByteArrayContent
+       {
+               public FormUrlEncodedContent (IEnumerable<KeyValuePair<string, string>> nameValueCollection)
+                       : base (EncodeContent (nameValueCollection))
+               {
+                       Headers.ContentType = new MediaTypeHeaderValue ("application/x-www-form-urlencoded");
+               }
+
+               static byte[] EncodeContent (IEnumerable<KeyValuePair<string, string>> nameValueCollection)
+               {
+                       if (nameValueCollection == null)
+                               throw new ArgumentNullException ("nameValueCollection");
+
+                       //
+                       // Serialization as application/x-www-form-urlencoded
+                       //
+                       // Element nodes selected for inclusion are encoded as EltName=value{sep}, where = is a literal
+                       // character, {sep} is the separator character from the separator attribute on submission,
+                       // EltName represents the element local name, and value represents the contents of the text node.
+                       //
+                       // The encoding of EltName and value are as follows: space characters are replaced by +, and then
+                       // non-ASCII and reserved characters (as defined by [RFC 2396] as amended by subsequent documents
+                       // in the IETF track) are escaped by replacing the character with one or more octets of the UTF-8
+                       // representation of the character, with each octet in turn replaced by %HH, where HH represents
+                       // the uppercase hexadecimal notation for the octet value and % is a literal character. Line breaks
+                       // are represented as "CR LF" pairs (i.e., %0D%0A).
+                       //
+                       var sb = new List<byte> ();
+                       foreach (var item in nameValueCollection) {
+                               if (sb.Count != 0)
+                                       sb.Add ((byte) '&');
+
+                               var data = SerializeValue (item.Key);
+                               if (data != null)
+                                       sb.AddRange (data);
+                               sb.Add ((byte) '=');
+
+                               data = SerializeValue (item.Value);
+                               if (data != null)
+                                       sb.AddRange (data);
+                       }
+
+                       return sb.ToArray ();
+               }
+
+               static byte[] SerializeValue (string value)
+               {
+                       if (value == null)
+                               return null;
+
+                       value = Uri.EscapeDataString (value).Replace ("%20", "+");
+                       return Encoding.ASCII.GetBytes (value);
+               }
+       }
+}
index 92e22982b87b8fe66ff164e4117fb4738ca23bd1..c2d7a5a29f6a8813f6feb6232ce50c19a5380ad1 100644 (file)
@@ -29,6 +29,7 @@
 using System.Threading;
 using System.Net.Http.Headers;
 using System.Threading.Tasks;
+using System.IO;
 
 namespace System.Net.Http
 {
@@ -275,5 +276,41 @@ namespace System.Net.Http
                                cancellation_token = null;
                        }
                }
+
+               public async Task<byte[]> GetByteArrayAsync (string requestUri)
+               {
+                       var resp = await GetAsync (requestUri, HttpCompletionOption.ResponseContentRead).ConfigureAwait (false);
+                       return await resp.Content.ReadAsByteArrayAsync ();
+               }
+
+               public async Task<byte[]> GetByteArrayAsync (Uri requestUri)
+               {
+                       var resp = await GetAsync (requestUri, HttpCompletionOption.ResponseContentRead).ConfigureAwait (false);
+                       return await resp.Content.ReadAsByteArrayAsync ();
+               }
+
+               public async Task<Stream> GetStreamAsync (string requestUri)
+               {
+                       var resp = await GetAsync (requestUri, HttpCompletionOption.ResponseContentRead).ConfigureAwait (false);
+                       return await resp.Content.ReadAsStreamAsync ();
+               }
+
+               public async Task<Stream> GetStreamAsync (Uri requestUri)
+               {
+                       var resp = await GetAsync (requestUri, HttpCompletionOption.ResponseContentRead).ConfigureAwait (false);
+                       return await resp.Content.ReadAsStreamAsync ();
+               }
+
+               public async Task<string> GetStringAsync (string requestUri)
+               {
+                       var resp = await GetAsync (requestUri, HttpCompletionOption.ResponseContentRead).ConfigureAwait (false);
+                       return await resp.Content.ReadAsStringAsync ();
+               }
+
+               public async Task<string> GetStringAsync (Uri requestUri)
+               {
+                       var resp = await GetAsync (requestUri, HttpCompletionOption.ResponseContentRead).ConfigureAwait (false);
+                       return await resp.Content.ReadAsStringAsync ();
+               }
        }
 }
index 00c1ff0eb9895f0b7ba39826cbfc4c53ff88b254..7beca3936cd9a6fe93e87d012ecaf26f5597e1a3 100644 (file)
@@ -46,6 +46,7 @@ namespace System.Net.Http
                bool useCookies;
                bool useDefaultCredentials;
                bool useProxy;
+               ClientCertificateOption certificate;
 
                public HttpClientHandler ()
                {
@@ -74,6 +75,15 @@ namespace System.Net.Http
                        }
                }
 
+               public ClientCertificateOption ClientCertificateOptions {
+                       get {
+                               return certificate;
+                       }
+                       set {
+                               certificate = value;
+                       }
+               }
+
                public CookieContainer CookieContainer {
                        get {
                                return cookieContainer ?? (cookieContainer = new CookieContainer ());
@@ -130,6 +140,9 @@ namespace System.Net.Http
                                return proxy;
                        }
                        set {
+                               if (!UseProxy)
+                                       throw new InvalidOperationException ();
+
                                proxy = value;
                        }
                }
index 8a66f60421f88acd49d5794f1fb610f8b64f7de0..a150582c9ee36d8bd43143a7399251d18b0447cb 100644 (file)
@@ -36,6 +36,7 @@ namespace System.Net.Http
        public abstract class HttpContent : IDisposable
        {
                MemoryStream buffer;
+               Stream stream;
                bool disposed;
                HttpContentHeaders headers;
 
@@ -58,6 +59,12 @@ namespace System.Net.Http
                        return SerializeToStreamAsync (stream, context);
                }
 
+               protected async virtual Task<Stream> CreateContentReadStreamAsync ()
+               {
+                       await LoadIntoBufferAsync ();
+                       return buffer;
+               }
+
                public void Dispose ()
                {
                        Dispose (true);
@@ -91,10 +98,15 @@ namespace System.Net.Http
                        buffer.Seek (0, SeekOrigin.Begin);
                }
                
-               public Task<Stream> ReadAsStreamAsync ()
+               public async Task<Stream> ReadAsStreamAsync ()
                {
-                       // TODO:
-                       throw new NotImplementedException ();
+                       if (disposed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (stream == null)
+                               stream = await CreateContentReadStreamAsync ().ConfigureAwait (false);
+
+                       return stream;
                }
 
                public async Task<byte[]> ReadAsByteArrayAsync ()
diff --git a/mcs/class/System.Net.Http/System.Net.Http/MessageProcessingHandler.cs b/mcs/class/System.Net.Http/System.Net.Http/MessageProcessingHandler.cs
new file mode 100644 (file)
index 0000000..3fa9db0
--- /dev/null
@@ -0,0 +1,54 @@
+//
+// MessageProcessingHandler.cs
+//
+// Authors:
+//     Marek Safar  <marek.safar@gmail.com>
+//
+// 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.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+       public abstract class MessageProcessingHandler : DelegatingHandler
+       {
+               protected MessageProcessingHandler ()
+               {
+               }
+
+               protected MessageProcessingHandler (HttpMessageHandler innerHandler)
+                       : base (innerHandler)
+               {
+               }
+
+               protected abstract HttpRequestMessage ProcessRequest (HttpRequestMessage request, CancellationToken cancellationToken);
+               protected abstract HttpResponseMessage ProcessResponse (HttpResponseMessage response, CancellationToken cancellationToken);
+               
+               protected internal sealed override async Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken)
+               {
+                       request = ProcessRequest (request, cancellationToken);
+                       return ProcessResponse (await base.SendAsync (request, cancellationToken).ConfigureAwait (false), cancellationToken);
+               }
+       }
+}
index fd51a9717093492c643a80ba77be1ff7a07cbb1e..6e3561a38bf744fa9d27c9a5d33ffa38e6d7b615 100644 (file)
@@ -53,6 +53,11 @@ namespace System.Net.Http
                        this.bufferSize = bufferSize;
                }
 
+               protected override Task<Stream> CreateContentReadStreamAsync ()
+               {
+                       return Task.FromResult (content);
+               }
+
                protected override void Dispose (bool disposing)
                {
                        if (disposing) {
index f84af5e5e373198154bcddeb03bf7e97f8a02aa9..ea1e0d882b51a7349d9b0fe58f360ba1cb3927a0 100644 (file)
@@ -1,4 +1,5 @@
 System.Net.Http/ByteArrayContentTest.cs
+System.Net.Http/FormUrlEncodedContentTest.cs
 System.Net.Http/HttpClientHandlerTest.cs
 System.Net.Http/HttpClientTest.cs
 System.Net.Http/HttpMethodTest.cs
index e02db43791908b370e40341f76108c842f5d4f8a..fc778fabf5a8b24b632b8209d82fd8d7661ced98 100644 (file)
@@ -38,6 +38,28 @@ namespace MonoTests.System.Net.Http
        [TestFixture]
        public class HttpClientHandlerTest
        {
+               class Proxy : IWebProxy
+               {
+                       public ICredentials Credentials {
+                               get {
+                                       throw new NotImplementedException ();
+                               }
+                               set {
+                                       throw new NotImplementedException ();
+                               }
+                       }
+
+                       public Uri GetProxy (Uri destination)
+                       {
+                               throw new NotImplementedException ();
+                       }
+
+                       public bool IsBypassed (Uri host)
+                       {
+                               throw new NotImplementedException ();
+                       }
+               }
+
                [Test]
                public void Properties_Defaults ()
                {
@@ -57,6 +79,7 @@ namespace MonoTests.System.Net.Http
                        Assert.IsTrue (h.UseCookies, "#12");
                        Assert.IsFalse (h.UseDefaultCredentials, "#13");
                        Assert.IsTrue (h.UseProxy, "#14");
+                       Assert.AreEqual (ClientCertificateOption.Manual, h.ClientCertificateOptions, "#15");
                }
 
                [Test]
@@ -75,6 +98,12 @@ namespace MonoTests.System.Net.Http
                        } catch (ArgumentOutOfRangeException) {
                        }
 
+                       h.UseProxy = false;
+                       try {
+                               h.Proxy = new Proxy ();
+                               Assert.Fail ("#3");
+                       } catch (InvalidOperationException) {
+                       }
                }
        }
 }
index 9533cb64c60c2db737a139f9e35cfb194679bd47..e7645bc6ba8a24c15c5d59d35a6d1dc0b8ba22a5 100644 (file)
@@ -182,7 +182,6 @@ namespace MonoTests.System.Net.Http
                }
 
                [Test]
-               [Ignore]
                public void Send ()
                {
                        var mh = new HttpMessageHandlerMock ();
@@ -222,7 +221,6 @@ namespace MonoTests.System.Net.Http
                }
 
                [Test]
-               [Ignore]
                public void Send_Complete_Default ()
                {
                        var listener = CreateListener (l => {
@@ -301,7 +299,6 @@ namespace MonoTests.System.Net.Http
                }
 
                [Test]
-               [Ignore]
                public void Send_Complete_ClientHandlerSettings ()
                {
                        var listener = CreateListener (l => {
@@ -356,7 +353,6 @@ namespace MonoTests.System.Net.Http
                }
 
                [Test]
-               [Ignore]
                public void Send_Complete_CustomHeaders ()
                {
                        var listener = CreateListener (l => {
@@ -512,7 +508,6 @@ namespace MonoTests.System.Net.Http
                }
 
                [Test]
-               [Ignore]
                public void Send_InvalidHandler ()
                {
                        var mh = new HttpMessageHandlerMock ();
index 86c28ca330ce9d23ee7cd5fc3050cc89bcd471f2..2e0975e030155c87497eb87404a473eef0d3c558 100644 (file)
@@ -299,7 +299,7 @@ namespace MonoTests.System.Net.Http
                        ms.Seek (0, SeekOrigin.Begin);
 
                        var sc = new StreamContent (ms);
-                       sc.LoadIntoBufferAsync (400).Wait ();
+                       Assert.IsTrue (sc.LoadIntoBufferAsync (400).Wait (200));
                }
 
                [Test]
@@ -332,5 +332,18 @@ namespace MonoTests.System.Net.Http
                        var res = sc.ReadAsStringAsync ().Result;
                        Assert.AreEqual ("M7", res, "#1");
                }
+
+               [Test]
+               public void ReadAsStream ()
+               {
+                       var ms = new MemoryStream ();
+                       ms.WriteByte (77);
+                       ms.WriteByte (55);
+                       ms.Seek (0, SeekOrigin.Begin);
+
+                       var sc = new StreamContent (ms);
+                       var res = sc.ReadAsStreamAsync ().Result;
+                       Assert.AreEqual (77, res.ReadByte (), "#1");
+               }
        }
 }