Merge pull request #1464 from akoeplinger/fix-portable-target
[mono.git] / mcs / class / System.Net.Http / Test / System.Net.Http / HttpClientTest.cs
1 //
2 // HttpClientTest.cs
3 //
4 // Authors:
5 //      Marek Safar  <marek.safar@gmail.com>
6 //
7 // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.Collections;
31 using System.Collections.Generic;
32 using NUnit.Framework;
33 using System.Net.Http;
34 using System.Net.Http.Headers;
35 using System.Threading;
36 using System.Threading.Tasks;
37 using System.Net;
38 using System.Linq;
39 using System.IO;
40
41 namespace MonoTests.System.Net.Http
42 {
43         [TestFixture]
44         public class HttpClientTest
45         {
46                 class HttpMessageHandlerMock : HttpMessageHandler
47                 {
48                         public Func<HttpRequestMessage, Task<HttpResponseMessage>> OnSend;
49                         public Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> OnSendFull;
50
51                         public HttpMessageHandlerMock ()
52                         {
53                         }
54
55                         protected override Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken)
56                         {
57                                 if (OnSend != null)
58                                         return OnSend (request);
59
60                                 if (OnSendFull != null)
61                                         return OnSendFull (request, cancellationToken);
62
63                                 Assert.Fail ("Send");
64                                 return null;
65                         }
66                 }
67
68                 class HttpClientHandlerMock : HttpClientHandler
69                 {
70                         public Func<HttpRequestMessage, Task<HttpResponseMessage>> OnSend;
71                         public Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> OnSendFull;
72
73                         protected override Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken)
74                         {
75                                 if (OnSend != null)
76                                         return OnSend (request);
77
78                                 if (OnSendFull != null)
79                                         return OnSendFull (request, cancellationToken);
80
81                                 Assert.Fail ("Send");
82                                 return null;
83                         }
84                 }
85
86                 class CustomStream : Stream
87                 {
88                         public override void Flush ()
89                         {
90                                 throw new NotImplementedException ();
91                         }
92
93                         int pos;
94
95                         public override int Read (byte[] buffer, int offset, int count)
96                         {
97                                 ++pos;
98                                 if (pos > 4)
99                                         return 0;
100
101                                 return 11;
102                         }
103
104                         public override long Seek (long offset, SeekOrigin origin)
105                         {
106                                 throw new NotImplementedException ();
107                         }
108
109                         public override void SetLength (long value)
110                         {
111                                 throw new NotImplementedException ();
112                         }
113
114                         public override void Write (byte[] buffer, int offset, int count)
115                         {
116                                 throw new NotImplementedException ();
117                         }
118
119                         public override bool CanRead {
120                                 get {
121                                         return true;
122                                 }
123                         }
124
125                         public override bool CanSeek {
126                                 get {
127                                         return false;
128                                 }
129                         }
130
131                         public override bool CanWrite {
132                                 get {
133                                         throw new NotImplementedException ();
134                                 }
135                         }
136
137                         public override long Length {
138                                 get {
139                                         throw new NotImplementedException ();
140                                 }
141                         }
142
143                         public override long Position {
144                                 get {
145                                         throw new NotImplementedException ();
146                                 }
147                                 set {
148                                         throw new NotImplementedException ();
149                                 }
150                         }
151                 }
152
153                 const int WaitTimeout = 5000;
154
155                 string port, TestHost, LocalServer;
156
157                 [SetUp]
158                 public void SetupFixture ()
159                 {
160                         if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
161                                 port = "810";
162                         } else {
163                                 port = "8810";
164                         }
165
166                         TestHost = "localhost:" + port;
167                         LocalServer = string.Format ("http://{0}/", TestHost);
168                 }
169
170                 [Test]
171                 public void Ctor_Default ()
172                 {
173                         var client = new HttpClient ();
174                         Assert.IsNull (client.BaseAddress, "#1");
175                         Assert.IsNotNull (client.DefaultRequestHeaders, "#2");  // TODO: full check
176                         Assert.AreEqual (int.MaxValue, client.MaxResponseContentBufferSize, "#3");
177                         Assert.AreEqual (TimeSpan.FromSeconds (100), client.Timeout, "#4");
178                 }
179
180                 [Test]
181                 public void CancelPendingRequests ()
182                 {
183                         var mh = new HttpMessageHandlerMock ();
184
185                         var client = new HttpClient (mh);
186                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
187                         var mre = new ManualResetEvent (false);
188
189                         mh.OnSendFull = (l, c) => {
190                                 mre.Set ();
191                                 Assert.IsTrue (c.WaitHandle.WaitOne (1000), "#20");
192                                 Assert.IsTrue (c.IsCancellationRequested, "#21");
193                                 mre.Set ();
194                                 return Task.FromResult (new HttpResponseMessage ());
195                         };
196
197                         var t = Task.Factory.StartNew (() => {
198                                 client.SendAsync (request).Wait (WaitTimeout);
199                         });
200
201                         Assert.IsTrue (mre.WaitOne (500), "#1");
202                         mre.Reset ();
203                         client.CancelPendingRequests ();
204                         Assert.IsTrue (t.Wait (500), "#2");
205
206                         request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
207                         mh.OnSendFull = (l, c) => {
208                                 Assert.IsFalse (c.IsCancellationRequested, "#30");
209                                 return Task.FromResult (new HttpResponseMessage ());
210                         };
211
212                         client.SendAsync (request).Wait (WaitTimeout);
213                 }
214
215                 [Test]
216                 public void CancelPendingRequests_BeforeSend ()
217                 {
218                         var ct = new CancellationTokenSource ();
219                         ct.Cancel ();
220                         var rr = CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken (), ct.Token);
221
222
223                         var mh = new HttpMessageHandlerMock ();
224
225                         var client = new HttpClient (mh);
226                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
227                         client.CancelPendingRequests ();
228
229                         mh.OnSendFull = (l, c) => {
230                                 Assert.IsFalse (c.IsCancellationRequested, "#30");
231                                 return Task.FromResult (new HttpResponseMessage ());
232                         };
233
234                         client.SendAsync (request).Wait (WaitTimeout);
235
236                         request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
237                         client.SendAsync (request).Wait (WaitTimeout);
238                 }
239
240
241                 [Test]
242                 public void CancelRequestViaProxy ()
243                 {
244                         var handler = new HttpClientHandler {
245                                 Proxy = new WebProxy ("192.168.10.25:8888/"), // proxy that doesn't exist
246                                 UseProxy = true,
247                                 AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
248                         };
249
250                         var httpClient = new HttpClient (handler) {
251                                 BaseAddress = new Uri ("https://google.com"),
252                                 Timeout = TimeSpan.FromMilliseconds (1)
253                         };
254
255                         try {
256                                 var restRequest = new HttpRequestMessage {
257                                         Method = HttpMethod.Post,
258                                         RequestUri = new Uri("foo", UriKind.Relative),
259                                         Content = new StringContent("", null, "application/json")
260                                 };
261
262                                 httpClient.PostAsync (restRequest.RequestUri, restRequest.Content).Wait (WaitTimeout);
263                                 Assert.Fail ("#1");
264                         } catch (AggregateException e) {
265                                 Assert.IsTrue (e.InnerException is TaskCanceledException, "#2");
266                         }
267                 }
268
269                 [Test]
270                 public void Properties ()
271                 {
272                         var client = new HttpClient ();
273                         client.BaseAddress = null;
274                         client.MaxResponseContentBufferSize = int.MaxValue;
275                         client.Timeout = Timeout.InfiniteTimeSpan;
276
277                         Assert.IsNull (client.BaseAddress, "#1");
278                         Assert.AreEqual (int.MaxValue, client.MaxResponseContentBufferSize, "#2");
279                         Assert.AreEqual (Timeout.InfiniteTimeSpan, client.Timeout, "#3");
280                 }
281
282                 [Test]
283                 public void Properties_Invalid ()
284                 {
285                         var client = new HttpClient ();
286                         try {
287                                 client.MaxResponseContentBufferSize = 0;
288                                 Assert.Fail ("#1");
289                         } catch (ArgumentOutOfRangeException) {
290                         }
291
292                         try {
293                                 client.Timeout = TimeSpan.MinValue;
294                                 Assert.Fail ("#2");
295                         } catch (ArgumentOutOfRangeException) {
296                         }
297                 }
298
299                 [Test]
300                 public void Send ()
301                 {
302                         var mh = new HttpMessageHandlerMock ();
303
304                         var client = new HttpClient (mh);
305                         client.BaseAddress = new Uri ("http://xamarin.com");
306                         var request = new HttpRequestMessage ();
307                         var response = new HttpResponseMessage ();
308
309                         mh.OnSend = l => {
310                                 Assert.AreEqual (l, request, "#2");
311                                 Assert.AreEqual (client.BaseAddress, l.RequestUri, "#2");
312                                 return Task.FromResult (response);
313                         };
314
315                         Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
316                 }
317
318                 [Test]
319                 public void Send_DefaultRequestHeaders ()
320                 {
321                         var mh = new HttpMessageHandlerMock ();
322
323                         var client = new HttpClient (mh);
324                         client.DefaultRequestHeaders.Referrer = new Uri ("http://google.com");
325
326                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
327                         var response = new HttpResponseMessage ();
328
329                         mh.OnSend = l => {
330                                 Assert.AreEqual (client.DefaultRequestHeaders.Referrer, l.Headers.Referrer, "#2");
331                                 Assert.IsNotNull (l.Headers.Referrer, "#3");
332                                 return Task.FromResult (response);
333                         };
334
335                         Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
336                 }
337
338                 [Test]
339                 public void Send_Complete_Default ()
340                 {
341                         bool? failed = null;
342                         var listener = CreateListener (l => {
343                                 try {
344                                         var request = l.Request;
345         
346                                         Assert.IsNull (request.AcceptTypes, "#1");
347                                         Assert.AreEqual (0, request.ContentLength64, "#2");
348                                         Assert.IsNull (request.ContentType, "#3");
349                                         Assert.AreEqual (0, request.Cookies.Count, "#4");
350                                         Assert.IsFalse (request.HasEntityBody, "#5");
351                                         Assert.AreEqual (TestHost, request.Headers["Host"], "#6b");
352                                         Assert.AreEqual ("GET", request.HttpMethod, "#7");
353                                         Assert.IsFalse (request.IsAuthenticated, "#8");
354                                         Assert.IsTrue (request.IsLocal, "#9");
355                                         Assert.IsFalse (request.IsSecureConnection, "#10");
356                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
357                                         Assert.IsTrue (request.KeepAlive, "#12");
358                                         Assert.AreEqual (HttpVersion.Version11, request.ProtocolVersion, "#13");
359                                         Assert.IsNull (request.ServiceName, "#14");
360                                         Assert.IsNull (request.UrlReferrer, "#15");
361                                         Assert.IsNull (request.UserAgent, "#16");
362                                         Assert.IsNull (request.UserLanguages, "#17");
363                                         failed = false;
364                                 } catch {
365                                         failed = true;
366                                 }
367                         });
368
369                         try {
370                                 var client = new HttpClient ();
371                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
372                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
373
374                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
375                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
376                                 Assert.AreEqual (false, failed, "#102");
377                         } finally {
378                                 listener.Close ();
379                         }
380                 }
381
382                 [Test]
383                 public void Send_Complete_Version_1_0 ()
384                 {
385                         bool? failed = null;
386                         
387                         var listener = CreateListener (l => {
388                                 try {
389                                         var request = l.Request;
390         
391                                         Assert.IsNull (request.AcceptTypes, "#1");
392                                         Assert.AreEqual (0, request.ContentLength64, "#2");
393                                         Assert.IsNull (request.ContentType, "#3");
394                                         Assert.AreEqual (0, request.Cookies.Count, "#4");
395                                         Assert.IsFalse (request.HasEntityBody, "#5");
396                                         Assert.AreEqual (1, request.Headers.Count, "#6");
397                                         Assert.AreEqual (TestHost, request.Headers["Host"], "#6a");
398                                         Assert.AreEqual ("GET", request.HttpMethod, "#7");
399                                         Assert.IsFalse (request.IsAuthenticated, "#8");
400                                         Assert.IsTrue (request.IsLocal, "#9");
401                                         Assert.IsFalse (request.IsSecureConnection, "#10");
402                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
403                                         Assert.IsFalse (request.KeepAlive, "#12");
404                                         Assert.AreEqual (HttpVersion.Version10, request.ProtocolVersion, "#13");
405                                         Assert.IsNull (request.ServiceName, "#14");
406                                         Assert.IsNull (request.UrlReferrer, "#15");
407                                         Assert.IsNull (request.UserAgent, "#16");
408                                         Assert.IsNull (request.UserLanguages, "#17");
409                                         failed = false;
410                                 } catch {
411                                         failed = true;
412                                 }
413                         });
414
415                         try {
416                                 var client = new HttpClient ();
417                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
418                                 request.Version = HttpVersion.Version10;
419                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
420
421                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
422                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
423                                 Assert.AreEqual (false, failed, "#102");
424                         } finally {
425                                 listener.Close ();
426                         }
427                 }
428
429                 [Test]
430                 public void Send_Complete_ClientHandlerSettings ()
431                 {
432                         bool? failed = null;
433                         
434                         var listener = CreateListener (l => {
435                                 var request = l.Request;
436                                 
437                                 try {
438                                         Assert.IsNull (request.AcceptTypes, "#1");
439                                         Assert.AreEqual (0, request.ContentLength64, "#2");
440                                         Assert.IsNull (request.ContentType, "#3");
441                                         Assert.AreEqual (1, request.Cookies.Count, "#4");
442                                         Assert.AreEqual (new Cookie ("mycookie", "vv"), request.Cookies[0], "#4a");
443                                         Assert.IsFalse (request.HasEntityBody, "#5");
444                                         Assert.AreEqual (4, request.Headers.Count, "#6");
445                                         Assert.AreEqual (TestHost, request.Headers["Host"], "#6a");
446                                         Assert.AreEqual ("gzip", request.Headers["Accept-Encoding"], "#6b");
447                                         Assert.AreEqual ("mycookie=vv", request.Headers["Cookie"], "#6c");
448                                         Assert.AreEqual ("GET", request.HttpMethod, "#7");
449                                         Assert.IsFalse (request.IsAuthenticated, "#8");
450                                         Assert.IsTrue (request.IsLocal, "#9");
451                                         Assert.IsFalse (request.IsSecureConnection, "#10");
452                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
453                                         Assert.IsTrue (request.KeepAlive, "#12");
454                                         Assert.AreEqual (HttpVersion.Version10, request.ProtocolVersion, "#13");
455                                         Assert.IsNull (request.ServiceName, "#14");
456                                         Assert.IsNull (request.UrlReferrer, "#15");
457                                         Assert.IsNull (request.UserAgent, "#16");
458                                         Assert.IsNull (request.UserLanguages, "#17");
459                                         failed = false;
460                                 } catch {
461                                         failed = true;
462                                 }
463                         });
464
465                         try {
466                                 var chandler = new HttpClientHandler ();
467                                 chandler.AllowAutoRedirect = true;
468                                 chandler.AutomaticDecompression = DecompressionMethods.GZip;
469                                 chandler.MaxAutomaticRedirections = 33;
470                                 chandler.MaxRequestContentBufferSize = 5555;
471                                 chandler.PreAuthenticate = true;
472                                 chandler.CookieContainer.Add (new Uri (LocalServer), new Cookie ( "mycookie", "vv"));
473                                 chandler.UseCookies = true;
474                                 chandler.UseDefaultCredentials = true;
475                                 chandler.Proxy = new WebProxy ("ee");
476                                 chandler.UseProxy = true;
477
478                                 var client = new HttpClient (chandler);
479                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
480                                 request.Version = HttpVersion.Version10;
481                                 request.Headers.Add ("Keep-Alive", "false");
482                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
483
484                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
485                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
486                                 Assert.AreEqual (false, failed, "#102");
487                         } finally {
488                                 listener.Abort ();
489                                 listener.Close ();
490                         }
491                 }
492
493                 [Test]
494                 public void Send_Complete_CustomHeaders ()
495                 {
496                         bool? failed = null;
497                         
498                         var listener = CreateListener (l => {
499                                 var request = l.Request;
500                                 try {
501                                         Assert.AreEqual ("vv", request.Headers["aa"], "#1");
502         
503                                         var response = l.Response;
504                                         response.Headers.Add ("rsp", "rrr");
505                                         response.Headers.Add ("upgrade", "vvvvaa");
506                                         response.Headers.Add ("Date", "aa");
507                                         response.Headers.Add ("cache-control", "audio");
508         
509                                         response.StatusDescription = "test description";
510                                         response.ProtocolVersion = HttpVersion.Version10;
511                                         response.SendChunked = true;
512                                         response.RedirectLocation = "w3.org";
513                                         
514                                         failed = false;
515                                 } catch {
516                                         failed = true;
517                                 }
518                         });
519
520                         try {
521                                 var client = new HttpClient ();
522                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
523                                 Assert.IsTrue (request.Headers.TryAddWithoutValidation ("aa", "vv"), "#0");
524                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
525
526                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
527                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
528                                 
529                                 IEnumerable<string> values;
530                                 Assert.IsTrue (response.Headers.TryGetValues ("rsp", out values), "#102");
531                                 Assert.AreEqual ("rrr", values.First (), "#102a");
532
533                                 Assert.IsTrue (response.Headers.TryGetValues ("Transfer-Encoding", out values), "#103");
534                                 Assert.AreEqual ("chunked", values.First (), "#103a");
535                                 Assert.AreEqual (true, response.Headers.TransferEncodingChunked, "#103b");
536
537                                 Assert.IsTrue (response.Headers.TryGetValues ("Date", out values), "#104");
538                                 Assert.AreEqual (1, values.Count (), "#104b");
539                                 // .NET overwrites Date, Mono does not
540                                 // Assert.IsNotNull (response.Headers.Date, "#104c");
541
542                                 Assert.AreEqual (new ProductHeaderValue ("vvvvaa"), response.Headers.Upgrade.First (), "#105");
543
544                                 Assert.AreEqual ("audio", response.Headers.CacheControl.Extensions.First ().Name, "#106");
545
546                                 Assert.AreEqual ("w3.org", response.Headers.Location.OriginalString, "#107");
547
548                                 Assert.AreEqual ("test description", response.ReasonPhrase, "#110");
549                                 Assert.AreEqual (HttpVersion.Version11, response.Version, "#111");
550                                 
551                                 Assert.AreEqual (false, failed, "#112");
552                         } finally {
553                                 listener.Close ();
554                         }
555                 }
556
557                 [Test]
558                 public void Send_Complete_Content ()
559                 {
560                         var listener = CreateListener (l => {
561                                 var request = l.Request;
562                                 l.Response.OutputStream.WriteByte (55);
563                                 l.Response.OutputStream.WriteByte (75);
564                         });
565
566                         try {
567                                 var client = new HttpClient ();
568                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
569                                 Assert.IsTrue (request.Headers.TryAddWithoutValidation ("aa", "vv"), "#0");
570                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
571
572                                 Assert.AreEqual ("7K", response.Content.ReadAsStringAsync ().Result, "#100");
573                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
574
575                                 IEnumerable<string> values;
576                                 Assert.IsTrue (response.Headers.TryGetValues ("Transfer-Encoding", out values), "#102");
577                                 Assert.AreEqual ("chunked", values.First (), "#102a");
578                                 Assert.AreEqual (true, response.Headers.TransferEncodingChunked, "#102b");
579                         } finally {
580                                 listener.Close ();
581                         }
582                 }
583
584                 [Test]
585                 public void Send_Complete_Content_MaxResponseContentBufferSize ()
586                 {
587                         var listener = CreateListener (l => {
588                                 var request = l.Request;
589                                 var b = new byte[4000];
590                                 l.Response.OutputStream.Write (b, 0, b.Length);
591                         });
592
593                         try {
594                                 var client = new HttpClient ();
595                                 client.MaxResponseContentBufferSize = 1000;
596                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
597                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
598
599                                 Assert.AreEqual (4000, response.Content.ReadAsStringAsync ().Result.Length, "#100");
600                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
601                         } finally {
602                                 listener.Close ();
603                         }
604                 }
605
606                 [Test]
607                 public void Send_Complete_Content_MaxResponseContentBufferSize_Error ()
608                 {
609                         var listener = CreateListener (l => {
610                                 var request = l.Request;
611                                 var b = new byte[4000];
612                                 l.Response.OutputStream.Write (b, 0, b.Length);
613                         });
614
615                         try {
616                                 var client = new HttpClient ();
617                                 client.MaxResponseContentBufferSize = 1000;
618                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
619
620                                 try {
621                                         client.SendAsync (request, HttpCompletionOption.ResponseContentRead).Wait (WaitTimeout);
622                                         Assert.Fail ("#2");
623                                 } catch (AggregateException e) {
624                                         Assert.IsTrue (e.InnerException is HttpRequestException, "#3");
625                                 }
626
627                         } finally {
628                                 listener.Close ();
629                         }
630                 }
631
632                 [Test]
633                 public void Send_Complete_NoContent ()
634                 {
635                         foreach (var method in new HttpMethod[] { HttpMethod.Post, HttpMethod.Put, HttpMethod.Delete }) {
636                                 bool? failed = null;
637                                 var listener = CreateListener (l => {
638                                         try {
639                                                 var request = l.Request;
640
641                                                 Assert.AreEqual (2, request.Headers.Count, "#1");
642                                                 Assert.AreEqual ("0", request.Headers ["Content-Length"], "#1b");
643                                                 Assert.AreEqual (method.Method, request.HttpMethod, "#2");
644                                                 failed = false;
645                                         } catch {
646                                                 failed = true;
647                                         }
648                                 });
649
650                                 try {
651                                         var client = new HttpClient ();
652                                         var request = new HttpRequestMessage (method, LocalServer);
653                                         var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
654
655                                         Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
656                                         Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
657                                         Assert.AreEqual (false, failed, "#102");
658                                 } finally {
659                                         listener.Close ();
660                                 }
661                         }
662                 }
663
664                 [Test]
665                 public void Send_Complete_Error ()
666                 {
667                         var listener = CreateListener (l => {
668                                 var response = l.Response;
669                                 response.StatusCode = 500;
670                         });
671
672                         try {
673                                 var client = new HttpClient ();
674                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
675                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
676
677                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
678                                 Assert.AreEqual (HttpStatusCode.InternalServerError, response.StatusCode, "#101");
679                         } finally {
680                                 listener.Close ();
681                         }
682                 }
683
684                 [Test]
685                 public void Send_Content_Get ()
686                 {
687                         var listener = CreateListener (l => {
688                                 var request = l.Request;
689                                 l.Response.OutputStream.WriteByte (72);
690                         });
691
692                         try {
693                                 var client = new HttpClient ();
694                                 var r = new HttpRequestMessage (HttpMethod.Get, LocalServer);
695                                 var response = client.SendAsync (r).Result;
696
697                                 Assert.AreEqual ("H", response.Content.ReadAsStringAsync ().Result);
698                         } finally {
699                                 listener.Close ();
700                         }
701                 }
702
703                 [Test]
704                 public void Send_Content_BomEncoding ()
705                 {
706                         var listener = CreateListener (l => {
707                                 var request = l.Request;
708
709                                 var str = l.Response.OutputStream;
710                                 str.WriteByte (0xEF);
711                                 str.WriteByte (0xBB);
712                                 str.WriteByte (0xBF);
713                                 str.WriteByte (71);
714                         });
715
716                         try {
717                                 var client = new HttpClient ();
718                                 var r = new HttpRequestMessage (HttpMethod.Get, LocalServer);
719                                 var response = client.SendAsync (r).Result;
720
721                                 Assert.AreEqual ("G", response.Content.ReadAsStringAsync ().Result);
722                         } finally {
723                                 listener.Close ();
724                         }
725                 }
726
727                 [Test]
728                 public void Send_Content_Put ()
729                 {
730                         bool passed = false;
731                         var listener = CreateListener (l => {
732                                 var request = l.Request;
733                                 passed = 7 == request.ContentLength64;
734                                 passed &= request.ContentType == "text/plain; charset=utf-8";
735                                 passed &= request.InputStream.ReadByte () == 'm';
736                         });
737
738                         try {
739                                 var client = new HttpClient ();
740                                 var r = new HttpRequestMessage (HttpMethod.Put, LocalServer);
741                                 r.Content = new StringContent ("my text");
742                                 var response = client.SendAsync (r).Result;
743
744                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#1");
745                                 Assert.IsTrue (passed, "#2");
746                         } finally {
747                                 listener.Abort ();
748                                 listener.Close ();
749                         }
750                 }
751
752                 [Test]
753                 public void Send_Content_Put_CustomStream ()
754                 {
755                         bool passed = false;
756                         var listener = CreateListener (l => {
757                                 var request = l.Request;
758                                 passed = 44 == request.ContentLength64;
759                                 passed &= request.ContentType == null;
760                         });
761
762                         try {
763                                 var client = new HttpClient ();
764                                 var r = new HttpRequestMessage (HttpMethod.Put, LocalServer);
765                                 r.Content = new StreamContent (new CustomStream ());
766                                 var response = client.SendAsync (r).Result;
767
768                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#1");
769                                 Assert.IsTrue (passed, "#2");
770                         } finally {
771                                 listener.Abort ();
772
773                                 listener.Close ();
774                         }
775                 }
776
777                 [Test]
778                 public void Send_Timeout ()
779                 {
780                         var mh = new HttpMessageHandlerMock ();
781
782                         var client = new HttpClient (mh);
783                         client.Timeout = TimeSpan.FromMilliseconds (100);
784                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
785                         var response = new HttpResponseMessage ();
786
787                         mh.OnSendFull = (l, c) => {
788                                 Assert.IsTrue (c.WaitHandle.WaitOne (500), "#2");
789                                 return Task.FromResult (response);
790                         };
791
792                         Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
793                 }
794
795                 [Test]
796                 public void Send_Invalid ()
797                 {
798                         var client = new HttpClient ();
799                         try {
800                                 client.SendAsync (null).Wait (WaitTimeout);
801                                 Assert.Fail ("#1");
802                         } catch (ArgumentNullException) {
803                         }
804
805                         try {
806                                 var request = new HttpRequestMessage ();
807                                 client.SendAsync (request).Wait (WaitTimeout);
808                                 Assert.Fail ("#2");
809                         } catch (InvalidOperationException) {
810                         }
811                 }
812
813                 [Test]
814                 public void Send_InvalidHandler ()
815                 {
816                         var mh = new HttpMessageHandlerMock ();
817
818                         var client = new HttpClient (mh);
819                         client.BaseAddress = new Uri ("http://xamarin.com");
820                         var request = new HttpRequestMessage ();
821
822                         mh.OnSend = l => {
823                                 Assert.AreEqual (l, request, "#1");
824                                 return null;
825                         };
826
827                         try {
828                                 // Broken by design
829                                 client.SendAsync (request).Wait (WaitTimeout);
830                                 Assert.Fail ("#2");
831                         } catch (Exception) {
832                         }
833                 }
834
835                 [Test]
836                 public void Send_SameMessage ()
837                 {
838                         var mh = new HttpMessageHandlerMock ();
839
840                         var client = new HttpClient (mh);
841                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
842
843                         mh.OnSend = l => Task.FromResult (new HttpResponseMessage ());
844
845                         client.SendAsync (request).Wait (WaitTimeout);
846                         try {
847                                 client.SendAsync (request).Wait (WaitTimeout);
848                                 Assert.Fail ("#1");
849                         } catch (InvalidOperationException) {
850                         }
851                 }
852
853                 [Test]
854                 public void GetString_RelativeUri ()
855                 {
856                         var client = new HttpClient ();
857                         client.BaseAddress = new Uri ("http://en.wikipedia.org/wiki/");
858                         var uri = new Uri ("Computer", UriKind.Relative);
859
860                         Assert.That (client.GetStringAsync (uri).Result != null);
861                         Assert.That (client.GetStringAsync ("Computer").Result != null);
862                 }
863
864                 [Test]
865                 [Category ("MobileNotWorking")] // Missing encoding
866                 public void GetString_Many ()
867                 {
868                         var client = new HttpClient ();
869                         var t1 = client.GetStringAsync ("http://www.google.com");
870                         var t2 = client.GetStringAsync ("http://www.google.com");
871                         Assert.IsTrue (Task.WaitAll (new [] { t1, t2 }, WaitTimeout));          
872                 }
873
874                 [Test]
875                 public void GetByteArray_ServerError ()
876                 {
877                         var listener = CreateListener (l => {
878                                 var response = l.Response;
879                                 response.StatusCode = 500;
880                                 l.Response.OutputStream.WriteByte (72);
881                         });
882
883                         try {
884                                 var client = new HttpClient ();
885                                 try {
886                                         client.GetByteArrayAsync (LocalServer).Wait (WaitTimeout);
887                                         Assert.Fail ("#1");
888                                 } catch (AggregateException e) {
889                                         Assert.IsTrue (e.InnerException is HttpRequestException , "#2");
890                                 }
891                         } finally {
892                                 listener.Close ();
893                         }
894                 }
895
896                 [Test]
897                 public void DisallowAutoRedirect ()
898                 {
899                         var listener = CreateListener (l => {
900                                 var request = l.Request;
901                                 var response = l.Response;
902                                 
903                                 response.StatusCode = (int)HttpStatusCode.Moved;
904                                 response.RedirectLocation = "http://xamarin.com/";
905                         });
906
907                         try {
908                                 var chandler = new HttpClientHandler ();
909                                 chandler.AllowAutoRedirect = false;
910                                 var client = new HttpClient (chandler);
911
912                                 try {
913                                         client.GetStringAsync (LocalServer).Wait (WaitTimeout);
914                                         Assert.Fail ("#1");
915                                 } catch (AggregateException e) {
916                                         Assert.IsTrue (e.InnerException is HttpRequestException, "#2");
917                                 }
918                         } finally {
919                                 listener.Abort ();
920                                 listener.Close ();
921                         }
922                 }
923
924                 [Test]
925                 public void RequestUriAfterRedirect ()
926                 {
927                         var listener = CreateListener (l => {
928                                 var request = l.Request;
929                                 var response = l.Response;
930
931                                 response.StatusCode = (int)HttpStatusCode.Moved;
932                                 response.RedirectLocation = "http://xamarin.com/";
933                         });
934
935                         try {
936                                 var chandler = new HttpClientHandler ();
937                                 chandler.AllowAutoRedirect = true;
938                                 var client = new HttpClient (chandler);
939
940                                 var r = client.GetAsync (LocalServer);
941                                 Assert.IsTrue (r.Wait (WaitTimeout), "#1");
942                                 var resp = r.Result;
943                                 Assert.AreEqual ("http://xamarin.com/", resp.RequestMessage.RequestUri.AbsoluteUri, "#2");
944                         } finally {
945                                 listener.Abort ();
946                                 listener.Close ();
947                         }
948                 }
949
950                 [Test]
951                 /*
952                  * Properties may only be modified before sending the first request.
953                  */
954                 public void ModifyHandlerAfterFirstRequest ()
955                 {
956                         var chandler = new HttpClientHandler ();
957                         chandler.AllowAutoRedirect = true;
958                         var client = new HttpClient (chandler, true);
959
960                         var listener = CreateListener (l => {
961                                 var response = l.Response;
962                                 response.StatusCode = 200;
963                                 response.OutputStream.WriteByte (55);
964                         });
965
966                         try {
967                                 client.GetStringAsync (LocalServer).Wait (WaitTimeout);
968                                 try {
969                                         chandler.AllowAutoRedirect = false;
970                                         Assert.Fail ("#1");
971                                 } catch (InvalidOperationException) {
972                                         ;
973                                 }
974                         } finally {
975                                 listener.Abort ();
976                                 listener.Close ();
977                         }
978                 }
979
980                 [Test]
981                 /*
982                  * However, this policy is not enforced for custom handlers and there
983                  * is also no way a derived class could tell its HttpClientHandler parent
984                  * that it just sent a request.
985                  * 
986                  */
987                 public void ModifyHandlerAfterFirstRequest_Mock ()
988                 {
989                         var ch = new HttpClientHandlerMock ();
990                         ch.AllowAutoRedirect = true;
991
992                         var client = new HttpClient (ch);
993
994                         ch.OnSend = (l) => {
995                                 return Task.FromResult (new HttpResponseMessage ());
996                         };
997
998                         client.GetAsync ("http://xamarin.com").Wait (WaitTimeout);
999                         ch.AllowAutoRedirect = false;
1000                 }
1001
1002                 HttpListener CreateListener (Action<HttpListenerContext> contextAssert)
1003                 {
1004                         var l = new HttpListener ();
1005                         l.Prefixes.Add (string.Format ("http://+:{0}/", port));
1006                         l.Start ();
1007                         l.BeginGetContext (ar => {
1008                                 var ctx = l.EndGetContext (ar);
1009
1010                                 try {
1011                                         if (contextAssert != null)
1012                                                 contextAssert (ctx);
1013                                 } finally {
1014                                         ctx.Response.Close ();
1015                                 }
1016                         }, null);
1017
1018                         return l;
1019                 }
1020         }
1021 }