[System*] Throw a PlatformNotSupported exception when using the networking stack...
[mono.git] / mcs / class / System / Test / System.Net / HttpListenerTest.cs
1 //
2 // HttpListenerTest.cs
3 //      - Unit tests for System.Net.HttpListener
4 //
5 // Author:
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
8 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System;
30 using System.IO;
31 using System.Net;
32 using System.Net.Sockets;
33 using System.Threading;
34 using System.Threading.Tasks;
35 using NUnit.Framework;
36 using MonoTests.Helpers;
37
38 namespace MonoTests.System.Net {
39         [TestFixture]
40         public class HttpListenerTest {
41
42                 int? _port;
43                 int port {
44                         get { return _port ?? (_port = NetworkHelpers.FindFreePort ()).Value; }
45                 }
46
47                 [Test]
48 #if FEATURE_NO_BSD_SOCKETS
49                 [ExpectedException (typeof (PlatformNotSupportedException))]
50 #endif
51                 public void DefaultProperties ()
52                 {
53                         HttpListener listener = new HttpListener ();
54                         Assert.AreEqual (AuthenticationSchemes.Anonymous, listener.AuthenticationSchemes, "#01");
55                         Assert.AreEqual (null, listener.AuthenticationSchemeSelectorDelegate, "#02");
56                         Assert.AreEqual (false, listener.IgnoreWriteExceptions, "#03");
57                         Assert.AreEqual (false, listener.IsListening, "#03");
58                         Assert.AreEqual (0, listener.Prefixes.Count, "#04");
59                         Assert.AreEqual (null, listener.Realm, "#05");
60                         Assert.AreEqual (false, listener.UnsafeConnectionNtlmAuthentication, "#06");
61                 }
62
63                 [Test]
64 #if FEATURE_NO_BSD_SOCKETS
65                 [ExpectedException (typeof (PlatformNotSupportedException))]
66 #endif
67                 public void Start1 ()
68                 {
69                         HttpListener listener = new HttpListener ();
70                         listener.Start ();
71                 }
72
73                 [Test]
74 #if FEATURE_NO_BSD_SOCKETS
75                 [ExpectedException (typeof (PlatformNotSupportedException))]
76 #endif
77                 public void Stop1 ()
78                 {
79                         HttpListener listener = new HttpListener ();
80                         listener.Stop ();
81                 }
82
83                 [Test]
84 #if FEATURE_NO_BSD_SOCKETS
85                 [ExpectedException (typeof (PlatformNotSupportedException))]
86 #else
87                 [ExpectedException (typeof (InvalidOperationException))]
88 #endif
89                 public void GetContext1 ()
90                 {
91                         HttpListener listener = new HttpListener ();
92                         // "Please call Start () before calling this method"
93                         listener.GetContext ();
94                 }
95
96                 [Test]
97 #if FEATURE_NO_BSD_SOCKETS
98                 [ExpectedException (typeof (PlatformNotSupportedException))]
99 #else
100                 [ExpectedException (typeof (InvalidOperationException))]
101 #endif
102                 public void GetContext2 ()
103                 {
104                         HttpListener listener = new HttpListener ();
105                         listener.Start ();
106                         // "Please call AddPrefix () before calling this method"
107                         listener.GetContext ();
108                 }
109
110                 [Test]
111 #if FEATURE_NO_BSD_SOCKETS
112                 [ExpectedException (typeof (PlatformNotSupportedException))]
113 #else
114                 [ExpectedException (typeof (InvalidOperationException))]
115 #endif
116                 public void BeginGetContext1 ()
117                 {
118                         HttpListener listener = new HttpListener ();
119                         // "Please call Start () before calling this method"
120                         listener.BeginGetContext (null, null);
121                 }
122
123                 [Test]
124 #if FEATURE_NO_BSD_SOCKETS
125                 [ExpectedException (typeof (PlatformNotSupportedException))]
126 #endif
127                 public void BeginGetContext2 ()
128                 {
129                         HttpListener listener = new HttpListener ();
130                         listener.Start ();
131                         // One would expect this to fail as BeginGetContext1 does not fail and
132                         // calling EndGetContext will wait forever.
133                         // Lame. They should check that we have no prefixes.
134                         IAsyncResult ares = listener.BeginGetContext (null, null);
135                         Assert.IsFalse (ares.IsCompleted);
136                 }
137
138                 private bool CanOpenPort(int port)
139                 {
140                         try
141                         {
142                                 using(Socket socket = new Socket (AddressFamily.InterNetwork,
143                                         SocketType.Stream,
144                                         ProtocolType.Tcp))
145                                 {
146                                         socket.Bind (new IPEndPoint (IPAddress.Loopback, port));
147                                         socket.Listen(1);
148                                 }
149                         }
150                         catch(Exception) {
151                                 //Can be AccessDeniedException(ports 80/443 need root access) or
152                                 //SocketException because other application is listening
153                                 return false;
154                         }
155                         return true;
156                 }
157
158                 [Test]
159 #if FEATURE_NO_BSD_SOCKETS
160                 [ExpectedException (typeof (PlatformNotSupportedException))]
161 #endif
162                 public void DefaultHttpPort ()
163                 {
164                         if (!CanOpenPort (80))
165                                 Assert.Ignore ("Can not open port 80 skipping test.");
166                         using(HttpListener listener = new HttpListener ())
167                         {
168                                 listener.Prefixes.Add ("http://127.0.0.1/");
169                                 listener.Start ();
170                                 Assert.IsFalse (CanOpenPort (80), "HttpListener is not listening on port 80.");
171                         }
172                 }
173
174                 [Test]
175 #if FEATURE_NO_BSD_SOCKETS
176                 [ExpectedException (typeof (PlatformNotSupportedException))]
177 #endif
178                 public void DefaultHttpsPort ()
179                 {
180                         if (!CanOpenPort (443))
181                                 Assert.Ignore ("Can not open port 443 skipping test.");
182                         using(HttpListener listener = new HttpListener ())
183                         {
184                                 listener.Prefixes.Add ("https://127.0.0.1/");
185                                 listener.Start ();
186                                 Assert.IsFalse (CanOpenPort (443), "HttpListener is not listening on port 443.");
187                         }
188                 }
189
190                 [Test]
191 #if FEATURE_NO_BSD_SOCKETS
192                 [ExpectedException (typeof (PlatformNotSupportedException))]
193 #endif
194                 public void TwoListeners_SameAddress ()
195                 {
196                         if (!CanOpenPort (port))
197                                 Assert.Ignore ("port");
198                         HttpListener listener1 = new HttpListener ();
199                         listener1.Prefixes.Add ("http://127.0.0.1:" + port + "/");
200                         HttpListener listener2 = new HttpListener ();
201                         listener2.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
202                         listener1.Start ();
203                         listener2.Start ();
204                 }
205
206                 [Test]
207 #if FEATURE_NO_BSD_SOCKETS
208                 [ExpectedException (typeof (PlatformNotSupportedException))]
209 #else
210                 [ExpectedException (typeof (HttpListenerException))]
211 #endif
212                 public void TwoListeners_SameURL ()
213                 {
214                         if (!CanOpenPort (port))
215                                 Assert.Ignore ("port");
216                         HttpListener listener1 = new HttpListener ();
217                         listener1.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
218                         HttpListener listener2 = new HttpListener ();
219                         listener2.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
220                         listener1.Start ();
221                         listener2.Start ();
222                 }
223
224                 [Test]
225 #if FEATURE_NO_BSD_SOCKETS
226                 [ExpectedException (typeof (PlatformNotSupportedException))]
227 #else
228                 [ExpectedException (typeof (HttpListenerException))]
229 #endif
230                 public void MultipleSlashes ()
231                 {
232                         if (!CanOpenPort (port))
233                                 Assert.Ignore ("port");
234                         HttpListener listener = new HttpListener ();
235                         listener.Prefixes.Add ("http://localhost:" + port + "/hola////");
236                         // this one throws on Start(), not when adding it.
237                         listener.Start ();
238                 }
239
240                 [Test]
241 #if FEATURE_NO_BSD_SOCKETS
242                 [ExpectedException (typeof (PlatformNotSupportedException))]
243 #else
244                 [ExpectedException (typeof (HttpListenerException))]
245 #endif
246                 public void PercentSign ()
247                 {
248                         if (!CanOpenPort (port))
249                                 Assert.Ignore ("port");
250                         HttpListener listener = new HttpListener ();
251                         listener.Prefixes.Add ("http://localhost:" + port + "/hola%3E/");
252                         // this one throws on Start(), not when adding it.
253                         listener.Start ();
254                 }
255
256                 [Test]
257 #if FEATURE_NO_BSD_SOCKETS
258                 [ExpectedException (typeof (PlatformNotSupportedException))]
259 #endif
260                 public void CloseBeforeStart ()
261                 {
262                         HttpListener listener = new HttpListener ();
263                         listener.Close ();
264                 }
265
266                 [Test]
267 #if FEATURE_NO_BSD_SOCKETS
268                 [ExpectedException (typeof (PlatformNotSupportedException))]
269 #endif
270                 public void CloseTwice ()
271                 {
272                         if (!CanOpenPort (port))
273                                 Assert.Ignore ("port");
274                         HttpListener listener = new HttpListener ();
275                         listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
276                         listener.Start ();
277                         listener.Close ();
278                         listener.Close ();
279                 }
280
281                 [Test]
282 #if FEATURE_NO_BSD_SOCKETS
283                 [ExpectedException (typeof (PlatformNotSupportedException))]
284 #endif
285                 public void StartStopStart ()
286                 {
287                         if (!CanOpenPort (port))
288                                 Assert.Ignore ("port");
289                         HttpListener listener = new HttpListener ();
290                         listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
291                         listener.Start ();
292                         listener.Stop ();
293                         listener.Start ();
294                         listener.Close ();
295                 }
296
297                 [Test]
298 #if FEATURE_NO_BSD_SOCKETS
299                 [ExpectedException (typeof (PlatformNotSupportedException))]
300 #endif
301                 public void StartStopDispose ()
302                 {
303                         if (!CanOpenPort (port))
304                                 Assert.Ignore ("port");
305                         using (HttpListener listener = new HttpListener ()){
306                                 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
307                                 listener.Start ();
308                                 listener.Stop ();
309                         }
310                 }
311                 
312                 [Test]
313 #if FEATURE_NO_BSD_SOCKETS
314                 [ExpectedException (typeof (PlatformNotSupportedException))]
315 #endif
316                 public void AbortBeforeStart ()
317                 {
318                         HttpListener listener = new HttpListener ();
319                         listener.Abort ();
320                 }
321
322                 [Test]
323 #if FEATURE_NO_BSD_SOCKETS
324                 [ExpectedException (typeof (PlatformNotSupportedException))]
325 #endif
326                 public void AbortTwice ()
327                 {
328                         if (!CanOpenPort (port))
329                                 Assert.Ignore ("port");
330                         HttpListener listener = new HttpListener ();
331                         listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
332                         listener.Start ();
333                         listener.Abort ();
334                         listener.Abort ();
335                 }
336
337                 [Test]
338 #if FEATURE_NO_BSD_SOCKETS
339                 [ExpectedException (typeof (PlatformNotSupportedException))]
340 #endif
341                 public void PropertiesWhenClosed1 ()
342                 {
343                         HttpListener listener = new HttpListener ();
344                         listener.Close ();
345                         Assert.AreEqual (AuthenticationSchemes.Anonymous, listener.AuthenticationSchemes, "#01");
346                         Assert.AreEqual (null, listener.AuthenticationSchemeSelectorDelegate, "#02");
347                         Assert.AreEqual (false, listener.IgnoreWriteExceptions, "#03");
348                         Assert.AreEqual (false, listener.IsListening, "#03");
349                         Assert.AreEqual (null, listener.Realm, "#05");
350                         Assert.AreEqual (false, listener.UnsafeConnectionNtlmAuthentication, "#06");
351                 }
352
353                 [Test]
354 #if FEATURE_NO_BSD_SOCKETS
355                 [ExpectedException (typeof (PlatformNotSupportedException))]
356 #else
357                 [ExpectedException (typeof (ObjectDisposedException))]
358 #endif
359                 public void PropertiesWhenClosed2 ()
360                 {
361                         HttpListener listener = new HttpListener ();
362                         listener.Close ();
363                         HttpListenerPrefixCollection p = listener.Prefixes;
364                 }
365
366                 [Test]
367 #if FEATURE_NO_BSD_SOCKETS
368                 [ExpectedException (typeof (PlatformNotSupportedException))]
369 #else
370                 [ExpectedException (typeof (ObjectDisposedException))]
371 #endif
372                 public void PropertiesWhenClosedSet1 ()
373                 {
374                         HttpListener listener = new HttpListener ();
375                         listener.Close ();
376                         listener.AuthenticationSchemes = AuthenticationSchemes.None;
377                 }
378
379                 [Test]
380 #if FEATURE_NO_BSD_SOCKETS
381                 [ExpectedException (typeof (PlatformNotSupportedException))]
382 #else
383                 [ExpectedException (typeof (ObjectDisposedException))]
384 #endif
385                 public void PropertiesWhenClosedSet2 ()
386                 {
387                         HttpListener listener = new HttpListener ();
388                         listener.Close ();
389                         listener.AuthenticationSchemeSelectorDelegate = null;
390                 }
391
392                 [Test]
393 #if FEATURE_NO_BSD_SOCKETS
394                 [ExpectedException (typeof (PlatformNotSupportedException))]
395 #else
396                 [ExpectedException (typeof (ObjectDisposedException))]
397 #endif
398                 public void PropertiesWhenClosedSet3 ()
399                 {
400                         HttpListener listener = new HttpListener ();
401                         listener.Close ();
402                         listener.IgnoreWriteExceptions = true;
403                 }
404
405                 [Test]
406 #if FEATURE_NO_BSD_SOCKETS
407                 [ExpectedException (typeof (PlatformNotSupportedException))]
408 #else
409                 [ExpectedException (typeof (ObjectDisposedException))]
410 #endif
411                 public void PropertiesWhenClosedSet4 ()
412                 {
413                         HttpListener listener = new HttpListener ();
414                         listener.Close ();
415                         listener.Realm = "hola";
416                 }
417
418                 [Test]
419 #if FEATURE_NO_BSD_SOCKETS
420                 [ExpectedException (typeof (PlatformNotSupportedException))]
421 #else
422                 [ExpectedException (typeof (ObjectDisposedException))]
423 #endif
424                 public void PropertiesWhenClosedSet5 ()
425                 {
426                         HttpListener listener = new HttpListener ();
427                         listener.Close ();
428                         listener.UnsafeConnectionNtlmAuthentication = true;
429                 }
430
431                 [Test]
432 #if FEATURE_NO_BSD_SOCKETS
433                 [ExpectedException (typeof (PlatformNotSupportedException))]
434 #endif
435                 public void PropertiesWhenClosed3 ()
436                 {
437                         HttpListener listener = new HttpListener ();
438                         listener.Close ();
439                         Assert.IsFalse (listener.IsListening);
440                 }
441
442                 [Test]
443 #if FEATURE_NO_BSD_SOCKETS
444                 [ExpectedException (typeof (PlatformNotSupportedException))]
445 #endif
446                 public void CloseWhileBegin ()
447                 {
448                         HttpListener listener = new HttpListener ();
449                         listener.Prefixes.Add ("http://127.0.0.1:" + NetworkHelpers.FindFreePort () + "/closewhilebegin/");
450                         listener.Start ();
451                         CallMe cm = new CallMe ();
452                         listener.BeginGetContext (cm.Callback, listener);
453                         listener.Close ();
454                         if (false == cm.Event.WaitOne (3000, false))
455                                 Assert.Fail ("This should not time out.");
456                         Assert.IsNotNull (cm.Error);
457                         Assert.AreEqual (typeof (ObjectDisposedException), cm.Error.GetType (), "Exception type");
458                         cm.Dispose ();
459                 }
460
461                 [Test]
462 #if FEATURE_NO_BSD_SOCKETS
463                 [ExpectedException (typeof (PlatformNotSupportedException))]
464 #endif
465                 public void AbortWhileBegin ()
466                 {
467                         HttpListener listener = new HttpListener ();
468                         listener.Prefixes.Add ("http://127.0.0.1:" + NetworkHelpers.FindFreePort () + "/abortwhilebegin/");
469                         listener.Start ();
470                         CallMe cm = new CallMe ();
471                         listener.BeginGetContext (cm.Callback, listener);
472                         listener.Abort ();
473                         if (false == cm.Event.WaitOne (3000, false))
474                                 Assert.Fail ("This should not time out.");
475                         Assert.IsNotNull (cm.Error);
476                         Assert.AreEqual (typeof (ObjectDisposedException), cm.Error.GetType (), "Exception type");
477                         cm.Dispose ();
478                 }
479
480                 [Test]
481 #if FEATURE_NO_BSD_SOCKETS
482                 [ExpectedException (typeof (PlatformNotSupportedException))]
483 #else
484                 [ExpectedException (typeof (HttpListenerException))]
485 #endif
486                 public void CloseWhileGet ()
487                 {
488                         // "System.Net.HttpListener Exception : The I/O operation has been aborted
489                         // because of either a thread exit or an application request
490                         //   at System.Net.HttpListener.GetContext()
491                         //   at MonoTests.System.Net.HttpListenerTest.CloseWhileGet()
492
493                         HttpListener listener = new HttpListener ();
494                         listener.Prefixes.Add ("http://127.0.0.1:" + NetworkHelpers.FindFreePort () + "/closewhileget/");
495                         listener.Start ();
496                         RunMe rm = new RunMe (1000, new ThreadStart (listener.Close), new object [0]);
497                         rm.Start ();
498                         HttpListenerContext ctx = listener.GetContext ();
499                 }
500
501                 [Test]
502 #if FEATURE_NO_BSD_SOCKETS
503                 [ExpectedException (typeof (PlatformNotSupportedException))]
504 #else
505                 [ExpectedException (typeof (HttpListenerException))]
506 #endif
507                 public void AbortWhileGet ()
508                 {
509                         // "System.Net.HttpListener Exception : The I/O operation has been aborted
510                         // because of either a thread exit or an application request
511                         //   at System.Net.HttpListener.GetContext()
512                         //   at MonoTests.System.Net.HttpListenerTest.CloseWhileGet()
513
514                         HttpListener listener = new HttpListener ();
515                         listener.Prefixes.Add ("http://127.0.0.1:" + NetworkHelpers.FindFreePort () + "/abortwhileget/");
516                         listener.Start ();
517                         RunMe rm = new RunMe (1000, new ThreadStart (listener.Abort), new object [0]);
518                         rm.Start ();
519                         HttpListenerContext ctx = listener.GetContext ();
520                 }
521
522                 class RunMe {
523                         Delegate d;
524                         int delay_ms;
525                         object [] args;
526                         public object Result;
527
528                         public RunMe (int delay_ms, Delegate d, object [] args)
529                         {
530                                 this.delay_ms = delay_ms;
531                                 this.d = d;
532                                 this.args = args;
533                         }
534
535                         public void Start ()
536                         {
537                                 Thread th = new Thread (new ThreadStart (Run));
538                                 th.Start ();
539                         }
540
541                         void Run ()
542                         {
543                                 Thread.Sleep (delay_ms);
544                                 Result = d.DynamicInvoke (args);
545                         }
546                 }
547
548                 class CallMe {
549                         public ManualResetEvent Event = new ManualResetEvent (false);
550                         public bool Called;
551                         public HttpListenerContext Context;
552                         public Exception Error;
553
554                         public void Reset ()
555                         {
556                                 Called = false;
557                                 Context = null;
558                                 Error = null;
559                                 Event.Reset ();
560                         }
561
562                         public void Callback (IAsyncResult ares)
563                         {
564                                 Called = true;
565                                 if (ares == null) {
566                                         Error = new ArgumentNullException ("ares");
567                                         return;
568                                 }
569                                 
570                                 try {
571                                         HttpListener listener = (HttpListener) ares.AsyncState;
572                                         Context = listener.EndGetContext (ares);
573                                 } catch (Exception e) {
574                                         Error = e;
575                                 }
576                                 Event.Set ();
577                         }
578
579                         public void Dispose ()
580                         {
581                                 Event.Close ();
582                         }
583                 }
584
585                 [Test]
586 #if FEATURE_NO_BSD_SOCKETS
587                 [ExpectedException (typeof (PlatformNotSupportedException))]
588 #endif
589                 public void ConnectionReuse ()
590                 {
591                         var uri = "http://localhost:" + NetworkHelpers.FindFreePort () + "/";
592
593                         HttpListener listener = new HttpListener ();
594                         listener.Prefixes.Add (uri);
595                         listener.Start ();
596
597                         IPEndPoint expectedIpEndPoint = CreateListenerRequest (listener, uri);
598
599                         Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse1");
600                         Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse2");
601                 }
602
603                 public IPEndPoint CreateListenerRequest (HttpListener listener, string uri)
604                 {
605                         IPEndPoint ipEndPoint = null;
606                         var mre = new ManualResetEventSlim ();
607                         listener.BeginGetContext (result => {
608                                 ipEndPoint = ListenerCallback (result);
609                                 mre.Set ();
610                         }, listener);
611
612                         var request = (HttpWebRequest) WebRequest.Create (uri);
613                         request.Method = "POST";
614
615                         // We need to write something
616                         request.GetRequestStream ().Write (new byte [] {(byte)'a'}, 0, 1);
617                         request.GetRequestStream ().Dispose ();
618
619                         // Send request, socket is created or reused.
620                         var response = request.GetResponse ();
621
622                         // Close response so socket can be reused.
623                         response.Close ();
624
625                         mre.Wait ();
626
627                         return ipEndPoint;
628                 }
629
630                 public static IPEndPoint ListenerCallback (IAsyncResult result)
631                 {
632                         var listener = (HttpListener) result.AsyncState;
633                         var context = listener.EndGetContext (result);
634                         var clientEndPoint = context.Request.RemoteEndPoint;
635
636                         // Disposing InputStream should not avoid socket reuse
637                         context.Request.InputStream.Dispose ();
638
639                         // Close OutputStream to send response
640                         context.Response.OutputStream.Close ();
641
642                         return clientEndPoint;
643                 }
644
645                 [Test]
646 #if FEATURE_NO_BSD_SOCKETS
647                 [ExpectedException (typeof (PlatformNotSupportedException))]
648 #endif
649                 public void UserHeaderWithDoubleMultiValue ()
650                 {
651                         string uri = "http://localhost:" + NetworkHelpers.FindFreePort () + "/";
652
653                         var l = new HttpListener ();
654                         l.Prefixes.Add (uri);
655                         l.Start ();
656                         l.BeginGetContext (ar => {
657                                 var ctx = l.EndGetContext (ar);
658
659                                 var response = ctx.Response;
660                                 response.Headers.Add ("X-Custom-Header", "A");
661                                 response.Headers.Add ("X-Custom-Header", "B");
662
663                                 response.Close ();
664                         }, null);
665
666                         HttpWebRequest wr = HttpWebRequest.CreateHttp (uri);
667                         var resp = wr.GetResponse ();
668                         var vls = resp.Headers.GetValues ("X-Custom-Header");
669
670                         Assert.AreEqual (2, vls.Length);
671
672                         l.Close ();
673                 }
674                 
675                 [Test]
676 #if FEATURE_NO_BSD_SOCKETS
677                 [ExpectedException (typeof (PlatformNotSupportedException))]
678 #endif
679                 public void HttpClientIsDisconnectedCheckForWriteException()
680                 {
681                         string uri = "http://localhost:" + NetworkHelpers.FindFreePort () + "/";
682
683                         AutoResetEvent exceptionOccuredEvent = new AutoResetEvent (false);
684                         HttpListener listener = new HttpListener {
685                                 IgnoreWriteExceptions = false
686                         };
687                         listener.Prefixes.Add (uri);
688                         listener.Start ();
689                         listener.BeginGetContext (result =>
690                         {
691                                 HttpListenerContext context = listener.EndGetContext (result);
692                                 context.Response.SendChunked = true;
693                                 context.Request.InputStream.Close ();
694                                 
695                                 var bytes = new byte [1024];
696                                 using(Stream outputStream = context.Response.OutputStream) {
697                                         try {
698                                                 while (true) 
699                                                         outputStream.Write (bytes, 0, bytes.Length);
700                                         } catch {
701                                                 exceptionOccuredEvent.Set ();
702                                         }
703                                 }
704                         }, null);
705
706                         Task.Factory.StartNew (() =>
707                         {
708                                 var webRequest = (HttpWebRequest)WebRequest.Create (uri);
709                                 webRequest.Method = "POST";
710                                 webRequest.KeepAlive = false;
711                                 Stream requestStream = webRequest.GetRequestStream ();
712                                 requestStream.WriteByte (1);
713                                 requestStream.Close ();
714                                 using (WebResponse response = webRequest.GetResponse ())
715                                 using (Stream stream = response.GetResponseStream ()) {
716                                         byte[] clientBytes = new byte [1024];
717                                         Assert.IsNotNull (stream, "#01");
718                                         stream.Read (clientBytes, 0, clientBytes.Length);
719                                 }
720                         });
721
722                         Assert.IsTrue (exceptionOccuredEvent.WaitOne (15 * 1000), "#02");
723                 }
724         }
725 }
726