2010-05-19 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.UI / PageParser.cs
1 //      
2 // System.Web.UI.PageParser
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (C) 2002,2003 Ximian, Inc (http://www.ximian.com)
8 // Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System.Collections;
31 using System.Collections.Specialized;
32 using System.Globalization;
33 using System.Security.Permissions;
34 using System.Text;
35 using System.Web.Compilation;
36 using System.Web.Configuration;
37 using System.Web.Hosting;
38 using System.Web.Util;
39 using System.IO;
40
41 namespace System.Web.UI
42 {
43         // CAS - no InheritanceDemand here as the class is sealed
44         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
45         public sealed class PageParser : TemplateControlParser
46         {
47                 PagesEnableSessionState enableSessionState = PagesEnableSessionState.True;
48                 bool enableViewStateMac;
49                 bool enableViewStateMacSet;
50                 bool smartNavigation;
51                 bool haveTrace;
52                 bool trace;
53                 bool notBuffer;
54                 TraceMode tracemode = TraceMode.Default;
55                 string contentType;
56                 MainDirectiveAttribute <int> codepage;
57                 MainDirectiveAttribute <string> responseEncoding;
58                 MainDirectiveAttribute <int> lcid;
59                 MainDirectiveAttribute <string> clientTarget;
60                 MainDirectiveAttribute <string> masterPage;
61                 MainDirectiveAttribute <string> title;
62                 MainDirectiveAttribute <string> theme;
63                 string culture;
64                 string uiculture;
65                 string errorPage;
66                 bool validateRequest;
67                 bool async;
68                 int asyncTimeout = -1;
69                 Type masterType;
70                 string masterVirtualPath;
71                 string styleSheetTheme;
72                 bool enable_event_validation;
73                 bool maintainScrollPositionOnPostBack;
74                 int maxPageStateFieldLength = -1;
75                 Type previousPageType;
76                 string previousPageVirtualPath;
77
78                 public PageParser ()
79                 {
80                         LoadConfigDefaults ();
81                 }
82                 
83                 internal PageParser (string virtualPath, string inputFile, HttpContext context)
84                 {
85                         this.VirtualPath = new VirtualPath (virtualPath);
86                         Context = context;
87                         BaseVirtualDir = VirtualPathUtility.GetDirectory (virtualPath, false);
88                         InputFile = inputFile;
89                         SetBaseType (null);
90                         AddApplicationAssembly ();
91                         LoadConfigDefaults ();
92                 }
93
94                 internal PageParser (VirtualPath virtualPath, TextReader reader, HttpContext context)
95                         : this (virtualPath, null, reader, context)
96                 {
97                 }
98                 
99                 internal PageParser (VirtualPath virtualPath, string inputFile, TextReader reader, HttpContext context)
100                 {
101                         this.VirtualPath = virtualPath;
102                         Context = context;
103                         BaseVirtualDir = virtualPath.DirectoryNoNormalize;
104                         Reader = reader;
105                         if (String.IsNullOrEmpty (inputFile))
106                                 InputFile = virtualPath.PhysicalPath;
107                         else
108                                 InputFile = inputFile;
109                         SetBaseType (null);
110                         AddApplicationAssembly ();
111                         LoadConfigDefaults ();
112                 }
113
114                 internal override void LoadConfigDefaults ()
115                 {
116                         base.LoadConfigDefaults ();
117                         PagesSection ps = PagesConfig;
118
119                         notBuffer = !ps.Buffer;
120                         enableSessionState = ps.EnableSessionState;
121                         enableViewStateMac = ps.EnableViewStateMac;
122                         smartNavigation = ps.SmartNavigation;
123                         validateRequest = ps.ValidateRequest;
124
125                         string value = ps.MasterPageFile;
126                         if (value.Length > 0)
127                                 masterPage = new MainDirectiveAttribute <string> (value, true);
128                         
129                         enable_event_validation = ps.EnableEventValidation;
130                         maxPageStateFieldLength = ps.MaxPageStateFieldLength;
131                         value = ps.Theme;
132                         if (value.Length > 0)
133                                 theme = new MainDirectiveAttribute <string> (value, true);
134                         
135                         styleSheetTheme = ps.StyleSheetTheme;
136                         if (styleSheetTheme.Length == 0)
137                                 styleSheetTheme = null;
138                         maintainScrollPositionOnPostBack = ps.MaintainScrollPositionOnPostBack;
139                 }
140                 
141                 public static IHttpHandler GetCompiledPageInstance (string virtualPath, string inputFile, HttpContext context)
142                 {
143                         bool isFake = false;
144
145                         if (!String.IsNullOrEmpty (inputFile))
146                                 isFake = !inputFile.StartsWith (HttpRuntime.AppDomainAppPath);
147                         
148                         return BuildManager.CreateInstanceFromVirtualPath (new VirtualPath (virtualPath, inputFile, isFake), typeof (IHttpHandler)) as IHttpHandler;
149                 }
150
151                 internal override void ProcessMainAttributes (IDictionary atts)
152                 {
153                         // note: the 'enableSessionState' configuration property is
154                         // processed in a case-sensitive manner while the page-level
155                         // attribute is processed case-insensitive
156                         string enabless = GetString (atts, "EnableSessionState", null);
157                         if (enabless != null) {
158                                 if (String.Compare (enabless, "readonly", true, Helpers.InvariantCulture) == 0)
159                                         enableSessionState = PagesEnableSessionState.ReadOnly;
160                                 else if (String.Compare (enabless, "true", true, Helpers.InvariantCulture) == 0)
161                                         enableSessionState = PagesEnableSessionState.True;
162                                 else if (String.Compare (enabless, "false", true, Helpers.InvariantCulture) == 0)
163                                         enableSessionState = PagesEnableSessionState.False;
164                                 else
165                                         ThrowParseException ("Invalid value for enableSessionState: " + enabless);
166                         }
167
168                         string value = GetString (atts, "CodePage", null);
169                         if (value != null) {
170                                 if (responseEncoding != null)
171                                         ThrowParseException ("CodePage and ResponseEncoding are mutually exclusive.");
172                                 
173                                 if (!BaseParser.IsExpression (value)) {
174                                         int cpval = -1;
175
176                                         try {
177                                                 cpval = (int) UInt32.Parse (value);
178                                         } catch {
179                                                 ThrowParseException ("Invalid value for CodePage: " + value);
180                                         }
181
182                                         try {
183                                                 Encoding.GetEncoding (cpval);
184                                         } catch {
185                                                 ThrowParseException ("Unsupported codepage: " + value);
186                                         }
187                                         codepage = new MainDirectiveAttribute <int> (cpval, true);
188                                 } else
189                                         codepage = new MainDirectiveAttribute <int> (value);
190                         }
191                         
192                         value = GetString (atts, "ResponseEncoding", null);
193                         if (value != null) {
194                                 if (codepage != null)
195                                         ThrowParseException ("CodePage and ResponseEncoding are mutually exclusive.");
196
197                                 if (!BaseParser.IsExpression (value)) {
198                                         try {
199                                                 Encoding.GetEncoding (value);
200                                         } catch {
201                                                 ThrowParseException ("Unsupported encoding: " + value);
202                                         }
203                                         responseEncoding = new MainDirectiveAttribute <string> (value, true);
204                                 } else
205                                         responseEncoding = new MainDirectiveAttribute <string> (value);
206                         }
207                         
208                         contentType = GetString (atts, "ContentType", null);
209
210                         value = GetString (atts, "LCID", null);
211                         if (value != null) {
212                                 if (!BaseParser.IsExpression (value)) {
213                                         int parsedLcid = -1;
214                                         try {
215                                                 parsedLcid = (int) UInt32.Parse (value);
216                                         } catch {
217                                                 ThrowParseException ("Invalid value for LCID: " + value);
218                                         }
219
220                                         CultureInfo ci = null;
221                                         try {
222                                                 ci = new CultureInfo (parsedLcid);
223                                         } catch {
224                                                 ThrowParseException ("Unsupported LCID: " + value);
225                                         }
226
227                                         if (ci.IsNeutralCulture) {
228                                                 string suggestedCulture = SuggestCulture (ci.Name);
229                                                 string fmt = "LCID attribute must be set to a non-neutral Culture.";
230                                                 if (suggestedCulture != null) {
231                                                         ThrowParseException (fmt + " Please try one of these: " +
232                                                                              suggestedCulture);
233                                                 } else {
234                                                         ThrowParseException (fmt);
235                                                 }
236                                         }
237                                         lcid = new MainDirectiveAttribute <int> (parsedLcid, true);
238                                 } else
239                                         lcid = new MainDirectiveAttribute <int> (value);
240                         }
241
242                         culture = GetString (atts, "Culture", null);
243                         if (culture != null) {
244                                 if (lcid != null) 
245                                         ThrowParseException ("Culture and LCID are mutually exclusive.");
246                                 
247                                 CultureInfo ci = null;
248                                 try {
249                                         if (!culture.StartsWith ("auto"))
250                                                 ci = new CultureInfo (culture);
251                                 } catch {
252                                         ThrowParseException ("Unsupported Culture: " + culture);
253                                 }
254
255                                 if (ci != null && ci.IsNeutralCulture) {
256                                         string suggestedCulture = SuggestCulture (culture);
257                                         string fmt = "Culture attribute must be set to a non-neutral Culture.";
258                                         if (suggestedCulture != null)
259                                                 ThrowParseException (fmt +
260                                                                 " Please try one of these: " + suggestedCulture);
261                                         else
262                                                 ThrowParseException (fmt);
263                                 }
264                         }
265
266                         uiculture = GetString (atts, "UICulture", null);
267                         if (uiculture != null) {
268                                 CultureInfo ci = null;
269                                 try {
270                                         if (!uiculture.StartsWith ("auto"))
271                                                 ci = new CultureInfo (uiculture);
272                                 } catch {
273                                         ThrowParseException ("Unsupported Culture: " + uiculture);
274                                 }
275
276                                 if (ci != null && ci.IsNeutralCulture) {
277                                         string suggestedCulture = SuggestCulture (uiculture);
278                                         string fmt = "UICulture attribute must be set to a non-neutral Culture.";
279                                         if (suggestedCulture != null)
280                                                 ThrowParseException (fmt +
281                                                                 " Please try one of these: " + suggestedCulture);
282                                         else
283                                                 ThrowParseException (fmt);
284                                 }
285                         }
286
287                         string tracestr = GetString (atts, "Trace", null);
288                         if (tracestr != null) {
289                                 haveTrace = true;
290                                 atts ["Trace"] = tracestr;
291                                 trace = GetBool (atts, "Trace", false);
292                         }
293
294                         string tracemodes = GetString (atts, "TraceMode", null);
295                         if (tracemodes != null) {
296                                 bool valid = true;
297                                 try {
298                                         tracemode = (TraceMode) Enum.Parse (typeof (TraceMode), tracemodes, false);
299                                 } catch {
300                                         valid = false;
301                                 }
302
303                                 if (!valid || tracemode == TraceMode.Default)
304                                         ThrowParseException ("The 'tracemode' attribute is case sensitive and must be " +
305                                                         "one of the following values: SortByTime, SortByCategory.");
306                         }
307
308                         errorPage = GetString (atts, "ErrorPage", null);
309                         validateRequest = GetBool (atts, "ValidateRequest", validateRequest);
310                         value = GetString (atts, "ClientTarget", null);
311                         if (value != null) {                            
312                                 if (!BaseParser.IsExpression (value)) {
313                                         value = value.Trim ();
314                                         
315                                         ClientTargetSection sec = GetConfigSection <ClientTargetSection> ("system.web/clientTarget");
316                                         ClientTarget ct = null;
317                                 
318                                         if ((ct = sec.ClientTargets [value]) == null)
319                                                 value = value.ToLowerInvariant ();
320                                 
321                                         if (ct == null && (ct = sec.ClientTargets [value]) == null) {
322                                                 ThrowParseException (String.Format (
323                                                                              "ClientTarget '{0}' is an invalid alias. See the " +
324                                                                              "documentation for <clientTarget> config. section.",
325                                                                              clientTarget));
326                                         }
327                                         value = ct.UserAgent;
328                                         clientTarget = new MainDirectiveAttribute <string> (value, true);
329                                 } else
330                                         clientTarget = new MainDirectiveAttribute <string> (value);
331                         }
332
333                         notBuffer = !GetBool (atts, "Buffer", true);
334                         async = GetBool (atts, "Async", false);
335                         string asyncTimeoutVal = GetString (atts, "AsyncTimeout", null);
336                         if (asyncTimeoutVal != null) {
337                                 try {
338                                         asyncTimeout = Int32.Parse (asyncTimeoutVal);
339                                 } catch (Exception) {
340                                         ThrowParseException ("AsyncTimeout must be an integer value");
341                                 }
342                         }
343                         
344                         value = GetString (atts, "MasterPageFile", masterPage != null ? masterPage.Value : null);
345                         if (!String.IsNullOrEmpty (value)) {
346                                 if (!BaseParser.IsExpression (value)) {
347                                         if (!HostingEnvironment.VirtualPathProvider.FileExists (value))
348                                                 ThrowParseFileNotFound (value);
349                                         AddDependency (value);
350                                         masterPage = new MainDirectiveAttribute <string> (value, true);
351                                 } else
352                                         masterPage = new MainDirectiveAttribute <string> (value);
353                         }
354                         
355                         value = GetString(atts, "Title", null);
356                         if (value != null) {
357                                 if (!BaseParser.IsExpression (value))
358                                         title = new MainDirectiveAttribute <string> (value, true);
359                                 else
360                                         title = new MainDirectiveAttribute <string> (value);
361                         }
362                         
363                         value = GetString (atts, "Theme", theme != null ? theme.Value : null);
364                         if (value != null) {
365                                 if (!BaseParser.IsExpression (value))
366                                         theme = new MainDirectiveAttribute <string> (value, true);
367                                 else
368                                         theme = new MainDirectiveAttribute <string> (value);
369                         }
370                         
371                         styleSheetTheme = GetString (atts, "StyleSheetTheme", styleSheetTheme);
372                         enable_event_validation = GetBool (atts, "EnableEventValidation", enable_event_validation);
373                         maintainScrollPositionOnPostBack = GetBool (atts, "MaintainScrollPositionOnPostBack", maintainScrollPositionOnPostBack);
374
375                         if (atts.Contains ("EnableViewState")) {
376                                 enableViewStateMac = GetBool (atts, "EnableViewStateMac", enableViewStateMac);
377                                 enableViewStateMacSet = true;
378                         }
379                         
380                         // Ignored by now
381                         GetString (atts, "SmartNavigation", null);
382
383                         base.ProcessMainAttributes (atts);
384                 }
385                 
386                 internal override void AddDirective (string directive, IDictionary atts)
387                 {
388                         bool isMasterType = String.Compare ("MasterType", directive, StringComparison.OrdinalIgnoreCase) == 0;
389                         bool isPreviousPageType = isMasterType ? false : String.Compare ("PreviousPageType", directive,
390                                                                                          StringComparison.OrdinalIgnoreCase) == 0;
391
392                         string typeName = null;
393                         string virtualPath = null;
394                         Type type = null;
395                         
396                         if (isMasterType || isPreviousPageType) {
397                                 PageParserFilter pfilter = PageParserFilter;
398                                 if (pfilter != null)
399                                         pfilter.PreprocessDirective (directive.ToLowerInvariant (), atts);
400                                 
401                                 typeName = GetString (atts, "TypeName", null);
402                                 virtualPath = GetString (atts, "VirtualPath", null);
403
404                                 if (typeName != null && virtualPath != null)
405                                         ThrowParseException (
406                                                 String.Format ("The '{0}' directive must have exactly one attribute: TypeName or VirtualPath", directive));
407                                 if (typeName != null) {
408                                         type = LoadType (typeName);
409                                         if (type == null)
410                                                 ThrowParseException (String.Format ("Could not load type '{0}'.", typeName));
411                                         if (isMasterType)
412                                                 masterType = type;
413                                         else
414                                                 previousPageType = type;
415                                 } else if (!String.IsNullOrEmpty (virtualPath)) {
416                                         if (!HostingEnvironment.VirtualPathProvider.FileExists (virtualPath))
417                                                 ThrowParseFileNotFound (virtualPath);
418
419                                         AddDependency (virtualPath);
420                                         if (isMasterType)
421                                                 masterVirtualPath = virtualPath;
422                                         else
423                                                 previousPageVirtualPath = virtualPath;
424                                 } else
425                                         ThrowParseException (String.Format ("The {0} directive must have either a TypeName or a VirtualPath attribute.", directive));
426
427                                 if (type != null)
428                                         AddAssembly (type.Assembly, true);
429                         } else
430                                 base.AddDirective (directive, atts);
431                 }
432                 
433                 static string SuggestCulture (string culture)
434                 {
435                         string retval = null;
436                         foreach (CultureInfo ci in CultureInfo.GetCultures (CultureTypes.SpecificCultures)) {
437                                 if (ci.Name.StartsWith (culture))
438                                         retval += ci.Name + " ";
439                         }
440                         return retval;
441                 }
442
443                 public static Type GetCompiledPageType (string virtualPath, string inputFile, HttpContext context)
444                 {
445                         return BuildManager.GetCompiledType (virtualPath);
446                 }
447                 
448                 protected override Type CompileIntoType ()
449                 {
450                         AspGenerator generator = new AspGenerator (this);
451                         return generator.GetCompiledType ();
452                 }
453
454                 internal bool EnableSessionState {
455                         get {
456                                 return enableSessionState == PagesEnableSessionState.True ||
457                                         ReadOnlySessionState;
458                         }
459                 }
460
461                 internal bool EnableViewStateMac {
462                         get { return enableViewStateMac; }
463                 }
464
465                 internal bool EnableViewStateMacSet {
466                         get { return enableViewStateMacSet; }
467                 }
468                 
469                 internal bool SmartNavigation {
470                         get { return smartNavigation; }
471                 }
472                 
473                 internal bool ReadOnlySessionState {
474                         get {
475                                 return enableSessionState == PagesEnableSessionState.ReadOnly;
476                         }
477                 }
478
479                 internal bool HaveTrace {
480                         get { return haveTrace; }
481                 }
482
483                 internal bool Trace {
484                         get { return trace; }
485                 }
486
487                 internal TraceMode TraceMode {
488                         get { return tracemode; }
489                 }               
490
491                 internal override string DefaultBaseTypeName {
492                         get { return PagesConfig.PageBaseType; }
493                 }
494                 
495                 internal override string DefaultDirectiveName {
496                         get { return "page"; }
497                 }
498
499                 internal string ContentType {
500                         get { return contentType; }
501                 }
502
503                 internal MainDirectiveAttribute <string> ResponseEncoding {
504                         get { return responseEncoding; }
505                 }
506                 
507                 internal MainDirectiveAttribute <int> CodePage {
508                         get { return codepage; }
509                 }
510
511                 internal MainDirectiveAttribute <int> LCID {
512                         get { return lcid; }
513                 }
514
515                 internal MainDirectiveAttribute <string> ClientTarget {
516                         get { return clientTarget; }
517                 }
518
519                 internal MainDirectiveAttribute <string> MasterPageFile {
520                         get { return masterPage; }
521                 }
522
523                 internal MainDirectiveAttribute <string> Title {
524                         get { return title; }
525                 }
526
527                 internal MainDirectiveAttribute <string> Theme {
528                         get { return theme; }
529                 }
530
531                 internal string Culture {
532                         get { return culture; }
533                 }
534
535                 internal string UICulture {
536                         get { return uiculture; }
537                 }
538
539                 internal string ErrorPage {
540                         get { return errorPage; }
541                 }
542
543                 internal bool ValidateRequest {
544                         get { return validateRequest; }
545                 }
546
547                 internal bool NotBuffer {
548                         get { return notBuffer; }
549                 }
550
551                 internal bool Async {
552                         get { return async; }
553                 }
554
555                 internal int AsyncTimeout {
556                         get { return asyncTimeout; }
557                 }
558
559                 internal string StyleSheetTheme {
560                         get { return styleSheetTheme; }
561                 }
562                 
563                 internal Type MasterType {
564                         get {
565                                 if (masterType == null && !String.IsNullOrEmpty (masterVirtualPath))
566                                         masterType = BuildManager.GetCompiledType (masterVirtualPath);
567                                 
568                                 return masterType;
569                         }
570                 }
571
572                 internal bool EnableEventValidation {
573                         get { return enable_event_validation; }
574                 }
575
576                 internal bool MaintainScrollPositionOnPostBack {
577                         get { return maintainScrollPositionOnPostBack; }
578                 }
579
580                 internal int MaxPageStateFieldLength {
581                         get { return maxPageStateFieldLength; }
582                 }
583
584                 internal Type PreviousPageType {
585                         get {
586                                 if (previousPageType == null && !String.IsNullOrEmpty (previousPageVirtualPath)) {
587                                         string mappedPath = MapPath (previousPageVirtualPath);
588                                         previousPageType = GetCompiledPageType (previousPageVirtualPath, mappedPath, HttpContext.Current);
589                                 }
590                                 
591                                 return previousPageType;
592                         }
593                 }
594         }
595 }
596