2008-12-10 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 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 = true;
49                 bool smartNavigation;
50                 bool haveTrace;
51                 bool trace;
52                 bool notBuffer;
53                 TraceMode tracemode = TraceMode.Default;
54                 string responseEncoding;
55                 string contentType;
56                 int codepage = -1;
57                 int lcid = -1;
58                 string culture;
59                 string uiculture;
60                 string errorPage;
61                 bool validateRequest;
62                 string clientTarget;
63
64 #if NET_2_0
65                 bool async;
66                 int asyncTimeout = -1;
67                 string masterPage;
68                 Type masterType;
69                 string masterVirtualPath;
70                 string title;
71                 string theme;
72                 string styleSheetTheme;
73                 bool enable_event_validation;
74                 bool maintainScrollPositionOnPostBack;
75                 int maxPageStateFieldLength = -1;
76                 string pageParserFilter = String.Empty;
77                 Type previousPageType;
78                 string previousPageVirtualPath;
79 #endif
80
81                 public PageParser ()
82                 {
83                         LoadConfigDefaults ();
84                 }
85                 
86                 internal PageParser (string virtualPath, string inputFile, HttpContext context)
87                 {
88                         Context = context;
89                         BaseVirtualDir = UrlUtils.GetDirectory (virtualPath);
90                         InputFile = inputFile;
91                         SetBaseType (null);
92                         AddApplicationAssembly ();
93                         LoadConfigDefaults ();
94 #if NET_2_0
95                         this.VirtualPath = new VirtualPath (virtualPath);
96 #endif
97                 }
98
99 #if NET_2_0
100                 internal PageParser (string virtualPath, TextReader reader, HttpContext context)
101                         : this (virtualPath, null, reader, context)
102                 {
103                 }
104                 
105                 internal PageParser (string virtualPath, string inputFile, TextReader reader, HttpContext context)
106                 {
107                         Context = context;
108                         BaseVirtualDir = UrlUtils.GetDirectory (virtualPath);
109                         Reader = reader;
110                         if (String.IsNullOrEmpty (inputFile)) {
111                                 HttpRequest req = context != null ? context.Request : null;
112                                 if (req != null)
113                                         InputFile = req.MapPath (virtualPath);
114                         } else
115                                 InputFile = inputFile;
116                         SetBaseType (null);
117                         AddApplicationAssembly ();
118                         LoadConfigDefaults ();
119 #if NET_2_0
120                         this.VirtualPath = new VirtualPath (virtualPath);
121 #endif
122                 }
123 #endif
124
125                 internal override void LoadConfigDefaults ()
126                 {
127                         base.LoadConfigDefaults ();
128 #if NET_2_0
129                         PagesSection ps = PagesConfig;
130 #else
131                         PagesConfiguration ps = PagesConfig;
132 #endif                  
133
134                         notBuffer = !ps.Buffer;
135                         enableSessionState = ps.EnableSessionState;
136                         enableViewStateMac = ps.EnableViewStateMac;
137                         smartNavigation = ps.SmartNavigation;
138                         validateRequest = ps.ValidateRequest;
139 #if NET_2_0
140                         masterPage = ps.MasterPageFile;
141                         if (masterPage.Length == 0)
142                                 masterPage = null;
143                         enable_event_validation = ps.EnableEventValidation;
144                         maxPageStateFieldLength = ps.MaxPageStateFieldLength;
145                         pageParserFilter = ps.PageParserFilterType;
146                         theme = ps.Theme;
147                         if (theme.Length == 0)
148                                 theme = null;
149                         styleSheetTheme = ps.StyleSheetTheme;
150                         if (styleSheetTheme.Length == 0)
151                                 styleSheetTheme = null;
152                         maintainScrollPositionOnPostBack = ps.MaintainScrollPositionOnPostBack;
153 #endif
154                 }
155                 
156                 public static IHttpHandler GetCompiledPageInstance (string virtualPath,
157                                                                     string inputFile, 
158                                                                     HttpContext context)
159                 {
160 #if NET_2_0
161                         return BuildManager.CreateInstanceFromVirtualPath (virtualPath, typeof (IHttpHandler)) as IHttpHandler;
162 #else
163                         PageParser pp = new PageParser (virtualPath, inputFile, context);
164                         IHttpHandler h = (IHttpHandler) pp.GetCompiledInstance ();
165                         return h;
166 #endif
167                 }
168                 
169                 internal override void ProcessMainAttributes (Hashtable atts)
170                 {
171                         // note: the 'enableSessionState' configuration property is
172                         // processed in a case-sensitive manner while the page-level
173                         // attribute is processed case-insensitive
174                         string enabless = GetString (atts, "EnableSessionState", null);
175                         if (enabless != null) {
176                                 if (String.Compare (enabless, "readonly", true) == 0)
177                                         enableSessionState = PagesEnableSessionState.ReadOnly;
178                                 else if (String.Compare (enabless, "true", true) == 0)
179                                         enableSessionState = PagesEnableSessionState.True;
180                                 else if (String.Compare (enabless, "false", true) == 0)
181                                         enableSessionState = PagesEnableSessionState.False;
182                                 else
183                                         ThrowParseException ("Invalid value for enableSessionState: " + enabless);
184                         }
185
186                         string cp = GetString (atts, "CodePage", null);
187                         if (cp != null) {
188                                 if (responseEncoding != null)
189                                         ThrowParseException ("CodePage and ResponseEncoding are " +
190                                                 "mutually exclusive.");
191
192                                 int codepage = 0;
193                                 try {
194                                         codepage = (int) UInt32.Parse (cp);
195                                 } catch {
196                                         ThrowParseException ("Invalid value for CodePage: " + cp);
197                                 }
198
199                                 try {
200                                         Encoding.GetEncoding (codepage);
201                                 } catch {
202                                         ThrowParseException ("Unsupported codepage: " + cp);
203                                 }
204                         }
205                         
206                         responseEncoding = GetString (atts, "ResponseEncoding", null);
207                         if (responseEncoding != null) {
208                                 if (codepage != -1)
209                                         ThrowParseException ("CodePage and ResponseEncoding are " +
210                                                              "mutually exclusive.");
211
212                                 try {
213                                         Encoding.GetEncoding (responseEncoding);
214                                 } catch {
215                                         ThrowParseException ("Unsupported encoding: " + responseEncoding);
216                                 }
217                         }
218                         
219                         contentType = GetString (atts, "ContentType", null);
220
221                         string lcidStr = GetString (atts, "LCID", null);
222                         if (lcidStr != null) {
223                                 try {
224                                         lcid = (int) UInt32.Parse (lcidStr);
225                                 } catch {
226                                         ThrowParseException ("Invalid value for LCID: " + lcid);
227                                 }
228
229                                 CultureInfo ci = null;
230                                 try {
231                                         ci = new CultureInfo (lcid);
232                                 } catch {
233                                         ThrowParseException ("Unsupported LCID: " + lcid);
234                                 }
235
236                                 if (ci.IsNeutralCulture) {
237                                         string suggestedCulture = SuggestCulture (ci.Name);
238                                         string fmt = "LCID attribute must be set to a non-neutral Culture.";
239                                         if (suggestedCulture != null) {
240                                                 ThrowParseException (fmt + " Please try one of these: " +
241                                                                      suggestedCulture);
242                                         } else {
243                                                 ThrowParseException (fmt);
244                                         }
245                                 }
246                         }
247
248                         culture = GetString (atts, "Culture", null);
249                         if (culture != null) {
250                                 if (lcidStr != null) 
251                                         ThrowParseException ("Culture and LCID are mutually exclusive.");
252                                 
253                                 CultureInfo ci = null;
254                                 try {
255 #if NET_2_0
256                                         if (!culture.StartsWith ("auto"))
257 #endif
258                                                 ci = new CultureInfo (culture);
259                                 } catch {
260                                         ThrowParseException ("Unsupported Culture: " + culture);
261                                 }
262
263                                 if (ci != null && ci.IsNeutralCulture) {
264                                         string suggestedCulture = SuggestCulture (culture);
265                                         string fmt = "Culture attribute must be set to a non-neutral Culture.";
266                                         if (suggestedCulture != null)
267                                                 ThrowParseException (fmt +
268                                                                 " Please try one of these: " + suggestedCulture);
269                                         else
270                                                 ThrowParseException (fmt);
271                                 }
272                         }
273
274                         uiculture = GetString (atts, "UICulture", null);
275                         if (uiculture != null) {
276                                 CultureInfo ci = null;
277                                 try {
278 #if NET_2_0
279                                         if (!uiculture.StartsWith ("auto"))
280 #endif
281                                                 ci = new CultureInfo (uiculture);
282                                 } catch {
283                                         ThrowParseException ("Unsupported Culture: " + uiculture);
284                                 }
285
286                                 if (ci != null && ci.IsNeutralCulture) {
287                                         string suggestedCulture = SuggestCulture (uiculture);
288                                         string fmt = "UICulture attribute must be set to a non-neutral Culture.";
289                                         if (suggestedCulture != null)
290                                                 ThrowParseException (fmt +
291                                                                 " Please try one of these: " + suggestedCulture);
292                                         else
293                                                 ThrowParseException (fmt);
294                                 }
295                         }
296
297                         string tracestr = GetString (atts, "Trace", null);
298                         if (tracestr != null) {
299                                 haveTrace = true;
300                                 atts ["Trace"] = tracestr;
301                                 trace = GetBool (atts, "Trace", false);
302                         }
303
304                         string tracemodes = GetString (atts, "TraceMode", null);
305                         if (tracemodes != null) {
306                                 bool valid = true;
307                                 try {
308                                         tracemode = (TraceMode) Enum.Parse (typeof (TraceMode), tracemodes, false);
309                                 } catch {
310                                         valid = false;
311                                 }
312
313                                 if (!valid || tracemode == TraceMode.Default)
314                                         ThrowParseException ("The 'tracemode' attribute is case sensitive and must be " +
315                                                         "one of the following values: SortByTime, SortByCategory.");
316                         }
317
318                         errorPage = GetString (atts, "ErrorPage", null);
319                         validateRequest = GetBool (atts, "ValidateRequest", validateRequest);
320                         clientTarget = GetString (atts, "ClientTarget", null);
321                         if (clientTarget != null) {
322                                 clientTarget = clientTarget.Trim ();
323 #if NET_2_0
324                                 ClientTargetSection sec = (ClientTargetSection)WebConfigurationManager.GetSection ("system.web/clientTarget");
325                                 ClientTarget ct = null;
326                                 
327                                 if ((ct = sec.ClientTargets [clientTarget]) == null)
328                                         clientTarget = clientTarget.ToLower (CultureInfo.InvariantCulture);
329                                 
330                                 if (ct == null && (ct = sec.ClientTargets [clientTarget]) == null) {
331                                         ThrowParseException (String.Format (
332                                                         "ClientTarget '{0}' is an invalid alias. See the " +
333                                                         "documentation for <clientTarget> config. section.",
334                                                         clientTarget));
335                                 }
336                                 clientTarget = ct.UserAgent;
337 #else
338                                 NameValueCollection coll;
339                                 coll = (NameValueCollection) Context.GetConfig ("system.web/clientTarget");
340                                 object ct = null;
341                                 
342                                 if (coll != null) {
343                                         ct = coll [clientTarget];
344                                         if (ct == null)
345                                                 ct = coll [clientTarget.ToLower ()];
346                                 }
347                                 
348                                 if (ct == null) {
349                                         ThrowParseException (String.Format (
350                                                         "ClientTarget '{0}' is an invalid alias. See the " +
351                                                         "documentation for <clientTarget> config. section.",
352                                                         clientTarget));
353                                 }
354                                 clientTarget = (string) ct;
355 #endif
356                         }
357
358                         notBuffer = !GetBool (atts, "Buffer", true);
359                         
360 #if NET_2_0
361                         async = GetBool (atts, "Async", false);
362                         string asyncTimeoutVal = GetString (atts, "AsyncTimeout", null);
363                         if (asyncTimeoutVal != null) {
364                                 try {
365                                         asyncTimeout = Int32.Parse (asyncTimeoutVal);
366                                 } catch (Exception) {
367                                         ThrowParseException ("AsyncTimeout must be an integer value");
368                                 }
369                         }
370                         
371                         masterPage = GetString (atts, "MasterPageFile", masterPage);
372                         
373                         if (!String.IsNullOrEmpty (masterPage)) {
374                                 if (!HostingEnvironment.VirtualPathProvider.FileExists (masterPage))
375                                         ThrowParseFileNotFound (masterPage);
376                                 AddDependency (masterPage);
377                         }
378                         
379                         title = GetString(atts, "Title", null);
380
381                         theme = GetString (atts, "Theme", theme);
382                         styleSheetTheme = GetString (atts, "StyleSheetTheme", styleSheetTheme);
383                         enable_event_validation = GetBool (atts, "EnableEventValidation", enable_event_validation);
384                         maintainScrollPositionOnPostBack = GetBool (atts, "MaintainScrollPositionOnPostBack", maintainScrollPositionOnPostBack);
385 #endif
386                         // Ignored by now
387                         GetString (atts, "EnableViewStateMac", null);
388                         GetString (atts, "SmartNavigation", null);
389
390                         base.ProcessMainAttributes (atts);
391                 }
392                 
393 #if NET_2_0
394                 internal override void AddDirective (string directive, Hashtable atts)
395                 {                       
396                         bool isMasterType = String.Compare ("MasterType", directive, StringComparison.OrdinalIgnoreCase) == 0;
397                         bool isPreviousPageType = isMasterType ? false : String.Compare ("PreviousPageType", directive,
398                                                                                          StringComparison.OrdinalIgnoreCase) == 0;
399                         
400                         string typeName = null;
401                         string virtualPath = null;
402                         Type type = null;
403                         
404                         if (isMasterType || isPreviousPageType) {
405                                 typeName = GetString (atts, "TypeName", null);
406                                 virtualPath = GetString (atts, "VirtualPath", null);
407
408                                 if (typeName != null && virtualPath != null)
409                                         ThrowParseException (
410                                                 String.Format ("The '{0}' directive must have exactly one attribute: TypeName or VirtualPath", directive));
411                                 if (typeName != null) {
412                                         type = LoadType (typeName);
413                                         if (type == null)
414                                                 ThrowParseException (String.Format ("Could not load type '{0}'.", typeName));
415                                         if (isMasterType)
416                                                 masterType = type;
417                                         else
418                                                 previousPageType = type;
419                                 } else if (!String.IsNullOrEmpty (virtualPath)) {
420                                         if (!HostingEnvironment.VirtualPathProvider.FileExists (virtualPath))
421                                                 ThrowParseFileNotFound (virtualPath);
422
423                                         AddDependency (virtualPath);
424                                         if (isMasterType)
425                                                 masterVirtualPath = virtualPath;
426                                         else
427                                                 previousPageVirtualPath = virtualPath;
428                                 } else
429                                         ThrowParseException (String.Format ("The {0} directive must have either a TypeName or a VirtualPath attribute.", directive));
430
431                                 if (type != null)
432                                         AddAssembly (type.Assembly, true);
433                         } else
434                                 base.AddDirective (directive, atts);
435                 }
436 #endif
437                 
438                 static string SuggestCulture (string culture)
439                 {
440                         string retval = null;
441                         foreach (CultureInfo ci in CultureInfo.GetCultures (CultureTypes.SpecificCultures)) {
442                                 if (ci.Name.StartsWith (culture))
443                                         retval += ci.Name + " ";
444                         }
445                         return retval;
446                 }
447
448                 public static Type GetCompiledPageType (string virtualPath, string inputFile, HttpContext context)
449                 {
450 #if NET_2_0
451                         return BuildManager.GetCompiledType (virtualPath);
452 #else
453                         PageParser pp = new PageParser (virtualPath, inputFile, context);
454                         return pp.CompileIntoType ();
455 #endif
456                 }
457                 
458                 protected override Type CompileIntoType ()
459                 {
460                         AspGenerator generator = new AspGenerator (this);
461                         return generator.GetCompiledType ();
462                 }
463
464                 internal bool EnableSessionState {
465                         get {
466                                 return enableSessionState == PagesEnableSessionState.True ||
467                                         ReadOnlySessionState;
468                         }
469                 }
470
471                 internal bool EnableViewStateMac {
472                         get { return enableViewStateMac; }
473                 }
474                 
475                 internal bool SmartNavigation {
476                         get { return smartNavigation; }
477                 }
478                 
479                 internal bool ReadOnlySessionState {
480                         get {
481                                 return enableSessionState == PagesEnableSessionState.ReadOnly;
482                         }
483                 }
484
485                 internal bool HaveTrace {
486                         get { return haveTrace; }
487                 }
488
489                 internal bool Trace {
490                         get { return trace; }
491                 }
492
493                 internal TraceMode TraceMode {
494                         get { return tracemode; }
495                 }               
496
497 #if NET_2_0
498                 internal override string DefaultBaseTypeName {
499                         get { return PagesConfig.PageBaseType; }
500                 }
501 #else
502                 internal override string DefaultBaseTypeName {
503                         get { return "System.Web.UI.Page"; }
504                 }
505 #endif
506                 
507                 internal override string DefaultDirectiveName {
508                         get { return "page"; }
509                 }
510
511                 internal string ResponseEncoding {
512                         get { return responseEncoding; }
513                 }
514
515                 internal string ContentType {
516                         get { return contentType; }
517                 }
518
519                 internal int CodePage {
520                         get { return codepage; }
521                 }
522
523                 internal string Culture {
524                         get { return culture; }
525                 }
526
527                 internal string UICulture {
528                         get { return uiculture; }
529                 }
530
531                 internal int LCID {
532                         get { return lcid; }
533                 }
534
535                 internal string ErrorPage {
536                         get { return errorPage; }
537                 }
538
539                 internal bool ValidateRequest {
540                         get { return validateRequest; }
541                 }
542
543                 internal string ClientTarget {
544                         get { return clientTarget; }
545                 }
546
547                 internal bool NotBuffer {
548                         get { return notBuffer; }
549                 }
550
551 #if NET_2_0
552                 internal bool Async {
553                         get { return async; }
554                 }
555
556                 internal int AsyncTimeout {
557                         get { return asyncTimeout; }
558                 }
559                 
560                 internal string Theme {
561                         get { return theme; }
562                 }
563
564                 internal string StyleSheetTheme {
565                         get { return styleSheetTheme; }
566                 }
567
568                 internal string MasterPageFile {
569                         get { return masterPage; }
570                 }
571                 
572                 internal Type MasterType {
573                         get {
574                                 if (masterType == null && !String.IsNullOrEmpty (masterVirtualPath))
575                                         masterType = BuildManager.GetCompiledType (masterVirtualPath);
576                                 
577                                 return masterType;
578                         }
579                 }
580
581                 internal string Title {
582                         get { return title; }
583                 }
584
585                 internal bool EnableEventValidation {
586                         get { return enable_event_validation; }
587                 }
588
589                 internal bool MaintainScrollPositionOnPostBack {
590                         get { return maintainScrollPositionOnPostBack; }
591                 }
592
593                 internal int MaxPageStateFieldLength {
594                         get { return maxPageStateFieldLength; }
595                 }
596
597                 internal string PageParserFilterType {
598                         get { return pageParserFilter; }
599                 }
600
601                 internal Type PreviousPageType {
602                         get {
603                                 if (previousPageType == null && !String.IsNullOrEmpty (previousPageVirtualPath)) {
604                                         string mappedPath = MapPath (previousPageVirtualPath);
605                                         previousPageType = GetCompiledPageType (previousPageVirtualPath, mappedPath, HttpContext.Current);
606                                 }
607                                 
608                                 return previousPageType;
609                         }
610                 }
611 #endif
612         }
613 }
614