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