2 // System.Web.HttpResponseTest.cs - Unit tests for System.Web.HttpResponse
5 // Miguel de Icaza <miguel@ximian.com>
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.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.Specialized;
36 using NUnit.Framework;
38 namespace MonoTests.System.Web {
40 public class FakeHttpWorkerRequest2 : HttpWorkerRequest {
41 public Hashtable KnownResponseHeaders;
42 public Hashtable UnknownResponseHeaders;
43 public int return_kind;
45 public FakeHttpWorkerRequest2 (int re)
47 KnownResponseHeaders = CollectionsUtil.CreateCaseInsensitiveHashtable();
48 UnknownResponseHeaders = CollectionsUtil.CreateCaseInsensitiveHashtable();
52 public override string GetUriPath()
57 public override string GetQueryString()
59 return "GetQueryString";
62 public override string GetRawUrl()
67 public override string GetHttpVerbName()
72 public override string GetHttpVersion()
80 public override string GetRemoteAddress()
82 return "__GetRemoteAddress";
85 public override int GetRemotePort()
90 public override string GetLocalAddress()
92 return "GetLocalAddress";
95 public override string GetAppPath ()
100 public override int GetLocalPort()
105 public bool status_sent;
106 public int status_code;
107 public string status_string;
109 public override void SendStatus(int s, string x)
116 void AddHeader (Hashtable table, string header_name, object header)
118 object o = table [header_name];
120 table.Add (header_name, header);
122 ArrayList al = o as ArrayList;
124 al = new ArrayList ();
126 table [header_name] = al;
135 public override void SendKnownResponseHeader(int x, string j)
137 string header_name = HttpWorkerRequest.GetKnownRequestHeaderName (x);
138 AddHeader (KnownResponseHeaders, header_name, new KnownResponseHeader (x, j));
142 public override void SendUnknownResponseHeader(string a, string b)
144 AddHeader (UnknownResponseHeaders, a, new UnknownResponseHeader (a, b));
151 public int total = 0;
153 public override void SendResponseFromMemory(byte[] arr, int x)
157 byte [] tmp = new byte [data.Length + x];
158 Array.Copy (data, tmp, data.Length);
159 Array.Copy (arr, 0, tmp, data.Length, x);
161 data_len = data.Length;
164 for (int i = 0; i < x; i++)
171 public override void SendResponseFromFile(string a, long b , long c)
176 public override void SendResponseFromFile (IntPtr a, long b, long c)
181 public override void FlushResponse(bool x)
185 public override void EndOfRequest() {
188 public override string GetKnownRequestHeader (int index)
193 public bool OutputProduced {
195 return headers_sent || data_sent;
200 class KnownResponseHeader
203 private string value;
205 public KnownResponseHeader (int index, string value)
212 get { return index; }
215 public string Value {
216 get { return value; }
220 class UnknownResponseHeader
223 private string value;
225 public UnknownResponseHeader (string name, string value)
235 public string Value {
236 get { return value; }
241 public class HttpResponseTest {
242 HttpContext Cook (int re, out FakeHttpWorkerRequest2 f)
244 f = new FakeHttpWorkerRequest2 (re);
245 HttpContext c = new HttpContext (f);
254 AppDomain.CurrentDomain.SetData (".appPath", AppDomain.CurrentDomain.BaseDirectory);
260 [Category ("NotWorking")] // char output stream in gh make this test fail
262 public void Test_Response ()
264 FakeHttpWorkerRequest2 f;
265 HttpContext c = Cook (1, out f);
267 c.Response.Write ("a");
268 Assert.AreEqual (false, f.OutputProduced, "T1");
270 Assert.AreEqual (1, f.data_len, "T2");
271 c.Response.Write ("Hola");
272 Assert.AreEqual (1, f.data_len, "T3");
274 Assert.AreEqual (5, f.data_len, "T4");
275 Assert.AreEqual ((byte) 'a', f.data [0], "T5");
276 Assert.AreEqual ((byte) 'H', f.data [1], "T6");
277 Assert.AreEqual ((byte) 'o', f.data [2], "T7");
278 Assert.AreEqual ((byte) 'l', f.data [3], "T8");
279 Assert.AreEqual ((byte) 'a', f.data [4], "T9");
284 [Category ("NotWorking")] // char output stream in gh make this test fail
286 public void TestResponse_Chunked ()
288 FakeHttpWorkerRequest2 f;
289 HttpContext c = Cook (2, out f);
291 c.Response.Write ("a");
292 Assert.AreEqual (false, f.OutputProduced, "CT1");
294 Assert.AreEqual (6, f.total, "CT2");
295 c.Response.Write ("Hola");
296 Assert.AreEqual (6, f.total, "CT3");
302 public void Status1 ()
304 FakeHttpWorkerRequest2 f;
305 HttpContext c = Cook (2, out f);
307 HttpResponse resp = c.Response;
308 resp.Status = "200 Lalala";
309 Assert.AreEqual (200, resp.StatusCode, "ST1");
310 Assert.AreEqual ("Lalala", resp.StatusDescription, "ST2");
312 resp.Status = "10000 La la la";
313 Assert.AreEqual (10000, resp.StatusCode, "ST3");
314 Assert.AreEqual ("La la la", resp.StatusDescription, "ST4");
316 resp.Status = "-1 La la la";
317 Assert.AreEqual (-1, resp.StatusCode, "ST5");
318 Assert.AreEqual ("La la la", resp.StatusDescription, "ST6");
320 resp.Status = "-200 La la la";
321 Assert.AreEqual (-200, resp.StatusCode, "ST7");
322 Assert.AreEqual ("La la la", resp.StatusDescription, "ST8");
324 resp.Status = "200 ";
325 Assert.AreEqual (200, resp.StatusCode, "ST7");
326 Assert.AreEqual ("", resp.StatusDescription, "ST8");
330 public void Status2 ()
332 FakeHttpWorkerRequest2 f;
333 HttpContext c = Cook (2, out f);
335 HttpResponse resp = c.Response;
339 } catch (HttpException) {
344 public void Status3 ()
346 FakeHttpWorkerRequest2 f;
347 HttpContext c = Cook (2, out f);
349 HttpResponse resp = c.Response;
351 resp.Status = "200\t";
353 } catch (HttpException) {
358 public void Status4 ()
360 FakeHttpWorkerRequest2 f;
361 HttpContext c = Cook (2, out f);
363 HttpResponse resp = c.Response;
365 Assert.AreEqual (200, resp.StatusCode, "STT1");
366 Assert.AreEqual (HttpWorkerRequest.GetStatusDescription (200), resp.StatusDescription, "STT2");
368 resp.StatusCode = 400;
369 Assert.AreEqual (400, resp.StatusCode, "STT3");
370 Assert.AreEqual (HttpWorkerRequest.GetStatusDescription (400), resp.StatusDescription, "STT4");
372 resp.StatusDescription = "Something else";
373 Assert.AreEqual (400, resp.StatusCode, "STT5");
374 Assert.AreEqual ("Something else", resp.StatusDescription, "STT6");
376 resp.StatusDescription = null;
377 Assert.AreEqual (400, resp.StatusCode, "STT7");
378 Assert.AreEqual (HttpWorkerRequest.GetStatusDescription (400), resp.StatusDescription, "STT8");
382 // TODO: Add test for BinaryWrite and the various writes to check for Chunked Mode
386 public void SetCacheability ()
388 FakeHttpWorkerRequest2 f;
389 HttpContext c = Cook (1, out f);
392 // Basically the values from CacheControl are useless once Response.Cache is used
394 c.Response.Cache.SetCacheability (HttpCacheability.ServerAndNoCache);
395 Assert.AreEqual ("private", c.Response.CacheControl, "C1");
397 c.Response.Cache.SetCacheability (HttpCacheability.ServerAndPrivate);
398 Assert.AreEqual ("private", c.Response.CacheControl, "C2");
400 c.Response.Cache.SetCacheability (HttpCacheability.NoCache);
401 Assert.AreEqual ("private", c.Response.CacheControl, "C3");
403 c.Response.Cache.SetCacheability (HttpCacheability.Private);
404 Assert.AreEqual ("private", c.Response.CacheControl, "C4");
406 c.Response.Cache.SetCacheability (HttpCacheability.Server);
407 Assert.AreEqual ("private", c.Response.CacheControl, "C5");
409 c.Response.Cache.SetCacheability (HttpCacheability.Public);
410 Assert.AreEqual ("private", c.Response.CacheControl, "C6");
414 // Test the values allowed; .NET only documents private and public, but
415 // "no-cache" from the spec is also allowed
418 public void CacheControl ()
420 FakeHttpWorkerRequest2 f;
421 HttpContext c = Cook (1, out f);
424 Assert.AreEqual ("private", c.Response.CacheControl, "D1");
426 c.Response.CacheControl = "private";
427 Assert.AreEqual ("private", c.Response.CacheControl, "D2");
429 c.Response.CacheControl = "public";
430 Assert.AreEqual ("public", c.Response.CacheControl, "D3");
432 c.Response.CacheControl = "no-cache";
433 Assert.AreEqual ("no-cache", c.Response.CacheControl, "D4");
435 c.Response.CacheControl = null;
436 Assert.AreEqual ("private", c.Response.CacheControl, "D5");
438 c.Response.CacheControl = "";
439 Assert.AreEqual ("private", c.Response.CacheControl, "D6");
443 // Just checks if the AddFileDepend* methods accept values, added after bug #342511
445 public void AddFileDependencies ()
447 FakeHttpWorkerRequest2 f;
448 HttpContext c = Cook (1, out f);
450 ArrayList a = new ArrayList (1);
451 a.Add ("somefile.txt");
452 c.Response.AddFileDependencies (a);
455 string[] sa = new string [1] {"somefile.txt"};
457 c.Response.AddFileDependencies (sa);
461 c.Response.AddFileDependency ("somefile.txt");
464 [Test] // bug #488702
465 public void WriteHeaders ()
467 FakeHttpWorkerRequest2 f;
468 HttpContext c = Cook (2, out f);
470 HttpResponse resp = c.Response;
471 resp.CacheControl = "public";
472 resp.Cache.SetCacheability (HttpCacheability.NoCache);
473 resp.ContentType = "text/xml";
474 resp.AppendHeader ("Content-Disposition", "inline");
475 resp.AppendHeader ("Content-Type", "application/ms-word");
476 resp.AppendHeader ("Content-Length", "40");
477 resp.AppendHeader ("Transfer-Encoding", "compress");
478 resp.AppendHeader ("My-Custom-Header", "never");
479 resp.AppendHeader ("My-Custom-Header", "always");
481 Assert.AreEqual ("public", resp.CacheControl, "#A1");
482 Assert.AreEqual ("application/ms-word", resp.ContentType, "#A2");
483 Assert.AreEqual (0, f.KnownResponseHeaders.Count, "#A3");
484 Assert.AreEqual (0, f.UnknownResponseHeaders.Count, "#A4");
488 KnownResponseHeader known;
490 Assert.AreEqual (6, f.KnownResponseHeaders.Count, "#B1");
492 known = (KnownResponseHeader)f.KnownResponseHeaders ["Content-Length"];
493 Assert.AreEqual (HttpWorkerRequest.HeaderContentLength, known.Index, "#B2");
494 Assert.AreEqual ("40", known.Value, "#B3");
496 known = (KnownResponseHeader)f.KnownResponseHeaders["Transfer-Encoding"];
497 Assert.AreEqual (HttpWorkerRequest.HeaderTransferEncoding, known.Index, "#B4");
498 Assert.AreEqual ("compress", known.Value, "#B5");
500 known = (KnownResponseHeader)f.KnownResponseHeaders["Cache-Control"];
501 Assert.AreEqual (HttpWorkerRequest.HeaderCacheControl, known.Index, "#B6");
502 Assert.AreEqual ("no-cache", known.Value, "#B7");
504 known = (KnownResponseHeader)f.KnownResponseHeaders["Pragma"];
505 Assert.AreEqual (HttpWorkerRequest.HeaderPragma, known.Index, "#B8");
506 Assert.AreEqual ("no-cache", known.Value, "#B9");
508 known = (KnownResponseHeader)f.KnownResponseHeaders["Expires"];
509 Assert.AreEqual (HttpWorkerRequest.HeaderExpires, known.Index, "#B10");
510 Assert.AreEqual ("-1", known.Value, "#B11");
512 known = (KnownResponseHeader)f.KnownResponseHeaders["Content-Type"];
513 Assert.AreEqual (HttpWorkerRequest.HeaderContentType, known.Index, "#B12");
514 Assert.AreEqual ("application/ms-word", known.Value, "#B13");
516 UnknownResponseHeader unknown;
518 Assert.AreEqual (3, f.UnknownResponseHeaders.Count, "#C1");
520 unknown = (UnknownResponseHeader) f.UnknownResponseHeaders ["X-AspNet-Version"];
521 Assert.AreEqual ("X-AspNet-Version", unknown.Name, "#C2");
522 Assert.AreEqual (Environment.Version.ToString (3), unknown.Value, "#C3");
524 unknown = (UnknownResponseHeader) f.UnknownResponseHeaders ["Content-Disposition"];
525 Assert.AreEqual ("Content-Disposition", unknown.Name, "#C4");
526 Assert.AreEqual ("inline", unknown.Value, "#C5");
528 ArrayList al = f.UnknownResponseHeaders ["My-Custom-Header"] as ArrayList;
529 Assert.AreEqual (2, al.Count, "#C6");
531 unknown = (UnknownResponseHeader) al [0];
532 Assert.AreEqual ("My-Custom-Header", unknown.Name, "#C7");
533 Assert.AreEqual ("never", unknown.Value, "#C8");
535 unknown = (UnknownResponseHeader) al [1];
536 Assert.AreEqual ("My-Custom-Header", unknown.Name, "#C9");
537 Assert.AreEqual ("always", unknown.Value, "#C10");
540 [Test] // bug #485557
541 [Category ("NotWorking")] // bug #488702
542 public void ClearHeaders ()
544 FakeHttpWorkerRequest2 f;
545 HttpContext c = Cook (2, out f);
547 HttpResponse resp = c.Response;
548 resp.CacheControl = "public";
549 resp.Cache.SetCacheability (HttpCacheability.NoCache);
550 resp.ContentType = "text/xml";
551 resp.AppendHeader ("Content-Disposition", "inline");
552 resp.AppendHeader ("Content-Type", "application/ms-word");
553 resp.AppendHeader ("Content-Length", "40");
554 resp.AppendHeader ("Transfer-Encoding", "compress");
555 resp.AppendHeader ("My-Custom-Header", "never");
556 resp.AppendHeader ("My-Custom-Header", "always");
557 resp.ClearHeaders ();
559 Assert.AreEqual ("private", resp.CacheControl, "#A1");
560 Assert.AreEqual ("text/html", resp.ContentType, "#A2");
561 Assert.AreEqual (0, f.KnownResponseHeaders.Count, "#A3");
562 Assert.AreEqual (0, f.UnknownResponseHeaders.Count, "#A4");
566 KnownResponseHeader known;
568 Assert.AreEqual (3, f.KnownResponseHeaders.Count, "#B1");
570 known = (KnownResponseHeader) f.KnownResponseHeaders ["Transfer-Encoding"];
571 Assert.AreEqual (HttpWorkerRequest.HeaderTransferEncoding, known.Index, "#B2");
572 Assert.AreEqual ("chunked", known.Value, "#B3");
574 known = (KnownResponseHeader) f.KnownResponseHeaders ["Cache-Control"];
575 Assert.AreEqual (HttpWorkerRequest.HeaderCacheControl, known.Index, "#B4");
576 Assert.AreEqual ("private", known.Value, "#B5");
578 known = (KnownResponseHeader) f.KnownResponseHeaders ["Content-Type"];
579 Assert.AreEqual (HttpWorkerRequest.HeaderContentType, known.Index, "#B6");
580 Assert.AreEqual ("text/html", known.Value, "#B7");
583 Assert.AreEqual (1, f.UnknownResponseHeaders.Count, "#C1");
584 UnknownResponseHeader unknown = (UnknownResponseHeader) f.UnknownResponseHeaders ["X-AspNet-Version"];
585 Assert.AreEqual ("X-AspNet-Version", unknown.Name, "#C2");
586 Assert.AreEqual (Environment.Version.ToString (3), unknown.Value, "#C3");
588 Assert.AreEqual (0, f.UnknownResponseHeaders.Count, "#C1");
594 public class HttpResponseOutputStreamTest
596 FakeHttpWorkerRequest2 worker;
598 HttpResponse response;
604 context = Cook (2, out worker);
605 response = context.Response;
606 out_stream = response.OutputStream;
610 public void TearDown ()
612 if (response != null)
617 public void CanRead ()
619 Assert.IsFalse (out_stream.CanRead, "#1");
621 Assert.IsFalse (out_stream.CanRead, "#2");
625 public void CanSeek ()
627 Assert.IsFalse (out_stream.CanSeek, "#1");
629 Assert.IsFalse (out_stream.CanSeek, "#2");
633 public void CanWrite ()
635 Assert.IsTrue (out_stream.CanWrite, "#1");
637 Assert.IsTrue (out_stream.CanWrite, "#2");
643 byte [] buffer = Encoding.UTF8.GetBytes ("mono");
644 out_stream.Write (buffer, 0, buffer.Length);
646 Assert.AreEqual (0, worker.data_len);
650 public void Length ()
653 long len = out_stream.Length;
654 Assert.Fail ("#1:" + len);
655 } catch (NotSupportedException ex) {
656 Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#2");
657 Assert.IsNull (ex.InnerException, "#3");
658 Assert.IsNotNull (ex.Message, "#4");
663 public void Position ()
666 long pos = out_stream.Position;
667 Assert.Fail ("#A1:" + pos);
668 } catch (NotSupportedException ex) {
669 Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#A2");
670 Assert.IsNull (ex.InnerException, "#A3");
671 Assert.IsNotNull (ex.Message, "#A4");
675 out_stream.Position = 0;
677 } catch (NotSupportedException ex) {
678 Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#B2");
679 Assert.IsNull (ex.InnerException, "#B3");
680 Assert.IsNotNull (ex.Message, "#B4");
687 byte [] buffer = new byte [5];
690 out_stream.Read (buffer, 0, buffer.Length);
692 } catch (NotSupportedException ex) {
693 Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#2");
694 Assert.IsNull (ex.InnerException, "#3");
695 Assert.IsNotNull (ex.Message, "#4");
703 out_stream.Seek (5, SeekOrigin.Begin);
705 } catch (NotSupportedException ex) {
706 Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#2");
707 Assert.IsNull (ex.InnerException, "#3");
708 Assert.IsNotNull (ex.Message, "#4");
713 public void SetLength ()
716 out_stream.SetLength (5L);
718 } catch (NotSupportedException ex) {
719 Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#2");
720 Assert.IsNull (ex.InnerException, "#3");
721 Assert.IsNotNull (ex.Message, "#4");
730 buffer = Encoding.UTF8.GetBytes ("mono");
731 out_stream.Write (buffer, 0, buffer.Length);
732 buffer = Encoding.UTF8.GetBytes ("just rocks!!");
733 out_stream.Write (buffer, 5, 6);
734 out_stream.Write (buffer, 0, 4);
735 Assert.IsFalse (worker.OutputProduced, "#1");
737 Assert.IsTrue (worker.OutputProduced, "#2");
739 string output = Encoding.UTF8.GetString (worker.data);
740 Assert.AreEqual ("e\r\nmonorocks!just\r\n", output);
744 public void Write_Buffer_Null ()
747 out_stream.Write ((byte []) null, 0, 0);
750 } catch (ArgumentNullException ex) {
751 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
752 Assert.IsNull (ex.InnerException, "#3");
753 Assert.IsNotNull (ex.Message, "#4");
754 Assert.AreEqual ("buffer", ex.ParamName, "#5");
757 } catch (NullReferenceException) {
763 public void Write_Count_Negative ()
765 byte [] buffer = new byte [] { 0x0a, 0x1f, 0x2d };
769 out_stream.Write (buffer, 1, -1);
771 } catch (ArgumentOutOfRangeException ex) {
772 Assert.AreEqual (typeof (ArgumentOutOfRangeException), ex.GetType (), "#2");
773 Assert.IsNull (ex.InnerException, "#3");
774 Assert.IsNotNull (ex.Message, "#4");
775 Assert.AreEqual ("count", ex.ParamName, "#5");
780 public void Write_Count_Overflow ()
784 buffer = Encoding.UTF8.GetBytes ("Mono");
785 out_stream.Write (buffer, 0, buffer.Length + 5);
786 buffer = Encoding.UTF8.GetBytes ("Just Rocks!!");
787 out_stream.Write (buffer, 5, buffer.Length - 2);
790 string output = Encoding.UTF8.GetString (worker.data);
791 Assert.AreEqual ("b\r\nMonoRocks!!\r\n", output);
795 public void Write_Offset_Negative ()
797 byte [] buffer = new byte [] { 0x0a, 0x1f, 0x2d };
801 out_stream.Write (buffer, -1, 0);
803 } catch (ArgumentOutOfRangeException ex) {
804 Assert.AreEqual (typeof (ArgumentOutOfRangeException), ex.GetType (), "#2");
805 Assert.IsNull (ex.InnerException, "#3");
806 Assert.IsNotNull (ex.Message, "#4");
807 Assert.AreEqual ("offset", ex.ParamName, "#5");
812 public void Write_Offset_Overflow ()
814 byte [] buffer = new byte [] { 0x0a, 0x1f, 0x2d };
816 // offset == buffer length
819 out_stream.Write (buffer, buffer.Length, 0);
821 } catch (ArgumentOutOfRangeException ex) {
822 Assert.AreEqual (typeof (ArgumentOutOfRangeException), ex.GetType (), "#A2");
823 Assert.IsNull (ex.InnerException, "#A3");
824 Assert.IsNotNull (ex.Message, "#A4");
825 Assert.AreEqual ("offset", ex.ParamName, "#A5");
828 out_stream.Write (buffer, buffer.Length, 0);
831 // offset > buffer length
834 out_stream.Write (buffer, buffer.Length + 1, 0);
836 } catch (ArgumentOutOfRangeException ex) {
837 Assert.AreEqual (typeof (ArgumentOutOfRangeException), ex.GetType (), "#B2");
838 Assert.IsNull (ex.InnerException, "#B3");
839 Assert.IsNotNull (ex.Message, "#B4");
840 Assert.AreEqual ("offset", ex.ParamName, "#B5");
843 out_stream.Write (buffer, buffer.Length + 1, 0);
847 Assert.AreEqual (0, worker.data_len);
851 public void Write_Stream_Closed ()
853 byte [] buffer = Encoding.UTF8.GetBytes ("mono");
855 out_stream.Write (buffer, 0, buffer.Length);
858 string output = Encoding.UTF8.GetString (worker.data);
859 Assert.AreEqual ("4\r\nmono\r\n", output);
862 HttpContext Cook (int re, out FakeHttpWorkerRequest2 f)
864 f = new FakeHttpWorkerRequest2 (re);
865 return new HttpContext (f);