Added Symbolicate tool.
[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                 const int WaitTimeout = 5000;
87
88                 string port, TestHost, LocalServer;
89
90                 [SetUp]
91                 public void SetupFixture ()
92                 {
93                         if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
94                                 port = "810";
95                         } else {
96                                 port = "8810";
97                         }
98
99                         TestHost = "localhost:" + port;
100                         LocalServer = string.Format ("http://{0}/", TestHost);
101                 }
102
103                 [Test]
104                 public void Ctor_Default ()
105                 {
106                         var client = new HttpClient ();
107                         Assert.IsNull (client.BaseAddress, "#1");
108                         Assert.IsNotNull (client.DefaultRequestHeaders, "#2");  // TODO: full check
109                         Assert.AreEqual (int.MaxValue, client.MaxResponseContentBufferSize, "#3");
110                         Assert.AreEqual (TimeSpan.FromSeconds (100), client.Timeout, "#4");
111                 }
112
113                 [Test]
114                 public void CancelPendingRequests ()
115                 {
116                         var mh = new HttpMessageHandlerMock ();
117
118                         var client = new HttpClient (mh);
119                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
120                         var mre = new ManualResetEvent (false);
121
122                         mh.OnSendFull = (l, c) => {
123                                 mre.Set ();
124                                 Assert.IsTrue (c.WaitHandle.WaitOne (1000), "#20");
125                                 Assert.IsTrue (c.IsCancellationRequested, "#21");
126                                 mre.Set ();
127                                 return Task.FromResult (new HttpResponseMessage ());
128                         };
129
130                         var t = Task.Factory.StartNew (() => {
131                                 client.SendAsync (request).Wait (WaitTimeout);
132                         });
133
134                         Assert.IsTrue (mre.WaitOne (500), "#1");
135                         mre.Reset ();
136                         client.CancelPendingRequests ();
137                         Assert.IsTrue (t.Wait (500), "#2");
138
139                         request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
140                         mh.OnSendFull = (l, c) => {
141                                 Assert.IsFalse (c.IsCancellationRequested, "#30");
142                                 return Task.FromResult (new HttpResponseMessage ());
143                         };
144
145                         client.SendAsync (request).Wait (WaitTimeout);
146                 }
147
148                 [Test]
149                 public void CancelPendingRequests_BeforeSend ()
150                 {
151                         var ct = new CancellationTokenSource ();
152                         ct.Cancel ();
153                         var rr = CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken (), ct.Token);
154
155
156                         var mh = new HttpMessageHandlerMock ();
157
158                         var client = new HttpClient (mh);
159                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
160                         client.CancelPendingRequests ();
161
162                         mh.OnSendFull = (l, c) => {
163                                 Assert.IsFalse (c.IsCancellationRequested, "#30");
164                                 return Task.FromResult (new HttpResponseMessage ());
165                         };
166
167                         client.SendAsync (request).Wait (WaitTimeout);
168
169                         request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
170                         client.SendAsync (request).Wait (WaitTimeout);
171                 }
172
173                 [Test]
174                 public void Properties ()
175                 {
176                         var client = new HttpClient ();
177                         client.BaseAddress = null;
178                         client.MaxResponseContentBufferSize = int.MaxValue;
179                         client.Timeout = Timeout.InfiniteTimeSpan;
180
181                         Assert.IsNull (client.BaseAddress, "#1");
182                         Assert.AreEqual (int.MaxValue, client.MaxResponseContentBufferSize, "#2");
183                         Assert.AreEqual (Timeout.InfiniteTimeSpan, client.Timeout, "#3");
184                 }
185
186                 [Test]
187                 public void Properties_Invalid ()
188                 {
189                         var client = new HttpClient ();
190                         try {
191                                 client.MaxResponseContentBufferSize = 0;
192                                 Assert.Fail ("#1");
193                         } catch (ArgumentOutOfRangeException) {
194                         }
195
196                         try {
197                                 client.Timeout = TimeSpan.MinValue;
198                                 Assert.Fail ("#2");
199                         } catch (ArgumentOutOfRangeException) {
200                         }
201                 }
202
203                 [Test]
204                 public void Send ()
205                 {
206                         var mh = new HttpMessageHandlerMock ();
207
208                         var client = new HttpClient (mh);
209                         client.BaseAddress = new Uri ("http://xamarin.com");
210                         var request = new HttpRequestMessage ();
211                         var response = new HttpResponseMessage ();
212
213                         mh.OnSend = l => {
214                                 Assert.AreEqual (l, request, "#2");
215                                 Assert.AreEqual (client.BaseAddress, l.RequestUri, "#2");
216                                 return Task.FromResult (response);
217                         };
218
219                         Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
220                 }
221
222                 [Test]
223                 public void Send_DefaultRequestHeaders ()
224                 {
225                         var mh = new HttpMessageHandlerMock ();
226
227                         var client = new HttpClient (mh);
228                         client.DefaultRequestHeaders.Referrer = new Uri ("http://google.com");
229
230                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
231                         var response = new HttpResponseMessage ();
232
233                         mh.OnSend = l => {
234                                 Assert.AreEqual (client.DefaultRequestHeaders.Referrer, l.Headers.Referrer, "#2");
235                                 Assert.IsNotNull (l.Headers.Referrer, "#3");
236                                 return Task.FromResult (response);
237                         };
238
239                         Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
240                 }
241
242                 [Test]
243                 public void Send_Complete_Default ()
244                 {
245                         bool? failed = null;
246                         var listener = CreateListener (l => {
247                                 try {
248                                         var request = l.Request;
249         
250                                         Assert.IsNull (request.AcceptTypes, "#1");
251                                         Assert.AreEqual (0, request.ContentLength64, "#2");
252                                         Assert.IsNull (request.ContentType, "#3");
253                                         Assert.AreEqual (0, request.Cookies.Count, "#4");
254                                         Assert.IsFalse (request.HasEntityBody, "#5");
255                                         Assert.AreEqual (TestHost, request.Headers["Host"], "#6b");
256                                         Assert.AreEqual ("GET", request.HttpMethod, "#7");
257                                         Assert.IsFalse (request.IsAuthenticated, "#8");
258                                         Assert.IsTrue (request.IsLocal, "#9");
259                                         Assert.IsFalse (request.IsSecureConnection, "#10");
260                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
261                                         Assert.IsTrue (request.KeepAlive, "#12");
262                                         Assert.AreEqual (HttpVersion.Version11, request.ProtocolVersion, "#13");
263                                         Assert.IsNull (request.ServiceName, "#14");
264                                         Assert.IsNull (request.UrlReferrer, "#15");
265                                         Assert.IsNull (request.UserAgent, "#16");
266                                         Assert.IsNull (request.UserLanguages, "#17");
267                                         failed = false;
268                                 } catch {
269                                         failed = true;
270                                 }
271                         });
272
273                         try {
274                                 var client = new HttpClient ();
275                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
276                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
277
278                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
279                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
280                                 Assert.AreEqual (false, failed, "#102");
281                         } finally {
282                                 listener.Close ();
283                         }
284                 }
285
286                 [Test]
287                 public void Send_Complete_Version_1_0 ()
288                 {
289                         bool? failed = null;
290                         
291                         var listener = CreateListener (l => {
292                                 try {
293                                         var request = l.Request;
294         
295                                         Assert.IsNull (request.AcceptTypes, "#1");
296                                         Assert.AreEqual (0, request.ContentLength64, "#2");
297                                         Assert.IsNull (request.ContentType, "#3");
298                                         Assert.AreEqual (0, request.Cookies.Count, "#4");
299                                         Assert.IsFalse (request.HasEntityBody, "#5");
300                                         Assert.AreEqual (1, request.Headers.Count, "#6");
301                                         Assert.AreEqual (TestHost, request.Headers["Host"], "#6a");
302                                         Assert.AreEqual ("GET", request.HttpMethod, "#7");
303                                         Assert.IsFalse (request.IsAuthenticated, "#8");
304                                         Assert.IsTrue (request.IsLocal, "#9");
305                                         Assert.IsFalse (request.IsSecureConnection, "#10");
306                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
307                                         Assert.IsFalse (request.KeepAlive, "#12");
308                                         Assert.AreEqual (HttpVersion.Version10, request.ProtocolVersion, "#13");
309                                         Assert.IsNull (request.ServiceName, "#14");
310                                         Assert.IsNull (request.UrlReferrer, "#15");
311                                         Assert.IsNull (request.UserAgent, "#16");
312                                         Assert.IsNull (request.UserLanguages, "#17");
313                                         failed = false;
314                                 } catch {
315                                         failed = true;
316                                 }
317                         });
318
319                         try {
320                                 var client = new HttpClient ();
321                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
322                                 request.Version = HttpVersion.Version10;
323                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
324
325                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
326                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
327                                 Assert.AreEqual (false, failed, "#102");
328                         } finally {
329                                 listener.Close ();
330                         }
331                 }
332
333                 [Test]
334                 public void Send_Complete_ClientHandlerSettings ()
335                 {
336                         bool? failed = null;
337                         
338                         var listener = CreateListener (l => {
339                                 var request = l.Request;
340                                 
341                                 try {
342                                         Assert.IsNull (request.AcceptTypes, "#1");
343                                         Assert.AreEqual (0, request.ContentLength64, "#2");
344                                         Assert.IsNull (request.ContentType, "#3");
345                                         Assert.AreEqual (1, request.Cookies.Count, "#4");
346                                         Assert.AreEqual (new Cookie ("mycookie", "vv"), request.Cookies[0], "#4a");
347                                         Assert.IsFalse (request.HasEntityBody, "#5");
348                                         Assert.AreEqual (4, request.Headers.Count, "#6");
349                                         Assert.AreEqual (TestHost, request.Headers["Host"], "#6a");
350                                         Assert.AreEqual ("gzip", request.Headers["Accept-Encoding"], "#6b");
351                                         Assert.AreEqual ("mycookie=vv", request.Headers["Cookie"], "#6c");
352                                         Assert.AreEqual ("GET", request.HttpMethod, "#7");
353                                         Assert.IsFalse (request.IsAuthenticated, "#8");
354                                         Assert.IsTrue (request.IsLocal, "#9");
355                                         Assert.IsFalse (request.IsSecureConnection, "#10");
356                                         Assert.IsFalse (request.IsWebSocketRequest, "#11");
357                                         Assert.IsTrue (request.KeepAlive, "#12");
358                                         Assert.AreEqual (HttpVersion.Version10, request.ProtocolVersion, "#13");
359                                         Assert.IsNull (request.ServiceName, "#14");
360                                         Assert.IsNull (request.UrlReferrer, "#15");
361                                         Assert.IsNull (request.UserAgent, "#16");
362                                         Assert.IsNull (request.UserLanguages, "#17");
363                                         failed = false;
364                                 } catch {
365                                         failed = true;
366                                 }
367                         });
368
369                         try {
370                                 var chandler = new HttpClientHandler ();
371                                 chandler.AllowAutoRedirect = true;
372                                 chandler.AutomaticDecompression = DecompressionMethods.GZip;
373                                 chandler.MaxAutomaticRedirections = 33;
374                                 chandler.MaxRequestContentBufferSize = 5555;
375                                 chandler.PreAuthenticate = true;
376                                 chandler.CookieContainer.Add (new Uri (LocalServer), new Cookie ( "mycookie", "vv"));
377                                 chandler.UseCookies = true;
378                                 chandler.UseDefaultCredentials = true;
379                                 chandler.Proxy = new WebProxy ("ee");
380                                 chandler.UseProxy = true;
381
382                                 var client = new HttpClient (chandler);
383                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
384                                 request.Version = HttpVersion.Version10;
385                                 request.Headers.Add ("Keep-Alive", "false");
386                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
387
388                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
389                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
390                                 Assert.AreEqual (false, failed, "#102");
391                         } finally {
392                                 listener.Abort ();
393                                 listener.Close ();
394                         }
395                 }
396
397                 [Test]
398                 public void Send_Complete_CustomHeaders ()
399                 {
400                         bool? failed = null;
401                         
402                         var listener = CreateListener (l => {
403                                 var request = l.Request;
404                                 try {
405                                         Assert.AreEqual ("vv", request.Headers["aa"], "#1");
406         
407                                         var response = l.Response;
408                                         response.Headers.Add ("rsp", "rrr");
409                                         response.Headers.Add ("upgrade", "vvvvaa");
410                                         response.Headers.Add ("Date", "aa");
411                                         response.Headers.Add ("cache-control", "audio");
412         
413                                         response.StatusDescription = "test description";
414                                         response.ProtocolVersion = HttpVersion.Version10;
415                                         response.SendChunked = true;
416                                         response.RedirectLocation = "w3.org";
417                                         
418                                         failed = false;
419                                 } catch {
420                                         failed = true;
421                                 }
422                         });
423
424                         try {
425                                 var client = new HttpClient ();
426                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
427                                 Assert.IsTrue (request.Headers.TryAddWithoutValidation ("aa", "vv"), "#0");
428                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
429
430                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
431                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
432                                 
433                                 IEnumerable<string> values;
434                                 Assert.IsTrue (response.Headers.TryGetValues ("rsp", out values), "#102");
435                                 Assert.AreEqual ("rrr", values.First (), "#102a");
436
437                                 Assert.IsTrue (response.Headers.TryGetValues ("Transfer-Encoding", out values), "#103");
438                                 Assert.AreEqual ("chunked", values.First (), "#103a");
439                                 Assert.AreEqual (true, response.Headers.TransferEncodingChunked, "#103b");
440
441                                 Assert.IsTrue (response.Headers.TryGetValues ("Date", out values), "#104");
442                                 Assert.AreEqual (1, values.Count (), "#104b");
443                                 // .NET overwrites Date, Mono does not
444                                 // Assert.IsNotNull (response.Headers.Date, "#104c");
445
446                                 Assert.AreEqual (new ProductHeaderValue ("vvvvaa"), response.Headers.Upgrade.First (), "#105");
447
448                                 Assert.AreEqual ("audio", response.Headers.CacheControl.Extensions.First ().Name, "#106");
449
450                                 Assert.AreEqual ("w3.org", response.Headers.Location.OriginalString, "#107");
451
452                                 Assert.AreEqual ("test description", response.ReasonPhrase, "#110");
453                                 Assert.AreEqual (HttpVersion.Version11, response.Version, "#111");
454                                 
455                                 Assert.AreEqual (false, failed, "#112");
456                         } finally {
457                                 listener.Close ();
458                         }
459                 }
460
461                 [Test]
462                 public void Send_Complete_Content ()
463                 {
464                         var listener = CreateListener (l => {
465                                 var request = l.Request;
466                                 l.Response.OutputStream.WriteByte (55);
467                                 l.Response.OutputStream.WriteByte (75);
468                         });
469
470                         try {
471                                 var client = new HttpClient ();
472                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
473                                 Assert.IsTrue (request.Headers.TryAddWithoutValidation ("aa", "vv"), "#0");
474                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
475
476                                 Assert.AreEqual ("7K", response.Content.ReadAsStringAsync ().Result, "#100");
477                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
478
479                                 IEnumerable<string> values;
480                                 Assert.IsTrue (response.Headers.TryGetValues ("Transfer-Encoding", out values), "#102");
481                                 Assert.AreEqual ("chunked", values.First (), "#102a");
482                                 Assert.AreEqual (true, response.Headers.TransferEncodingChunked, "#102b");
483                         } finally {
484                                 listener.Close ();
485                         }
486                 }
487
488                 [Test]
489                 public void Send_Complete_Content_MaxResponseContentBufferSize ()
490                 {
491                         var listener = CreateListener (l => {
492                                 var request = l.Request;
493                                 var b = new byte[4000];
494                                 l.Response.OutputStream.Write (b, 0, b.Length);
495                         });
496
497                         try {
498                                 var client = new HttpClient ();
499                                 client.MaxResponseContentBufferSize = 1000;
500                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
501                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
502
503                                 Assert.AreEqual (4000, response.Content.ReadAsStringAsync ().Result.Length, "#100");
504                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
505                         } finally {
506                                 listener.Close ();
507                         }
508                 }
509
510                 [Test]
511                 public void Send_Complete_Content_MaxResponseContentBufferSize_Error ()
512                 {
513                         var listener = CreateListener (l => {
514                                 var request = l.Request;
515                                 var b = new byte[4000];
516                                 l.Response.OutputStream.Write (b, 0, b.Length);
517                         });
518
519                         try {
520                                 var client = new HttpClient ();
521                                 client.MaxResponseContentBufferSize = 1000;
522                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
523
524                                 try {
525                                         client.SendAsync (request, HttpCompletionOption.ResponseContentRead).Wait (WaitTimeout);
526                                         Assert.Fail ("#2");
527                                 } catch (AggregateException e) {
528                                         Assert.IsTrue (e.InnerException is HttpRequestException, "#3");
529                                 }
530
531                         } finally {
532                                 listener.Close ();
533                         }
534                 }
535
536                 [Test]
537                 public void Send_Complete_NoContent ()
538                 {
539                         foreach (var method in new HttpMethod[] { HttpMethod.Post, HttpMethod.Put, HttpMethod.Delete }) {
540                                 bool? failed = null;
541                                 var listener = CreateListener (l => {
542                                         try {
543                                                 var request = l.Request;
544
545                                                 Assert.AreEqual (2, request.Headers.Count, "#1");
546                                                 Assert.AreEqual ("0", request.Headers ["Content-Length"], "#1b");
547                                                 Assert.AreEqual (method.Method, request.HttpMethod, "#2");
548                                                 failed = false;
549                                         } catch {
550                                                 failed = true;
551                                         }
552                                 });
553
554                                 try {
555                                         var client = new HttpClient ();
556                                         var request = new HttpRequestMessage (method, LocalServer);
557                                         var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
558
559                                         Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
560                                         Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
561                                         Assert.AreEqual (false, failed, "#102");
562                                 } finally {
563                                         listener.Close ();
564                                 }
565                         }
566                 }
567
568                 [Test]
569                 public void Send_Complete_Error ()
570                 {
571                         var listener = CreateListener (l => {
572                                 var response = l.Response;
573                                 response.StatusCode = 500;
574                         });
575
576                         try {
577                                 var client = new HttpClient ();
578                                 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
579                                 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
580
581                                 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
582                                 Assert.AreEqual (HttpStatusCode.InternalServerError, response.StatusCode, "#101");
583                         } finally {
584                                 listener.Close ();
585                         }
586                 }
587
588                 [Test]
589                 public void Send_Content_Get ()
590                 {
591                         var listener = CreateListener (l => {
592                                 var request = l.Request;
593                                 l.Response.OutputStream.WriteByte (72);
594                         });
595
596                         try {
597                                 var client = new HttpClient ();
598                                 var r = new HttpRequestMessage (HttpMethod.Get, LocalServer);
599                                 var response = client.SendAsync (r).Result;
600
601                                 Assert.AreEqual ("H", response.Content.ReadAsStringAsync ().Result);
602                         } finally {
603                                 listener.Close ();
604                         }
605                 }
606
607                 [Test]
608                 public void Send_Content_BomEncoding ()
609                 {
610                         var listener = CreateListener (l => {
611                                 var request = l.Request;
612
613                                 var str = l.Response.OutputStream;
614                                 str.WriteByte (0xEF);
615                                 str.WriteByte (0xBB);
616                                 str.WriteByte (0xBF);
617                                 str.WriteByte (71);
618                         });
619
620                         try {
621                                 var client = new HttpClient ();
622                                 var r = new HttpRequestMessage (HttpMethod.Get, LocalServer);
623                                 var response = client.SendAsync (r).Result;
624
625                                 Assert.AreEqual ("G", response.Content.ReadAsStringAsync ().Result);
626                         } finally {
627                                 listener.Close ();
628                         }
629                 }
630
631                 [Test]
632                 public void Send_Content_Put ()
633                 {
634                         bool passed = false;
635                         var listener = CreateListener (l => {
636                                 var request = l.Request;
637                                 passed = 7 == request.ContentLength64;
638                                 passed &= request.ContentType == "text/plain; charset=utf-8";
639                                 passed &= request.InputStream.ReadByte () == 'm';
640                         });
641
642                         try {
643                                 var client = new HttpClient ();
644                                 var r = new HttpRequestMessage (HttpMethod.Put, LocalServer);
645                                 r.Content = new StringContent ("my text");
646                                 var response = client.SendAsync (r).Result;
647
648                                 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#1");
649                                 Assert.IsTrue (passed, "#2");
650                         } finally {
651                                 listener.Abort ();
652                                 listener.Close ();
653                         }
654                 }
655
656                 [Test]
657                 public void Send_Timeout ()
658                 {
659                         var mh = new HttpMessageHandlerMock ();
660
661                         var client = new HttpClient (mh);
662                         client.Timeout = TimeSpan.FromMilliseconds (100);
663                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
664                         var response = new HttpResponseMessage ();
665
666                         mh.OnSendFull = (l, c) => {
667                                 Assert.IsTrue (c.WaitHandle.WaitOne (500), "#2");
668                                 return Task.FromResult (response);
669                         };
670
671                         Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
672                 }
673
674                 [Test]
675                 public void Send_Invalid ()
676                 {
677                         var client = new HttpClient ();
678                         try {
679                                 client.SendAsync (null).Wait (WaitTimeout);
680                                 Assert.Fail ("#1");
681                         } catch (ArgumentNullException) {
682                         }
683
684                         try {
685                                 var request = new HttpRequestMessage ();
686                                 client.SendAsync (request).Wait (WaitTimeout);
687                                 Assert.Fail ("#2");
688                         } catch (InvalidOperationException) {
689                         }
690                 }
691
692                 [Test]
693                 public void Send_InvalidHandler ()
694                 {
695                         var mh = new HttpMessageHandlerMock ();
696
697                         var client = new HttpClient (mh);
698                         client.BaseAddress = new Uri ("http://xamarin.com");
699                         var request = new HttpRequestMessage ();
700
701                         mh.OnSend = l => {
702                                 Assert.AreEqual (l, request, "#1");
703                                 return null;
704                         };
705
706                         try {
707                                 // Broken by design
708                                 client.SendAsync (request).Wait (WaitTimeout);
709                                 Assert.Fail ("#2");
710                         } catch (Exception) {
711                         }
712                 }
713
714                 [Test]
715                 public void Send_SameMessage ()
716                 {
717                         var mh = new HttpMessageHandlerMock ();
718
719                         var client = new HttpClient (mh);
720                         var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
721
722                         mh.OnSend = l => Task.FromResult (new HttpResponseMessage ());
723
724                         client.SendAsync (request).Wait (WaitTimeout);
725                         try {
726                                 client.SendAsync (request).Wait (WaitTimeout);
727                                 Assert.Fail ("#1");
728                         } catch (InvalidOperationException) {
729                         }
730                 }
731
732                 [Test]
733                 public void GetString_RelativeUri ()
734                 {
735                         var client = new HttpClient ();
736                         client.BaseAddress = new Uri ("http://en.wikipedia.org/wiki/");
737                         var uri = new Uri ("Computer", UriKind.Relative);
738
739                         Assert.That (client.GetStringAsync (uri).Result != null);
740                         Assert.That (client.GetStringAsync ("Computer").Result != null);
741                 }
742
743                 [Test]
744                 [Category ("MobileNotWorking")] // Missing encoding
745                 public void GetString_Many ()
746                 {
747                         var client = new HttpClient ();
748                         var t1 = client.GetStringAsync ("http://www.google.com");
749                         var t2 = client.GetStringAsync ("http://www.google.com");
750                         Assert.IsTrue (Task.WaitAll (new [] { t1, t2 }, WaitTimeout));          
751                 }
752
753                 [Test]
754                 public void GetByteArray_ServerError ()
755                 {
756                         var listener = CreateListener (l => {
757                                 var response = l.Response;
758                                 response.StatusCode = 500;
759                                 l.Response.OutputStream.WriteByte (72);
760                         });
761
762                         try {
763                                 var client = new HttpClient ();
764                                 try {
765                                         client.GetByteArrayAsync (LocalServer).Wait (WaitTimeout);
766                                         Assert.Fail ("#1");
767                                 } catch (AggregateException e) {
768                                         Assert.IsTrue (e.InnerException is HttpRequestException , "#2");
769                                 }
770                         } finally {
771                                 listener.Close ();
772                         }
773                 }
774
775                 [Test]
776                 public void DisallowAutoRedirect ()
777                 {
778                         var listener = CreateListener (l => {
779                                 var request = l.Request;
780                                 var response = l.Response;
781                                 
782                                 response.StatusCode = (int)HttpStatusCode.Moved;
783                                 response.RedirectLocation = "http://xamarin.com/";
784                         });
785
786                         try {
787                                 var chandler = new HttpClientHandler ();
788                                 chandler.AllowAutoRedirect = false;
789                                 var client = new HttpClient (chandler);
790
791                                 try {
792                                         client.GetStringAsync (LocalServer).Wait (WaitTimeout);
793                                         Assert.Fail ("#1");
794                                 } catch (AggregateException e) {
795                                         Assert.IsTrue (e.InnerException is HttpRequestException, "#2");
796                                 }
797                         } finally {
798                                 listener.Abort ();
799                                 listener.Close ();
800                         }
801                 }
802
803                 [Test]
804                 public void RequestUriAfterRedirect ()
805                 {
806                         var listener = CreateListener (l => {
807                                 var request = l.Request;
808                                 var response = l.Response;
809
810                                 response.StatusCode = (int)HttpStatusCode.Moved;
811                                 response.RedirectLocation = "http://xamarin.com/";
812                         });
813
814                         try {
815                                 var chandler = new HttpClientHandler ();
816                                 chandler.AllowAutoRedirect = true;
817                                 var client = new HttpClient (chandler);
818
819                                 var resp = client.GetAsync (LocalServer).Result;
820                                 Assert.AreEqual ("http://xamarin.com/", resp.RequestMessage.RequestUri.AbsoluteUri, "#1");
821                         } finally {
822                                 listener.Abort ();
823                                 listener.Close ();
824                         }
825                 }
826
827                 [Test]
828                 /*
829                  * Properties may only be modified before sending the first request.
830                  */
831                 public void ModifyHandlerAfterFirstRequest ()
832                 {
833                         var chandler = new HttpClientHandler ();
834                         chandler.AllowAutoRedirect = true;
835                         var client = new HttpClient (chandler, true);
836
837                         var listener = CreateListener (l => {
838                                 var response = l.Response;
839                                 response.StatusCode = 200;
840                                 response.OutputStream.WriteByte (55);
841                         });
842
843                         try {
844                                 client.GetStringAsync (LocalServer).Wait (WaitTimeout);
845                                 try {
846                                         chandler.AllowAutoRedirect = false;
847                                         Assert.Fail ("#1");
848                                 } catch (InvalidOperationException) {
849                                         ;
850                                 }
851                         } finally {
852                                 listener.Abort ();
853                                 listener.Close ();
854                         }
855                 }
856
857                 [Test]
858                 /*
859                  * However, this policy is not enforced for custom handlers and there
860                  * is also no way a derived class could tell its HttpClientHandler parent
861                  * that it just sent a request.
862                  * 
863                  */
864                 public void ModifyHandlerAfterFirstRequest_Mock ()
865                 {
866                         var ch = new HttpClientHandlerMock ();
867                         ch.AllowAutoRedirect = true;
868
869                         var client = new HttpClient (ch);
870
871                         ch.OnSend = (l) => {
872                                 return Task.FromResult (new HttpResponseMessage ());
873                         };
874
875                         client.GetAsync ("http://xamarin.com").Wait (WaitTimeout);
876                         ch.AllowAutoRedirect = false;
877                 }
878
879                 HttpListener CreateListener (Action<HttpListenerContext> contextAssert)
880                 {
881                         var l = new HttpListener ();
882                         l.Prefixes.Add (string.Format ("http://+:{0}/", port));
883                         l.Start ();
884                         l.BeginGetContext (ar => {
885                                 var ctx = l.EndGetContext (ar);
886
887                                 try {
888                                         if (contextAssert != null)
889                                                 contextAssert (ctx);
890                                 } finally {
891                                         ctx.Response.Close ();
892                                 }
893                         }, null);
894
895                         return l;
896                 }
897         }
898 }