[System.Net.Http] Updates range check from 3741d16503a973a99c724bdab9a255a5f07a3637
[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 using MonoTests.Helpers;
42
43 namespace MonoTests.System.Net.Http
44 {
45         [TestFixture]
46         public class HttpClientTest
47         {
48                 class HttpMessageHandlerMock : HttpMessageHandler
49                 {
50                         public Func<HttpRequestMessage, Task<HttpResponseMessage>> OnSend;
51                         public Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> OnSendFull;
52
53                         public HttpMessageHandlerMock ()
54                         {
55                         }
56
57                         protected override Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken)
58                         {
59                                 if (OnSend != null)
60                                         return OnSend (request);
61
62                                 if (OnSendFull != null)
63                                         return OnSendFull (request, cancellationToken);
64
65                                 Assert.Fail ("Send");
66                                 return null;
67                         }
68                 }
69
70                 class HttpClientHandlerMock : HttpClientHandler
71                 {
72                         public Func<HttpRequestMessage, Task<HttpResponseMessage>> OnSend;
73                         public Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> OnSendFull;
74
75                         protected override Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken)
76                         {
77                                 if (OnSend != null)
78                                         return OnSend (request);
79
80                                 if (OnSendFull != null)
81                                         return OnSendFull (request, cancellationToken);
82
83                                 Assert.Fail ("Send");
84                                 return null;
85                         }
86                 }
87
88                 class CustomStream : Stream
89                 {
90                         public override void Flush ()
91                         {
92                                 throw new NotImplementedException ();
93                         }
94
95                         int pos;
96
97                         public override int Read (byte[] buffer, int offset, int count)
98                         {
99                                 ++pos;
100                                 if (pos > 4)
101                                         return 0;
102
103                                 return 11;
104                         }
105
106                         public override long Seek (long offset, SeekOrigin origin)
107                         {
108                                 throw new NotImplementedException ();
109                         }
110
111                         public override void SetLength (long value)
112                         {
113                                 throw new NotImplementedException ();
114                         }
115
116                         public override void Write (byte[] buffer, int offset, int count)
117                         {
118                                 throw new NotImplementedException ();
119                         }
120
121                         public override bool CanRead {
122                                 get {
123                                         return true;
124                                 }
125                         }
126
127                         public override bool CanSeek {
128                                 get {
129                                         return false;
130                                 }
131                         }
132
133                         public override bool CanWrite {
134                                 get {
135                                         throw new NotImplementedException ();
136                                 }
137                         }
138
139                         public override long Length {
140                                 get {
141                                         throw new NotImplementedException ();
142                                 }
143                         }
144
145                         public override long Position {
146                                 get {
147                                         throw new NotImplementedException ();
148                                 }
149                                 set {
150                                         throw new NotImplementedException ();
151                                 }
152                         }
153                 }
154
155                 class ThrowOnlyProxy : IWebProxy
156                 {
157                         public ICredentials Credentials {
158                                 get {
159                                         throw new NotImplementedException ();
160                                 }
161
162                                 set {
163                                         throw new NotImplementedException ();
164                                 }
165                         }
166
167                         public Uri GetProxy (Uri destination)
168                         {
169                                 throw new NotImplementedException ();
170                         }
171
172                         public bool IsBypassed (Uri host)
173                         {
174                                 throw new NotImplementedException ();
175                         }
176                 }
177
178                 const int WaitTimeout = 5000;
179
180                 [Test]
181                 public void Ctor_Default ()
182                 {
183                         var client = new HttpClient ();
184                         Assert.IsNull (client.BaseAddress, "#1");
185                         Assert.IsNotNull (client.DefaultRequestHeaders, "#2");  // TODO: full check
186                         Assert.AreEqual (int.MaxValue, client.MaxResponseContentBufferSize, "#3");
187                         Assert.AreEqual (TimeSpan.FromSeconds (100), client.Timeout, "#4");
188                 }
189
190                 [Test]
191                 public void CancelPendingRequests ()
192                 {
193                         var mh = new HttpMessageHandlerMock ();
194
195                         var client = new HttpClient (mh);
196                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
197                         var mre = new ManualResetEvent (false);
198
199                         mh.OnSendFull = (l, c) => {
200                                 mre.Set ();
201                                 Assert.IsTrue (c.WaitHandle.WaitOne (1000), "#20");
202                                 Assert.IsTrue (c.IsCancellationRequested, "#21");
203                                 mre.Set ();
204                                 return Task.FromResult (new HttpResponseMessage ());
205                         };
206
207                         var t = Task.Factory.StartNew (() => {
208                                 client.SendAsync (request).Wait (WaitTimeout);
209                         });
210
211                         Assert.IsTrue (mre.WaitOne (500), "#1");
212                         mre.Reset ();
213                         client.CancelPendingRequests ();
214                         Assert.IsTrue (t.Wait (500), "#2");
215
216                         request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
217                         mh.OnSendFull = (l, c) => {
218                                 Assert.IsFalse (c.IsCancellationRequested, "#30");
219                                 return Task.FromResult (new HttpResponseMessage ());
220                         };
221
222                         client.SendAsync (request).Wait (WaitTimeout);
223                 }
224
225                 [Test]
226                 public void CancelPendingRequests_BeforeSend ()
227                 {
228                         var ct = new CancellationTokenSource ();
229                         ct.Cancel ();
230                         var rr = CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken (), ct.Token);
231
232
233                         var mh = new HttpMessageHandlerMock ();
234
235                         var client = new HttpClient (mh);
236                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
237                         client.CancelPendingRequests ();
238
239                         mh.OnSendFull = (l, c) => {
240                                 Assert.IsFalse (c.IsCancellationRequested, "#30");
241                                 return Task.FromResult (new HttpResponseMessage ());
242                         };
243
244                         client.SendAsync (request).Wait (WaitTimeout);
245
246                         request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
247                         client.SendAsync (request).Wait (WaitTimeout);
248                 }
249
250
251                 [Test]
252 #if FEATURE_NO_BSD_SOCKETS
253                 // Using HttpClientHandler, which indirectly requires BSD sockets.
254                 [ExpectedException (typeof (PlatformNotSupportedException))]
255 #endif
256                 public void CancelRequestViaProxy ()
257                 {
258                         var handler = new HttpClientHandler {
259                                 Proxy = new WebProxy ("192.168.10.25:8888/"), // proxy that doesn't exist
260                                 UseProxy = true,
261                                 AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
262                         };
263
264                         var httpClient = new HttpClient (handler) {
265                                 BaseAddress = new Uri ("https://google.com"),
266                                 Timeout = TimeSpan.FromMilliseconds (1)
267                         };
268
269                         try {
270                                 var restRequest = new HttpRequestMessage {
271                                         Method = HttpMethod.Post,
272                                         RequestUri = new Uri("foo", UriKind.Relative),
273                                         Content = new StringContent("", null, "application/json")
274                                 };
275
276                                 httpClient.PostAsync (restRequest.RequestUri, restRequest.Content).Wait (WaitTimeout);
277                                 Assert.Fail ("#1");
278                         } catch (AggregateException e) {
279                                 Assert.IsTrue (e.InnerException is TaskCanceledException, "#2");
280                         }
281                 }
282
283                 [Test]
284                 public void Properties ()
285                 {
286                         var client = new HttpClient ();
287                         client.BaseAddress = null;
288                         client.MaxResponseContentBufferSize = int.MaxValue;
289                         client.Timeout = Timeout.InfiniteTimeSpan;
290
291                         Assert.IsNull (client.BaseAddress, "#1");
292                         Assert.AreEqual (int.MaxValue, client.MaxResponseContentBufferSize, "#2");
293                         Assert.AreEqual (Timeout.InfiniteTimeSpan, client.Timeout, "#3");
294                 }
295
296                 [Test]
297                 public void Properties_Invalid ()
298                 {
299                         var client = new HttpClient ();
300                         try {
301                                 client.MaxResponseContentBufferSize = 0;
302                                 Assert.Fail ("#1");
303                         } catch (ArgumentOutOfRangeException) {
304                         }
305
306                         try {
307                                 client.Timeout = TimeSpan.MinValue;
308                                 Assert.Fail ("#2");
309                         } catch (ArgumentOutOfRangeException) {
310                         }
311
312                         try {
313                                 client.Timeout = TimeSpan.Zero;
314                                 Assert.Fail ("#3");
315                         } catch (ArgumentOutOfRangeException) {
316                         }
317
318                         try {
319                                 client.Timeout = TimeSpan.FromMilliseconds (int.MaxValue + 1L);
320                                 Assert.Fail ("#3");
321                         } catch (ArgumentOutOfRangeException) {
322                         }
323                 }
324
325                 [Test]
326 #if FEATURE_NO_BSD_SOCKETS
327                 [ExpectedException (typeof (PlatformNotSupportedException))]
328 #endif
329                 public void Proxy_Disabled ()
330                 {
331                         var pp = WebRequest.DefaultWebProxy;
332
333                         try {
334                                 WebRequest.DefaultWebProxy = new ThrowOnlyProxy ();
335
336                                 var request = new HttpClientHandler {
337                                         UseProxy = false
338                                 };
339
340                                 var client = new HttpClient (request);
341                                 Assert.IsTrue (client.GetAsync ("http://google.com").Wait (5000), "needs internet access");
342                         } finally {
343                                 WebRequest.DefaultWebProxy = pp;
344                         }
345                 }
346
347                 [Test]
348                 public void Send ()
349                 {
350                         var mh = new HttpMessageHandlerMock ();
351
352                         var client = new HttpClient (mh);
353                         client.BaseAddress = new Uri ("http://xamarin.com");
354                         var request = new HttpRequestMessage ();
355                         var response = new HttpResponseMessage ();
356
357                         mh.OnSend = l => {
358                                 Assert.AreEqual (l, request, "#2");
359                                 Assert.AreEqual (client.BaseAddress, l.RequestUri, "#2");
360                                 return Task.FromResult (response);
361                         };
362
363                         Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
364                 }
365
366                 [Test]
367                 public void Send_BaseAddress ()
368                 {
369                         var mh = new HttpMessageHandlerMock ();
370
371                         var client = new HttpClient (mh);
372                         client.BaseAddress = new Uri ("http://localhost/");
373                         var response = new HttpResponseMessage ();
374
375                         mh.OnSend = l => {
376                                 Assert.AreEqual ("http://localhost/relative", l.RequestUri.ToString (), "#2");
377                                 return Task.FromResult (response);
378                         };
379
380                         Assert.AreEqual (response, client.GetAsync ("relative").Result, "#1");
381                         Assert.AreEqual (response, client.GetAsync ("/relative").Result, "#2");
382                 }
383
384                 [Test]
385                 public void Send_DefaultRequestHeaders ()
386                 {
387                         var mh = new HttpMessageHandlerMock ();
388
389                         var client = new HttpClient (mh);
390                         client.DefaultRequestHeaders.Referrer = new Uri ("http://google.com");
391
392                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
393                         var response = new HttpResponseMessage ();
394
395                         mh.OnSend = l => {
396                                 Assert.AreEqual (client.DefaultRequestHeaders.Referrer, l.Headers.Referrer, "#2");
397                                 Assert.IsNotNull (l.Headers.Referrer, "#3");
398                                 return Task.FromResult (response);
399                         };
400
401                         Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
402                 }
403
404                 [Test]
405 #if FEATURE_NO_BSD_SOCKETS
406                 [ExpectedException (typeof (PlatformNotSupportedException))]
407 #endif
408                 public void Send_Complete_Default ()
409                 {
410                         bool? failed = null;
411                         var port = NetworkHelpers.FindFreePort ();
412                         var listener = CreateListener (l => {
413                                 try {
414                                         var request = l.Request;
415         
416                                         Assert.IsNull (request.AcceptTypes, "#1");
417                                         Assert.AreEqual (0, request.ContentLength64, "#2");
418                                         Assert.IsNull (request.ContentType, "#3");
419                                         Assert.AreEqual (0, request.Cookies.Count, "#4");
420                                         Assert.IsFalse (request.HasEntityBody, "#5");
421                                         Assert.AreEqual ($"localhost:{port}", request.Headers["Host"], "#6b");
422                                         Assert.AreEqual ("GET", request.HttpMethod, "#7");
423                                         Assert.IsFalse (request.IsAuthenticated, "#8");
424                                         Assert.IsTrue (request.IsLocal, "#9");
425                                         Assert.IsFalse (request.IsSecureConnection, "#10");
426                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
427                                         Assert.IsTrue (request.KeepAlive, "#12");
428                                         Assert.AreEqual (HttpVersion.Version11, request.ProtocolVersion, "#13");
429                                         Assert.IsNull (request.ServiceName, "#14");
430                                         Assert.IsNull (request.UrlReferrer, "#15");
431                                         Assert.IsNull (request.UserAgent, "#16");
432                                         Assert.IsNull (request.UserLanguages, "#17");
433                                         failed = false;
434                                 } catch {
435                                         failed = true;
436                                 }
437                         }, port);
438
439                         try {
440                                 var client = new HttpClient ();
441                                 var request = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
442                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
443
444                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
445                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
446                                 Assert.AreEqual (false, failed, "#102");
447                         } finally {
448                                 listener.Close ();
449                         }
450                 }
451
452                 [Test]
453 #if FEATURE_NO_BSD_SOCKETS
454                 [ExpectedException (typeof (PlatformNotSupportedException))]
455 #endif
456                 public void Send_Complete_Version_1_0 ()
457                 {
458                         bool? failed = null;
459                         
460                         var port = NetworkHelpers.FindFreePort ();
461                         var listener = CreateListener (l => {
462                                 try {
463                                         var request = l.Request;
464         
465                                         Assert.IsNull (request.AcceptTypes, "#1");
466                                         Assert.AreEqual (0, request.ContentLength64, "#2");
467                                         Assert.IsNull (request.ContentType, "#3");
468                                         Assert.AreEqual (0, request.Cookies.Count, "#4");
469                                         Assert.IsFalse (request.HasEntityBody, "#5");
470                                         Assert.AreEqual (1, request.Headers.Count, "#6");
471                                         Assert.AreEqual ($"localhost:{port}", request.Headers["Host"], "#6a");
472                                         Assert.AreEqual ("GET", request.HttpMethod, "#7");
473                                         Assert.IsFalse (request.IsAuthenticated, "#8");
474                                         Assert.IsTrue (request.IsLocal, "#9");
475                                         Assert.IsFalse (request.IsSecureConnection, "#10");
476                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
477                                         Assert.IsFalse (request.KeepAlive, "#12");
478                                         Assert.AreEqual (HttpVersion.Version10, request.ProtocolVersion, "#13");
479                                         Assert.IsNull (request.ServiceName, "#14");
480                                         Assert.IsNull (request.UrlReferrer, "#15");
481                                         Assert.IsNull (request.UserAgent, "#16");
482                                         Assert.IsNull (request.UserLanguages, "#17");
483                                         failed = false;
484                                 } catch {
485                                         failed = true;
486                                 }
487                         }, port);
488
489                         try {
490                                 var client = new HttpClient ();
491                                 var request = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
492                                 request.Version = HttpVersion.Version10;
493                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
494
495                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
496                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
497                                 Assert.AreEqual (false, failed, "#102");
498                         } finally {
499                                 listener.Close ();
500                         }
501                 }
502
503                 [Test]
504 #if FEATURE_NO_BSD_SOCKETS
505                 [ExpectedException (typeof (PlatformNotSupportedException))]
506 #endif
507                 public void Send_Complete_ClientHandlerSettings ()
508                 {
509                         bool? failed = null;
510                         
511                         var port = NetworkHelpers.FindFreePort ();
512                         var listener = CreateListener (l => {
513                                 var request = l.Request;
514                                 
515                                 try {
516                                         Assert.IsNull (request.AcceptTypes, "#1");
517                                         Assert.AreEqual (0, request.ContentLength64, "#2");
518                                         Assert.IsNull (request.ContentType, "#3");
519                                         Assert.AreEqual (1, request.Cookies.Count, "#4");
520                                         Assert.AreEqual (new Cookie ("mycookie", "vv"), request.Cookies[0], "#4a");
521                                         Assert.IsFalse (request.HasEntityBody, "#5");
522                                         Assert.AreEqual (4, request.Headers.Count, "#6");
523                                         Assert.AreEqual ($"localhost:{port}", request.Headers["Host"], "#6a");
524                                         Assert.AreEqual ("gzip", request.Headers["Accept-Encoding"], "#6b");
525                                         Assert.AreEqual ("mycookie=vv", request.Headers["Cookie"], "#6c");
526                                         Assert.AreEqual ("GET", request.HttpMethod, "#7");
527                                         Assert.IsFalse (request.IsAuthenticated, "#8");
528                                         Assert.IsTrue (request.IsLocal, "#9");
529                                         Assert.IsFalse (request.IsSecureConnection, "#10");
530                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
531                                         Assert.IsTrue (request.KeepAlive, "#12");
532                                         Assert.AreEqual (HttpVersion.Version10, request.ProtocolVersion, "#13");
533                                         Assert.IsNull (request.ServiceName, "#14");
534                                         Assert.IsNull (request.UrlReferrer, "#15");
535                                         Assert.IsNull (request.UserAgent, "#16");
536                                         Assert.IsNull (request.UserLanguages, "#17");
537                                         failed = false;
538                                 } catch {
539                                         failed = true;
540                                 }
541                         }, port);
542
543                         try {
544                                 var chandler = new HttpClientHandler ();
545                                 chandler.AllowAutoRedirect = true;
546                                 chandler.AutomaticDecompression = DecompressionMethods.GZip;
547                                 chandler.MaxAutomaticRedirections = 33;
548                                 chandler.MaxRequestContentBufferSize = 5555;
549                                 chandler.PreAuthenticate = true;
550                                 chandler.CookieContainer.Add (new Uri ($"http://localhost:{port}/"), new Cookie ( "mycookie", "vv"));
551                                 chandler.UseCookies = true;
552                                 chandler.UseDefaultCredentials = true;
553                                 chandler.Proxy = new WebProxy ("ee");
554                                 chandler.UseProxy = true;
555
556                                 var client = new HttpClient (chandler);
557                                 var request = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
558                                 request.Version = HttpVersion.Version10;
559                                 request.Headers.Add ("Keep-Alive", "false");
560                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
561
562                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
563                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
564                                 Assert.AreEqual (false, failed, "#102");
565                         } finally {
566                                 listener.Abort ();
567                                 listener.Close ();
568                         }
569                 }
570
571                 [Test]
572 #if FEATURE_NO_BSD_SOCKETS
573                 [ExpectedException (typeof (PlatformNotSupportedException))]
574 #endif
575                 public void Send_Complete_CustomHeaders ()
576                 {
577                         bool? failed = null;
578                         
579                         var port = NetworkHelpers.FindFreePort ();
580                         var listener = CreateListener (l => {
581                                 var request = l.Request;
582                                 try {
583                                         Assert.AreEqual ("vv", request.Headers["aa"], "#1");
584         
585                                         var response = l.Response;
586                                         response.Headers.Add ("rsp", "rrr");
587                                         response.Headers.Add ("upgrade", "vvvvaa");
588                                         response.Headers.Add ("Date", "aa");
589                                         response.Headers.Add ("cache-control", "audio");
590         
591                                         response.StatusDescription = "test description";
592                                         response.ProtocolVersion = HttpVersion.Version10;
593                                         response.SendChunked = true;
594                                         response.RedirectLocation = "w3.org";
595                                         
596                                         failed = false;
597                                 } catch {
598                                         failed = true;
599                                 }
600                         }, port);
601
602                         try {
603                                 var client = new HttpClient ();
604                                 var request = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
605                                 Assert.IsTrue (request.Headers.TryAddWithoutValidation ("aa", "vv"), "#0");
606                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
607
608                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
609                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
610                                 
611                                 IEnumerable<string> values;
612                                 Assert.IsTrue (response.Headers.TryGetValues ("rsp", out values), "#102");
613                                 Assert.AreEqual ("rrr", values.First (), "#102a");
614
615                                 Assert.IsTrue (response.Headers.TryGetValues ("Transfer-Encoding", out values), "#103");
616                                 Assert.AreEqual ("chunked", values.First (), "#103a");
617                                 Assert.AreEqual (true, response.Headers.TransferEncodingChunked, "#103b");
618
619                                 Assert.IsTrue (response.Headers.TryGetValues ("Date", out values), "#104");
620                                 Assert.AreEqual (1, values.Count (), "#104b");
621                                 // .NET overwrites Date, Mono does not
622                                 // Assert.IsNotNull (response.Headers.Date, "#104c");
623
624                                 Assert.AreEqual (new ProductHeaderValue ("vvvvaa"), response.Headers.Upgrade.First (), "#105");
625
626                                 Assert.AreEqual ("audio", response.Headers.CacheControl.Extensions.First ().Name, "#106");
627
628                                 Assert.AreEqual ("w3.org", response.Headers.Location.OriginalString, "#107");
629
630                                 Assert.AreEqual ("test description", response.ReasonPhrase, "#110");
631                                 Assert.AreEqual (HttpVersion.Version11, response.Version, "#111");
632                                 
633                                 Assert.AreEqual (false, failed, "#112");
634                         } finally {
635                                 listener.Close ();
636                         }
637                 }
638
639                 [Test]
640 #if FEATURE_NO_BSD_SOCKETS
641                 [ExpectedException (typeof (PlatformNotSupportedException))]
642 #endif
643                 public void Send_Complete_CustomHeaders_SpecialSeparators ()
644                 {
645                         bool? failed = null;
646
647                         var port = NetworkHelpers.FindFreePort ();
648                         var listener = CreateListener (l => {
649                                 var request = l.Request;
650
651                                 try {
652                                         Assert.AreEqual ("MLK Android Phone 1.1.9", request.UserAgent, "#1");
653                                         failed = false;
654                                 } catch {
655                                         failed = true;
656                                 }
657                         }, port);
658
659                         try {
660                                 var client = new HttpClient ();
661
662                                 client.DefaultRequestHeaders.Add("User-Agent", "MLK Android Phone 1.1.9");
663
664                                 var request = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
665
666                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
667
668                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
669                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
670                                 Assert.AreEqual (false, failed, "#102");
671                         } finally {
672                                 listener.Abort ();
673                                 listener.Close ();
674                         }
675                 }
676
677                 [Test]
678 #if FEATURE_NO_BSD_SOCKETS
679                 [ExpectedException (typeof (PlatformNotSupportedException))]
680 #endif
681                 public void Send_Complete_CustomHeaders_Host ()
682                 {
683                         bool? failed = null;
684                         var port = NetworkHelpers.FindFreePort ();
685                         var listener = CreateListener (l => {
686                                 var request = l.Request;
687
688                                 try {
689                                         Assert.AreEqual ("customhost", request.Headers["Host"], "#1");
690                                         failed = false;
691                                 } catch {
692                                         failed = true;
693                                 }
694                         }, port);
695
696                         try {
697                                 var client = new HttpClient ();
698
699                                 client.DefaultRequestHeaders.Add("Host", "customhost");
700
701                                 var request = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
702
703                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
704
705                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
706                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
707                                 Assert.AreEqual (false, failed, "#102");
708                         } finally {
709                                 listener.Abort ();
710                                 listener.Close ();
711                         }
712                 }
713
714                 [Test]
715 #if FEATURE_NO_BSD_SOCKETS
716                 [ExpectedException (typeof (PlatformNotSupportedException))]
717 #endif
718                 public void Send_Transfer_Encoding_Chunked ()
719                 {
720                         bool? failed = null;
721
722                         var port = NetworkHelpers.FindFreePort ();
723                         var listener = CreateListener (l => {
724                                 var request = l.Request;
725
726                                 try {
727                                         Assert.AreEqual (2, request.Headers.Count, "#1");
728                                         Assert.AreEqual ("keep-alive", request.Headers ["Connection"], "#2");
729                                         failed = false;
730                                 } catch (Exception ex){
731                                         Console.WriteLine (ex);
732                                         Console.WriteLine (String.Join ("#", l.Request.Headers.AllKeys));
733                                         failed = true;
734                                 }
735                         }, port);
736
737                         try {
738                                 var client = new HttpClient ();
739                                 client.DefaultRequestHeaders.TransferEncodingChunked = true;
740
741                                 client.GetAsync ($"http://localhost:{port}/").Wait ();
742
743                                 Assert.AreEqual (false, failed, "#102");
744                         } finally {
745                                 listener.Abort ();
746                                 listener.Close ();
747                         }
748                 }
749
750                 [Test]
751 #if FEATURE_NO_BSD_SOCKETS
752                 [ExpectedException (typeof (PlatformNotSupportedException))]
753 #endif
754                 public void Send_Transfer_Encoding_Custom ()
755                 {
756                         bool? failed = null;
757
758                         var port = NetworkHelpers.FindFreePort ();
759                         var listener = CreateListener (l => {
760                                 failed = true;
761                         }, port);
762
763                         try {
764                                 var client = new HttpClient ();
765                                 client.DefaultRequestHeaders.TransferEncoding.Add (new TransferCodingHeaderValue ("chunked2"));
766
767                                 var request = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
768
769                                 try {
770                                         client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Wait ();
771                                         Assert.Fail ("#1");
772                                 } catch (AggregateException e) {
773                                         Assert.AreEqual (typeof (ProtocolViolationException), e.InnerException.GetType (), "#2");
774                                 }
775                                 Assert.IsNull (failed, "#102");
776                         } finally {
777                                 listener.Abort ();
778                                 listener.Close ();
779                         }
780                 }
781
782                 [Test]
783 #if FEATURE_NO_BSD_SOCKETS
784                 [ExpectedException (typeof (PlatformNotSupportedException))]
785 #endif
786                 public void Send_Complete_Content ()
787                 {
788                         var port = NetworkHelpers.FindFreePort ();
789                         var listener = CreateListener (l => {
790                                 var request = l.Request;
791                                 l.Response.OutputStream.WriteByte (55);
792                                 l.Response.OutputStream.WriteByte (75);
793                         }, port);
794
795                         try {
796                                 var client = new HttpClient ();
797                                 var request = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
798                                 Assert.IsTrue (request.Headers.TryAddWithoutValidation ("aa", "vv"), "#0");
799                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
800
801                                 Assert.AreEqual ("7K", response.Content.ReadAsStringAsync ().Result, "#100");
802                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
803
804                                 IEnumerable<string> values;
805                                 Assert.IsTrue (response.Headers.TryGetValues ("Transfer-Encoding", out values), "#102");
806                                 Assert.AreEqual ("chunked", values.First (), "#102a");
807                                 Assert.AreEqual (true, response.Headers.TransferEncodingChunked, "#102b");
808                         } finally {
809                                 listener.Close ();
810                         }
811                 }
812
813                 [Test]
814 #if FEATURE_NO_BSD_SOCKETS
815                 [ExpectedException (typeof (PlatformNotSupportedException))]
816 #endif
817                 public void Send_Complete_Content_MaxResponseContentBufferSize ()
818                 {
819                         var port = NetworkHelpers.FindFreePort ();
820                         var listener = CreateListener (l => {
821                                 var request = l.Request;
822                                 var b = new byte[4000];
823                                 l.Response.OutputStream.Write (b, 0, b.Length);
824                         }, port);
825
826                         try {
827                                 var client = new HttpClient ();
828                                 client.MaxResponseContentBufferSize = 1000;
829                                 var request = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
830                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
831
832                                 Assert.AreEqual (4000, response.Content.ReadAsStringAsync ().Result.Length, "#100");
833                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
834                         } finally {
835                                 listener.Close ();
836                         }
837                 }
838
839                 [Test]
840 #if FEATURE_NO_BSD_SOCKETS
841                 [ExpectedException (typeof (PlatformNotSupportedException))]
842 #endif
843                 public void Send_Complete_Content_MaxResponseContentBufferSize_Error ()
844                 {
845                         var port = NetworkHelpers.FindFreePort ();
846                         var listener = CreateListener (l => {
847                                 var request = l.Request;
848                                 var b = new byte[4000];
849                                 l.Response.OutputStream.Write (b, 0, b.Length);
850                         }, port);
851
852                         try {
853                                 var client = new HttpClient ();
854                                 client.MaxResponseContentBufferSize = 1000;
855                                 var request = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
856
857                                 try {
858                                         client.SendAsync (request, HttpCompletionOption.ResponseContentRead).Wait (WaitTimeout);
859                                         Assert.Fail ("#2");
860                                 } catch (AggregateException e) {
861                                         Assert.IsTrue (e.InnerException is HttpRequestException, "#3");
862                                 }
863
864                         } finally {
865                                 listener.Close ();
866                         }
867                 }
868
869                 [Test]
870 #if FEATURE_NO_BSD_SOCKETS
871                 [ExpectedException (typeof (PlatformNotSupportedException))]
872 #endif
873                 public void Send_Complete_NoContent_Post ()
874                 {
875                         Send_Complete_NoContent (HttpMethod.Post);
876                 }
877
878                 [Test]
879 #if FEATURE_NO_BSD_SOCKETS
880                 [ExpectedException (typeof (PlatformNotSupportedException))]
881 #endif
882                 public void Send_Complete_NoContent_Put ()
883                 {
884                         Send_Complete_NoContent (HttpMethod.Put);
885                 }
886
887                 [Test]
888 #if FEATURE_NO_BSD_SOCKETS
889                 [ExpectedException (typeof (PlatformNotSupportedException))]
890 #endif
891                 public void Send_Complete_NoContent_Delete ()
892                 {
893                         Send_Complete_NoContent (HttpMethod.Delete);
894                 }
895
896                 void Send_Complete_NoContent (HttpMethod method)
897                 {
898                         bool? failed = null;
899                         var port = NetworkHelpers.FindFreePort ();
900                         var listener = CreateListener (l => {
901                                 try {
902                                         var request = l.Request;
903
904                                         Assert.AreEqual (3, request.Headers.Count, "#1");
905                                         Assert.AreEqual ("0", request.Headers ["Content-Length"], "#1b");
906                                         Assert.AreEqual ("keep-alive", request.Headers ["Connection"], "#1c");
907                                         Assert.AreEqual (method.Method, request.HttpMethod, "#2");
908                                         failed = false;
909                                 } catch (Exception ex){
910                                         Console.WriteLine (ex);
911                                         Console.WriteLine (String.Join ("#", l.Request.Headers.AllKeys));
912                                         
913                                         failed = true;
914                                 }
915                         }, port);
916
917                         try {
918                                 var client = new HttpClient ();
919                                 var request = new HttpRequestMessage (method, $"http://localhost:{port}/");
920                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
921
922                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
923                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
924                                 Assert.AreEqual (false, failed, "#102");
925                         } finally {
926                                 listener.Close ();
927                         }
928                 }
929
930                 [Test]
931 #if FEATURE_NO_BSD_SOCKETS
932                 [ExpectedException (typeof (PlatformNotSupportedException))]
933 #endif
934                 public void Send_Complete_Error ()
935                 {
936                         var port = NetworkHelpers.FindFreePort ();
937                         var listener = CreateListener (l => {
938                                 var response = l.Response;
939                                 response.StatusCode = 500;
940                         }, port);
941
942                         try {
943                                 var client = new HttpClient ();
944                                 var request = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
945                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
946
947                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
948                                 Assert.AreEqual (HttpStatusCode.InternalServerError, response.StatusCode, "#101");
949                         } finally {
950                                 listener.Close ();
951                         }
952                 }
953
954                 [Test]
955 #if FEATURE_NO_BSD_SOCKETS
956                 [ExpectedException (typeof (PlatformNotSupportedException))]
957 #endif
958                 public void Send_Content_Get ()
959                 {
960                         var port = NetworkHelpers.FindFreePort ();
961                         var listener = CreateListener (l => {
962                                 var request = l.Request;
963                                 l.Response.OutputStream.WriteByte (72);
964                         }, port);
965
966                         try {
967                                 var client = new HttpClient ();
968                                 var r = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
969                                 var response = client.SendAsync (r).Result;
970
971                                 Assert.AreEqual ("H", response.Content.ReadAsStringAsync ().Result);
972                         } finally {
973                                 listener.Close ();
974                         }
975                 }
976
977                 [Test]
978 #if FEATURE_NO_BSD_SOCKETS
979                 [ExpectedException (typeof (PlatformNotSupportedException))]
980 #endif
981                 public void Send_Content_BomEncoding ()
982                 {
983                         var port = NetworkHelpers.FindFreePort ();
984                         var listener = CreateListener (l => {
985                                 var request = l.Request;
986
987                                 var str = l.Response.OutputStream;
988                                 str.WriteByte (0xEF);
989                                 str.WriteByte (0xBB);
990                                 str.WriteByte (0xBF);
991                                 str.WriteByte (71);
992                         }, port);
993
994                         try {
995                                 var client = new HttpClient ();
996                                 var r = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{port}/");
997                                 var response = client.SendAsync (r).Result;
998
999                                 Assert.AreEqual ("G", response.Content.ReadAsStringAsync ().Result);
1000                         } finally {
1001                                 listener.Close ();
1002                         }
1003                 }
1004
1005                 [Test]
1006 #if FEATURE_NO_BSD_SOCKETS
1007                 [ExpectedException (typeof (PlatformNotSupportedException))]
1008 #endif
1009                 public void Send_Content_Put ()
1010                 {
1011                         bool passed = false;
1012                         var port = NetworkHelpers.FindFreePort ();
1013                         var listener = CreateListener (l => {
1014                                 var request = l.Request;
1015                                 passed = 7 == request.ContentLength64;
1016                                 passed &= request.ContentType == "text/plain; charset=utf-8";
1017                                 passed &= request.InputStream.ReadByte () == 'm';
1018                         }, port);
1019
1020                         try {
1021                                 var client = new HttpClient ();
1022                                 var r = new HttpRequestMessage (HttpMethod.Put, $"http://localhost:{port}/");
1023                                 r.Content = new StringContent ("my text");
1024                                 var response = client.SendAsync (r).Result;
1025
1026                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#1");
1027                                 Assert.IsTrue (passed, "#2");
1028                         } finally {
1029                                 listener.Abort ();
1030                                 listener.Close ();
1031                         }
1032                 }
1033
1034                 [Test]
1035 #if FEATURE_NO_BSD_SOCKETS
1036                 [ExpectedException (typeof (PlatformNotSupportedException))]
1037 #endif
1038                 public void Send_Content_Put_CustomStream ()
1039                 {
1040                         bool passed = false;
1041                         var port = NetworkHelpers.FindFreePort ();
1042                         var listener = CreateListener (l => {
1043                                 var request = l.Request;
1044                                 passed = 44 == request.ContentLength64;
1045                                 passed &= request.ContentType == null;
1046                         }, port);
1047
1048                         try {
1049                                 var client = new HttpClient ();
1050                                 var r = new HttpRequestMessage (HttpMethod.Put, $"http://localhost:{port}/");
1051                                 r.Content = new StreamContent (new CustomStream ());
1052                                 var response = client.SendAsync (r).Result;
1053
1054                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#1");
1055                                 Assert.IsTrue (passed, "#2");
1056                         } finally {
1057                                 listener.Abort ();
1058
1059                                 listener.Close ();
1060                         }
1061                 }
1062
1063                 [Test]
1064                 public void Send_Timeout ()
1065                 {
1066                         var mh = new HttpMessageHandlerMock ();
1067
1068                         var client = new HttpClient (mh);
1069                         client.Timeout = TimeSpan.FromMilliseconds (100);
1070                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
1071                         var response = new HttpResponseMessage ();
1072
1073                         mh.OnSendFull = (l, c) => {
1074                                 Assert.IsTrue (c.WaitHandle.WaitOne (500), "#2");
1075                                 return Task.FromResult (response);
1076                         };
1077
1078                         Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
1079                 }
1080
1081                 [Test]
1082                 public void Send_Invalid ()
1083                 {
1084                         var client = new HttpClient ();
1085                         try {
1086                                 client.SendAsync (null).Wait (WaitTimeout);
1087                                 Assert.Fail ("#1");
1088                         } catch (ArgumentNullException) {
1089                         }
1090
1091                         try {
1092                                 var request = new HttpRequestMessage ();
1093                                 client.SendAsync (request).Wait (WaitTimeout);
1094                                 Assert.Fail ("#2");
1095                         } catch (InvalidOperationException) {
1096                         }
1097                 }
1098
1099                 [Test]
1100                 public void Send_InvalidHandler ()
1101                 {
1102                         var mh = new HttpMessageHandlerMock ();
1103
1104                         var client = new HttpClient (mh);
1105                         client.BaseAddress = new Uri ("http://xamarin.com");
1106                         var request = new HttpRequestMessage ();
1107
1108                         mh.OnSend = l => {
1109                                 Assert.AreEqual (l, request, "#1");
1110                                 return null;
1111                         };
1112
1113                         try {
1114                                 // Broken by design
1115                                 client.SendAsync (request).Wait (WaitTimeout);
1116                                 Assert.Fail ("#2");
1117                         } catch (Exception) {
1118                         }
1119                 }
1120
1121                 [Test]
1122                 public void Send_SameMessage ()
1123                 {
1124                         var mh = new HttpMessageHandlerMock ();
1125
1126                         var client = new HttpClient (mh);
1127                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
1128
1129                         mh.OnSend = l => Task.FromResult (new HttpResponseMessage ());
1130
1131                         client.SendAsync (request).Wait (WaitTimeout);
1132                         try {
1133                                 client.SendAsync (request).Wait (WaitTimeout);
1134                                 Assert.Fail ("#1");
1135                         } catch (InvalidOperationException) {
1136                         }
1137                 }
1138
1139                 [Test]
1140 #if FEATURE_NO_BSD_SOCKETS
1141                 [ExpectedException (typeof (PlatformNotSupportedException))]
1142 #endif
1143                 public void Post_TransferEncodingChunked ()
1144                 {
1145                         bool? failed = null;
1146                         var port = NetworkHelpers.FindFreePort ();
1147                         var listener = CreateListener (l => {
1148                                 try {
1149                                         var request = l.Request;
1150
1151                                         Assert.IsNull (request.AcceptTypes, "#1");
1152                                         Assert.AreEqual (-1, request.ContentLength64, "#2");
1153                                         Assert.IsNull (request.ContentType, "#3");
1154                                         Assert.AreEqual (0, request.Cookies.Count, "#4");
1155                                         Assert.IsTrue (request.HasEntityBody, "#5");
1156                                         Assert.AreEqual ($"localhost:{port}", request.Headers ["Host"], "#6b");
1157                                         Assert.AreEqual ("POST", request.HttpMethod, "#7");
1158                                         Assert.IsFalse (request.IsAuthenticated, "#8");
1159                                         Assert.IsTrue (request.IsLocal, "#9");
1160                                         Assert.IsFalse (request.IsSecureConnection, "#10");
1161                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
1162                                         Assert.IsTrue (request.KeepAlive, "#12");
1163                                         Assert.AreEqual (HttpVersion.Version11, request.ProtocolVersion, "#13");
1164                                         Assert.IsNull (request.ServiceName, "#14");
1165                                         Assert.IsNull (request.UrlReferrer, "#15");
1166                                         Assert.IsNull (request.UserAgent, "#16");
1167                                         Assert.IsNull (request.UserLanguages, "#17");
1168                                         Assert.AreEqual ("chunked", request.Headers ["Transfer-Encoding"], "#18");
1169                                         Assert.IsNull (request.Headers ["Content-Length"], "#19");
1170                                         failed = false;
1171                                 } catch (Exception e) {
1172                                         failed = true;
1173                                         Console.WriteLine (e);
1174                                 }
1175                         }, port);
1176
1177                         try {
1178                                 var client = new HttpClient ();
1179
1180                                 client.DefaultRequestHeaders.TransferEncodingChunked = true;
1181
1182                                 var imageContent = new StreamContent (new MemoryStream ());
1183
1184                                 var response = client.PostAsync ($"http://localhost:{port}/", imageContent).Result;
1185
1186                                 Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "#101");
1187                                 Assert.AreEqual(false, failed, "#102");
1188                         } finally {
1189                                 listener.Close ();
1190                         }
1191                 }
1192
1193                 [Test]
1194 #if FEATURE_NO_BSD_SOCKETS
1195                 [ExpectedException (typeof (PlatformNotSupportedException))]
1196 #endif
1197                 public void Post_StreamCaching ()
1198                 {
1199                         bool? failed = null;
1200                         var port = NetworkHelpers.FindFreePort ();
1201                         var listener = CreateListener (l => {
1202                                 try {
1203                                         var request = l.Request;
1204
1205                                         Assert.IsNull (request.AcceptTypes, "#1");
1206                                         Assert.AreEqual (0, request.ContentLength64, "#2");
1207                                         Assert.IsNull (request.ContentType, "#3");
1208                                         Assert.AreEqual (0, request.Cookies.Count, "#4");
1209                                         Assert.IsFalse (request.HasEntityBody, "#5");
1210                                         Assert.AreEqual ($"localhost:{port}", request.Headers ["Host"], "#6b");
1211                                         Assert.AreEqual ("POST", request.HttpMethod, "#7");
1212                                         Assert.IsFalse (request.IsAuthenticated, "#8");
1213                                         Assert.IsTrue (request.IsLocal, "#9");
1214                                         Assert.IsFalse (request.IsSecureConnection, "#10");
1215                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
1216                                         Assert.IsTrue (request.KeepAlive, "#12");
1217                                         Assert.AreEqual (HttpVersion.Version11, request.ProtocolVersion, "#13");
1218                                         Assert.IsNull (request.ServiceName, "#14");
1219                                         Assert.IsNull (request.UrlReferrer, "#15");
1220                                         Assert.IsNull (request.UserAgent, "#16");
1221                                         Assert.IsNull (request.UserLanguages, "#17");
1222                                         Assert.IsNull (request.Headers ["Transfer-Encoding"], "#18");
1223                                         Assert.AreEqual ("0", request.Headers ["Content-Length"], "#19");
1224                                         failed = false;
1225                                 } catch (Exception e) {
1226                                         failed = true;
1227                                         Console.WriteLine (e);
1228                                 }
1229                         }, port);
1230
1231                         try {
1232                                 var client = new HttpClient ();
1233
1234                                 var imageContent = new StreamContent (new MemoryStream ());
1235
1236                                 var response = client.PostAsync ($"http://localhost:{port}/", imageContent).Result;
1237
1238                                 Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "#101");
1239                                 Assert.AreEqual(false, failed, "#102");
1240                         } finally {
1241                                 listener.Close ();
1242                         }
1243                 }
1244
1245                 [Test]
1246                 [Category ("MobileNotWorking")] // Missing encoding
1247 #if FEATURE_NO_BSD_SOCKETS
1248                 [ExpectedException (typeof (PlatformNotSupportedException))]
1249 #endif
1250                 public void GetString_Many ()
1251                 {
1252                         Action<HttpListenerContext> context = (HttpListenerContext l) => {
1253                                 var response = l.Response;
1254                                 response.StatusCode = 200;
1255                                 response.OutputStream.WriteByte (0x68);
1256                                 response.OutputStream.WriteByte (0x65);
1257                                 response.OutputStream.WriteByte (0x6c);
1258                                 response.OutputStream.WriteByte (0x6c);
1259                                 response.OutputStream.WriteByte (0x6f);
1260                         };
1261
1262                         var port = NetworkHelpers.FindFreePort ();
1263                         var listener = CreateListener (context, port); // creates a default request handler
1264                         AddListenerContext (listener, context);  // add another request handler for the second request
1265
1266                         try {
1267                                 var client = new HttpClient ();
1268                                 var t1 = client.GetStringAsync ($"http://localhost:{port}/");
1269                                 var t2 = client.GetStringAsync ($"http://localhost:{port}/");
1270                                 Assert.IsTrue (Task.WaitAll (new [] { t1, t2 }, WaitTimeout));
1271                                 Assert.AreEqual ("hello", t1.Result, "#1");
1272                                 Assert.AreEqual ("hello", t2.Result, "#2");
1273                         } finally {
1274                                 listener.Abort ();
1275                                 listener.Close ();
1276                         }
1277                 }
1278
1279                 [Test]
1280 #if FEATURE_NO_BSD_SOCKETS
1281                 [ExpectedException (typeof (PlatformNotSupportedException))]
1282 #endif
1283                 public void GetByteArray_ServerError ()
1284                 {
1285                         var port = NetworkHelpers.FindFreePort ();
1286                         var listener = CreateListener (l => {
1287                                 var response = l.Response;
1288                                 response.StatusCode = 500;
1289                                 l.Response.OutputStream.WriteByte (72);
1290                         }, port);
1291
1292                         try {
1293                                 var client = new HttpClient ();
1294                                 try {
1295                                         client.GetByteArrayAsync ($"http://localhost:{port}/").Wait (WaitTimeout);
1296                                         Assert.Fail ("#1");
1297                                 } catch (AggregateException e) {
1298                                         Assert.IsTrue (e.InnerException is HttpRequestException , "#2");
1299                                 }
1300                         } finally {
1301                                 listener.Close ();
1302                         }
1303                 }
1304
1305                 [Test]
1306 #if FEATURE_NO_BSD_SOCKETS
1307                 [ExpectedException (typeof (PlatformNotSupportedException))]
1308 #endif
1309                 public void DisallowAutoRedirect ()
1310                 {
1311                         var port = NetworkHelpers.FindFreePort ();
1312                         var listener = CreateListener (l => {
1313                                 var request = l.Request;
1314                                 var response = l.Response;
1315                                 
1316                                 response.StatusCode = (int)HttpStatusCode.Moved;
1317                                 response.RedirectLocation = "http://xamarin.com/";
1318                         }, port);
1319
1320                         try {
1321                                 var chandler = new HttpClientHandler ();
1322                                 chandler.AllowAutoRedirect = false;
1323                                 var client = new HttpClient (chandler);
1324
1325                                 try {
1326                                         client.GetStringAsync ($"http://localhost:{port}/").Wait (WaitTimeout);
1327                                         Assert.Fail ("#1");
1328                                 } catch (AggregateException e) {
1329                                         Assert.IsTrue (e.InnerException is HttpRequestException, "#2");
1330                                 }
1331                         } finally {
1332                                 listener.Abort ();
1333                                 listener.Close ();
1334                         }
1335                 }
1336
1337                 [Test]
1338 #if FEATURE_NO_BSD_SOCKETS
1339                 [ExpectedException (typeof (PlatformNotSupportedException))]
1340 #endif
1341                 public void RequestUriAfterRedirect ()
1342                 {
1343                         var port = NetworkHelpers.FindFreePort ();
1344                         var redirectPort = NetworkHelpers.FindFreePort ();
1345
1346                         var listener = CreateListener (l => {
1347                                 var request = l.Request;
1348                                 var response = l.Response;
1349
1350                                 response.StatusCode = (int)HttpStatusCode.Moved;
1351                                 response.RedirectLocation = $"http://localhost:{redirectPort}/";
1352                         }, port);
1353
1354                         var listener2 = CreateListener (l => {
1355                                 var response = l.Response;
1356
1357                                 response.StatusCode = (int)HttpStatusCode.OK;
1358                                 response.OutputStream.WriteByte (0x68);
1359                                 response.OutputStream.WriteByte (0x65);
1360                                 response.OutputStream.WriteByte (0x6c);
1361                                 response.OutputStream.WriteByte (0x6c);
1362                                 response.OutputStream.WriteByte (0x6f);
1363                         }, redirectPort);
1364
1365                         try {
1366                                 var chandler = new HttpClientHandler ();
1367                                 chandler.AllowAutoRedirect = true;
1368                                 var client = new HttpClient (chandler);
1369
1370                                 var r = client.GetAsync ($"http://localhost:{port}/");
1371                                 Assert.IsTrue (r.Wait (WaitTimeout), "#1");
1372                                 var resp = r.Result;
1373                                 Assert.AreEqual ($"http://localhost:{redirectPort}/", resp.RequestMessage.RequestUri.AbsoluteUri, "#2");
1374                                 Assert.AreEqual ("hello", resp.Content.ReadAsStringAsync ().Result, "#3");
1375                         } finally {
1376                                 listener.Abort ();
1377                                 listener.Close ();
1378                                 listener2.Abort ();
1379                                 listener2.Close ();
1380                         }
1381                 }
1382
1383                 [Test]
1384 #if FEATURE_NO_BSD_SOCKETS
1385                 [ExpectedException (typeof (PlatformNotSupportedException))]
1386 #endif
1387                 /*
1388                  * Properties may only be modified before sending the first request.
1389                  */
1390                 public void ModifyHandlerAfterFirstRequest ()
1391                 {
1392                         var chandler = new HttpClientHandler ();
1393                         chandler.AllowAutoRedirect = true;
1394                         var client = new HttpClient (chandler, true);
1395
1396                         var port = NetworkHelpers.FindFreePort ();
1397                         var listener = CreateListener (l => {
1398                                 var response = l.Response;
1399                                 response.StatusCode = 200;
1400                                 response.OutputStream.WriteByte (55);
1401                         }, port);
1402
1403                         try {
1404                                 client.GetStringAsync ($"http://localhost:{port}/").Wait (WaitTimeout);
1405                                 try {
1406                                         chandler.AllowAutoRedirect = false;
1407                                         Assert.Fail ("#1");
1408                                 } catch (InvalidOperationException) {
1409                                         ;
1410                                 }
1411                         } finally {
1412                                 listener.Abort ();
1413                                 listener.Close ();
1414                         }
1415                 }
1416
1417                 [Test]
1418 #if FEATURE_NO_BSD_SOCKETS
1419                 // Using HttpClientHandler, which indirectly requires BSD sockets.
1420                 [ExpectedException (typeof (PlatformNotSupportedException))]
1421 #endif
1422                 /*
1423                  * However, this policy is not enforced for custom handlers and there
1424                  * is also no way a derived class could tell its HttpClientHandler parent
1425                  * that it just sent a request.
1426                  * 
1427                  */
1428                 public void ModifyHandlerAfterFirstRequest_Mock ()
1429                 {
1430                         var ch = new HttpClientHandlerMock ();
1431                         ch.AllowAutoRedirect = true;
1432
1433                         var client = new HttpClient (ch);
1434
1435                         ch.OnSend = (l) => {
1436                                 return Task.FromResult (new HttpResponseMessage ());
1437                         };
1438
1439                         client.GetAsync ("http://xamarin.com").Wait (WaitTimeout);
1440                         ch.AllowAutoRedirect = false;
1441                 }
1442
1443                 HttpListener CreateListener (Action<HttpListenerContext> contextAssert, int port)
1444                 {
1445                         var l = new HttpListener ();
1446                         l.Prefixes.Add (string.Format ("http://+:{0}/", port));
1447                         l.Start ();
1448                         AddListenerContext(l, contextAssert);
1449
1450                         return l;
1451                 }
1452
1453                 HttpListener AddListenerContext (HttpListener l, Action<HttpListenerContext> contextAssert)
1454                 {
1455                         l.BeginGetContext (ar => {
1456                                 var ctx = l.EndGetContext (ar);
1457
1458                                 try {
1459                                         if (contextAssert != null)
1460                                                 contextAssert (ctx);
1461                                 } finally {
1462                                         ctx.Response.Close ();
1463                                 }
1464                         }, null);
1465
1466                         return l;
1467                 }
1468         }
1469 }