e9295b67241cec3a1c7a17c74d15a0a9f10a0403
[mono.git] / mcs / class / System.Web / Test / System.Web / HttpRequestTest.cs
1 //
2 // System.Web.HttpRequestTest.cs - Unit tests for System.Web.HttpRequest
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //      Miguel de Icaza    <miguel@novell.com>
7 //      Gonzalo Paniagua Javier <gonzalo@novell.com>
8 //
9 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 using System;
31 using System.Text;
32 using System.Web;
33 using System.Collections.Specialized;
34 using NUnit.Framework;
35 using System.Diagnostics;
36 using MonoTests.SystemWeb.Framework;
37 using System.IO;
38 using System.Threading;
39 using System.Globalization;
40
41 using MonoTests.Common;
42
43 namespace MonoTests.System.Web {
44
45         [TestFixture]
46         public class HttpRequestTest {
47
48 #if NET_1_1
49                 [Test]
50                 [ExpectedException (typeof (HttpRequestValidationException))]
51                 public void ValidateInput_XSS ()
52                 {
53                         string problem = "http://server.com/attack2.aspx?test=<script>alert('vulnerability')</script>";
54                         string decoded = HttpUtility.UrlDecode (problem);
55                         int n = decoded.IndexOf ('?');
56                         HttpRequest request = new HttpRequest (null, decoded.Substring (0,n), decoded.Substring (n+1));
57                         request.ValidateInput ();
58                         // the next statement throws
59                         Assert.AreEqual ("<script>alert('vulnerability')</script>", request.QueryString ["test"], "QueryString");
60                 }
61
62                 // Notes:
63                 // * this is to avoid a regression that would cause Mono to 
64                 //   fail again on item #2 of the XSS vulnerabilities listed at:
65                 //   http://it-project.ru/andir/docs/aspxvuln/aspxvuln.en.xml
66                 // * The author notes that Microsoft has decided not to fix 
67                 //   this issue (hence the NotDotNet category).
68
69                 [Test]
70                 [Category ("NotDotNet")]
71                 [ExpectedException (typeof (HttpRequestValidationException))]
72                 public void ValidateInput_XSS_Unicode ()
73                 {
74                         string problem = "http://server.com/attack2.aspx?test=%uff1cscript%uff1ealert('vulnerability')%uff1c/script%uff1e";
75                         string decoded = HttpUtility.UrlDecode (problem);
76                         int n = decoded.IndexOf ('?');
77                         HttpRequest request = new HttpRequest (null, decoded.Substring (0,n), decoded.Substring (n+1));
78                         request.ValidateInput ();
79                         // the next statement throws
80                         Assert.AreEqual ("\xff1cscript\xff1ealert('vulnerability')\xff1c/script\xff1e", request.QueryString ["test"], "QueryString");
81                 }
82
83                 // This has affected ASP.NET 1.1 but it seems fixed now
84                 // http://secunia.com/advisories/9716/
85                 // http://weblogs.asp.net/kaevans/archive/2003/11/12/37169.aspx
86                 [Test]
87                 [ExpectedException (typeof (HttpRequestValidationException))]
88                 public void ValidateInput_XSS_Null ()
89                 {
90                         string problem = "http://secunia.com/?test=<%00SCRIPT>alert(document.cookie)</SCRIPT>";
91                         string decoded = HttpUtility.UrlDecode (problem);
92                         int n = decoded.IndexOf ('?');
93                         HttpRequest request = new HttpRequest (null, decoded.Substring (0,n), decoded.Substring (n+1));
94                         request.ValidateInput ();
95                         // the next statement throws
96                         Assert.AreEqual ("<SCRIPT>alert(document.cookie)</SCRIPT>", request.QueryString ["test"], "QueryString");
97                 }
98 #endif
99                 //
100                 // Tests the properties from the simple constructor.
101                 [Test]
102                 public void Test_PropertiesSimpleConstructor ()
103                 {
104                         string url = "http://www.gnome.org/";
105                         string qs = "key=value&key2=value%32second";
106                         
107                         HttpRequest r = new HttpRequest ("file", url, qs);
108
109                         Assert.AreEqual ("/?" + qs, r.RawUrl, "U1");
110                         Assert.AreEqual (url, r.Url.ToString (), "U2");
111
112                         r = new HttpRequest ("file", "http://www.gnome.org", qs);
113                         Assert.AreEqual (url, r.Url.ToString (), "U3");
114
115                         qs = "a&b=1&c=d&e&b=2&d=";
116                         r = new HttpRequest ("file", url, qs);
117                         NameValueCollection nvc = r.QueryString;
118
119                         Assert.AreEqual ("a,e", nvc [null], "U4");
120                         Assert.AreEqual ("1,2", nvc ["b"], "U5");
121                         Assert.AreEqual ("d", nvc ["c"], "U5");
122                         Assert.AreEqual ("", nvc ["d"], "U6");
123                         Assert.AreEqual (4, nvc.Count, "U6");
124
125                         Assert.AreEqual (null, r.ApplicationPath, "U7");
126                 }
127
128                 [Test]
129                 [ExpectedException(typeof(ArgumentNullException))]
130                 public void Test_AccessToVars ()
131                 {
132                         string url = "http://www.gnome.org/";
133                         string qs = "key=value&key2=value%32second";
134                         
135                         HttpRequest r = new HttpRequest ("file", url, qs);
136                         string s = r.PhysicalApplicationPath;
137                 }
138         
139                 [Test]
140                 public void Test_QueryStringDecoding()
141                 {
142                         // Note: The string to encode must exist in default encoding language 
143                         // \r - will exist in all encodings
144                         string url = "http://www.gnome.org/";
145                         string qs = "umlaut=" + HttpUtility.UrlEncode("\r", Encoding.Default);
146
147                         HttpRequest r = new HttpRequest ("file", url, qs);
148                         Assert.AreEqual ("\r", r.QueryString["umlaut"]);
149                 }
150
151                 [Test]
152                 [Category ("NunitWeb")]
153                 public void Test_PhysicalApplicationPath ()
154                 {
155                         WebTest t = new WebTest (new HandlerInvoker (new HandlerDelegate (
156                                 PhysicalApplicationPathDelegate)));
157                         t.Run ();
158                 }
159
160                 static public void PhysicalApplicationPathDelegate ()
161                 {
162                         HttpRequest r = HttpContext.Current.Request;
163                         string pap = r.PhysicalApplicationPath;
164                         Assert.IsTrue (pap.EndsWith (Path.DirectorySeparatorChar.ToString()), "#1");
165                         Assert.AreEqual (Path.GetFullPath (pap), pap, "#2");
166                 }
167
168                 [Test]
169                 [Category ("NunitWeb")]
170                 public void Test_MapPath ()
171                 {
172                         WebTest t = new WebTest (new HandlerInvoker (new HandlerDelegate (
173                                 MapPathDelegate)));
174                         t.Run ();
175                 }
176
177                 static public void MapPathDelegate ()
178                 {
179                         HttpRequest r = HttpContext.Current.Request;
180                         string appBase = r.PhysicalApplicationPath.TrimEnd (Path.DirectorySeparatorChar);
181                         Assert.AreEqual (appBase, r.MapPath ("~"), "test1");
182                         Assert.AreEqual (appBase, r.MapPath (null), "test1a");
183                         Assert.AreEqual (appBase, r.MapPath (""), "test1b");
184                         Assert.AreEqual (appBase, r.MapPath (" "), "test1c");
185                         Assert.AreEqual (appBase + Path.DirectorySeparatorChar, r.MapPath ("~/"), "test1");
186                         Assert.AreEqual (appBase, r.MapPath ("/NunitWeb"), "test1.1");
187                         Assert.AreEqual (Path.Combine (appBase, "Web.config"),
188                                 r.MapPath ("Web.config"), "test2");
189                         Assert.AreEqual (Path.Combine (appBase, "Web.config"),
190                                 r.MapPath ("~/Web.config"), "test3");
191                         Assert.AreEqual (Path.Combine (appBase, "Web.config"),
192                                 r.MapPath ("/NunitWeb/Web.config"), "test4");
193                         Assert.AreEqual (Path.Combine (appBase, "Web.config"),
194                                 r.MapPath ("Web.config", null, false), "test5");
195                         Assert.AreEqual (Path.Combine (appBase, "Web.config"),
196                                 r.MapPath ("Web.config", "", false), "test6");
197                         Assert.AreEqual (Path.Combine (appBase, "Web.config"),
198                                 r.MapPath ("Web.config", "/NunitWeb", false), "test7");
199                         Assert.AreEqual (Path.Combine (appBase, "Web.config"),
200                                 r.MapPath ("/NunitWeb/Web.config", "/NunitWeb", false), "test8");
201                         
202                         Assert.AreEqual (Path.Combine (appBase, "Web.config"),
203                                 r.MapPath ("Web.config", "/NunitWeb/", false), "test8");
204                         Assert.AreEqual (Path.Combine (appBase, "Web.config"),
205                                 r.MapPath ("Web.config", "~", false), "test10");
206                         Assert.AreEqual (Path.Combine (appBase, "DIR" + Path.DirectorySeparatorChar + "Web.config"),
207                                 r.MapPath ("Web.config", "~/DIR", false), "test11");
208
209                         AssertExtensions.Throws<InvalidOperationException> (() => {
210                                 // Throws because the test's virtual dir is /NunitWeb and / is above it
211                                 r.MapPath ("/test.txt");
212                         }, "test12");
213
214                         AssertExtensions.Throws<InvalidOperationException> (() => {
215                                 // Throws because the test's virtual dir is /NunitWeb and /NunitWeb1 does not match it
216                                 r.MapPath ("/NunitWeb1/test.txt");
217                         }, "test13");
218
219                         AssertExtensions.Throws<ArgumentException> (() => {
220                                 r.MapPath ("/test.txt", "/", false);
221                         }, "test14");
222
223                         AssertExtensions.Throws<ArgumentException> (() => {
224                                 r.MapPath ("/test.txt", "/NunitWeb", false);
225                         }, "test15");
226
227                         Assert.AreEqual (Path.Combine (appBase, "test.txt"), r.MapPath ("/NunitWeb/test.txt", "/NunitWeb", true), "test16");
228                 }
229         
230                 [Test]
231                 [Category ("NunitWeb")]
232                 [ExpectedException (typeof (ArgumentException))]
233                 public void Test_MapPath_InvalidBase_1 ()
234                 {
235                         WebTest t = new WebTest (new HandlerInvoker (new HandlerDelegate (
236                                 MapPathDelegate_InvalidBase_1)));
237                         t.Run ();
238                 }
239
240                 static public void MapPathDelegate_InvalidBase_1 ()
241                 {
242                         HttpContext.Current.Request.MapPath ("Web.config", "something", true);
243                 }
244
245                 [Test]
246                 [Category ("NunitWeb")]
247                 [ExpectedException (typeof (ArgumentException))]
248                 public void Test_MapPath_InvalidBase_2 ()
249                 {
250                         WebTest t = new WebTest (new HandlerInvoker (new HandlerDelegate (
251                                 MapPathDelegate_InvalidBase_2)));
252                         t.Run ();
253                 }
254
255                 static public void MapPathDelegate_InvalidBase_2 ()
256                 {
257                         HttpContext.Current.Request.MapPath ("Web.config", "something", false);
258                 }
259         }
260         
261         [TestFixture]
262         public class Test_HttpFakeRequest {
263                 class FakeHttpWorkerRequest : HttpWorkerRequest {
264                         public int return_kind;
265
266                         [Conditional ("REQUEST_TEST_VERY_VERBOSE")]
267                         void WhereAmI ()
268                         {
269                                 Console.WriteLine (Environment.StackTrace);
270                         }
271                         
272
273                         public FakeHttpWorkerRequest (int re)
274                         {
275                                 return_kind = re;
276                         }
277                         
278                         public override string GetFilePath()
279                         {
280                                 WhereAmI ();
281                                 return "/tmp/uri.aspx";
282                         }
283
284                         public override string GetUriPath()
285                         {
286                                 WhereAmI ();
287                                 return "/uri.aspx";
288                         }
289         
290                         public override string GetQueryString()
291                         {
292                                 WhereAmI ();
293
294                                 switch (return_kind) {
295                                 case 20:
296                                         return null;
297                                 case 16:
298                                         return "key1=value1&key2=value2";
299                                 case 25: // HEAD
300                                 case 30: // POST
301                                         return "mapa.x=10&mapa.y=20";
302                                 case 26: // HEAD
303                                 case 31: // POST
304                                         return "mapa.x=10&mapa=20";
305                                 case 27: // GET
306                                         return "mapa.x=10&mapa.y=20";
307                                 case 28: // GET
308                                         return "mapa.x=10";
309                                 case 29: // GET
310                                         return "mapa=10";
311                                 case 32: // GET
312                                         return "mapa.x=pi&mapa.y=20";
313                                 case 50:
314                                         return "PlainString";
315                                 case 51:
316                                         return "Plain&Arg=1";
317                                 case 52:
318                                         return "Empty=";
319                                 default:
320                                         return "GetQueryString";
321                                 }
322                         }
323         
324                         public override string GetRawUrl()
325                         {
326                                 WhereAmI ();
327                                 return "/bb.aspx";
328                         }
329         
330                         public override string GetHttpVerbName()
331                         {
332                                 WhereAmI ();
333                                 if (return_kind == 25 || return_kind == 26)
334                                         return "HEAD";
335                                 if (return_kind == 30 || return_kind == 31)
336                                         return "POST";
337                                 return "GET";
338                         }
339         
340                         public override string GetHttpVersion()
341                         {
342                                 WhereAmI ();
343                                 return "HTTP/1.1";
344                         }
345         
346                         public override byte [] GetPreloadedEntityBody ()
347                         {
348                                 if (return_kind != 30 && return_kind != 31)
349                                         return base.GetPreloadedEntityBody ();
350
351                                 return Encoding.UTF8.GetBytes (GetQueryString ());
352                         }
353
354                         public override bool IsEntireEntityBodyIsPreloaded ()
355                         {
356                                 if (return_kind != 30 && return_kind != 31)
357                                         return base.IsEntireEntityBodyIsPreloaded ();
358
359                                 return true;
360                         }
361
362                         public override int GetRemotePort()
363                         {
364                                 return 1010;
365                         }
366         
367                         public override string GetLocalAddress()
368                         {
369                                 return "localhost";
370                         }
371
372                         public override string GetAppPath ()
373                         {
374                                 return "AppPath";
375                         }
376
377                         public override string GetRemoteName ()
378                         {
379                                 return "RemoteName";
380                         }
381
382                         public override string GetRemoteAddress ()
383                         {
384                                 return "RemoteAddress";
385                         }
386
387                         public override string GetServerName ()
388                         {
389                                 return "localhost";
390                         }
391                         
392                         public override int GetLocalPort()
393                         {
394                                 return 2020;
395                         }
396         
397                         public override void SendStatus(int s, string x)
398                         {
399                         }
400         
401                         public override void SendKnownResponseHeader(int x, string j)
402                         {
403                         }
404         
405                         public override void SendUnknownResponseHeader(string a, string b)
406                         {
407                         }
408                 
409                         public override void SendResponseFromMemory(byte[] arr, int x)
410                         {
411                         }
412         
413                         public override void SendResponseFromFile(string a, long b , long c)
414                         {
415                                 WhereAmI ();
416                         }
417         
418                         public override void SendResponseFromFile (IntPtr a, long b, long c)
419                         {
420                         }
421         
422                         public override void FlushResponse(bool x)
423                         {
424                         }
425         
426                         public override void EndOfRequest() {
427                         }
428
429                         public override string GetKnownRequestHeader (int index)
430                         {
431                                 switch (index){
432                                 case HttpWorkerRequest.HeaderContentType: 
433                                         switch (return_kind){
434                                         case 1: return "text/plain";
435                                         case 2: return "text/plain; charset=latin1";
436                                         case 3: return "text/plain; charset=iso-8859-1";
437                                         case 4: return "text/plain; charset=\"iso-8859-1\"";    
438                                         case 5: return "text/plain; charset=\"iso-8859-1\" ; other";
439                                         case 30:
440                                         case 31:
441                                                 return "application/x-www-form-urlencoded";
442                                         }
443                                         break;
444                                         
445                                 case HttpWorkerRequest.HeaderContentLength:
446                                         switch (return_kind){
447                                         case 0:  return "1024";
448                                         case 1:  return "-1024";
449                                         case 30:
450                                         case 31:
451                                                 return GetQueryString ().Length.ToString ();
452                                         case -1: return "Blah";
453                                         case -2: return "";
454                                         }
455                                                 break;
456
457                                 case HttpWorkerRequest.HeaderCookie:
458                                         switch (return_kind){
459                                         case 10: return "Key=Value";
460                                         case 11: return "Key=<value>";
461                                         case 12: return "Key=>";
462                                         case 13: return "Key=\xff1c";
463                                         case 14: return "Key=\xff1e";
464                                         }
465                                         break;
466                                 case HttpWorkerRequest.HeaderReferer:
467                                         switch (return_kind){
468                                         case 1: return null;
469                                         case 2: return "http://www.mono-project.com/test.aspx";
470                                         case 15: return "http://www.mono-project.com";
471                                         case 33: return "x";
472                                         }
473                                         break;
474                                 case HttpWorkerRequest.HeaderUserAgent:
475                                         switch (return_kind){
476                                         case 15: return "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040913 Firefox/0.10";
477                                         }
478                                         break;
479                                 case HttpWorkerRequest.HeaderAccept:
480                                         switch (return_kind){
481                                         case 21: return "text/xml,application/xml, application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
482                                         }
483                                         break;
484                                 case HttpWorkerRequest.HeaderAcceptLanguage:
485                                         switch (return_kind){
486                                         case 21: return "en-us, en;q=0.5";
487                                         }
488                                         break;
489                                 }
490                                 return "";
491                         }
492
493                         public override string [][] GetUnknownRequestHeaders ()
494                         {
495                                 if (return_kind == 0)
496                                         return new string [0][];
497
498                                 if (return_kind == 3){
499                                         string [][] x = new string [4][];
500                                         x [0] = new string [] { "k1", "v1" };
501                                         x [1] = new string [] { "k2", "v2" };
502                                         x [2] = new string [] { "k3", "v3" };
503                                         x [3] = new string [] { "k4", "v4" };
504
505                                         return x;
506                                 }
507
508                                 if (return_kind == 4){
509                                         //
510                                         // This tests the bad values and the extra row with an error
511                                         //
512                                         string [][] x = new string [3][];
513                                         x [0] = new string [] { "k1", "" };
514                                         x [1] = new string [] { "k2", null };
515                                         x [2] = new string [] { "k3", "   " };
516
517                                         return x;
518                                 }
519
520                                 if (return_kind == 2){
521                                         string [][] x = new string [2][];
522                                         x [0] = new string [] { "k1", "" };
523
524                                         // Returns an empty row.
525                                         return x;
526                                 }
527
528                                 return null;
529                         }
530                 }
531
532                 HttpContext Cook (int re)
533                 {
534                         FakeHttpWorkerRequest f = new FakeHttpWorkerRequest (re);
535                         HttpContext c = new HttpContext (f);
536
537                         return c;
538                 }
539                 
540                 [Test] public void Test_BrokenContentLength ()
541                 {
542                         HttpContext c = Cook (-1);
543                         Assert.AreEqual (0, c.Request.ContentLength, "C1");
544
545                         c = Cook (-2);
546                         Assert.AreEqual (0, c.Request.ContentLength, "C2");
547
548                 }
549
550                 [Test]
551                 [Ignore ("tests undocumented behavior that depends on implementation")] 
552                 [ExpectedException(typeof(NullReferenceException))]
553                 public void Test_EmptyUnknownRow ()
554                 {
555                         HttpContext c = Cook (2);
556                         NameValueCollection x = c.Request.Headers;
557                 }
558                 
559                 [Test] 
560         [Category ("NotWorking")]
561         public void Test_RequestFields ()
562                 {
563                         HttpContext c = Cook (1);
564
565 #if NET_2_0
566                         Assert.IsNull (c.Request.ApplicationPath, "A1");
567 #else
568                         Assert.AreEqual ("AppPath", c.Request.ApplicationPath, "A1");
569 #endif
570                         Assert.AreEqual ("text/plain", c.Request.ContentType, "A2");
571
572                         c = Cook (0);
573                         Assert.AreEqual (1024, c.Request.ContentLength, "A3");
574                         
575                         c = Cook (3);
576                         Assert.AreEqual ("iso-8859-1", c.Request.ContentEncoding.WebName, "A4");
577                         NameValueCollection x = c.Request.Headers;
578                         
579                         Assert.AreEqual ("v1", x ["k1"], "K1");
580                         Assert.AreEqual ("v2", x ["k2"], "K2");
581                         Assert.AreEqual ("v3", x ["k3"], "K3");
582                         Assert.AreEqual ("v4", x ["k4"], "K4");
583                         Assert.AreEqual ("text/plain; charset=iso-8859-1", x ["Content-Type"], "K4");
584                         Assert.AreEqual (5, x.Count, "K5");
585
586                         c = Cook (2);
587                         Assert.AreEqual ("iso-8859-1", c.Request.ContentEncoding.WebName, "A5");
588                         Assert.AreEqual ("text/plain; charset=latin1", c.Request.ContentType, "A5-1");
589
590                         c = Cook (4);
591                         Assert.AreEqual ("iso-8859-1", c.Request.ContentEncoding.WebName, "A6");
592                         x = c.Request.Headers;
593                         Assert.AreEqual ("", x ["k1"], "K6");
594                         Assert.AreEqual (null, x ["k2"], "K7");
595                         Assert.AreEqual ("   ", x ["k3"], "K8");
596                         Assert.AreEqual (4, x.Count, "K9");
597
598                         c = Cook (5);
599                         Assert.AreEqual ("iso-8859-1", c.Request.ContentEncoding.WebName, "A7");
600
601                         Assert.AreEqual ("RemoteName", c.Request.UserHostName, "A8");
602                         Assert.AreEqual ("RemoteAddress", c.Request.UserHostAddress, "A9");
603
604                         // Difference between Url property and RawUrl one: one is resolved, the other is not
605                         Assert.AreEqual ("/bb.aspx", c.Request.RawUrl, "A10");
606                         Assert.AreEqual ("http://localhost:2020/uri.aspx?GetQueryString", c.Request.Url.ToString (), "A11");
607                 }
608                 
609                 [Test] public void Test_Cookies ()
610                 {
611                         HttpContext c;
612
613                         c = Cook (10);
614                         c.Request.ValidateInput ();
615                         Assert.AreEqual ("Value", c.Request.Cookies ["Key"].Value, "cookie1");
616                 }
617
618                 [Test]
619                 [ExpectedException(typeof (HttpRequestValidationException))]
620                 public void Test_DangerousCookie ()
621                 {
622                         HttpContext c;
623
624                         c = Cook (11);
625                         c.Request.ValidateInput ();
626                         object a = c.Request.Cookies;
627                 }
628                 
629                 [Test]
630                 public void Test_DangerousCookie2 ()
631                 {
632                         HttpContext c;
633
634                         c = Cook (12);
635                         c.Request.ValidateInput ();
636                         object a = c.Request.Cookies;
637                 }
638                 
639                 [Test]
640                 public void Test_DangerousCookie3 ()
641                 {
642                         HttpContext c;
643
644                         c = Cook (13);
645                         c.Request.ValidateInput ();
646                         object a = c.Request.Cookies;
647                 }
648                 
649                 [Test]
650                 public void Test_DangerousCookie4 ()
651                 {
652                         HttpContext c;
653
654                         c = Cook (14);
655                         c.Request.ValidateInput ();
656                         object a = c.Request.Cookies;
657                 }
658
659                 [Test]
660                 public void Test_MiscHeaders ()
661                 {
662                         HttpContext c = Cook (15);
663
664                         // The uri ToString contains the trailing slash.
665                         Assert.AreEqual ("http://www.mono-project.com/", c.Request.UrlReferrer.ToString (), "ref1");
666                         
667                         Assert.AreEqual ("Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040913 Firefox/0.10", c.Request.UserAgent, "ref2");
668
669                         // All the AcceptTypes and UserLanguages tests below here pass under MS
670                         c = Cook (20);
671                         string [] at = c.Request.AcceptTypes;
672                         string [] ul = c.Request.UserLanguages;
673                         Assert.IsNull (at, "AT1");
674                         Assert.IsNull (ul, "UL1");
675                         c = Cook (21);
676                         at = c.Request.AcceptTypes;
677                         Assert.IsNotNull (at, "AT2");
678                         string [] expected = { "text/xml", "application/xml", "application/xhtml+xml", "text/html;q=0.9",
679                                                 "text/plain;q=0.8", "image/png", "*/*;q=0.5" };
680
681                         Assert.AreEqual (expected.Length, at.Length, "AT3");
682                         for (int i = expected.Length - 1; i >= 0; i--)
683                                 Assert.AreEqual (expected [i], at [i], "AT" + (3 + i));
684
685                         ul = c.Request.UserLanguages;
686                         Assert.IsNotNull (ul, "UL2");
687                         expected = new string [] { "en-us", "en;q=0.5" };
688
689                         Assert.AreEqual (expected.Length, ul.Length, "UL3");
690                         for (int i = expected.Length - 1; i >= 0; i--)
691                                 Assert.AreEqual (expected [i], ul [i], "UL" + (3 + i));
692
693                 }
694
695                 [Test]
696                 public void Empty_WorkerRequest_QueryString ()
697                 {
698                         HttpContext c = Cook (20);
699
700                         //
701                         // Checks that the following line does not throw an exception if
702                         // the querystring returned by the HttpWorkerRequest is null.
703                         //
704                         NameValueCollection nvc = c.Request.QueryString;
705                 }
706
707                 [Test]
708                 public void Test_QueryString_ToString ()
709                 {
710                         HttpContext c = Cook (50);
711
712                         Assert.AreEqual (c.Request.QueryString.ToString (), "PlainString", "QTS#1");
713
714                         c = Cook (51);
715                         Assert.AreEqual (c.Request.QueryString.ToString (), "Plain&Arg=1", "QTS#2");
716                 }
717
718 #if NET_2_0
719                 [Test]
720                 public void QueryString_NullTest ()
721                 {
722                         HttpRequest req = new HttpRequest ("file.aspx", "http://localhost/file.aspx", null);
723                         
724                         Assert.AreEqual (req.QueryString.ToString (), "", "QSNT#1");
725                 }
726 #endif
727                 
728                 [Test]
729                 public void Leading_qm_in_QueryString ()
730                 {
731                         HttpContext c = Cook (16);
732                         NameValueCollection nvc = c.Request.QueryString;
733                         foreach (string id in nvc.AllKeys) {
734                                 if (id.StartsWith ("?"))
735                                         Assert.Fail (id);
736                         }
737                 }
738
739                 [Test]
740                 public void TestPath ()
741                 {
742                         HttpContext c = Cook (16);
743
744                         // This used to crash, ifolder exposed this
745                         string x = c.Request.Path;
746                 }
747                 
748                 [Test]
749                 public void MapImageCoordinatesHEAD ()
750                 {
751                         HttpContext c = Cook (25);
752                         int [] coords = c.Request.MapImageCoordinates ("mapa");
753                         Assert.IsNotNull (coords, "A1");
754                         Assert.AreEqual (10, coords [0], "X");
755                         Assert.AreEqual (20, coords [1], "Y");
756
757                         c = Cook (26);
758                         coords = c.Request.MapImageCoordinates ("mapa");
759                         Assert.AreEqual (null, coords, "coords");
760                 }
761
762                 [Test]
763                 public void MapImageCoordinatesGET ()
764                 {
765                         HttpContext c = Cook (27);
766                         int [] coords = c.Request.MapImageCoordinates ("mapa");
767                         Assert.AreEqual (10, coords [0], "X");
768                         Assert.AreEqual (20, coords [1], "Y");
769
770                         coords = c.Request.MapImageCoordinates ("m");
771                         Assert.AreEqual (null, coords, "coords1");
772
773                         c = Cook (28);
774                         coords = c.Request.MapImageCoordinates ("mapa");
775                         Assert.AreEqual (null, coords, "coords2");
776                         c = Cook (29);
777                         coords = c.Request.MapImageCoordinates ("mapa");
778                         Assert.AreEqual (null, coords, "coords3");
779                         c = Cook (32);
780                         coords = c.Request.MapImageCoordinates ("mapa");
781                         Assert.AreEqual (null, coords, "coords4");
782                 }
783
784                 [Test]
785                 public void MapImageCoordinatesPOST ()
786                 {
787                         HttpContext c = Cook (30);
788                         int [] coords = c.Request.MapImageCoordinates ("mapa");
789                         Assert.IsNotNull (coords, "A1");
790                         Assert.AreEqual (10, coords [0], "X");
791                         Assert.AreEqual (20, coords [1], "Y");
792
793                         c = Cook (31);
794                         coords = c.Request.MapImageCoordinates ("mapa");
795                         Assert.AreEqual (null, coords, "coords2");
796                 }
797
798                 [Test]
799                 public void TestReferer ()
800                 {
801                         HttpContext c = Cook (1);
802
803                         Assert.AreEqual (null, c.Request.UrlReferrer, "REF1");
804
805                         c = Cook (2);
806                         Assert.AreEqual ("http://www.mono-project.com/test.aspx", c.Request.UrlReferrer.ToString (), "REF1");
807
808                         c = Cook (33);
809                         Assert.AreEqual (null, c.Request.UrlReferrer, "REF1");                  
810                 }
811                 
812
813                 [Test]
814                 public void NegativeContentLength ()
815                 {
816                         HttpContext c = Cook (1);
817                         HttpRequest req = c.Request;
818                         Assert.AreEqual (0, req.ContentLength, "#01");
819                 }
820
821                 [Test]
822                 public void EmptyQueryValueParams ()
823                 {
824                         HttpContext c = Cook (52);
825                         Assert.AreEqual ("", c.Request.Params["Empty"]);
826                 }
827         }
828
829         // This class is defined here to make it easy to create fake
830         // HttpWorkerRequest-derived classes by only overriding the methods
831         // necessary for testing.
832         class BaseFakeHttpWorkerRequest : HttpWorkerRequest
833         {
834                 public override void EndOfRequest()
835                 {
836                 }
837
838                 public override void FlushResponse(bool finalFlush)
839                 {
840                 }
841
842                 public override string GetHttpVerbName()
843                 {
844                         return "GET";
845                 }
846
847                 public override string GetHttpVersion()
848                 {
849                         return "HTTP/1.1";
850                 }
851
852                 public override string GetLocalAddress()
853                 {
854                         return "localhost";
855                 }
856
857                 public override int GetLocalPort()
858                 {
859                         return 8080;
860                 }
861
862                 public override string GetQueryString()
863                 {
864                         return String.Empty;
865                 }
866
867                 public override string GetRawUrl()
868                 {
869                         string rawUrl = GetUriPath();
870                         string queryString = GetQueryString();
871                         if (queryString != null && queryString.Length > 0)
872                         {
873                                 rawUrl += "?" + queryString;
874                         }
875                         return rawUrl;
876                 }
877
878                 public override string GetRemoteAddress()
879                 {
880                         return "remotehost";
881                 }
882
883                 public override int GetRemotePort()
884                 {
885                         return 8080;
886                 }
887
888                 public override string GetUriPath()
889                 {
890                         return "default.aspx";
891                 }
892
893                 public override void SendKnownResponseHeader(int index, string value)
894                 {
895                 }
896
897                 public override void SendResponseFromFile(IntPtr handle, long offset, long length)
898                 {
899                 }
900
901                 public override void SendResponseFromFile(string filename, long offset, long length)
902                 {
903                 }
904
905                 public override void SendResponseFromMemory(byte[] data, int length)
906                 {
907                 }
908
909                 public override void SendStatus(int statusCode, string statusDescription)
910                 {
911                 }
912
913                 public override void SendUnknownResponseHeader(string name, string value)
914                 {
915                 }
916         }
917
918         // This test ensures accessing the Form property does not throw an
919         // exception when the length of data in the request exceeds the length
920         // as reported by the Content-Length header. This bug was discovered
921         // with an AJAX application using XMLHttpRequest to POST back to the
922         // server. The Content-Length header was two bytes less than the length
923         // of the buffer returned from GetPreloadedEntityBody. This was causing
924         // an exception to be thrown by Mono because it was trying to allocate
925         // a buffer that was -2 bytes in length.
926         [TestFixture]
927         public class Test_UrlEncodedBodyWithExtraCRLF
928         {
929                 class FakeHttpWorkerRequest : BaseFakeHttpWorkerRequest
930                 {
931                         // This string is 9 bytes in length. That's 2 more than
932                         // the Content-Length header says it should be.
933                         string data = "foo=bar\r\n";
934
935                         public override string GetKnownRequestHeader(int index)
936                         {
937                                 switch (index)
938                                 {
939                                         case HttpWorkerRequest.HeaderContentLength:
940                                                 return (data.Length - 2).ToString();
941                                         case HttpWorkerRequest.HeaderContentType:
942                                                 return "application/x-www-form-urlencoded";
943                                 }
944                                 return String.Empty;
945                         }
946
947                         public override byte[] GetPreloadedEntityBody()
948                         {
949                                 return Encoding.ASCII.GetBytes(data);
950                         }
951                 }
952
953                 HttpContext context = null;
954
955                 [SetUp]
956                 [Category ("NotDotNet")] // Cannot be runned on .net with no web context
957                 public void SetUp()
958                 {
959                         HttpWorkerRequest workerRequest = new FakeHttpWorkerRequest();
960                         context = new HttpContext(workerRequest);
961                 }
962
963                 [Test]
964                 [Category ("NotDotNet")] // Cannot be runned on .net with no web context
965                 public void ContentLength()
966                 {
967                         Assert.AreEqual(7, context.Request.ContentLength);
968                 }
969
970                 [Test]
971                 [Category ("NotDotNet")] // Cannot be runned on .net with no web context
972                 public void Form_Count()
973                 {
974                         Assert.AreEqual(1, context.Request.Form.Count);
975                 }
976
977                 [Test]
978                 [Category ("NotDotNet")] // Cannot be runned on .net with no web context
979                 public void Form_Item()
980                 {
981                         // I would have expected the extra two characters to be stripped
982                         // but Microsoft's CLR keeps them so Mono should, too.
983                         //Assert.AreEqual("bar\r\n", context.Request.Form["foo"]);
984                         Assert.AreEqual("bar", context.Request.Form["foo"]);
985                 }
986         }
987
988         // This test ensures the HttpRequet object's Form property gets
989         // properly constructed and populated when the Content-Type header
990         // includes a charset parameter and that the charset parameter is
991         // respected.
992         [TestFixture]
993         public class Test_UrlEncodedBodyWithUtf8CharsetParameter
994         {
995                 class FakeHttpWorkerRequest : BaseFakeHttpWorkerRequest
996                 {
997                         // The two funny-looking characters are really a single
998                         // accented "a" character encoded in UTF-8.
999                         string data = "foo=b%C3%A1r";
1000
1001                         public override string GetKnownRequestHeader(int index)
1002                         {
1003                                 switch (index)
1004                                 {
1005                                         case HttpWorkerRequest.HeaderContentLength:
1006                                                 return data.Length.ToString();
1007                                         case HttpWorkerRequest.HeaderContentType:
1008                                                 return "application/x-www-form-urlencoded; charset=utf-8";
1009                                 }
1010                                 return String.Empty;
1011                         }
1012
1013                         public override byte[] GetPreloadedEntityBody()
1014                         {
1015                                 return Encoding.ASCII.GetBytes(data);
1016                         }
1017                 }
1018
1019                 HttpContext context = null;
1020
1021                 [SetUp]
1022                 [Category ("NotDotNet")] // Cannot be runned on .net with no web context
1023                 public void SetUp()
1024                 {
1025                         HttpWorkerRequest workerRequest = new FakeHttpWorkerRequest();
1026                         context = new HttpContext(workerRequest);
1027                 }
1028
1029                 [Test]
1030                 [Category ("NotDotNet")] // Cannot be runned on .net with no web context
1031                 public void Form_Count()
1032                 {
1033                         Assert.AreEqual(1, context.Request.Form.Count);
1034                 }
1035
1036                 [Test]
1037                 [Category ("NotDotNet")] // Cannot be runned on .net with no web context
1038                 public void Form_Item()
1039                 {
1040                         Assert.AreEqual("b\xE1r", context.Request.Form["foo"]);
1041                 }
1042
1043         }
1044 }
1045