TemplateParser.cs 35 KB

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