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