2 // System.Web.UI.PageParser
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2002,2003 Ximian, Inc (http://www.ximian.com)
8 // Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
30 using System.Collections;
31 using System.Collections.Specialized;
32 using System.Globalization;
33 using System.Security.Permissions;
35 using System.Web.Compilation;
36 using System.Web.Configuration;
37 using System.Web.Hosting;
38 using System.Web.Util;
41 namespace System.Web.UI
43 // CAS - no InheritanceDemand here as the class is sealed
44 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
45 public sealed class PageParser : TemplateControlParser
48 static Type defaultPageBaseType;
49 static Type defaultApplicationBaseType;
50 static Type defaultPageParserFilterType;
51 static Type defaultUserControlBaseType;
52 static bool enableLongStringsAsResources = true;
54 PagesEnableSessionState enableSessionState = PagesEnableSessionState.True;
55 bool enableViewStateMac;
56 bool enableViewStateMacSet;
61 TraceMode tracemode = TraceMode.Default;
63 MainDirectiveAttribute <int> codepage;
64 MainDirectiveAttribute <string> responseEncoding;
65 MainDirectiveAttribute <int> lcid;
66 MainDirectiveAttribute <string> clientTarget;
67 MainDirectiveAttribute <string> masterPage;
68 MainDirectiveAttribute <string> title;
69 MainDirectiveAttribute <string> theme;
71 MainDirectiveAttribute <string> metaDescription;
72 MainDirectiveAttribute <string> metaKeywords;
79 int asyncTimeout = -1;
81 string masterVirtualPath;
82 string styleSheetTheme;
83 bool enable_event_validation;
84 bool maintainScrollPositionOnPostBack;
85 int maxPageStateFieldLength = -1;
86 Type previousPageType;
87 string previousPageVirtualPath;
89 public static bool EnableLongStringsAsResources {
90 get { return enableLongStringsAsResources; }
92 BuildManager.AssertPreStartMethodsRunning ();
93 enableLongStringsAsResources = value;
97 public static Type DefaultPageBaseType {
98 get { return defaultPageBaseType; }
100 BuildManager.AssertPreStartMethodsRunning ();
101 if (value != null && !typeof (Page).IsAssignableFrom (value))
102 throw new ArgumentException (String.Format ("The value assigned to property '{0}' is invalid.", "DefaultPageBaseType"));
104 defaultPageBaseType = value;
108 public static Type DefaultApplicationBaseType {
109 get { return defaultApplicationBaseType; }
111 BuildManager.AssertPreStartMethodsRunning ();
112 if (value != null && !typeof (HttpApplication).IsAssignableFrom (value))
113 throw new ArgumentException (String.Format ("The value assigned to property '{0}' is invalid.", "DefaultApplicationBaseType"));
114 defaultApplicationBaseType = value;
118 public static Type DefaultPageParserFilterType {
119 get { return defaultPageParserFilterType; }
121 BuildManager.AssertPreStartMethodsRunning ();
122 if (value != null && !typeof (PageParserFilter).IsAssignableFrom (value))
123 throw new ArgumentException (String.Format ("The value assigned to property '{0}' is invalid.", "DefaultPageParserFilterType"));
124 defaultPageParserFilterType = value;
128 public static Type DefaultUserControlBaseType {
129 get { return defaultUserControlBaseType; }
131 if (value != null && !typeof (UserControl).IsAssignableFrom (value))
132 throw new ArgumentException (String.Format ("The value assigned to property '{0}' is invalid.", "DefaultUserControlBaseType"));
133 BuildManager.AssertPreStartMethodsRunning ();
134 defaultUserControlBaseType = value;
140 LoadConfigDefaults ();
143 internal PageParser (string virtualPath, string inputFile, HttpContext context)
145 this.VirtualPath = new VirtualPath (virtualPath);
147 BaseVirtualDir = VirtualPathUtility.GetDirectory (virtualPath, false);
148 InputFile = inputFile;
150 AddApplicationAssembly ();
151 LoadConfigDefaults ();
154 internal PageParser (VirtualPath virtualPath, TextReader reader, HttpContext context)
155 : this (virtualPath, null, reader, context)
159 internal PageParser (VirtualPath virtualPath, string inputFile, TextReader reader, HttpContext context)
161 this.VirtualPath = virtualPath;
163 BaseVirtualDir = virtualPath.DirectoryNoNormalize;
165 if (String.IsNullOrEmpty (inputFile))
166 InputFile = virtualPath.PhysicalPath;
168 InputFile = inputFile;
170 AddApplicationAssembly ();
171 LoadConfigDefaults ();
174 internal override void LoadConfigDefaults ()
176 base.LoadConfigDefaults ();
177 PagesSection ps = PagesConfig;
179 notBuffer = !ps.Buffer;
180 enableSessionState = ps.EnableSessionState;
181 enableViewStateMac = ps.EnableViewStateMac;
182 smartNavigation = ps.SmartNavigation;
183 validateRequest = ps.ValidateRequest;
185 string value = ps.MasterPageFile;
186 if (value.Length > 0)
187 masterPage = new MainDirectiveAttribute <string> (value, true);
189 enable_event_validation = ps.EnableEventValidation;
190 maxPageStateFieldLength = ps.MaxPageStateFieldLength;
192 if (value.Length > 0)
193 theme = new MainDirectiveAttribute <string> (value, true);
195 styleSheetTheme = ps.StyleSheetTheme;
196 if (styleSheetTheme.Length == 0)
197 styleSheetTheme = null;
198 maintainScrollPositionOnPostBack = ps.MaintainScrollPositionOnPostBack;
201 public static IHttpHandler GetCompiledPageInstance (string virtualPath, string inputFile, HttpContext context)
205 if (!String.IsNullOrEmpty (inputFile))
206 isFake = !inputFile.StartsWith (HttpRuntime.AppDomainAppPath);
208 return BuildManager.CreateInstanceFromVirtualPath (new VirtualPath (virtualPath, inputFile, isFake), typeof (IHttpHandler)) as IHttpHandler;
211 internal override void ProcessMainAttributes (IDictionary atts)
213 // note: the 'enableSessionState' configuration property is
214 // processed in a case-sensitive manner while the page-level
215 // attribute is processed case-insensitive
216 string enabless = GetString (atts, "EnableSessionState", null);
217 if (enabless != null) {
218 if (String.Compare (enabless, "readonly", true, Helpers.InvariantCulture) == 0)
219 enableSessionState = PagesEnableSessionState.ReadOnly;
220 else if (String.Compare (enabless, "true", true, Helpers.InvariantCulture) == 0)
221 enableSessionState = PagesEnableSessionState.True;
222 else if (String.Compare (enabless, "false", true, Helpers.InvariantCulture) == 0)
223 enableSessionState = PagesEnableSessionState.False;
225 ThrowParseException ("Invalid value for enableSessionState: " + enabless);
228 string value = GetString (atts, "CodePage", null);
230 if (responseEncoding != null)
231 ThrowParseException ("CodePage and ResponseEncoding are mutually exclusive.");
233 if (!BaseParser.IsExpression (value)) {
237 cpval = (int) UInt32.Parse (value);
239 ThrowParseException ("Invalid value for CodePage: " + value);
243 Encoding.GetEncoding (cpval);
245 ThrowParseException ("Unsupported codepage: " + value);
247 codepage = new MainDirectiveAttribute <int> (cpval, true);
249 codepage = new MainDirectiveAttribute <int> (value);
252 value = GetString (atts, "ResponseEncoding", null);
254 if (codepage != null)
255 ThrowParseException ("CodePage and ResponseEncoding are mutually exclusive.");
257 if (!BaseParser.IsExpression (value)) {
259 Encoding.GetEncoding (value);
261 ThrowParseException ("Unsupported encoding: " + value);
263 responseEncoding = new MainDirectiveAttribute <string> (value, true);
265 responseEncoding = new MainDirectiveAttribute <string> (value);
268 contentType = GetString (atts, "ContentType", null);
270 value = GetString (atts, "LCID", null);
272 if (!BaseParser.IsExpression (value)) {
275 parsedLcid = (int) UInt32.Parse (value);
277 ThrowParseException ("Invalid value for LCID: " + value);
280 CultureInfo ci = null;
282 ci = new CultureInfo (parsedLcid);
284 ThrowParseException ("Unsupported LCID: " + value);
287 if (ci.IsNeutralCulture) {
288 string suggestedCulture = SuggestCulture (ci.Name);
289 string fmt = "LCID attribute must be set to a non-neutral Culture.";
290 if (suggestedCulture != null) {
291 ThrowParseException (fmt + " Please try one of these: " +
294 ThrowParseException (fmt);
297 lcid = new MainDirectiveAttribute <int> (parsedLcid, true);
299 lcid = new MainDirectiveAttribute <int> (value);
302 culture = GetString (atts, "Culture", null);
303 if (culture != null) {
305 ThrowParseException ("Culture and LCID are mutually exclusive.");
307 CultureInfo ci = null;
309 if (!culture.StartsWith ("auto"))
310 ci = new CultureInfo (culture);
312 ThrowParseException ("Unsupported Culture: " + culture);
315 if (ci != null && ci.IsNeutralCulture) {
316 string suggestedCulture = SuggestCulture (culture);
317 string fmt = "Culture attribute must be set to a non-neutral Culture.";
318 if (suggestedCulture != null)
319 ThrowParseException (fmt +
320 " Please try one of these: " + suggestedCulture);
322 ThrowParseException (fmt);
326 uiculture = GetString (atts, "UICulture", null);
327 if (uiculture != null) {
328 CultureInfo ci = null;
330 if (!uiculture.StartsWith ("auto"))
331 ci = new CultureInfo (uiculture);
333 ThrowParseException ("Unsupported Culture: " + uiculture);
336 if (ci != null && ci.IsNeutralCulture) {
337 string suggestedCulture = SuggestCulture (uiculture);
338 string fmt = "UICulture attribute must be set to a non-neutral Culture.";
339 if (suggestedCulture != null)
340 ThrowParseException (fmt +
341 " Please try one of these: " + suggestedCulture);
343 ThrowParseException (fmt);
347 string tracestr = GetString (atts, "Trace", null);
348 if (tracestr != null) {
350 atts ["Trace"] = tracestr;
351 trace = GetBool (atts, "Trace", false);
354 string tracemodes = GetString (atts, "TraceMode", null);
355 if (tracemodes != null) {
358 tracemode = (TraceMode) Enum.Parse (typeof (TraceMode), tracemodes, false);
363 if (!valid || tracemode == TraceMode.Default)
364 ThrowParseException ("The 'tracemode' attribute is case sensitive and must be " +
365 "one of the following values: SortByTime, SortByCategory.");
368 errorPage = GetString (atts, "ErrorPage", null);
369 validateRequest = GetBool (atts, "ValidateRequest", validateRequest);
370 value = GetString (atts, "ClientTarget", null);
372 if (!BaseParser.IsExpression (value)) {
373 value = value.Trim ();
375 ClientTargetSection sec = GetConfigSection <ClientTargetSection> ("system.web/clientTarget");
376 ClientTarget ct = null;
378 if ((ct = sec.ClientTargets [value]) == null)
379 value = value.ToLowerInvariant ();
381 if (ct == null && (ct = sec.ClientTargets [value]) == null) {
382 ThrowParseException (String.Format (
383 "ClientTarget '{0}' is an invalid alias. See the " +
384 "documentation for <clientTarget> config. section.",
387 value = ct.UserAgent;
388 clientTarget = new MainDirectiveAttribute <string> (value, true);
390 clientTarget = new MainDirectiveAttribute <string> (value);
393 notBuffer = !GetBool (atts, "Buffer", true);
394 async = GetBool (atts, "Async", false);
395 string asyncTimeoutVal = GetString (atts, "AsyncTimeout", null);
396 if (asyncTimeoutVal != null) {
398 asyncTimeout = Int32.Parse (asyncTimeoutVal);
399 } catch (Exception) {
400 ThrowParseException ("AsyncTimeout must be an integer value");
404 value = GetString (atts, "MasterPageFile", masterPage != null ? masterPage.Value : null);
405 if (!String.IsNullOrEmpty (value)) {
406 if (!BaseParser.IsExpression (value)) {
407 value = System.Web.VirtualPathUtility.Combine(BaseVirtualDir, value);
408 var vpp = HostingEnvironment.VirtualPathProvider;
409 if (!vpp.FileExists (value))
410 ThrowParseFileNotFound (value);
411 value = vpp.CombineVirtualPaths (VirtualPath.Absolute, VirtualPathUtility.ToAbsolute (value));
412 AddDependency (value, false);
413 masterPage = new MainDirectiveAttribute <string> (value, true);
415 masterPage = new MainDirectiveAttribute <string> (value);
418 value = GetString(atts, "Title", null);
420 if (!BaseParser.IsExpression (value))
421 title = new MainDirectiveAttribute <string> (value, true);
423 title = new MainDirectiveAttribute <string> (value);
426 value = GetString (atts, "Theme", theme != null ? theme.Value : null);
428 if (!BaseParser.IsExpression (value))
429 theme = new MainDirectiveAttribute <string> (value, true);
431 theme = new MainDirectiveAttribute <string> (value);
434 styleSheetTheme = GetString (atts, "StyleSheetTheme", styleSheetTheme);
435 enable_event_validation = GetBool (atts, "EnableEventValidation", enable_event_validation);
436 maintainScrollPositionOnPostBack = GetBool (atts, "MaintainScrollPositionOnPostBack", maintainScrollPositionOnPostBack);
438 if (atts.Contains ("EnableViewStateMac")) {
439 enableViewStateMac = GetBool (atts, "EnableViewStateMac", enableViewStateMac);
440 enableViewStateMacSet = true;
443 value = GetString (atts, "MetaDescription", null);
445 if (!BaseParser.IsExpression (value))
446 metaDescription = new MainDirectiveAttribute <string> (value, true);
448 metaDescription = new MainDirectiveAttribute <string> (value);
451 value = GetString (atts, "MetaKeywords", null);
453 if (!BaseParser.IsExpression (value))
454 metaKeywords = new MainDirectiveAttribute <string> (value, true);
456 metaKeywords = new MainDirectiveAttribute <string> (value);
460 GetString (atts, "SmartNavigation", null);
462 base.ProcessMainAttributes (atts);
465 internal override void AddDirective (string directive, IDictionary atts)
467 bool isMasterType = String.Compare ("MasterType", directive, StringComparison.OrdinalIgnoreCase) == 0;
468 bool isPreviousPageType = isMasterType ? false : String.Compare ("PreviousPageType", directive,
469 StringComparison.OrdinalIgnoreCase) == 0;
471 string typeName = null;
472 string virtualPath = null;
475 if (isMasterType || isPreviousPageType) {
476 PageParserFilter pfilter = PageParserFilter;
478 pfilter.PreprocessDirective (directive.ToLowerInvariant (), atts);
480 typeName = GetString (atts, "TypeName", null);
481 virtualPath = GetString (atts, "VirtualPath", null);
483 if (typeName != null && virtualPath != null)
484 ThrowParseException (
485 String.Format ("The '{0}' directive must have exactly one attribute: TypeName or VirtualPath", directive));
486 if (typeName != null) {
487 type = LoadType (typeName);
489 ThrowParseException (String.Format ("Could not load type '{0}'.", typeName));
493 previousPageType = type;
494 } else if (!String.IsNullOrEmpty (virtualPath)) {
495 if (!HostingEnvironment.VirtualPathProvider.FileExists (virtualPath))
496 ThrowParseFileNotFound (virtualPath);
498 AddDependency (virtualPath, true);
500 masterVirtualPath = virtualPath;
502 previousPageVirtualPath = virtualPath;
504 ThrowParseException (String.Format ("The {0} directive must have either a TypeName or a VirtualPath attribute.", directive));
507 AddAssembly (type.Assembly, true);
509 base.AddDirective (directive, atts);
512 static string SuggestCulture (string culture)
514 string retval = null;
515 foreach (CultureInfo ci in CultureInfo.GetCultures (CultureTypes.SpecificCultures)) {
516 if (ci.Name.StartsWith (culture))
517 retval += ci.Name + " ";
522 internal Type GetCompiledPageType (string virtualPath, string inputFile, HttpContext context)
524 return BuildManager.GetCompiledType (virtualPath);
527 internal override Type CompileIntoType ()
529 AspGenerator generator = new AspGenerator (this);
530 return generator.GetCompiledType ();
533 internal bool EnableSessionState {
535 return enableSessionState == PagesEnableSessionState.True ||
536 ReadOnlySessionState;
540 internal bool EnableViewStateMac {
541 get { return enableViewStateMac; }
544 internal bool EnableViewStateMacSet {
545 get { return enableViewStateMacSet; }
548 internal bool SmartNavigation {
549 get { return smartNavigation; }
552 internal bool ReadOnlySessionState {
554 return enableSessionState == PagesEnableSessionState.ReadOnly;
558 internal bool HaveTrace {
559 get { return haveTrace; }
562 internal bool Trace {
563 get { return trace; }
566 internal TraceMode TraceMode {
567 get { return tracemode; }
570 internal override Type DefaultBaseType {
572 Type ret = DefaultPageBaseType;
574 return base.DefaultBaseType;
580 internal override string DefaultBaseTypeName {
581 get { return PagesConfig.PageBaseType; }
584 internal override string DefaultDirectiveName {
585 get { return "page"; }
588 internal string ContentType {
589 get { return contentType; }
592 internal MainDirectiveAttribute <string> ResponseEncoding {
593 get { return responseEncoding; }
596 internal MainDirectiveAttribute <int> CodePage {
597 get { return codepage; }
600 internal MainDirectiveAttribute <int> LCID {
604 internal MainDirectiveAttribute <string> ClientTarget {
605 get { return clientTarget; }
608 internal MainDirectiveAttribute <string> MasterPageFile {
609 get { return masterPage; }
612 internal MainDirectiveAttribute <string> Title {
613 get { return title; }
616 internal MainDirectiveAttribute <string> Theme {
617 get { return theme; }
620 internal MainDirectiveAttribute <string> MetaDescription {
621 get { return metaDescription; }
624 internal MainDirectiveAttribute <string> MetaKeywords {
625 get { return metaKeywords; }
628 internal string Culture {
629 get { return culture; }
632 internal string UICulture {
633 get { return uiculture; }
636 internal string ErrorPage {
637 get { return errorPage; }
640 internal bool ValidateRequest {
641 get { return validateRequest; }
644 internal bool NotBuffer {
645 get { return notBuffer; }
648 internal bool Async {
649 get { return async; }
652 internal int AsyncTimeout {
653 get { return asyncTimeout; }
656 internal string StyleSheetTheme {
657 get { return styleSheetTheme; }
660 internal Type MasterType {
662 if (masterType == null && !String.IsNullOrEmpty (masterVirtualPath))
663 masterType = BuildManager.GetCompiledType (masterVirtualPath);
669 internal bool EnableEventValidation {
670 get { return enable_event_validation; }
673 internal bool MaintainScrollPositionOnPostBack {
674 get { return maintainScrollPositionOnPostBack; }
677 internal int MaxPageStateFieldLength {
678 get { return maxPageStateFieldLength; }
681 internal Type PreviousPageType {
683 if (previousPageType == null && !String.IsNullOrEmpty (previousPageVirtualPath)) {
684 string mappedPath = MapPath (previousPageVirtualPath);
685 previousPageType = GetCompiledPageType (previousPageVirtualPath, mappedPath, HttpContext.Current);
688 return previousPageType;