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