PageRenderTime 61ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.Web/System.Web.UI/TemplateParser.cs

https://bitbucket.org/danipen/mono
C# | 1295 lines | 1011 code | 233 blank | 51 comment | 268 complexity | 383522b40a80023df45ae533c9922f51 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // System.Web.UI.TemplateParser
  3. //
  4. // Authors:
  5. // Duncan Mak (duncan@ximian.com)
  6. // Gonzalo Paniagua Javier (gonzalo@ximian.com)
  7. // Marek Habersack (mhabersack@novell.com)
  8. //
  9. // (C) 2002,2003 Ximian, Inc. (http://www.ximian.com)
  10. // Copyright (C) 2005-2008 Novell, Inc (http://www.novell.com)
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining
  13. // a copy of this software and associated documentation files (the
  14. // "Software"), to deal in the Software without restriction, including
  15. // without limitation the rights to use, copy, modify, merge, publish,
  16. // distribute, sublicense, and/or sell copies of the Software, and to
  17. // permit persons to whom the Software is furnished to do so, subject to
  18. // the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be
  21. // included in all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  27. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  28. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  29. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  30. //
  31. using System.CodeDom.Compiler;
  32. using System.Collections;
  33. using System.Collections.Generic;
  34. using System.ComponentModel;
  35. using System.Globalization;
  36. using System.IO;
  37. using System.Reflection;
  38. using System.Security.Permissions;
  39. using System.Text;
  40. using System.Threading;
  41. using System.Web.Compilation;
  42. using System.Web.Hosting;
  43. using System.Web.Configuration;
  44. using System.Web.Util;
  45. namespace System.Web.UI {
  46. internal class ServerSideScript
  47. {
  48. public readonly string Script;
  49. public readonly ILocation Location;
  50. public ServerSideScript (string script, ILocation location)
  51. {
  52. Script = script;
  53. Location = location;
  54. }
  55. }
  56. // CAS
  57. [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
  58. [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
  59. public abstract class TemplateParser : BaseParser
  60. {
  61. [Flags]
  62. internal enum OutputCacheParsedParams
  63. {
  64. Location = 0x0001,
  65. CacheProfile = 0x0002,
  66. NoStore = 0x0004,
  67. SqlDependency = 0x0008,
  68. VaryByCustom = 0x0010,
  69. VaryByHeader = 0x0020,
  70. VaryByControl = 0x0040,
  71. VaryByContentEncodings = 0x0080
  72. }
  73. string inputFile;
  74. string text;
  75. IDictionary mainAttributes;
  76. List <string> dependencies;
  77. List <string> assemblies;
  78. IDictionary anames;
  79. string[] binDirAssemblies;
  80. Dictionary <string, bool> namespacesCache;
  81. Dictionary <string, bool> imports;
  82. List <string> interfaces;
  83. List <ServerSideScript> scripts;
  84. Type baseType;
  85. bool baseTypeIsGlobal = true;
  86. string className;
  87. RootBuilder rootBuilder;
  88. bool debug;
  89. string compilerOptions;
  90. string language;
  91. bool implicitLanguage;
  92. bool strictOn ;
  93. bool explicitOn;
  94. bool linePragmasOn = true;
  95. bool output_cache;
  96. int oc_duration;
  97. string oc_header, oc_custom, oc_param, oc_controls;
  98. string oc_content_encodings, oc_cacheprofile, oc_sqldependency;
  99. bool oc_nostore;
  100. OutputCacheParsedParams oc_parsed_params = 0;
  101. bool oc_shared;
  102. OutputCacheLocation oc_location;
  103. // Kludge needed to support pre-parsing of the main directive (see
  104. // AspNetGenerator.GetRootBuilderType)
  105. internal int allowedMainDirectives = 0;
  106. byte[] md5checksum;
  107. string src;
  108. bool srcIsLegacy;
  109. string partialClassName;
  110. string codeFileBaseClass;
  111. string metaResourceKey;
  112. Type codeFileBaseClassType;
  113. Type pageParserFilterType;
  114. PageParserFilter pageParserFilter;
  115. List <UnknownAttributeDescriptor> unknownMainAttributes;
  116. Stack <string> includeDirs;
  117. List <string> registeredTagNames;
  118. ILocation directiveLocation;
  119. int appAssemblyIndex = -1;
  120. internal TemplateParser ()
  121. {
  122. imports = new Dictionary <string, bool> (StringComparer.Ordinal);
  123. LoadConfigDefaults ();
  124. assemblies = new List <string> ();
  125. CompilationSection compConfig = CompilationConfig;
  126. foreach (AssemblyInfo info in compConfig.Assemblies) {
  127. if (info.Assembly != "*")
  128. AddAssemblyByName (info.Assembly);
  129. }
  130. language = compConfig.DefaultLanguage;
  131. implicitLanguage = true;
  132. }
  133. internal virtual void LoadConfigDefaults ()
  134. {
  135. AddNamespaces (imports);
  136. debug = CompilationConfig.Debug;
  137. }
  138. internal void AddApplicationAssembly ()
  139. {
  140. if (Context.ApplicationInstance == null)
  141. return; // this may happen if we have Global.asax and have
  142. // controls registered from Web.Config
  143. string location = Context.ApplicationInstance.AssemblyLocation;
  144. if (location != typeof (TemplateParser).Assembly.Location) {
  145. assemblies.Add (location);
  146. appAssemblyIndex = assemblies.Count - 1;
  147. }
  148. }
  149. internal abstract Type CompileIntoType ();
  150. internal void AddControl (Type type, IDictionary attributes)
  151. {
  152. AspGenerator generator = AspGenerator;
  153. if (generator == null)
  154. return;
  155. generator.AddControl (type, attributes);
  156. }
  157. void AddNamespaces (Dictionary <string, bool> imports)
  158. {
  159. if (BuildManager.HaveResources)
  160. imports.Add ("System.Resources", true);
  161. PagesSection pages = PagesConfig;
  162. if (pages == null)
  163. return;
  164. NamespaceCollection namespaces = pages.Namespaces;
  165. if (namespaces == null || namespaces.Count == 0)
  166. return;
  167. foreach (NamespaceInfo nsi in namespaces) {
  168. string ns = nsi.Namespace;
  169. if (imports.ContainsKey (ns))
  170. continue;
  171. imports.Add (ns, true);
  172. }
  173. }
  174. internal void RegisterCustomControl (string tagPrefix, string tagName, string src)
  175. {
  176. string realpath = null;
  177. bool fileExists = false;
  178. VirtualFile vf = null;
  179. VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
  180. VirtualPath vp = new VirtualPath (src, BaseVirtualDir);
  181. string vpAbsolute = vpp.CombineVirtualPaths (VirtualPath.Absolute, vp.Absolute);
  182. if (vpp.FileExists (vpAbsolute)) {
  183. fileExists = true;
  184. vf = vpp.GetFile (vpAbsolute);
  185. if (vf != null)
  186. realpath = MapPath (vf.VirtualPath);
  187. }
  188. if (!fileExists)
  189. ThrowParseFileNotFound (src);
  190. if (String.Compare (realpath, inputFile, StringComparison.Ordinal) == 0)
  191. return;
  192. string vpath = vf.VirtualPath;
  193. try {
  194. RegisterTagName (tagPrefix + ":" + tagName);
  195. RootBuilder.Foundry.RegisterFoundry (tagPrefix, tagName, vpath);
  196. AddDependency (vpath);
  197. } catch (ParseException pe) {
  198. if (this is UserControlParser)
  199. throw new ParseException (Location, pe.Message, pe);
  200. throw;
  201. }
  202. }
  203. internal void RegisterNamespace (string tagPrefix, string ns, string assembly)
  204. {
  205. AddImport (ns);
  206. Assembly ass = null;
  207. if (assembly != null && assembly.Length > 0)
  208. ass = AddAssemblyByName (assembly);
  209. RootBuilder.Foundry.RegisterFoundry (tagPrefix, ass, ns);
  210. }
  211. internal virtual void HandleOptions (object obj)
  212. {
  213. }
  214. internal static string GetOneKey (IDictionary tbl)
  215. {
  216. foreach (object key in tbl.Keys)
  217. return key.ToString ();
  218. return null;
  219. }
  220. internal virtual void AddDirective (string directive, IDictionary atts)
  221. {
  222. var pageParserFilter = PageParserFilter;
  223. if (String.Compare (directive, DefaultDirectiveName, true, Helpers.InvariantCulture) == 0) {
  224. bool allowMainDirective = allowedMainDirectives > 0;
  225. if (mainAttributes != null && !allowMainDirective)
  226. ThrowParseException ("Only 1 " + DefaultDirectiveName + " is allowed");
  227. allowedMainDirectives--;
  228. if (mainAttributes != null)
  229. return;
  230. if (pageParserFilter != null)
  231. pageParserFilter.PreprocessDirective (directive.ToLower (Helpers.InvariantCulture), atts);
  232. mainAttributes = atts;
  233. ProcessMainAttributes (mainAttributes);
  234. return;
  235. } else if (pageParserFilter != null)
  236. pageParserFilter.PreprocessDirective (directive.ToLower (Helpers.InvariantCulture), atts);
  237. int cmp = String.Compare ("Assembly", directive, true, Helpers.InvariantCulture);
  238. if (cmp == 0) {
  239. string name = GetString (atts, "Name", null);
  240. string src = GetString (atts, "Src", null);
  241. if (atts.Count > 0)
  242. ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
  243. if (name == null && src == null)
  244. ThrowParseException ("You gotta specify Src or Name");
  245. if (name != null && src != null)
  246. ThrowParseException ("Src and Name cannot be used together");
  247. if (name != null) {
  248. AddAssemblyByName (name);
  249. } else {
  250. GetAssemblyFromSource (src);
  251. }
  252. return;
  253. }
  254. cmp = String.Compare ("Import", directive, true, Helpers.InvariantCulture);
  255. if (cmp == 0) {
  256. string namesp = GetString (atts, "Namespace", null);
  257. if (atts.Count > 0)
  258. ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
  259. AddImport (namesp);
  260. return;
  261. }
  262. cmp = String.Compare ("Implements", directive, true, Helpers.InvariantCulture);
  263. if (cmp == 0) {
  264. string ifacename = GetString (atts, "Interface", "");
  265. if (atts.Count > 0)
  266. ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
  267. Type iface = LoadType (ifacename);
  268. if (iface == null)
  269. ThrowParseException ("Cannot find type " + ifacename);
  270. if (!iface.IsInterface)
  271. ThrowParseException (iface + " is not an interface");
  272. AddInterface (iface.FullName);
  273. return;
  274. }
  275. cmp = String.Compare ("OutputCache", directive, true, Helpers.InvariantCulture);
  276. if (cmp == 0) {
  277. HttpResponse response = HttpContext.Current.Response;
  278. if (response != null)
  279. response.Cache.SetValidUntilExpires (true);
  280. output_cache = true;
  281. ProcessOutputCacheAttributes (atts);
  282. return;
  283. }
  284. ThrowParseException ("Unknown directive: " + directive);
  285. }
  286. internal virtual void ProcessOutputCacheAttributes (IDictionary atts)
  287. {
  288. if (atts ["Duration"] == null)
  289. ThrowParseException ("The directive is missing a 'duration' attribute.");
  290. if (atts ["VaryByParam"] == null && atts ["VaryByControl"] == null)
  291. ThrowParseException ("This directive is missing 'VaryByParam' " +
  292. "or 'VaryByControl' attribute, which should be set to \"none\", \"*\", " +
  293. "or a list of name/value pairs.");
  294. foreach (DictionaryEntry entry in atts) {
  295. string key = (string) entry.Key;
  296. if (key == null)
  297. continue;
  298. switch (key.ToLower (Helpers.InvariantCulture)) {
  299. case "duration":
  300. oc_duration = Int32.Parse ((string) entry.Value);
  301. if (oc_duration < 1)
  302. ThrowParseException ("The 'duration' attribute must be set " +
  303. "to a positive integer value");
  304. break;
  305. case "sqldependency":
  306. oc_sqldependency = (string) entry.Value;
  307. break;
  308. case "nostore":
  309. try {
  310. oc_nostore = Boolean.Parse ((string) entry.Value);
  311. oc_parsed_params |= OutputCacheParsedParams.NoStore;
  312. } catch {
  313. ThrowParseException ("The 'NoStore' attribute is case sensitive" +
  314. " and must be set to 'true' or 'false'.");
  315. }
  316. break;
  317. case "cacheprofile":
  318. oc_cacheprofile = (string) entry.Value;
  319. oc_parsed_params |= OutputCacheParsedParams.CacheProfile;
  320. break;
  321. case "varybycontentencodings":
  322. oc_content_encodings = (string) entry.Value;
  323. oc_parsed_params |= OutputCacheParsedParams.VaryByContentEncodings;
  324. break;
  325. case "varybyparam":
  326. oc_param = (string) entry.Value;
  327. if (String.Compare (oc_param, "none", true, Helpers.InvariantCulture) == 0)
  328. oc_param = null;
  329. break;
  330. case "varybyheader":
  331. oc_header = (string) entry.Value;
  332. oc_parsed_params |= OutputCacheParsedParams.VaryByHeader;
  333. break;
  334. case "varybycustom":
  335. oc_custom = (string) entry.Value;
  336. oc_parsed_params |= OutputCacheParsedParams.VaryByCustom;
  337. break;
  338. case "location":
  339. if (!(this is PageParser))
  340. goto default;
  341. try {
  342. oc_location = (OutputCacheLocation) Enum.Parse (
  343. typeof (OutputCacheLocation), (string) entry.Value, true);
  344. oc_parsed_params |= OutputCacheParsedParams.Location;
  345. } catch {
  346. ThrowParseException ("The 'location' attribute is case sensitive and " +
  347. "must be one of the following values: Any, Client, " +
  348. "Downstream, Server, None, ServerAndClient.");
  349. }
  350. break;
  351. case "varybycontrol":
  352. oc_controls = (string) entry.Value;
  353. oc_parsed_params |= OutputCacheParsedParams.VaryByControl;
  354. break;
  355. case "shared":
  356. if (this is PageParser)
  357. goto default;
  358. try {
  359. oc_shared = Boolean.Parse ((string) entry.Value);
  360. } catch {
  361. ThrowParseException ("The 'shared' attribute is case sensitive" +
  362. " and must be set to 'true' or 'false'.");
  363. }
  364. break;
  365. default:
  366. ThrowParseException ("The '" + key + "' attribute is not " +
  367. "supported by the 'Outputcache' directive.");
  368. break;
  369. }
  370. }
  371. }
  372. internal Type LoadType (string typeName)
  373. {
  374. Type type = HttpApplication.LoadType (typeName);
  375. if (type == null)
  376. return null;
  377. Assembly asm = type.Assembly;
  378. string location = asm.Location;
  379. string dirname = Path.GetDirectoryName (location);
  380. bool doAddAssembly = true;
  381. if (dirname == HttpApplication.BinDirectory)
  382. doAddAssembly = false;
  383. if (doAddAssembly)
  384. AddAssembly (asm, true);
  385. return type;
  386. }
  387. internal virtual void AddInterface (string iface)
  388. {
  389. if (interfaces == null)
  390. interfaces = new List <string> ();
  391. if (!interfaces.Contains (iface))
  392. interfaces.Add (iface);
  393. }
  394. internal virtual void AddImport (string namesp)
  395. {
  396. if (namesp == null || namesp.Length == 0)
  397. return;
  398. if (imports == null)
  399. imports = new Dictionary <string, bool> (StringComparer.Ordinal);
  400. if (imports.ContainsKey (namesp))
  401. return;
  402. imports.Add (namesp, true);
  403. AddAssemblyForNamespace (namesp);
  404. }
  405. void AddAssemblyForNamespace (string namesp)
  406. {
  407. if (binDirAssemblies == null)
  408. binDirAssemblies = HttpApplication.BinDirectoryAssemblies;
  409. if (binDirAssemblies.Length == 0)
  410. return;
  411. if (namespacesCache == null)
  412. namespacesCache = new Dictionary <string, bool> ();
  413. else if (namespacesCache.ContainsKey (namesp))
  414. return;
  415. foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies ())
  416. if (FindNamespaceInAssembly (asm, namesp))
  417. return;
  418. IList tla = BuildManager.TopLevelAssemblies;
  419. if (tla != null && tla.Count > 0) {
  420. foreach (Assembly asm in tla) {
  421. if (FindNamespaceInAssembly (asm, namesp))
  422. return;
  423. }
  424. }
  425. Assembly a;
  426. foreach (string s in binDirAssemblies) {
  427. a = Assembly.LoadFrom (s);
  428. if (FindNamespaceInAssembly (a, namesp))
  429. return;
  430. }
  431. }
  432. bool FindNamespaceInAssembly (Assembly asm, string namesp)
  433. {
  434. Type[] asmTypes;
  435. try {
  436. asmTypes = asm.GetTypes ();
  437. } catch (ReflectionTypeLoadException) {
  438. // ignore
  439. return false;
  440. }
  441. foreach (Type type in asmTypes) {
  442. if (String.Compare (type.Namespace, namesp, StringComparison.Ordinal) == 0) {
  443. namespacesCache.Add (namesp, true);
  444. AddAssembly (asm, true);
  445. return true;
  446. }
  447. }
  448. return false;
  449. }
  450. internal virtual void AddSourceDependency (string filename)
  451. {
  452. if (dependencies != null && dependencies.Contains (filename))
  453. ThrowParseException ("Circular file references are not allowed. File: " + filename);
  454. AddDependency (filename);
  455. }
  456. internal virtual void AddDependency (string filename)
  457. {
  458. AddDependency (filename, true);
  459. }
  460. internal virtual void AddDependency (string filename, bool combinePaths)
  461. {
  462. if (String.IsNullOrEmpty (filename))
  463. return;
  464. if (dependencies == null)
  465. dependencies = new List <string> ();
  466. if (combinePaths)
  467. filename = HostingEnvironment.VirtualPathProvider.CombineVirtualPaths (VirtualPath.Absolute, filename);
  468. if (!dependencies.Contains (filename))
  469. dependencies.Add (filename);
  470. }
  471. internal virtual void AddAssembly (Assembly assembly, bool fullPath)
  472. {
  473. if (assembly == null || assembly.Location == String.Empty)
  474. return;
  475. if (anames == null)
  476. anames = new Dictionary <string, object> ();
  477. string name = assembly.GetName ().Name;
  478. string loc = assembly.Location;
  479. if (fullPath) {
  480. if (!assemblies.Contains (loc)) {
  481. assemblies.Add (loc);
  482. }
  483. anames [name] = loc;
  484. anames [loc] = assembly;
  485. } else {
  486. if (!assemblies.Contains (name)) {
  487. assemblies.Add (name);
  488. }
  489. anames [name] = assembly;
  490. }
  491. }
  492. internal virtual Assembly AddAssemblyByFileName (string filename)
  493. {
  494. Assembly assembly = null;
  495. Exception error = null;
  496. try {
  497. assembly = Assembly.LoadFrom (filename);
  498. } catch (Exception e) { error = e; }
  499. if (assembly == null)
  500. ThrowParseException ("Assembly " + filename + " not found", error);
  501. AddAssembly (assembly, true);
  502. return assembly;
  503. }
  504. internal virtual Assembly AddAssemblyByName (string name)
  505. {
  506. if (anames == null)
  507. anames = new Dictionary <string, object> ();
  508. if (anames.Contains (name)) {
  509. object o = anames [name];
  510. if (o is string)
  511. o = anames [o];
  512. return (Assembly) o;
  513. }
  514. Assembly assembly = null;
  515. Exception error = null;
  516. try {
  517. assembly = Assembly.Load (name);
  518. } catch (Exception e) { error = e; }
  519. if (assembly == null) {
  520. try {
  521. assembly = Assembly.LoadWithPartialName (name);
  522. } catch (Exception e) { error = e; }
  523. }
  524. if (assembly == null)
  525. ThrowParseException ("Assembly " + name + " not found", error);
  526. AddAssembly (assembly, true);
  527. return assembly;
  528. }
  529. internal virtual void ProcessMainAttributes (IDictionary atts)
  530. {
  531. directiveLocation = new System.Web.Compilation.Location (Location);
  532. CompilationSection compConfig;
  533. compConfig = CompilationConfig;
  534. atts.Remove ("Description"); // ignored
  535. atts.Remove ("CodeBehind"); // ignored
  536. atts.Remove ("AspCompat"); // ignored
  537. debug = GetBool (atts, "Debug", compConfig.Debug);
  538. compilerOptions = GetString (atts, "CompilerOptions", String.Empty);
  539. language = GetString (atts, "Language", "");
  540. if (language.Length != 0)
  541. implicitLanguage = false;
  542. else
  543. language = compConfig.DefaultLanguage;
  544. strictOn = GetBool (atts, "Strict", compConfig.Strict);
  545. explicitOn = GetBool (atts, "Explicit", compConfig.Explicit);
  546. if (atts.Contains ("LinePragmas"))
  547. linePragmasOn = GetBool (atts, "LinePragmas", true);
  548. string inherits = GetString (atts, "Inherits", null);
  549. string srcRealPath = null;
  550. // In ASP 2+, the source file is actually integrated with
  551. // the generated file via the use of partial classes. This
  552. // means that the code file has to be confirmed, but not
  553. // used at this point.
  554. src = GetString (atts, "CodeFile", null);
  555. codeFileBaseClass = GetString (atts, "CodeFileBaseClass", null);
  556. if (src == null && codeFileBaseClass != null)
  557. ThrowParseException ("The 'CodeFileBaseClass' attribute cannot be used without a 'CodeFile' attribute");
  558. string legacySrc = GetString (atts, "Src", null);
  559. var vpp = HostingEnvironment.VirtualPathProvider;
  560. if (legacySrc != null) {
  561. legacySrc = vpp.CombineVirtualPaths (BaseVirtualDir, legacySrc);
  562. GetAssemblyFromSource (legacySrc);
  563. if (src == null) {
  564. src = legacySrc;
  565. legacySrc = MapPath (legacySrc, false);
  566. srcRealPath = legacySrc;
  567. if (!File.Exists (srcRealPath))
  568. ThrowParseException ("File " + src + " not found");
  569. srcIsLegacy = true;
  570. } else
  571. legacySrc = MapPath (legacySrc, false);
  572. AddDependency (legacySrc, false);
  573. }
  574. if (!srcIsLegacy && src != null && inherits != null) {
  575. // Make sure the source exists
  576. src = vpp.CombineVirtualPaths (BaseVirtualDir, src);
  577. srcRealPath = MapPath (src, false);
  578. if (!vpp.FileExists (src))
  579. ThrowParseException ("File " + src + " not found");
  580. // We are going to create a partial class that shares
  581. // the same name as the inherits tag, so reset the
  582. // name. The base type is changed because it is the
  583. // code file's responsibilty to extend the classes
  584. // needed.
  585. partialClassName = inherits;
  586. // Add the code file as an option to the
  587. // compiler. This lets both files be compiled at once.
  588. compilerOptions += " \"" + srcRealPath + "\"";
  589. if (codeFileBaseClass != null) {
  590. try {
  591. codeFileBaseClassType = LoadType (codeFileBaseClass);
  592. } catch (Exception) {
  593. }
  594. if (codeFileBaseClassType == null)
  595. ThrowParseException ("Could not load type '{0}'", codeFileBaseClass);
  596. }
  597. } else if (inherits != null) {
  598. // We just set the inherits directly because this is a
  599. // Single-Page model.
  600. SetBaseType (inherits);
  601. }
  602. if (src != null) {
  603. if (VirtualPathUtility.IsAbsolute (src))
  604. src = VirtualPathUtility.ToAppRelative (src);
  605. AddDependency (src, false);
  606. }
  607. className = GetString (atts, "ClassName", null);
  608. if (className != null) {
  609. string [] identifiers = className.Split ('.');
  610. for (int i = 0; i < identifiers.Length; i++)
  611. if (!CodeGenerator.IsValidLanguageIndependentIdentifier (identifiers [i]))
  612. ThrowParseException (String.Format ("'{0}' is not a valid "
  613. + "value for attribute 'classname'.", className));
  614. }
  615. if (this is TemplateControlParser)
  616. metaResourceKey = GetString (atts, "meta:resourcekey", null);
  617. if (inherits != null && (this is PageParser || this is UserControlParser) && atts.Count > 0) {
  618. if (unknownMainAttributes == null)
  619. unknownMainAttributes = new List <UnknownAttributeDescriptor> ();
  620. string key, val;
  621. foreach (DictionaryEntry de in atts) {
  622. key = de.Key as string;
  623. val = de.Value as string;
  624. if (String.IsNullOrEmpty (key) || String.IsNullOrEmpty (val))
  625. continue;
  626. CheckUnknownAttribute (key, val, inherits);
  627. }
  628. return;
  629. }
  630. if (atts.Count > 0)
  631. ThrowParseException ("Unknown attribute: " + GetOneKey (atts));
  632. }
  633. void RegisterTagName (string tagName)
  634. {
  635. if (registeredTagNames == null)
  636. registeredTagNames = new List <string> ();
  637. if (registeredTagNames.Contains (tagName))
  638. return;
  639. registeredTagNames.Add (tagName);
  640. }
  641. void CheckUnknownAttribute (string name, string val, string inherits)
  642. {
  643. MemberInfo mi = null;
  644. bool missing = false;
  645. string memberName = name.Trim ().ToLower (Helpers.InvariantCulture);
  646. Type parent = codeFileBaseClassType;
  647. if (parent == null)
  648. parent = baseType;
  649. try {
  650. MemberInfo[] infos = parent.GetMember (memberName,
  651. MemberTypes.Field | MemberTypes.Property,
  652. BindingFlags.Public | BindingFlags.Instance |
  653. BindingFlags.IgnoreCase | BindingFlags.Static);
  654. if (infos.Length != 0) {
  655. // prefer public properties to public methods (it's what MS.NET does)
  656. foreach (MemberInfo tmp in infos) {
  657. if (tmp is PropertyInfo) {
  658. mi = tmp;
  659. break;
  660. }
  661. }
  662. if (mi == null)
  663. mi = infos [0];
  664. } else
  665. missing = true;
  666. } catch (Exception) {
  667. missing = true;
  668. }
  669. if (missing)
  670. ThrowParseException (
  671. "Error parsing attribute '{0}': Type '{1}' does not have a public property named '{0}'",
  672. memberName, inherits);
  673. Type memberType = null;
  674. if (mi is PropertyInfo) {
  675. PropertyInfo pi = mi as PropertyInfo;
  676. if (!pi.CanWrite)
  677. ThrowParseException (
  678. "Error parsing attribute '{0}': The '{0}' property is read-only and cannot be set.",
  679. memberName);
  680. memberType = pi.PropertyType;
  681. } else if (mi is FieldInfo) {
  682. memberType = ((FieldInfo)mi).FieldType;
  683. } else
  684. ThrowParseException ("Could not determine member the kind of '{0}' in base type '{1}",
  685. memberName, inherits);
  686. TypeConverter converter = TypeDescriptor.GetConverter (memberType);
  687. bool convertible = true;
  688. object value = null;
  689. if (converter == null || !converter.CanConvertFrom (typeof (string)))
  690. convertible = false;
  691. if (convertible) {
  692. try {
  693. value = converter.ConvertFromInvariantString (val);
  694. } catch (Exception) {
  695. convertible = false;
  696. }
  697. }
  698. if (!convertible)
  699. ThrowParseException ("Error parsing attribute '{0}': Cannot create an object of type '{1}' from its string representation '{2}' for the '{3}' property.",
  700. memberName, memberType, val, mi.Name);
  701. UnknownAttributeDescriptor desc = new UnknownAttributeDescriptor (mi, value);
  702. unknownMainAttributes.Add (desc);
  703. }
  704. internal void SetBaseType (string type)
  705. {
  706. Type parent;
  707. if (type == null || type == DefaultBaseTypeName)
  708. parent = DefaultBaseType;
  709. else
  710. parent = null;
  711. if (parent == null) {
  712. parent = LoadType (type);
  713. if (parent == null)
  714. ThrowParseException ("Cannot find type " + type);
  715. if (!DefaultBaseType.IsAssignableFrom (parent))
  716. ThrowParseException ("The parent type '" + type + "' does not derive from " + DefaultBaseType);
  717. }
  718. var pageParserFilter = PageParserFilter;
  719. if (pageParserFilter != null && !pageParserFilter.AllowBaseType (parent))
  720. throw new HttpException ("Base type '" + parent + "' is not allowed.");
  721. baseType = parent;
  722. }
  723. internal void SetLanguage (string language)
  724. {
  725. this.language = language;
  726. implicitLanguage = false;
  727. }
  728. internal void PushIncludeDir (string dir)
  729. {
  730. if (includeDirs == null)
  731. includeDirs = new Stack <string> (1);
  732. includeDirs.Push (dir);
  733. }
  734. internal string PopIncludeDir ()
  735. {
  736. if (includeDirs == null || includeDirs.Count == 0)
  737. return null;
  738. return includeDirs.Pop () as string;
  739. }
  740. Assembly GetAssemblyFromSource (string vpath)
  741. {
  742. vpath = UrlUtils.Combine (BaseVirtualDir, vpath);
  743. string realPath = MapPath (vpath, false);
  744. if (!File.Exists (realPath))
  745. ThrowParseException ("File " + vpath + " not found");
  746. AddSourceDependency (vpath);
  747. CompilerResults result;
  748. string tmp;
  749. CompilerParameters parameters;
  750. CodeDomProvider provider = BaseCompiler.CreateProvider (HttpContext.Current, language, out parameters, out tmp);
  751. if (provider == null)
  752. throw new HttpException ("Cannot find provider for language '" + language + "'.");
  753. AssemblyBuilder abuilder = new AssemblyBuilder (provider);
  754. abuilder.CompilerOptions = parameters;
  755. abuilder.AddAssemblyReference (BuildManager.GetReferencedAssemblies () as List <Assembly>);
  756. abuilder.AddCodeFile (realPath);
  757. result = abuilder.BuildAssembly (new VirtualPath (vpath));
  758. if (result.NativeCompilerReturnValue != 0) {
  759. using (StreamReader reader = new StreamReader (realPath)) {
  760. throw new CompilationException (realPath, result.Errors, reader.ReadToEnd ());
  761. }
  762. }
  763. AddAssembly (result.CompiledAssembly, true);
  764. return result.CompiledAssembly;
  765. }
  766. internal abstract string DefaultBaseTypeName { get; }
  767. internal abstract string DefaultDirectiveName { get; }
  768. internal bool LinePragmasOn {
  769. get { return linePragmasOn; }
  770. }
  771. internal byte[] MD5Checksum {
  772. get { return md5checksum; }
  773. set { md5checksum = value; }
  774. }
  775. internal PageParserFilter PageParserFilter {
  776. get {
  777. if (pageParserFilter != null)
  778. return pageParserFilter;
  779. Type t = PageParserFilterType;
  780. if (t == null)
  781. return null;
  782. pageParserFilter = Activator.CreateInstance (t) as PageParserFilter;
  783. pageParserFilter.Initialize (this);
  784. return pageParserFilter;
  785. }
  786. }
  787. internal Type PageParserFilterType {
  788. get {
  789. if (pageParserFilterType == null) {
  790. #if NET_4_0
  791. pageParserFilterType = PageParser.DefaultPageParserFilterType;
  792. if (pageParserFilterType != null)
  793. return pageParserFilterType;
  794. #endif
  795. string typeName = PagesConfig.PageParserFilterType;
  796. if (String.IsNullOrEmpty (typeName))
  797. return null;
  798. pageParserFilterType = HttpApplication.LoadType (typeName, true);
  799. }
  800. return pageParserFilterType;
  801. }
  802. }
  803. #if NET_4_0
  804. internal virtual
  805. #else
  806. internal
  807. #endif
  808. Type DefaultBaseType {
  809. get {
  810. Type type = Type.GetType (DefaultBaseTypeName, true);
  811. return type;
  812. }
  813. }
  814. internal ILocation DirectiveLocation {
  815. get { return directiveLocation; }
  816. }
  817. internal string ParserDir {
  818. get {
  819. if (includeDirs == null || includeDirs.Count == 0)
  820. return BaseDir;
  821. return includeDirs.Peek () as string;
  822. }
  823. }
  824. internal string InputFile
  825. {
  826. get { return inputFile; }
  827. set { inputFile = value; }
  828. }
  829. internal bool IsPartial {
  830. get { return (!srcIsLegacy && src != null); }
  831. }
  832. internal string CodeBehindSource {
  833. get {
  834. if (srcIsLegacy)
  835. return null;
  836. return src;
  837. }
  838. }
  839. internal string PartialClassName {
  840. get { return partialClassName; }
  841. }
  842. internal string CodeFileBaseClass {
  843. get { return codeFileBaseClass; }
  844. }
  845. internal string MetaResourceKey {
  846. get { return metaResourceKey; }
  847. }
  848. internal Type CodeFileBaseClassType
  849. {
  850. get { return codeFileBaseClassType; }
  851. }
  852. internal List <UnknownAttributeDescriptor> UnknownMainAttributes
  853. {
  854. get { return unknownMainAttributes; }
  855. }
  856. internal string Text {
  857. get { return text; }
  858. set { text = value; }
  859. }
  860. internal Type BaseType {
  861. get {
  862. if (baseType == null)
  863. SetBaseType (DefaultBaseTypeName);
  864. return baseType;
  865. }
  866. }
  867. internal bool BaseTypeIsGlobal {
  868. get { return baseTypeIsGlobal; }
  869. set { baseTypeIsGlobal = value; }
  870. }
  871. static long autoClassCounter = 0;
  872. internal string EncodeIdentifier (string value)
  873. {
  874. if (value == null || value.Length == 0 || CodeGenerator.IsValidLanguageIndependentIdentifier (value))
  875. return value;
  876. StringBuilder ret = new StringBuilder ();
  877. char ch = value [0];
  878. switch (Char.GetUnicodeCategory (ch)) {
  879. case UnicodeCategory.LetterNumber:
  880. case UnicodeCategory.LowercaseLetter:
  881. case UnicodeCategory.TitlecaseLetter:
  882. case UnicodeCategory.UppercaseLetter:
  883. case UnicodeCategory.OtherLetter:
  884. case UnicodeCategory.ModifierLetter:
  885. case UnicodeCategory.ConnectorPunctuation:
  886. ret.Append (ch);
  887. break;
  888. case UnicodeCategory.DecimalDigitNumber:
  889. ret.Append ('_');
  890. ret.Append (ch);
  891. break;
  892. default:
  893. ret.Append ('_');
  894. break;
  895. }
  896. for (int i = 1; i < value.Length; i++) {
  897. ch = value [i];
  898. switch (Char.GetUnicodeCategory (ch)) {
  899. case UnicodeCategory.LetterNumber:
  900. case UnicodeCategory.LowercaseLetter:
  901. case UnicodeCategory.TitlecaseLetter:
  902. case UnicodeCategory.UppercaseLetter:
  903. case UnicodeCategory.OtherLetter:
  904. case UnicodeCategory.ModifierLetter:
  905. case UnicodeCategory.ConnectorPunctuation:
  906. case UnicodeCategory.DecimalDigitNumber:
  907. case UnicodeCategory.NonSpacingMark:
  908. case UnicodeCategory.SpacingCombiningMark:
  909. case UnicodeCategory.Format:
  910. ret.Append (ch);
  911. break;
  912. default:
  913. ret.Append ('_');
  914. break;
  915. }
  916. }
  917. return ret.ToString ();
  918. }
  919. internal string ClassName {
  920. get {
  921. if (className != null)
  922. return className;
  923. string physPath = HttpContext.Current.Request.PhysicalApplicationPath;
  924. string inFile;
  925. if (String.IsNullOrEmpty (inputFile)) {
  926. inFile = null;
  927. using (StreamReader sr = Reader as StreamReader) {
  928. if (sr != null) {
  929. FileStream fr = sr.BaseStream as FileStream;
  930. if (fr != null)
  931. inFile = fr.Name;
  932. }
  933. }
  934. } else
  935. inFile = inputFile;
  936. if (String.IsNullOrEmpty (inFile)) {
  937. // generate a unique class name
  938. long suffix;
  939. suffix = Interlocked.Increment (ref autoClassCounter);
  940. className = String.Format ("autoclass_nosource_{0:x}", suffix);
  941. return className;
  942. }
  943. if (StrUtils.StartsWith (inFile, physPath))
  944. className = inputFile.Substring (physPath.Length).ToLower (Helpers.InvariantCulture);
  945. else
  946. className = Path.GetFileName (inputFile);
  947. className = EncodeIdentifier (className);
  948. return className;
  949. }
  950. }
  951. internal List <ServerSideScript> Scripts {
  952. get {
  953. if (scripts == null)
  954. scripts = new List <ServerSideScript> ();
  955. return scripts;
  956. }
  957. }
  958. internal Dictionary <string, bool> Imports {
  959. get { return imports; }
  960. }
  961. internal List <string> Interfaces {
  962. get { return interfaces; }
  963. }
  964. internal List <string> Assemblies {
  965. get {
  966. if (appAssemblyIndex != -1) {
  967. string o = assemblies [appAssemblyIndex];
  968. assemblies.RemoveAt (appAssemblyIndex);
  969. assemblies.Add (o);
  970. appAssemblyIndex = -1;
  971. }
  972. return assemblies;
  973. }
  974. }
  975. internal RootBuilder RootBuilder {
  976. get {
  977. if (rootBuilder != null)
  978. return rootBuilder;
  979. AspGenerator generator = AspGenerator;
  980. if (generator != null)
  981. rootBuilder = generator.RootBuilder;
  982. return rootBuilder;
  983. }
  984. set { rootBuilder = value; }
  985. }
  986. internal List <string> Dependencies {
  987. get { return dependencies; }
  988. set { dependencies = value; }
  989. }
  990. internal string CompilerOptions {
  991. get { return compilerOptions; }
  992. }
  993. internal string Language {
  994. get { return language; }
  995. }
  996. internal bool ImplicitLanguage {
  997. get { return implicitLanguage; }
  998. }
  999. internal bool StrictOn {
  1000. get { return strictOn; }
  1001. }
  1002. internal bool ExplicitOn {
  1003. get { return explicitOn; }
  1004. }
  1005. internal bool Debug {
  1006. get { return debug; }
  1007. }
  1008. internal bool OutputCache {
  1009. get { return output_cache; }
  1010. }
  1011. internal int OutputCacheDuration {
  1012. get { return oc_duration; }
  1013. }
  1014. internal OutputCacheParsedParams OutputCacheParsedParameters {
  1015. get { return oc_parsed_params; }
  1016. }
  1017. internal string OutputCacheSqlDependency {
  1018. get { return oc_sqldependency; }
  1019. }
  1020. internal string OutputCacheCacheProfile {
  1021. get { return oc_cacheprofile; }
  1022. }
  1023. internal string OutputCacheVaryByContentEncodings {
  1024. get { return oc_content_encodings; }
  1025. }
  1026. internal bool OutputCacheNoStore {
  1027. get { return oc_nostore; }
  1028. }
  1029. internal virtual TextReader Reader {
  1030. get { return null; }
  1031. set { /* no-op */ }
  1032. }
  1033. internal string OutputCacheVaryByHeader {
  1034. get { return oc_header; }
  1035. }
  1036. internal string OutputCacheVaryByCustom {
  1037. get { return oc_custom; }
  1038. }
  1039. internal string OutputCacheVaryByControls {
  1040. get { return oc_controls; }
  1041. }
  1042. internal bool OutputCacheShared {
  1043. get { return oc_shared; }
  1044. }
  1045. internal OutputCacheLocation OutputCacheLocation {
  1046. get { return oc_location; }
  1047. }
  1048. internal string OutputCacheVaryByParam {
  1049. get { return oc_param; }
  1050. }
  1051. internal List <string> RegisteredTagNames {
  1052. get { return registeredTagNames; }
  1053. }
  1054. internal PagesSection PagesConfig {
  1055. get { return GetConfigSection <PagesSection> ("system.web/pages") as PagesSection; }
  1056. }
  1057. internal AspGenerator AspGenerator {
  1058. get;
  1059. set;
  1060. }
  1061. }
  1062. }