5 // Marek Safar <marek.safar@gmail.com>
7 // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
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;
41 namespace MonoTests.System.Net.Http
44 public class HttpClientTest
46 class HttpMessageHandlerMock : HttpMessageHandler
48 public Func<HttpRequestMessage, Task<HttpResponseMessage>> OnSend;
49 public Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> OnSendFull;
51 public HttpMessageHandlerMock ()
55 protected override Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken)
58 return OnSend (request);
60 if (OnSendFull != null)
61 return OnSendFull (request, cancellationToken);
68 class HttpClientHandlerMock : HttpClientHandler
70 public Func<HttpRequestMessage, Task<HttpResponseMessage>> OnSend;
71 public Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> OnSendFull;
73 protected override Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken)
76 return OnSend (request);
78 if (OnSendFull != null)
79 return OnSendFull (request, cancellationToken);
86 class CustomStream : Stream
88 public override void Flush ()
90 throw new NotImplementedException ();
95 public override int Read (byte[] buffer, int offset, int count)
104 public override long Seek (long offset, SeekOrigin origin)
106 throw new NotImplementedException ();
109 public override void SetLength (long value)
111 throw new NotImplementedException ();
114 public override void Write (byte[] buffer, int offset, int count)
116 throw new NotImplementedException ();
119 public override bool CanRead {
125 public override bool CanSeek {
131 public override bool CanWrite {
133 throw new NotImplementedException ();
137 public override long Length {
139 throw new NotImplementedException ();
143 public override long Position {
145 throw new NotImplementedException ();
148 throw new NotImplementedException ();
153 class ThrowOnlyProxy : IWebProxy
155 public ICredentials Credentials {
157 throw new NotImplementedException ();
161 throw new NotImplementedException ();
165 public Uri GetProxy (Uri destination)
167 throw new NotImplementedException ();
170 public bool IsBypassed (Uri host)
172 throw new NotImplementedException ();
176 const int WaitTimeout = 5000;
178 string TestHost, LocalServer;
182 public void SetupFixture ()
184 if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
190 TestHost = "localhost:" + port;
191 LocalServer = string.Format ("http://{0}/", TestHost);
195 public void Ctor_Default ()
197 var client = new HttpClient ();
198 Assert.IsNull (client.BaseAddress, "#1");
199 Assert.IsNotNull (client.DefaultRequestHeaders, "#2"); // TODO: full check
200 Assert.AreEqual (int.MaxValue, client.MaxResponseContentBufferSize, "#3");
201 Assert.AreEqual (TimeSpan.FromSeconds (100), client.Timeout, "#4");
205 public void CancelPendingRequests ()
207 var mh = new HttpMessageHandlerMock ();
209 var client = new HttpClient (mh);
210 var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
211 var mre = new ManualResetEvent (false);
213 mh.OnSendFull = (l, c) => {
215 Assert.IsTrue (c.WaitHandle.WaitOne (1000), "#20");
216 Assert.IsTrue (c.IsCancellationRequested, "#21");
218 return Task.FromResult (new HttpResponseMessage ());
221 var t = Task.Factory.StartNew (() => {
222 client.SendAsync (request).Wait (WaitTimeout);
225 Assert.IsTrue (mre.WaitOne (500), "#1");
227 client.CancelPendingRequests ();
228 Assert.IsTrue (t.Wait (500), "#2");
230 request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
231 mh.OnSendFull = (l, c) => {
232 Assert.IsFalse (c.IsCancellationRequested, "#30");
233 return Task.FromResult (new HttpResponseMessage ());
236 client.SendAsync (request).Wait (WaitTimeout);
240 public void CancelPendingRequests_BeforeSend ()
242 var ct = new CancellationTokenSource ();
244 var rr = CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken (), ct.Token);
247 var mh = new HttpMessageHandlerMock ();
249 var client = new HttpClient (mh);
250 var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
251 client.CancelPendingRequests ();
253 mh.OnSendFull = (l, c) => {
254 Assert.IsFalse (c.IsCancellationRequested, "#30");
255 return Task.FromResult (new HttpResponseMessage ());
258 client.SendAsync (request).Wait (WaitTimeout);
260 request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
261 client.SendAsync (request).Wait (WaitTimeout);
266 public void CancelRequestViaProxy ()
268 var handler = new HttpClientHandler {
269 Proxy = new WebProxy ("192.168.10.25:8888/"), // proxy that doesn't exist
271 AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
274 var httpClient = new HttpClient (handler) {
275 BaseAddress = new Uri ("https://google.com"),
276 Timeout = TimeSpan.FromMilliseconds (1)
280 var restRequest = new HttpRequestMessage {
281 Method = HttpMethod.Post,
282 RequestUri = new Uri("foo", UriKind.Relative),
283 Content = new StringContent("", null, "application/json")
286 httpClient.PostAsync (restRequest.RequestUri, restRequest.Content).Wait (WaitTimeout);
288 } catch (AggregateException e) {
289 Assert.IsTrue (e.InnerException is TaskCanceledException, "#2");
294 public void Properties ()
296 var client = new HttpClient ();
297 client.BaseAddress = null;
298 client.MaxResponseContentBufferSize = int.MaxValue;
299 client.Timeout = Timeout.InfiniteTimeSpan;
301 Assert.IsNull (client.BaseAddress, "#1");
302 Assert.AreEqual (int.MaxValue, client.MaxResponseContentBufferSize, "#2");
303 Assert.AreEqual (Timeout.InfiniteTimeSpan, client.Timeout, "#3");
307 public void Properties_Invalid ()
309 var client = new HttpClient ();
311 client.MaxResponseContentBufferSize = 0;
313 } catch (ArgumentOutOfRangeException) {
317 client.Timeout = TimeSpan.MinValue;
319 } catch (ArgumentOutOfRangeException) {
324 [Category ("RequiresBSDSockets")]
325 public void Proxy_Disabled ()
327 var pp = WebRequest.DefaultWebProxy;
330 WebRequest.DefaultWebProxy = new ThrowOnlyProxy ();
332 var request = new HttpClientHandler {
336 var client = new HttpClient (request);
337 Assert.IsTrue (client.GetAsync ("http://google.com").Wait (5000), "needs internet access");
339 WebRequest.DefaultWebProxy = pp;
346 var mh = new HttpMessageHandlerMock ();
348 var client = new HttpClient (mh);
349 client.BaseAddress = new Uri ("http://xamarin.com");
350 var request = new HttpRequestMessage ();
351 var response = new HttpResponseMessage ();
354 Assert.AreEqual (l, request, "#2");
355 Assert.AreEqual (client.BaseAddress, l.RequestUri, "#2");
356 return Task.FromResult (response);
359 Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
363 public void Send_BaseAddress ()
365 var mh = new HttpMessageHandlerMock ();
367 var client = new HttpClient (mh);
368 client.BaseAddress = new Uri ("http://localhost/");
369 var response = new HttpResponseMessage ();
372 Assert.AreEqual ("http://localhost/relative", l.RequestUri.ToString (), "#2");
373 return Task.FromResult (response);
376 Assert.AreEqual (response, client.GetAsync ("relative").Result, "#1");
377 Assert.AreEqual (response, client.GetAsync ("/relative").Result, "#2");
381 public void Send_DefaultRequestHeaders ()
383 var mh = new HttpMessageHandlerMock ();
385 var client = new HttpClient (mh);
386 client.DefaultRequestHeaders.Referrer = new Uri ("http://google.com");
388 var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
389 var response = new HttpResponseMessage ();
392 Assert.AreEqual (client.DefaultRequestHeaders.Referrer, l.Headers.Referrer, "#2");
393 Assert.IsNotNull (l.Headers.Referrer, "#3");
394 return Task.FromResult (response);
397 Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
401 [Category ("RequiresBSDSockets")]
402 public void Send_Complete_Default ()
405 var listener = CreateListener (l => {
407 var request = l.Request;
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 (TestHost, request.Headers["Host"], "#6b");
415 Assert.AreEqual ("GET", request.HttpMethod, "#7");
416 Assert.IsFalse (request.IsAuthenticated, "#8");
417 Assert.IsTrue (request.IsLocal, "#9");
418 Assert.IsFalse (request.IsSecureConnection, "#10");
419 Assert.IsFalse (request.IsWebSocketRequest, "#11");
420 Assert.IsTrue (request.KeepAlive, "#12");
421 Assert.AreEqual (HttpVersion.Version11, request.ProtocolVersion, "#13");
422 Assert.IsNull (request.ServiceName, "#14");
423 Assert.IsNull (request.UrlReferrer, "#15");
424 Assert.IsNull (request.UserAgent, "#16");
425 Assert.IsNull (request.UserLanguages, "#17");
433 var client = new HttpClient ();
434 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
435 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
437 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
438 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
439 Assert.AreEqual (false, failed, "#102");
446 [Category ("RequiresBSDSockets")]
447 public void Send_Complete_Version_1_0 ()
451 var listener = CreateListener (l => {
453 var request = l.Request;
455 Assert.IsNull (request.AcceptTypes, "#1");
456 Assert.AreEqual (0, request.ContentLength64, "#2");
457 Assert.IsNull (request.ContentType, "#3");
458 Assert.AreEqual (0, request.Cookies.Count, "#4");
459 Assert.IsFalse (request.HasEntityBody, "#5");
460 Assert.AreEqual (1, request.Headers.Count, "#6");
461 Assert.AreEqual (TestHost, request.Headers["Host"], "#6a");
462 Assert.AreEqual ("GET", request.HttpMethod, "#7");
463 Assert.IsFalse (request.IsAuthenticated, "#8");
464 Assert.IsTrue (request.IsLocal, "#9");
465 Assert.IsFalse (request.IsSecureConnection, "#10");
466 Assert.IsFalse (request.IsWebSocketRequest, "#11");
467 Assert.IsFalse (request.KeepAlive, "#12");
468 Assert.AreEqual (HttpVersion.Version10, request.ProtocolVersion, "#13");
469 Assert.IsNull (request.ServiceName, "#14");
470 Assert.IsNull (request.UrlReferrer, "#15");
471 Assert.IsNull (request.UserAgent, "#16");
472 Assert.IsNull (request.UserLanguages, "#17");
480 var client = new HttpClient ();
481 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
482 request.Version = HttpVersion.Version10;
483 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
485 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
486 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
487 Assert.AreEqual (false, failed, "#102");
494 [Category ("RequiresBSDSockets")]
495 public void Send_Complete_ClientHandlerSettings ()
499 var listener = CreateListener (l => {
500 var request = l.Request;
503 Assert.IsNull (request.AcceptTypes, "#1");
504 Assert.AreEqual (0, request.ContentLength64, "#2");
505 Assert.IsNull (request.ContentType, "#3");
506 Assert.AreEqual (1, request.Cookies.Count, "#4");
507 Assert.AreEqual (new Cookie ("mycookie", "vv"), request.Cookies[0], "#4a");
508 Assert.IsFalse (request.HasEntityBody, "#5");
509 Assert.AreEqual (4, request.Headers.Count, "#6");
510 Assert.AreEqual (TestHost, request.Headers["Host"], "#6a");
511 Assert.AreEqual ("gzip", request.Headers["Accept-Encoding"], "#6b");
512 Assert.AreEqual ("mycookie=vv", request.Headers["Cookie"], "#6c");
513 Assert.AreEqual ("GET", request.HttpMethod, "#7");
514 Assert.IsFalse (request.IsAuthenticated, "#8");
515 Assert.IsTrue (request.IsLocal, "#9");
516 Assert.IsFalse (request.IsSecureConnection, "#10");
517 Assert.IsFalse (request.IsWebSocketRequest, "#11");
518 Assert.IsTrue (request.KeepAlive, "#12");
519 Assert.AreEqual (HttpVersion.Version10, request.ProtocolVersion, "#13");
520 Assert.IsNull (request.ServiceName, "#14");
521 Assert.IsNull (request.UrlReferrer, "#15");
522 Assert.IsNull (request.UserAgent, "#16");
523 Assert.IsNull (request.UserLanguages, "#17");
531 var chandler = new HttpClientHandler ();
532 chandler.AllowAutoRedirect = true;
533 chandler.AutomaticDecompression = DecompressionMethods.GZip;
534 chandler.MaxAutomaticRedirections = 33;
535 chandler.MaxRequestContentBufferSize = 5555;
536 chandler.PreAuthenticate = true;
537 chandler.CookieContainer.Add (new Uri (LocalServer), new Cookie ( "mycookie", "vv"));
538 chandler.UseCookies = true;
539 chandler.UseDefaultCredentials = true;
540 chandler.Proxy = new WebProxy ("ee");
541 chandler.UseProxy = true;
543 var client = new HttpClient (chandler);
544 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
545 request.Version = HttpVersion.Version10;
546 request.Headers.Add ("Keep-Alive", "false");
547 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
549 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
550 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
551 Assert.AreEqual (false, failed, "#102");
559 [Category ("RequiresBSDSockets")]
560 public void Send_Complete_CustomHeaders ()
564 var listener = CreateListener (l => {
565 var request = l.Request;
567 Assert.AreEqual ("vv", request.Headers["aa"], "#1");
569 var response = l.Response;
570 response.Headers.Add ("rsp", "rrr");
571 response.Headers.Add ("upgrade", "vvvvaa");
572 response.Headers.Add ("Date", "aa");
573 response.Headers.Add ("cache-control", "audio");
575 response.StatusDescription = "test description";
576 response.ProtocolVersion = HttpVersion.Version10;
577 response.SendChunked = true;
578 response.RedirectLocation = "w3.org";
587 var client = new HttpClient ();
588 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
589 Assert.IsTrue (request.Headers.TryAddWithoutValidation ("aa", "vv"), "#0");
590 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
592 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
593 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
595 IEnumerable<string> values;
596 Assert.IsTrue (response.Headers.TryGetValues ("rsp", out values), "#102");
597 Assert.AreEqual ("rrr", values.First (), "#102a");
599 Assert.IsTrue (response.Headers.TryGetValues ("Transfer-Encoding", out values), "#103");
600 Assert.AreEqual ("chunked", values.First (), "#103a");
601 Assert.AreEqual (true, response.Headers.TransferEncodingChunked, "#103b");
603 Assert.IsTrue (response.Headers.TryGetValues ("Date", out values), "#104");
604 Assert.AreEqual (1, values.Count (), "#104b");
605 // .NET overwrites Date, Mono does not
606 // Assert.IsNotNull (response.Headers.Date, "#104c");
608 Assert.AreEqual (new ProductHeaderValue ("vvvvaa"), response.Headers.Upgrade.First (), "#105");
610 Assert.AreEqual ("audio", response.Headers.CacheControl.Extensions.First ().Name, "#106");
612 Assert.AreEqual ("w3.org", response.Headers.Location.OriginalString, "#107");
614 Assert.AreEqual ("test description", response.ReasonPhrase, "#110");
615 Assert.AreEqual (HttpVersion.Version11, response.Version, "#111");
617 Assert.AreEqual (false, failed, "#112");
624 [Category ("RequiresBSDSockets")]
625 public void Send_Complete_CustomHeaders_SpecialSeparators ()
629 var listener = CreateListener (l => {
630 var request = l.Request;
633 Assert.AreEqual ("MLK Android Phone 1.1.9", request.UserAgent, "#1");
641 var client = new HttpClient ();
643 client.DefaultRequestHeaders.Add("User-Agent", "MLK Android Phone 1.1.9");
645 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
647 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
649 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
650 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
651 Assert.AreEqual (false, failed, "#102");
659 [Category ("RequiresBSDSockets")]
660 public void Send_Complete_CustomHeaders_Host ()
663 var listener = CreateListener (l => {
664 var request = l.Request;
667 Assert.AreEqual ("customhost", request.Headers["Host"], "#1");
675 var client = new HttpClient ();
677 client.DefaultRequestHeaders.Add("Host", "customhost");
679 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
681 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
683 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
684 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
685 Assert.AreEqual (false, failed, "#102");
693 [Category ("RequiresBSDSockets")]
694 public void Send_Transfer_Encoding_Chunked ()
698 var listener = CreateListener (l => {
699 var request = l.Request;
702 Assert.AreEqual (1, request.Headers.Count, "#1");
710 var client = new HttpClient ();
711 client.DefaultRequestHeaders.TransferEncodingChunked = true;
713 client.GetAsync (LocalServer).Wait ();
715 Assert.AreEqual (false, failed, "#102");
723 [Category ("RequiresBSDSockets")]
724 public void Send_Transfer_Encoding_Custom ()
728 var listener = CreateListener (l => {
733 var client = new HttpClient ();
734 client.DefaultRequestHeaders.TransferEncoding.Add (new TransferCodingHeaderValue ("chunked2"));
736 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
739 client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Wait ();
741 } catch (AggregateException e) {
742 Assert.AreEqual (typeof (ProtocolViolationException), e.InnerException.GetType (), "#2");
744 Assert.IsNull (failed, "#102");
752 [Category ("RequiresBSDSockets")]
753 public void Send_Complete_Content ()
755 var listener = CreateListener (l => {
756 var request = l.Request;
757 l.Response.OutputStream.WriteByte (55);
758 l.Response.OutputStream.WriteByte (75);
762 var client = new HttpClient ();
763 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
764 Assert.IsTrue (request.Headers.TryAddWithoutValidation ("aa", "vv"), "#0");
765 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
767 Assert.AreEqual ("7K", response.Content.ReadAsStringAsync ().Result, "#100");
768 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
770 IEnumerable<string> values;
771 Assert.IsTrue (response.Headers.TryGetValues ("Transfer-Encoding", out values), "#102");
772 Assert.AreEqual ("chunked", values.First (), "#102a");
773 Assert.AreEqual (true, response.Headers.TransferEncodingChunked, "#102b");
780 [Category ("RequiresBSDSockets")]
781 public void Send_Complete_Content_MaxResponseContentBufferSize ()
783 var listener = CreateListener (l => {
784 var request = l.Request;
785 var b = new byte[4000];
786 l.Response.OutputStream.Write (b, 0, b.Length);
790 var client = new HttpClient ();
791 client.MaxResponseContentBufferSize = 1000;
792 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
793 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
795 Assert.AreEqual (4000, response.Content.ReadAsStringAsync ().Result.Length, "#100");
796 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
803 [Category ("RequiresBSDSockets")]
804 public void Send_Complete_Content_MaxResponseContentBufferSize_Error ()
806 var listener = CreateListener (l => {
807 var request = l.Request;
808 var b = new byte[4000];
809 l.Response.OutputStream.Write (b, 0, b.Length);
813 var client = new HttpClient ();
814 client.MaxResponseContentBufferSize = 1000;
815 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
818 client.SendAsync (request, HttpCompletionOption.ResponseContentRead).Wait (WaitTimeout);
820 } catch (AggregateException e) {
821 Assert.IsTrue (e.InnerException is HttpRequestException, "#3");
830 [Category ("RequiresBSDSockets")]
831 public void Send_Complete_NoContent ()
833 foreach (var method in new HttpMethod[] { HttpMethod.Post, HttpMethod.Put, HttpMethod.Delete }) {
835 var listener = CreateListener (l => {
837 var request = l.Request;
839 Assert.AreEqual (2, request.Headers.Count, "#1");
840 Assert.AreEqual ("0", request.Headers ["Content-Length"], "#1b");
841 Assert.AreEqual (method.Method, request.HttpMethod, "#2");
849 var client = new HttpClient ();
850 var request = new HttpRequestMessage (method, LocalServer);
851 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
853 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
854 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#101");
855 Assert.AreEqual (false, failed, "#102");
863 [Category ("RequiresBSDSockets")]
864 public void Send_Complete_Error ()
866 var listener = CreateListener (l => {
867 var response = l.Response;
868 response.StatusCode = 500;
872 var client = new HttpClient ();
873 var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
874 var response = client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Result;
876 Assert.AreEqual ("", response.Content.ReadAsStringAsync ().Result, "#100");
877 Assert.AreEqual (HttpStatusCode.InternalServerError, response.StatusCode, "#101");
884 [Category ("RequiresBSDSockets")]
885 public void Send_Content_Get ()
887 var listener = CreateListener (l => {
888 var request = l.Request;
889 l.Response.OutputStream.WriteByte (72);
893 var client = new HttpClient ();
894 var r = new HttpRequestMessage (HttpMethod.Get, LocalServer);
895 var response = client.SendAsync (r).Result;
897 Assert.AreEqual ("H", response.Content.ReadAsStringAsync ().Result);
904 [Category ("RequiresBSDSockets")]
905 public void Send_Content_BomEncoding ()
907 var listener = CreateListener (l => {
908 var request = l.Request;
910 var str = l.Response.OutputStream;
911 str.WriteByte (0xEF);
912 str.WriteByte (0xBB);
913 str.WriteByte (0xBF);
918 var client = new HttpClient ();
919 var r = new HttpRequestMessage (HttpMethod.Get, LocalServer);
920 var response = client.SendAsync (r).Result;
922 Assert.AreEqual ("G", response.Content.ReadAsStringAsync ().Result);
929 [Category ("RequiresBSDSockets")]
930 public void Send_Content_Put ()
933 var listener = CreateListener (l => {
934 var request = l.Request;
935 passed = 7 == request.ContentLength64;
936 passed &= request.ContentType == "text/plain; charset=utf-8";
937 passed &= request.InputStream.ReadByte () == 'm';
941 var client = new HttpClient ();
942 var r = new HttpRequestMessage (HttpMethod.Put, LocalServer);
943 r.Content = new StringContent ("my text");
944 var response = client.SendAsync (r).Result;
946 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#1");
947 Assert.IsTrue (passed, "#2");
955 [Category ("RequiresBSDSockets")]
956 public void Send_Content_Put_CustomStream ()
959 var listener = CreateListener (l => {
960 var request = l.Request;
961 passed = 44 == request.ContentLength64;
962 passed &= request.ContentType == null;
966 var client = new HttpClient ();
967 var r = new HttpRequestMessage (HttpMethod.Put, LocalServer);
968 r.Content = new StreamContent (new CustomStream ());
969 var response = client.SendAsync (r).Result;
971 Assert.AreEqual (HttpStatusCode.OK, response.StatusCode, "#1");
972 Assert.IsTrue (passed, "#2");
981 public void Send_Timeout ()
983 var mh = new HttpMessageHandlerMock ();
985 var client = new HttpClient (mh);
986 client.Timeout = TimeSpan.FromMilliseconds (100);
987 var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
988 var response = new HttpResponseMessage ();
990 mh.OnSendFull = (l, c) => {
991 Assert.IsTrue (c.WaitHandle.WaitOne (500), "#2");
992 return Task.FromResult (response);
995 Assert.AreEqual (response, client.SendAsync (request).Result, "#1");
999 public void Send_Invalid ()
1001 var client = new HttpClient ();
1003 client.SendAsync (null).Wait (WaitTimeout);
1005 } catch (ArgumentNullException) {
1009 var request = new HttpRequestMessage ();
1010 client.SendAsync (request).Wait (WaitTimeout);
1012 } catch (InvalidOperationException) {
1017 public void Send_InvalidHandler ()
1019 var mh = new HttpMessageHandlerMock ();
1021 var client = new HttpClient (mh);
1022 client.BaseAddress = new Uri ("http://xamarin.com");
1023 var request = new HttpRequestMessage ();
1026 Assert.AreEqual (l, request, "#1");
1032 client.SendAsync (request).Wait (WaitTimeout);
1034 } catch (Exception) {
1039 public void Send_SameMessage ()
1041 var mh = new HttpMessageHandlerMock ();
1043 var client = new HttpClient (mh);
1044 var request = new HttpRequestMessage (HttpMethod.Get, "http://xamarin.com");
1046 mh.OnSend = l => Task.FromResult (new HttpResponseMessage ());
1048 client.SendAsync (request).Wait (WaitTimeout);
1050 client.SendAsync (request).Wait (WaitTimeout);
1052 } catch (InvalidOperationException) {
1057 [Category ("MobileNotWorking")] // Missing encoding
1058 [Category ("RequiresBSDSockets")]
1059 public void GetString_Many ()
1061 Action<HttpListenerContext> context = (HttpListenerContext l) => {
1062 var response = l.Response;
1063 response.StatusCode = 200;
1064 response.OutputStream.WriteByte (0x68);
1065 response.OutputStream.WriteByte (0x65);
1066 response.OutputStream.WriteByte (0x6c);
1067 response.OutputStream.WriteByte (0x6c);
1068 response.OutputStream.WriteByte (0x6f);
1071 var listener = CreateListener (context); // creates a default request handler
1072 AddListenerContext (listener, context); // add another request handler for the second request
1075 var client = new HttpClient ();
1076 var t1 = client.GetStringAsync (LocalServer);
1077 var t2 = client.GetStringAsync (LocalServer);
1078 Assert.IsTrue (Task.WaitAll (new [] { t1, t2 }, WaitTimeout));
1079 Assert.AreEqual ("hello", t1.Result, "#1");
1080 Assert.AreEqual ("hello", t2.Result, "#2");
1088 [Category ("RequiresBSDSockets")]
1089 public void GetByteArray_ServerError ()
1091 var listener = CreateListener (l => {
1092 var response = l.Response;
1093 response.StatusCode = 500;
1094 l.Response.OutputStream.WriteByte (72);
1098 var client = new HttpClient ();
1100 client.GetByteArrayAsync (LocalServer).Wait (WaitTimeout);
1102 } catch (AggregateException e) {
1103 Assert.IsTrue (e.InnerException is HttpRequestException , "#2");
1111 [Category ("RequiresBSDSockets")]
1112 public void DisallowAutoRedirect ()
1114 var listener = CreateListener (l => {
1115 var request = l.Request;
1116 var response = l.Response;
1118 response.StatusCode = (int)HttpStatusCode.Moved;
1119 response.RedirectLocation = "http://xamarin.com/";
1123 var chandler = new HttpClientHandler ();
1124 chandler.AllowAutoRedirect = false;
1125 var client = new HttpClient (chandler);
1128 client.GetStringAsync (LocalServer).Wait (WaitTimeout);
1130 } catch (AggregateException e) {
1131 Assert.IsTrue (e.InnerException is HttpRequestException, "#2");
1140 [Category ("RequiresBSDSockets")]
1141 public void RequestUriAfterRedirect ()
1143 var listener = CreateListener (l => {
1144 var request = l.Request;
1145 var response = l.Response;
1147 response.StatusCode = (int)HttpStatusCode.Moved;
1148 response.RedirectLocation = "http://localhost:8811/";
1151 var listener2 = CreateListener (l => {
1152 var response = l.Response;
1154 response.StatusCode = (int)HttpStatusCode.OK;
1155 response.OutputStream.WriteByte (0x68);
1156 response.OutputStream.WriteByte (0x65);
1157 response.OutputStream.WriteByte (0x6c);
1158 response.OutputStream.WriteByte (0x6c);
1159 response.OutputStream.WriteByte (0x6f);
1163 var chandler = new HttpClientHandler ();
1164 chandler.AllowAutoRedirect = true;
1165 var client = new HttpClient (chandler);
1167 var r = client.GetAsync (LocalServer);
1168 Assert.IsTrue (r.Wait (WaitTimeout), "#1");
1169 var resp = r.Result;
1170 Assert.AreEqual ("http://localhost:8811/", resp.RequestMessage.RequestUri.AbsoluteUri, "#2");
1171 Assert.AreEqual ("hello", resp.Content.ReadAsStringAsync ().Result, "#3");
1181 [Category ("RequiresBSDSockets")]
1183 * Properties may only be modified before sending the first request.
1185 public void ModifyHandlerAfterFirstRequest ()
1187 var chandler = new HttpClientHandler ();
1188 chandler.AllowAutoRedirect = true;
1189 var client = new HttpClient (chandler, true);
1191 var listener = CreateListener (l => {
1192 var response = l.Response;
1193 response.StatusCode = 200;
1194 response.OutputStream.WriteByte (55);
1198 client.GetStringAsync (LocalServer).Wait (WaitTimeout);
1200 chandler.AllowAutoRedirect = false;
1202 } catch (InvalidOperationException) {
1213 * However, this policy is not enforced for custom handlers and there
1214 * is also no way a derived class could tell its HttpClientHandler parent
1215 * that it just sent a request.
1218 public void ModifyHandlerAfterFirstRequest_Mock ()
1220 var ch = new HttpClientHandlerMock ();
1221 ch.AllowAutoRedirect = true;
1223 var client = new HttpClient (ch);
1225 ch.OnSend = (l) => {
1226 return Task.FromResult (new HttpResponseMessage ());
1229 client.GetAsync ("http://xamarin.com").Wait (WaitTimeout);
1230 ch.AllowAutoRedirect = false;
1233 HttpListener CreateListener (Action<HttpListenerContext> contextAssert)
1235 return CreateListener (contextAssert, port);
1238 HttpListener CreateListener (Action<HttpListenerContext> contextAssert, int port)
1240 var l = new HttpListener ();
1241 l.Prefixes.Add (string.Format ("http://+:{0}/", port));
1243 AddListenerContext(l, contextAssert);
1248 HttpListener AddListenerContext (HttpListener l, Action<HttpListenerContext> contextAssert)
1250 l.BeginGetContext (ar => {
1251 var ctx = l.EndGetContext (ar);
1254 if (contextAssert != null)
1255 contextAssert (ctx);
1257 ctx.Response.Close ();