Merge pull request #2545 from ermshiperete/Xamarin-24974
[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 TestHost, LocalServer;
156                 int port;
157
158                 [SetUp]
159                 public void SetupFixture ()
160                 {
161                         if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
162                                 port = 810;
163                         } else {
164                                 port = 8810;
165                         }
166
167                         TestHost = "localhost:" + port;
168                         LocalServer = string.Format ("http://{0}/", TestHost);
169                 }
170
171                 [Test]
172                 public void Ctor_Default ()
173                 {
174                         var client = new HttpClient ();
175                         Assert.IsNull (client.BaseAddress, "#1");
176                         Assert.IsNotNull (client.DefaultRequestHeaders, "#2");  // TODO: full check
177                         Assert.AreEqual (int.MaxValue, client.MaxResponseContentBufferSize, "#3");
178                         Assert.AreEqual (TimeSpan.FromSeconds (100), client.Timeout, "#4");
179                 }
180
181                 [Test]
182                 public void CancelPendingRequests ()
183                 {
184                         var mh = new HttpMessageHandlerMock ();
185
186                         var client = new HttpClient (mh);
187                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
188                         var mre = new ManualResetEvent (false);
189
190                         mh.OnSendFull = (l, c) => {
191                                 mre.Set ();
192                                 Assert.IsTrue (c.WaitHandle.WaitOne (1000), "#20");
193                                 Assert.IsTrue (c.IsCancellationRequested, "#21");
194                                 mre.Set ();
195                                 return Task.FromResult (new HttpResponseMessage ());
196                         };
197
198                         var t = Task.Factory.StartNew (() => {
199                                 client.SendAsync (request).Wait (WaitTimeout);
200                         });
201
202                         Assert.IsTrue (mre.WaitOne (500), "#1");
203                         mre.Reset ();
204                         client.CancelPendingRequests ();
205                         Assert.IsTrue (t.Wait (500), "#2");
206
207                         request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
208                         mh.OnSendFull = (l, c) => {
209                                 Assert.IsFalse (c.IsCancellationRequested, "#30");
210                                 return Task.FromResult (new HttpResponseMessage ());
211                         };
212
213                         client.SendAsync (request).Wait (WaitTimeout);
214                 }
215
216                 [Test]
217                 public void CancelPendingRequests_BeforeSend ()
218                 {
219                         var ct = new CancellationTokenSource ();
220                         ct.Cancel ();
221                         var rr = CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken (), ct.Token);
222
223
224                         var mh = new HttpMessageHandlerMock ();
225
226                         var client = new HttpClient (mh);
227                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
228                         client.CancelPendingRequests ();
229
230                         mh.OnSendFull = (l, c) => {
231                                 Assert.IsFalse (c.IsCancellationRequested, "#30");
232                                 return Task.FromResult (new HttpResponseMessage ());
233                         };
234
235                         client.SendAsync (request).Wait (WaitTimeout);
236
237                         request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
238                         client.SendAsync (request).Wait (WaitTimeout);
239                 }
240
241
242                 [Test]
243                 public void CancelRequestViaProxy ()
244                 {
245                         var handler = new HttpClientHandler {
246                                 Proxy = new WebProxy ("192.168.10.25:8888/"), // proxy that doesn't exist
247                                 UseProxy = true,
248                                 AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
249                         };
250
251                         var httpClient = new HttpClient (handler) {
252                                 BaseAddress = new Uri ("https://google.com"),
253                                 Timeout = TimeSpan.FromMilliseconds (1)
254                         };
255
256                         try {
257                                 var restRequest = new HttpRequestMessage {
258                                         Method = HttpMethod.Post,
259                                         RequestUri = new Uri("foo", UriKind.Relative),
260                                         Content = new StringContent("", null, "application/json")
261                                 };
262
263                                 httpClient.PostAsync (restRequest.RequestUri, restRequest.Content).Wait (WaitTimeout);
264                                 Assert.Fail ("#1");
265                         } catch (AggregateException e) {
266                                 Assert.IsTrue (e.InnerException is TaskCanceledException, "#2");
267                         }
268                 }
269
270                 [Test]
271                 public void Properties ()
272                 {
273                         var client = new HttpClient ();
274                         client.BaseAddress = null;
275                         client.MaxResponseContentBufferSize = int.MaxValue;
276                         client.Timeout = Timeout.InfiniteTimeSpan;
277
278                         Assert.IsNull (client.BaseAddress, "#1");
279                         Assert.AreEqual (int.MaxValue, client.MaxResponseContentBufferSize, "#2");
280                         Assert.AreEqual (Timeout.InfiniteTimeSpan, client.Timeout, "#3");
281                 }
282
283                 [Test]
284                 public void Properties_Invalid ()
285                 {
286                         var client = new HttpClient ();
287                         try {
288                                 client.MaxResponseContentBufferSize = 0;
289                                 Assert.Fail ("#1");
290                         } catch (ArgumentOutOfRangeException) {
291                         }
292
293                         try {
294                                 client.Timeout = TimeSpan.MinValue;
295                                 Assert.Fail ("#2");
296                         } catch (ArgumentOutOfRangeException) {
297                         }
298                 }
299
300                 [Test]
301                 public void Send ()
302                 {
303                         var mh = new HttpMessageHandlerMock ();
304
305                         var client = new HttpClient (mh);
306                         client.BaseAddress = new Uri ("http://xamarin.com");
307                         var request = new HttpRequestMessage ();
308                         var response = new HttpResponseMessage ();
309
310                         mh.OnSend = l => {
311                                 Assert.AreEqual (l, request, "#2");
312                                 Assert.AreEqual (client.BaseAddress, l.RequestUri, "#2");
313                                 return Task.FromResult (response);
314                         };
315
316                         Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
317                 }
318
319                 [Test]
320                 public void Send_BaseAddress ()
321                 {
322                         var mh = new HttpMessageHandlerMock ();
323
324                         var client = new HttpClient (mh);
325                         client.BaseAddress = new Uri ("http://localhost/");
326                         var response = new HttpResponseMessage ();
327
328                         mh.OnSend = l => {
329                                 Assert.AreEqual ("http://localhost/relative", l.RequestUri.ToString (), "#2");
330                                 return Task.FromResult (response);
331                         };
332
333                         Assert.AreEqual (response, client.GetAsync ("relative").Result, "#1");
334                         Assert.AreEqual (response, client.GetAsync ("/relative").Result, "#2");
335                 }
336
337                 [Test]
338                 public void Send_DefaultRequestHeaders ()
339                 {
340                         var mh = new HttpMessageHandlerMock ();
341
342                         var client = new HttpClient (mh);
343                         client.DefaultRequestHeaders.Referrer = new Uri ("http://google.com");
344
345                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
346                         var response = new HttpResponseMessage ();
347
348                         mh.OnSend = l => {
349                                 Assert.AreEqual (client.DefaultRequestHeaders.Referrer, l.Headers.Referrer, "#2");
350                                 Assert.IsNotNull (l.Headers.Referrer, "#3");
351                                 return Task.FromResult (response);
352                         };
353
354                         Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
355                 }
356
357                 [Test]
358                 public void Send_Complete_Default ()
359                 {
360                         bool? failed = null;
361                         var listener = CreateListener (l => {
362                                 try {
363                                         var request = l.Request;
364         
365                                         Assert.IsNull (request.AcceptTypes, "#1");
366                                         Assert.AreEqual (0, request.ContentLength64, "#2");
367                                         Assert.IsNull (request.ContentType, "#3");
368                                         Assert.AreEqual (0, request.Cookies.Count, "#4");
369                                         Assert.IsFalse (request.HasEntityBody, "#5");
370                                         Assert.AreEqual (TestHost, request.Headers["Host"], "#6b");
371                                         Assert.AreEqual ("GET", request.HttpMethod, "#7");
372                                         Assert.IsFalse (request.IsAuthenticated, "#8");
373                                         Assert.IsTrue (request.IsLocal, "#9");
374                                         Assert.IsFalse (request.IsSecureConnection, "#10");
375                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
376                                         Assert.IsTrue (request.KeepAlive, "#12");
377                                         Assert.AreEqual (HttpVersion.Version11, request.ProtocolVersion, "#13");
378                                         Assert.IsNull (request.ServiceName, "#14");
379                                         Assert.IsNull (request.UrlReferrer, "#15");
380                                         Assert.IsNull (request.UserAgent, "#16");
381                                         Assert.IsNull (request.UserLanguages, "#17");
382                                         failed = false;
383                                 } catch {
384                                         failed = true;
385                                 }
386                         });
387
388                         try {
389                                 var client = new HttpClient ();
390                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
391                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
392
393                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
394                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
395                                 Assert.AreEqual (false, failed, "#102");
396                         } finally {
397                                 listener.Close ();
398                         }
399                 }
400
401                 [Test]
402                 public void Send_Complete_Version_1_0 ()
403                 {
404                         bool? failed = null;
405                         
406                         var listener = CreateListener (l => {
407                                 try {
408                                         var request = l.Request;
409         
410                                         Assert.IsNull (request.AcceptTypes, "#1");
411                                         Assert.AreEqual (0, request.ContentLength64, "#2");
412                                         Assert.IsNull (request.ContentType, "#3");
413                                         Assert.AreEqual (0, request.Cookies.Count, "#4");
414                                         Assert.IsFalse (request.HasEntityBody, "#5");
415                                         Assert.AreEqual (1, request.Headers.Count, "#6");
416                                         Assert.AreEqual (TestHost, request.Headers["Host"], "#6a");
417                                         Assert.AreEqual ("GET", request.HttpMethod, "#7");
418                                         Assert.IsFalse (request.IsAuthenticated, "#8");
419                                         Assert.IsTrue (request.IsLocal, "#9");
420                                         Assert.IsFalse (request.IsSecureConnection, "#10");
421                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
422                                         Assert.IsFalse (request.KeepAlive, "#12");
423                                         Assert.AreEqual (HttpVersion.Version10, request.ProtocolVersion, "#13");
424                                         Assert.IsNull (request.ServiceName, "#14");
425                                         Assert.IsNull (request.UrlReferrer, "#15");
426                                         Assert.IsNull (request.UserAgent, "#16");
427                                         Assert.IsNull (request.UserLanguages, "#17");
428                                         failed = false;
429                                 } catch {
430                                         failed = true;
431                                 }
432                         });
433
434                         try {
435                                 var client = new HttpClient ();
436                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
437                                 request.Version = HttpVersion.Version10;
438                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
439
440                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
441                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
442                                 Assert.AreEqual (false, failed, "#102");
443                         } finally {
444                                 listener.Close ();
445                         }
446                 }
447
448                 [Test]
449                 public void Send_Complete_ClientHandlerSettings ()
450                 {
451                         bool? failed = null;
452                         
453                         var listener = CreateListener (l => {
454                                 var request = l.Request;
455                                 
456                                 try {
457                                         Assert.IsNull (request.AcceptTypes, "#1");
458                                         Assert.AreEqual (0, request.ContentLength64, "#2");
459                                         Assert.IsNull (request.ContentType, "#3");
460                                         Assert.AreEqual (1, request.Cookies.Count, "#4");
461                                         Assert.AreEqual (new Cookie ("mycookie", "vv"), request.Cookies[0], "#4a");
462                                         Assert.IsFalse (request.HasEntityBody, "#5");
463                                         Assert.AreEqual (4, request.Headers.Count, "#6");
464                                         Assert.AreEqual (TestHost, request.Headers["Host"], "#6a");
465                                         Assert.AreEqual ("gzip", request.Headers["Accept-Encoding"], "#6b");
466                                         Assert.AreEqual ("mycookie=vv", request.Headers["Cookie"], "#6c");
467                                         Assert.AreEqual ("GET", request.HttpMethod, "#7");
468                                         Assert.IsFalse (request.IsAuthenticated, "#8");
469                                         Assert.IsTrue (request.IsLocal, "#9");
470                                         Assert.IsFalse (request.IsSecureConnection, "#10");
471                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
472                                         Assert.IsTrue (request.KeepAlive, "#12");
473                                         Assert.AreEqual (HttpVersion.Version10, request.ProtocolVersion, "#13");
474                                         Assert.IsNull (request.ServiceName, "#14");
475                                         Assert.IsNull (request.UrlReferrer, "#15");
476                                         Assert.IsNull (request.UserAgent, "#16");
477                                         Assert.IsNull (request.UserLanguages, "#17");
478                                         failed = false;
479                                 } catch {
480                                         failed = true;
481                                 }
482                         });
483
484                         try {
485                                 var chandler = new HttpClientHandler ();
486                                 chandler.AllowAutoRedirect = true;
487                                 chandler.AutomaticDecompression = DecompressionMethods.GZip;
488                                 chandler.MaxAutomaticRedirections = 33;
489                                 chandler.MaxRequestContentBufferSize = 5555;
490                                 chandler.PreAuthenticate = true;
491                                 chandler.CookieContainer.Add (new Uri (LocalServer), new Cookie ( "mycookie", "vv"));
492                                 chandler.UseCookies = true;
493                                 chandler.UseDefaultCredentials = true;
494                                 chandler.Proxy = new WebProxy ("ee");
495                                 chandler.UseProxy = true;
496
497                                 var client = new HttpClient (chandler);
498                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
499                                 request.Version = HttpVersion.Version10;
500                                 request.Headers.Add ("Keep-Alive", "false");
501                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
502
503                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
504                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
505                                 Assert.AreEqual (false, failed, "#102");
506                         } finally {
507                                 listener.Abort ();
508                                 listener.Close ();
509                         }
510                 }
511
512                 [Test]
513                 public void Send_Complete_CustomHeaders ()
514                 {
515                         bool? failed = null;
516                         
517                         var listener = CreateListener (l => {
518                                 var request = l.Request;
519                                 try {
520                                         Assert.AreEqual ("vv", request.Headers["aa"], "#1");
521         
522                                         var response = l.Response;
523                                         response.Headers.Add ("rsp", "rrr");
524                                         response.Headers.Add ("upgrade", "vvvvaa");
525                                         response.Headers.Add ("Date", "aa");
526                                         response.Headers.Add ("cache-control", "audio");
527         
528                                         response.StatusDescription = "test description";
529                                         response.ProtocolVersion = HttpVersion.Version10;
530                                         response.SendChunked = true;
531                                         response.RedirectLocation = "w3.org";
532                                         
533                                         failed = false;
534                                 } catch {
535                                         failed = true;
536                                 }
537                         });
538
539                         try {
540                                 var client = new HttpClient ();
541                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
542                                 Assert.IsTrue (request.Headers.TryAddWithoutValidation ("aa", "vv"), "#0");
543                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
544
545                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
546                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
547                                 
548                                 IEnumerable<string> values;
549                                 Assert.IsTrue (response.Headers.TryGetValues ("rsp", out values), "#102");
550                                 Assert.AreEqual ("rrr", values.First (), "#102a");
551
552                                 Assert.IsTrue (response.Headers.TryGetValues ("Transfer-Encoding", out values), "#103");
553                                 Assert.AreEqual ("chunked", values.First (), "#103a");
554                                 Assert.AreEqual (true, response.Headers.TransferEncodingChunked, "#103b");
555
556                                 Assert.IsTrue (response.Headers.TryGetValues ("Date", out values), "#104");
557                                 Assert.AreEqual (1, values.Count (), "#104b");
558                                 // .NET overwrites Date, Mono does not
559                                 // Assert.IsNotNull (response.Headers.Date, "#104c");
560
561                                 Assert.AreEqual (new ProductHeaderValue ("vvvvaa"), response.Headers.Upgrade.First (), "#105");
562
563                                 Assert.AreEqual ("audio", response.Headers.CacheControl.Extensions.First ().Name, "#106");
564
565                                 Assert.AreEqual ("w3.org", response.Headers.Location.OriginalString, "#107");
566
567                                 Assert.AreEqual ("test description", response.ReasonPhrase, "#110");
568                                 Assert.AreEqual (HttpVersion.Version11, response.Version, "#111");
569                                 
570                                 Assert.AreEqual (false, failed, "#112");
571                         } finally {
572                                 listener.Close ();
573                         }
574                 }
575
576                 [Test]
577                 public void Send_Complete_CustomHeaders_SpecialSeparators ()
578                 {
579                         bool? failed = null;
580
581                         var listener = CreateListener (l => {
582                                 var request = l.Request;
583
584                                 try {
585                                         Assert.AreEqual ("MLK Android Phone 1.1.9", request.UserAgent, "#1");
586                                         failed = false;
587                                 } catch {
588                                         failed = true;
589                                 }
590                         });
591
592                         try {
593                                 var client = new HttpClient ();
594
595                                 client.DefaultRequestHeaders.Add("User-Agent", "MLK Android Phone 1.1.9");
596
597                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
598
599                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
600
601                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
602                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
603                                 Assert.AreEqual (false, failed, "#102");
604                         } finally {
605                                 listener.Abort ();
606                                 listener.Close ();
607                         }
608                 }
609
610                 [Test]
611                 public void Send_Complete_CustomHeaders_Host ()
612                 {
613                         bool? failed = null;
614                         var listener = CreateListener (l => {
615                                 var request = l.Request;
616
617                                 try {
618                                         Assert.AreEqual ("customhost", request.Headers["Host"], "#1");
619                                         failed = false;
620                                 } catch {
621                                         failed = true;
622                                 }
623                         });
624
625                         try {
626                                 var client = new HttpClient ();
627
628                                 client.DefaultRequestHeaders.Add("Host", "customhost");
629
630                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
631
632                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
633
634                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
635                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
636                                 Assert.AreEqual (false, failed, "#102");
637                         } finally {
638                                 listener.Abort ();
639                                 listener.Close ();
640                         }
641                 }
642
643                 [Test]
644                 public void Send_Transfer_Encoding_Chunked ()
645                 {
646                         bool? failed = null;
647
648                         var listener = CreateListener (l => {
649                                 var request = l.Request;
650
651                                 try {
652                                         Assert.AreEqual (1, request.Headers.Count, "#1");
653                                         failed = false;
654                                 } catch {
655                                         failed = true;
656                                 }
657                         });
658
659                         try {
660                                 var client = new HttpClient ();
661                                 client.DefaultRequestHeaders.TransferEncodingChunked = true;
662
663                                 client.GetAsync (LocalServer).Wait ();
664
665                                 Assert.AreEqual (false, failed, "#102");
666                         } finally {
667                                 listener.Abort ();
668                                 listener.Close ();
669                         }
670                 }
671
672                 [Test]
673                 public void Send_Transfer_Encoding_Custom ()
674                 {
675                         bool? failed = null;
676
677                         var listener = CreateListener (l => {
678                                 failed = true;
679                         });
680
681                         try {
682                                 var client = new HttpClient ();
683                                 client.DefaultRequestHeaders.TransferEncoding.Add (new TransferCodingHeaderValue ("chunked2"));
684
685                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
686
687                                 try {
688                                         client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Wait ();
689                                         Assert.Fail ("#1");
690                                 } catch (AggregateException e) {
691                                         Assert.AreEqual (typeof (ProtocolViolationException), e.InnerException.GetType (), "#2");
692                                 }
693                                 Assert.IsNull (failed, "#102");
694                         } finally {
695                                 listener.Abort ();
696                                 listener.Close ();
697                         }
698                 }
699
700                 [Test]
701                 public void Send_Complete_Content ()
702                 {
703                         var listener = CreateListener (l => {
704                                 var request = l.Request;
705                                 l.Response.OutputStream.WriteByte (55);
706                                 l.Response.OutputStream.WriteByte (75);
707                         });
708
709                         try {
710                                 var client = new HttpClient ();
711                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
712                                 Assert.IsTrue (request.Headers.TryAddWithoutValidation ("aa", "vv"), "#0");
713                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
714
715                                 Assert.AreEqual ("7K", response.Content.ReadAsStringAsync ().Result, "#100");
716                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
717
718                                 IEnumerable<string> values;
719                                 Assert.IsTrue (response.Headers.TryGetValues ("Transfer-Encoding", out values), "#102");
720                                 Assert.AreEqual ("chunked", values.First (), "#102a");
721                                 Assert.AreEqual (true, response.Headers.TransferEncodingChunked, "#102b");
722                         } finally {
723                                 listener.Close ();
724                         }
725                 }
726
727                 [Test]
728                 public void Send_Complete_Content_MaxResponseContentBufferSize ()
729                 {
730                         var listener = CreateListener (l => {
731                                 var request = l.Request;
732                                 var b = new byte[4000];
733                                 l.Response.OutputStream.Write (b, 0, b.Length);
734                         });
735
736                         try {
737                                 var client = new HttpClient ();
738                                 client.MaxResponseContentBufferSize = 1000;
739                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
740                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
741
742                                 Assert.AreEqual (4000, response.Content.ReadAsStringAsync ().Result.Length, "#100");
743                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
744                         } finally {
745                                 listener.Close ();
746                         }
747                 }
748
749                 [Test]
750                 public void Send_Complete_Content_MaxResponseContentBufferSize_Error ()
751                 {
752                         var listener = CreateListener (l => {
753                                 var request = l.Request;
754                                 var b = new byte[4000];
755                                 l.Response.OutputStream.Write (b, 0, b.Length);
756                         });
757
758                         try {
759                                 var client = new HttpClient ();
760                                 client.MaxResponseContentBufferSize = 1000;
761                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
762
763                                 try {
764                                         client.SendAsync (request, HttpCompletionOption.ResponseContentRead).Wait (WaitTimeout);
765                                         Assert.Fail ("#2");
766                                 } catch (AggregateException e) {
767                                         Assert.IsTrue (e.InnerException is HttpRequestException, "#3");
768                                 }
769
770                         } finally {
771                                 listener.Close ();
772                         }
773                 }
774
775                 [Test]
776                 public void Send_Complete_NoContent ()
777                 {
778                         foreach (var method in new HttpMethod[] { HttpMethod.Post, HttpMethod.Put, HttpMethod.Delete }) {
779                                 bool? failed = null;
780                                 var listener = CreateListener (l => {
781                                         try {
782                                                 var request = l.Request;
783
784                                                 Assert.AreEqual (2, request.Headers.Count, "#1");
785                                                 Assert.AreEqual ("0", request.Headers ["Content-Length"], "#1b");
786                                                 Assert.AreEqual (method.Method, request.HttpMethod, "#2");
787                                                 failed = false;
788                                         } catch {
789                                                 failed = true;
790                                         }
791                                 });
792
793                                 try {
794                                         var client = new HttpClient ();
795                                         var request = new HttpRequestMessage (method, LocalServer);
796                                         var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
797
798                                         Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
799                                         Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
800                                         Assert.AreEqual (false, failed, "#102");
801                                 } finally {
802                                         listener.Close ();
803                                 }
804                         }
805                 }
806
807                 [Test]
808                 public void Send_Complete_Error ()
809                 {
810                         var listener = CreateListener (l => {
811                                 var response = l.Response;
812                                 response.StatusCode = 500;
813                         });
814
815                         try {
816                                 var client = new HttpClient ();
817                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
818                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
819
820                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
821                                 Assert.AreEqual (HttpStatusCode.InternalServerError, response.StatusCode, "#101");
822                         } finally {
823                                 listener.Close ();
824                         }
825                 }
826
827                 [Test]
828                 public void Send_Content_Get ()
829                 {
830                         var listener = CreateListener (l => {
831                                 var request = l.Request;
832                                 l.Response.OutputStream.WriteByte (72);
833                         });
834
835                         try {
836                                 var client = new HttpClient ();
837                                 var r = new HttpRequestMessage (HttpMethod.Get, LocalServer);
838                                 var response = client.SendAsync (r).Result;
839
840                                 Assert.AreEqual ("H", response.Content.ReadAsStringAsync ().Result);
841                         } finally {
842                                 listener.Close ();
843                         }
844                 }
845
846                 [Test]
847                 public void Send_Content_BomEncoding ()
848                 {
849                         var listener = CreateListener (l => {
850                                 var request = l.Request;
851
852                                 var str = l.Response.OutputStream;
853                                 str.WriteByte (0xEF);
854                                 str.WriteByte (0xBB);
855                                 str.WriteByte (0xBF);
856                                 str.WriteByte (71);
857                         });
858
859                         try {
860                                 var client = new HttpClient ();
861                                 var r = new HttpRequestMessage (HttpMethod.Get, LocalServer);
862                                 var response = client.SendAsync (r).Result;
863
864                                 Assert.AreEqual ("G", response.Content.ReadAsStringAsync ().Result);
865                         } finally {
866                                 listener.Close ();
867                         }
868                 }
869
870                 [Test]
871                 public void Send_Content_Put ()
872                 {
873                         bool passed = false;
874                         var listener = CreateListener (l => {
875                                 var request = l.Request;
876                                 passed = 7 == request.ContentLength64;
877                                 passed &= request.ContentType == "text/plain; charset=utf-8";
878                                 passed &= request.InputStream.ReadByte () == 'm';
879                         });
880
881                         try {
882                                 var client = new HttpClient ();
883                                 var r = new HttpRequestMessage (HttpMethod.Put, LocalServer);
884                                 r.Content = new StringContent ("my text");
885                                 var response = client.SendAsync (r).Result;
886
887                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#1");
888                                 Assert.IsTrue (passed, "#2");
889                         } finally {
890                                 listener.Abort ();
891                                 listener.Close ();
892                         }
893                 }
894
895                 [Test]
896                 public void Send_Content_Put_CustomStream ()
897                 {
898                         bool passed = false;
899                         var listener = CreateListener (l => {
900                                 var request = l.Request;
901                                 passed = 44 == request.ContentLength64;
902                                 passed &= request.ContentType == null;
903                         });
904
905                         try {
906                                 var client = new HttpClient ();
907                                 var r = new HttpRequestMessage (HttpMethod.Put, LocalServer);
908                                 r.Content = new StreamContent (new CustomStream ());
909                                 var response = client.SendAsync (r).Result;
910
911                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#1");
912                                 Assert.IsTrue (passed, "#2");
913                         } finally {
914                                 listener.Abort ();
915
916                                 listener.Close ();
917                         }
918                 }
919
920                 [Test]
921                 public void Send_Timeout ()
922                 {
923                         var mh = new HttpMessageHandlerMock ();
924
925                         var client = new HttpClient (mh);
926                         client.Timeout = TimeSpan.FromMilliseconds (100);
927                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
928                         var response = new HttpResponseMessage ();
929
930                         mh.OnSendFull = (l, c) => {
931                                 Assert.IsTrue (c.WaitHandle.WaitOne (500), "#2");
932                                 return Task.FromResult (response);
933                         };
934
935                         Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
936                 }
937
938                 [Test]
939                 public void Send_Invalid ()
940                 {
941                         var client = new HttpClient ();
942                         try {
943                                 client.SendAsync (null).Wait (WaitTimeout);
944                                 Assert.Fail ("#1");
945                         } catch (ArgumentNullException) {
946                         }
947
948                         try {
949                                 var request = new HttpRequestMessage ();
950                                 client.SendAsync (request).Wait (WaitTimeout);
951                                 Assert.Fail ("#2");
952                         } catch (InvalidOperationException) {
953                         }
954                 }
955
956                 [Test]
957                 public void Send_InvalidHandler ()
958                 {
959                         var mh = new HttpMessageHandlerMock ();
960
961                         var client = new HttpClient (mh);
962                         client.BaseAddress = new Uri ("http://xamarin.com");
963                         var request = new HttpRequestMessage ();
964
965                         mh.OnSend = l => {
966                                 Assert.AreEqual (l, request, "#1");
967                                 return null;
968                         };
969
970                         try {
971                                 // Broken by design
972                                 client.SendAsync (request).Wait (WaitTimeout);
973                                 Assert.Fail ("#2");
974                         } catch (Exception) {
975                         }
976                 }
977
978                 [Test]
979                 public void Send_SameMessage ()
980                 {
981                         var mh = new HttpMessageHandlerMock ();
982
983                         var client = new HttpClient (mh);
984                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
985
986                         mh.OnSend = l => Task.FromResult (new HttpResponseMessage ());
987
988                         client.SendAsync (request).Wait (WaitTimeout);
989                         try {
990                                 client.SendAsync (request).Wait (WaitTimeout);
991                                 Assert.Fail ("#1");
992                         } catch (InvalidOperationException) {
993                         }
994                 }
995
996                 [Test]
997                 [Category ("MobileNotWorking")] // Missing encoding
998                 public void GetString_Many ()
999                 {
1000                         Action<HttpListenerContext> context = (HttpListenerContext l) => {
1001                                 var response = l.Response;
1002                                 response.StatusCode = 200;
1003                                 response.OutputStream.WriteByte (0x68);
1004                                 response.OutputStream.WriteByte (0x65);
1005                                 response.OutputStream.WriteByte (0x6c);
1006                                 response.OutputStream.WriteByte (0x6c);
1007                                 response.OutputStream.WriteByte (0x6f);
1008                         };
1009
1010                         var listener = CreateListener (context); // creates a default request handler
1011                         AddListenerContext (listener, context);  // add another request handler for the second request
1012
1013                         try {
1014                                 var client = new HttpClient ();
1015                                 var t1 = client.GetStringAsync (LocalServer);
1016                                 var t2 = client.GetStringAsync (LocalServer);
1017                                 Assert.IsTrue (Task.WaitAll (new [] { t1, t2 }, WaitTimeout));
1018                                 Assert.AreEqual ("hello", t1.Result, "#1");
1019                                 Assert.AreEqual ("hello", t2.Result, "#2");
1020                         } finally {
1021                                 listener.Abort ();
1022                                 listener.Close ();
1023                         }
1024                 }
1025
1026                 [Test]
1027                 public void GetByteArray_ServerError ()
1028                 {
1029                         var listener = CreateListener (l => {
1030                                 var response = l.Response;
1031                                 response.StatusCode = 500;
1032                                 l.Response.OutputStream.WriteByte (72);
1033                         });
1034
1035                         try {
1036                                 var client = new HttpClient ();
1037                                 try {
1038                                         client.GetByteArrayAsync (LocalServer).Wait (WaitTimeout);
1039                                         Assert.Fail ("#1");
1040                                 } catch (AggregateException e) {
1041                                         Assert.IsTrue (e.InnerException is HttpRequestException , "#2");
1042                                 }
1043                         } finally {
1044                                 listener.Close ();
1045                         }
1046                 }
1047
1048                 [Test]
1049                 public void DisallowAutoRedirect ()
1050                 {
1051                         var listener = CreateListener (l => {
1052                                 var request = l.Request;
1053                                 var response = l.Response;
1054                                 
1055                                 response.StatusCode = (int)HttpStatusCode.Moved;
1056                                 response.RedirectLocation = "http://xamarin.com/";
1057                         });
1058
1059                         try {
1060                                 var chandler = new HttpClientHandler ();
1061                                 chandler.AllowAutoRedirect = false;
1062                                 var client = new HttpClient (chandler);
1063
1064                                 try {
1065                                         client.GetStringAsync (LocalServer).Wait (WaitTimeout);
1066                                         Assert.Fail ("#1");
1067                                 } catch (AggregateException e) {
1068                                         Assert.IsTrue (e.InnerException is HttpRequestException, "#2");
1069                                 }
1070                         } finally {
1071                                 listener.Abort ();
1072                                 listener.Close ();
1073                         }
1074                 }
1075
1076                 [Test]
1077                 public void RequestUriAfterRedirect ()
1078                 {
1079                         var listener = CreateListener (l => {
1080                                 var request = l.Request;
1081                                 var response = l.Response;
1082
1083                                 response.StatusCode = (int)HttpStatusCode.Moved;
1084                                 response.RedirectLocation = "http://localhost:8811/";
1085                         });
1086
1087                         var listener2 = CreateListener (l => {
1088                                 var response = l.Response;
1089
1090                                 response.StatusCode = (int)HttpStatusCode.OK;
1091                                 response.OutputStream.WriteByte (0x68);
1092                                 response.OutputStream.WriteByte (0x65);
1093                                 response.OutputStream.WriteByte (0x6c);
1094                                 response.OutputStream.WriteByte (0x6c);
1095                                 response.OutputStream.WriteByte (0x6f);
1096                         }, 8811);
1097
1098                         try {
1099                                 var chandler = new HttpClientHandler ();
1100                                 chandler.AllowAutoRedirect = true;
1101                                 var client = new HttpClient (chandler);
1102
1103                                 var r = client.GetAsync (LocalServer);
1104                                 Assert.IsTrue (r.Wait (WaitTimeout), "#1");
1105                                 var resp = r.Result;
1106                                 Assert.AreEqual ("http://localhost:8811/", resp.RequestMessage.RequestUri.AbsoluteUri, "#2");
1107                                 Assert.AreEqual ("hello", resp.Content.ReadAsStringAsync ().Result, "#3");
1108                         } finally {
1109                                 listener.Abort ();
1110                                 listener.Close ();
1111                                 listener2.Abort ();
1112                                 listener2.Close ();
1113                         }
1114                 }
1115
1116                 [Test]
1117                 /*
1118                  * Properties may only be modified before sending the first request.
1119                  */
1120                 public void ModifyHandlerAfterFirstRequest ()
1121                 {
1122                         var chandler = new HttpClientHandler ();
1123                         chandler.AllowAutoRedirect = true;
1124                         var client = new HttpClient (chandler, true);
1125
1126                         var listener = CreateListener (l => {
1127                                 var response = l.Response;
1128                                 response.StatusCode = 200;
1129                                 response.OutputStream.WriteByte (55);
1130                         });
1131
1132                         try {
1133                                 client.GetStringAsync (LocalServer).Wait (WaitTimeout);
1134                                 try {
1135                                         chandler.AllowAutoRedirect = false;
1136                                         Assert.Fail ("#1");
1137                                 } catch (InvalidOperationException) {
1138                                         ;
1139                                 }
1140                         } finally {
1141                                 listener.Abort ();
1142                                 listener.Close ();
1143                         }
1144                 }
1145
1146                 [Test]
1147                 /*
1148                  * However, this policy is not enforced for custom handlers and there
1149                  * is also no way a derived class could tell its HttpClientHandler parent
1150                  * that it just sent a request.
1151                  * 
1152                  */
1153                 public void ModifyHandlerAfterFirstRequest_Mock ()
1154                 {
1155                         var ch = new HttpClientHandlerMock ();
1156                         ch.AllowAutoRedirect = true;
1157
1158                         var client = new HttpClient (ch);
1159
1160                         ch.OnSend = (l) => {
1161                                 return Task.FromResult (new HttpResponseMessage ());
1162                         };
1163
1164                         client.GetAsync ("http://xamarin.com").Wait (WaitTimeout);
1165                         ch.AllowAutoRedirect = false;
1166                 }
1167
1168                 HttpListener CreateListener (Action<HttpListenerContext> contextAssert)
1169                 {
1170                         return CreateListener (contextAssert, port);
1171                 }
1172
1173                 HttpListener CreateListener (Action<HttpListenerContext> contextAssert, int port)
1174                 {
1175                         var l = new HttpListener ();
1176                         l.Prefixes.Add (string.Format ("http://+:{0}/", port));
1177                         l.Start ();
1178                         AddListenerContext(l, contextAssert);
1179
1180                         return l;
1181                 }
1182
1183                 HttpListener AddListenerContext (HttpListener l, Action<HttpListenerContext> contextAssert)
1184                 {
1185                         l.BeginGetContext (ar => {
1186                                 var ctx = l.EndGetContext (ar);
1187
1188                                 try {
1189                                         if (contextAssert != null)
1190                                                 contextAssert (ctx);
1191                                 } finally {
1192                                         ctx.Response.Close ();
1193                                 }
1194                         }, null);
1195
1196                         return l;
1197                 }
1198         }
1199 }