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