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 if (!HostingEnvironment
.VirtualPathProvider
.FileExists (value))
409 ThrowParseFileNotFound (value);
410 AddDependency (value);
411 masterPage
= new MainDirectiveAttribute
<string> (value, true);
413 masterPage
= new MainDirectiveAttribute
<string> (value);
416 value = GetString(atts
, "Title", null);
418 if (!BaseParser
.IsExpression (value))
419 title
= new MainDirectiveAttribute
<string> (value, true);
421 title
= new MainDirectiveAttribute
<string> (value);
424 value = GetString (atts
, "Theme", theme
!= null ? theme
.Value
: null);
426 if (!BaseParser
.IsExpression (value))
427 theme
= new MainDirectiveAttribute
<string> (value, true);
429 theme
= new MainDirectiveAttribute
<string> (value);
432 styleSheetTheme
= GetString (atts
, "StyleSheetTheme", styleSheetTheme
);
433 enable_event_validation
= GetBool (atts
, "EnableEventValidation", enable_event_validation
);
434 maintainScrollPositionOnPostBack
= GetBool (atts
, "MaintainScrollPositionOnPostBack", maintainScrollPositionOnPostBack
);
436 if (atts
.Contains ("EnableViewStateMac")) {
437 enableViewStateMac
= GetBool (atts
, "EnableViewStateMac", enableViewStateMac
);
438 enableViewStateMacSet
= true;
441 value = GetString (atts
, "MetaDescription", null);
443 if (!BaseParser
.IsExpression (value))
444 metaDescription
= new MainDirectiveAttribute
<string> (value, true);
446 metaDescription
= new MainDirectiveAttribute
<string> (value);
449 value = GetString (atts
, "MetaKeywords", null);
451 if (!BaseParser
.IsExpression (value))
452 metaKeywords
= new MainDirectiveAttribute
<string> (value, true);
454 metaKeywords
= new MainDirectiveAttribute
<string> (value);
458 GetString (atts
, "SmartNavigation", null);
460 base.ProcessMainAttributes (atts
);
463 internal override void AddDirective (string directive
, IDictionary atts
)
465 bool isMasterType
= String
.Compare ("MasterType", directive
, StringComparison
.OrdinalIgnoreCase
) == 0;
466 bool isPreviousPageType
= isMasterType
? false : String
.Compare ("PreviousPageType", directive
,
467 StringComparison
.OrdinalIgnoreCase
) == 0;
469 string typeName
= null;
470 string virtualPath
= null;
473 if (isMasterType
|| isPreviousPageType
) {
474 PageParserFilter pfilter
= PageParserFilter
;
476 pfilter
.PreprocessDirective (directive
.ToLowerInvariant (), atts
);
478 typeName
= GetString (atts
, "TypeName", null);
479 virtualPath
= GetString (atts
, "VirtualPath", null);
481 if (typeName
!= null && virtualPath
!= null)
482 ThrowParseException (
483 String
.Format ("The '{0}' directive must have exactly one attribute: TypeName or VirtualPath", directive
));
484 if (typeName
!= null) {
485 type
= LoadType (typeName
);
487 ThrowParseException (String
.Format ("Could not load type '{0}'.", typeName
));
491 previousPageType
= type
;
492 } else if (!String
.IsNullOrEmpty (virtualPath
)) {
493 if (!HostingEnvironment
.VirtualPathProvider
.FileExists (virtualPath
))
494 ThrowParseFileNotFound (virtualPath
);
496 AddDependency (virtualPath
);
498 masterVirtualPath
= virtualPath
;
500 previousPageVirtualPath
= virtualPath
;
502 ThrowParseException (String
.Format ("The {0} directive must have either a TypeName or a VirtualPath attribute.", directive
));
505 AddAssembly (type
.Assembly
, true);
507 base.AddDirective (directive
, atts
);
510 static string SuggestCulture (string culture
)
512 string retval
= null;
513 foreach (CultureInfo ci
in CultureInfo
.GetCultures (CultureTypes
.SpecificCultures
)) {
514 if (ci
.Name
.StartsWith (culture
))
515 retval
+= ci
.Name
+ " ";
520 internal Type
GetCompiledPageType (string virtualPath
, string inputFile
, HttpContext context
)
522 return BuildManager
.GetCompiledType (virtualPath
);
525 internal override Type
CompileIntoType ()
527 AspGenerator generator
= new AspGenerator (this);
528 return generator
.GetCompiledType ();
531 internal bool EnableSessionState
{
533 return enableSessionState
== PagesEnableSessionState
.True
||
534 ReadOnlySessionState
;
538 internal bool EnableViewStateMac
{
539 get { return enableViewStateMac; }
542 internal bool EnableViewStateMacSet
{
543 get { return enableViewStateMacSet; }
546 internal bool SmartNavigation
{
547 get { return smartNavigation; }
550 internal bool ReadOnlySessionState
{
552 return enableSessionState
== PagesEnableSessionState
.ReadOnly
;
556 internal bool HaveTrace
{
557 get { return haveTrace; }
560 internal bool Trace
{
561 get { return trace; }
564 internal TraceMode TraceMode
{
565 get { return tracemode; }
568 internal override Type DefaultBaseType
{
570 Type ret
= DefaultPageBaseType
;
572 return base.DefaultBaseType
;
578 internal override string DefaultBaseTypeName
{
579 get { return PagesConfig.PageBaseType; }
582 internal override string DefaultDirectiveName
{
583 get { return "page"; }
586 internal string ContentType
{
587 get { return contentType; }
590 internal MainDirectiveAttribute
<string> ResponseEncoding
{
591 get { return responseEncoding; }
594 internal MainDirectiveAttribute
<int> CodePage
{
595 get { return codepage; }
598 internal MainDirectiveAttribute
<int> LCID
{
602 internal MainDirectiveAttribute
<string> ClientTarget
{
603 get { return clientTarget; }
606 internal MainDirectiveAttribute
<string> MasterPageFile
{
607 get { return masterPage; }
610 internal MainDirectiveAttribute
<string> Title
{
611 get { return title; }
614 internal MainDirectiveAttribute
<string> Theme
{
615 get { return theme; }
618 internal MainDirectiveAttribute
<string> MetaDescription
{
619 get { return metaDescription; }
622 internal MainDirectiveAttribute
<string> MetaKeywords
{
623 get { return metaKeywords; }
626 internal string Culture
{
627 get { return culture; }
630 internal string UICulture
{
631 get { return uiculture; }
634 internal string ErrorPage
{
635 get { return errorPage; }
638 internal bool ValidateRequest
{
639 get { return validateRequest; }
642 internal bool NotBuffer
{
643 get { return notBuffer; }
646 internal bool Async
{
647 get { return async; }
650 internal int AsyncTimeout
{
651 get { return asyncTimeout; }
654 internal string StyleSheetTheme
{
655 get { return styleSheetTheme; }
658 internal Type MasterType
{
660 if (masterType
== null && !String
.IsNullOrEmpty (masterVirtualPath
))
661 masterType
= BuildManager
.GetCompiledType (masterVirtualPath
);
667 internal bool EnableEventValidation
{
668 get { return enable_event_validation; }
671 internal bool MaintainScrollPositionOnPostBack
{
672 get { return maintainScrollPositionOnPostBack; }
675 internal int MaxPageStateFieldLength
{
676 get { return maxPageStateFieldLength; }
679 internal Type PreviousPageType
{
681 if (previousPageType
== null && !String
.IsNullOrEmpty (previousPageVirtualPath
)) {
682 string mappedPath
= MapPath (previousPageVirtualPath
);
683 previousPageType
= GetCompiledPageType (previousPageVirtualPath
, mappedPath
, HttpContext
.Current
);
686 return previousPageType
;