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