TemplateParser.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. //
  2. // System.Web.UI.TemplateParser
  3. //
  4. // Authors:
  5. // Duncan Mak ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. //
  8. // (C) 2002,2003 Ximian, Inc. (http://www.ximian.com)
  9. //
  10. using System;
  11. using System.CodeDom.Compiler;
  12. using System.Collections;
  13. using System.IO;
  14. using System.Reflection;
  15. using System.Web;
  16. using System.Web.Compilation;
  17. using System.Web.Configuration;
  18. using System.Web.Util;
  19. namespace System.Web.UI
  20. {
  21. public abstract class TemplateParser : BaseParser
  22. {
  23. string inputFile;
  24. string text;
  25. string privateBinPath;
  26. Hashtable mainAttributes;
  27. ArrayList dependencies;
  28. ArrayList assemblies;
  29. Hashtable anames;
  30. ArrayList imports;
  31. ArrayList interfaces;
  32. ArrayList scripts;
  33. Type baseType;
  34. string className;
  35. RootBuilder rootBuilder;
  36. bool debug;
  37. string compilerOptions;
  38. string language;
  39. bool output_cache;
  40. int oc_duration;
  41. string oc_header, oc_custom, oc_param, oc_controls;
  42. bool oc_shared;
  43. OutputCacheLocation oc_location;
  44. Assembly srcAssembly;
  45. int appAssemblyIndex = -1;
  46. internal TemplateParser ()
  47. {
  48. imports = new ArrayList ();
  49. imports.Add ("System");
  50. imports.Add ("System.Collections");
  51. imports.Add ("System.Collections.Specialized");
  52. imports.Add ("System.Configuration");
  53. imports.Add ("System.Text");
  54. imports.Add ("System.Text.RegularExpressions");
  55. imports.Add ("System.Web");
  56. imports.Add ("System.Web.Caching");
  57. imports.Add ("System.Web.Security");
  58. imports.Add ("System.Web.SessionState");
  59. imports.Add ("System.Web.UI");
  60. imports.Add ("System.Web.UI.WebControls");
  61. imports.Add ("System.Web.UI.HtmlControls");
  62. assemblies = new ArrayList ();
  63. assemblies.AddRange (CompilationConfig.Assemblies);
  64. if (CompilationConfig.AssembliesInBin)
  65. AddAssembliesInBin ();
  66. language = CompilationConfig.DefaultLanguage;
  67. }
  68. internal void AddApplicationAssembly ()
  69. {
  70. string location = Context.ApplicationInstance.AssemblyLocation;
  71. if (location != typeof (TemplateParser).Assembly.Location) {
  72. appAssemblyIndex = assemblies.Add (location);
  73. }
  74. }
  75. protected abstract Type CompileIntoType ();
  76. internal virtual void HandleOptions (object obj)
  77. {
  78. }
  79. internal static string GetOneKey (Hashtable tbl)
  80. {
  81. foreach (object key in tbl.Keys)
  82. return key.ToString ();
  83. return null;
  84. }
  85. internal virtual void AddDirective (string directive, Hashtable atts)
  86. {
  87. if (String.Compare (directive, DefaultDirectiveName, true) == 0) {
  88. if (mainAttributes != null)
  89. ThrowParseException ("Only 1 " + DefaultDirectiveName + " is allowed");
  90. mainAttributes = atts;
  91. ProcessMainAttributes (mainAttributes);
  92. return;
  93. }
  94. int cmp = String.Compare ("Assembly", directive, true);
  95. if (cmp == 0) {
  96. string name = GetString (atts, "Name", null);
  97. string src = GetString (atts, "Src", null);
  98. if (atts.Count > 0)
  99. ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
  100. if (name == null && src == null)
  101. ThrowParseException ("You gotta specify Src or Name");
  102. if (name != null && src != null)
  103. ThrowParseException ("Src and Name cannot be used together");
  104. if (name != null) {
  105. AddAssemblyByName (name);
  106. } else {
  107. GetAssemblyFromSource (src);
  108. }
  109. return;
  110. }
  111. cmp = String.Compare ("Import", directive, true);
  112. if (cmp == 0) {
  113. string namesp = GetString (atts, "Namespace", null);
  114. if (atts.Count > 0)
  115. ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
  116. if (namesp != null && namesp != "")
  117. AddImport (namesp);
  118. return;
  119. }
  120. cmp = String.Compare ("Implements", directive, true);
  121. if (cmp == 0) {
  122. string ifacename = GetString (atts, "Interface", "");
  123. if (atts.Count > 0)
  124. ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
  125. Type iface = LoadType (ifacename);
  126. if (iface == null)
  127. ThrowParseException ("Cannot find type " + ifacename);
  128. if (!iface.IsInterface)
  129. ThrowParseException (iface + " is not an interface");
  130. AddInterface (iface.FullName);
  131. return;
  132. }
  133. cmp = String.Compare ("OutputCache", directive, true);
  134. if (cmp == 0) {
  135. output_cache = true;
  136. if (atts ["Duration"] == null)
  137. ThrowParseException ("The directive is missing a 'duration' attribute.");
  138. if (atts ["VaryByParam"] == null)
  139. ThrowParseException ("This directive is missing a 'VaryByParam' " +
  140. "attribute, which should be set to \"none\", \"*\", " +
  141. "or a list of name/value pairs.");
  142. foreach (DictionaryEntry entry in atts) {
  143. string key = (string) entry.Key;
  144. switch (key.ToLower ()) {
  145. case "duration":
  146. oc_duration = Int32.Parse ((string) entry.Value);
  147. if (oc_duration < 1)
  148. ThrowParseException ("The 'duration' attribute must be set " +
  149. "to a positive integer value");
  150. break;
  151. case "varybyparam":
  152. oc_param = (string) entry.Value;
  153. if (String.Compare (oc_param, "none") == 0)
  154. oc_param = null;
  155. break;
  156. case "varybyheader":
  157. oc_header = (string) entry.Value;
  158. break;
  159. case "varybycustom":
  160. oc_custom = (string) entry.Value;
  161. break;
  162. case "location":
  163. if (!(this is PageParser))
  164. goto default;
  165. try {
  166. oc_location = (OutputCacheLocation) Enum.Parse (
  167. typeof (OutputCacheLocation), (string) entry.Value, true);
  168. } catch {
  169. ThrowParseException ("The 'location' attribute is case sensitive and " +
  170. "must be one of the following values: Any, Client, " +
  171. "Downstream, Server, None, ServerAndClient.");
  172. }
  173. break;
  174. case "varybycontrol":
  175. if (this is PageParser)
  176. goto default;
  177. oc_controls = (string) entry.Value;
  178. break;
  179. case "shared":
  180. if (this is PageParser)
  181. goto default;
  182. try {
  183. oc_shared = Boolean.Parse ((string) entry.Value);
  184. } catch {
  185. ThrowParseException ("The 'shared' attribute is case sensitive" +
  186. " and must be set to 'true' or 'false'.");
  187. }
  188. break;
  189. default:
  190. ThrowParseException ("The '" + key + "' attribute is not " +
  191. "supported by the 'Outputcache' directive.");
  192. break;
  193. }
  194. }
  195. return;
  196. }
  197. ThrowParseException ("Unknown directive: " + directive);
  198. }
  199. internal Type LoadType (string typeName)
  200. {
  201. // First try loaded assemblies, then try assemblies in Bin directory.
  202. Type type = null;
  203. bool seenBin = false;
  204. Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
  205. foreach (Assembly ass in assemblies) {
  206. type = ass.GetType (typeName);
  207. if (type == null)
  208. continue;
  209. if (Path.GetDirectoryName (ass.Location) != PrivateBinPath) {
  210. AddAssembly (ass, false);
  211. } else {
  212. seenBin = true;
  213. }
  214. AddDependency (ass.Location);
  215. return type;
  216. }
  217. if (seenBin)
  218. return null;
  219. // Load from bin
  220. string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
  221. foreach (string s in binDlls) {
  222. Assembly binA = Assembly.LoadFrom (s);
  223. type = binA.GetType (typeName);
  224. if (type == null)
  225. continue;
  226. AddDependency (binA.Location);
  227. return type;
  228. }
  229. return null;
  230. }
  231. void AddAssembliesInBin ()
  232. {
  233. if (!Directory.Exists (PrivateBinPath))
  234. return;
  235. string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
  236. foreach (string s in binDlls) {
  237. assemblies.Add (s);
  238. }
  239. }
  240. internal virtual void AddInterface (string iface)
  241. {
  242. if (interfaces == null)
  243. interfaces = new ArrayList ();
  244. if (!interfaces.Contains (iface))
  245. interfaces.Add (iface);
  246. }
  247. internal virtual void AddImport (string namesp)
  248. {
  249. if (imports == null)
  250. imports = new ArrayList ();
  251. if (!imports.Contains (namesp))
  252. imports.Add (namesp);
  253. }
  254. internal virtual void AddDependency (string filename)
  255. {
  256. if (dependencies == null)
  257. dependencies = new ArrayList ();
  258. if (!dependencies.Contains (filename))
  259. dependencies.Add (filename);
  260. }
  261. internal virtual void AddAssembly (Assembly assembly, bool fullPath)
  262. {
  263. if (anames == null)
  264. anames = new Hashtable ();
  265. string name = assembly.GetName ().Name;
  266. string loc = assembly.Location;
  267. if (fullPath) {
  268. if (!assemblies.Contains (loc)) {
  269. assemblies.Add (loc);
  270. }
  271. anames [name] = loc;
  272. anames [loc] = assembly;
  273. } else {
  274. if (!assemblies.Contains (name)) {
  275. assemblies.Add (name);
  276. }
  277. anames [name] = assembly;
  278. }
  279. }
  280. internal virtual Assembly AddAssemblyByName (string name)
  281. {
  282. if (anames == null)
  283. anames = new Hashtable ();
  284. if (anames.Contains (name)) {
  285. object o = anames [name];
  286. if (o is string)
  287. o = anames [o];
  288. return (Assembly) o;
  289. }
  290. bool fullpath = false;
  291. Assembly assembly = null;
  292. try {
  293. assembly = Assembly.LoadWithPartialName (name);
  294. string loc = assembly.Location;
  295. fullpath = (Path.GetDirectoryName (loc) == PrivateBinPath);
  296. } catch (Exception e) {
  297. ThrowParseException ("Assembly " + name + " not found", e);
  298. }
  299. AddAssembly (assembly, fullpath);
  300. return assembly;
  301. }
  302. internal virtual void ProcessMainAttributes (Hashtable atts)
  303. {
  304. atts.Remove ("Description"); // ignored
  305. atts.Remove ("CodeBehind"); // ignored
  306. atts.Remove ("AspCompat"); // ignored
  307. debug = GetBool (atts, "Debug", true);
  308. compilerOptions = GetString (atts, "CompilerOptions", "");
  309. language = GetString (atts, "Language", CompilationConfig.DefaultLanguage);
  310. string src = GetString (atts, "Src", null);
  311. if (src != null)
  312. srcAssembly = GetAssemblyFromSource (src);
  313. string inherits = GetString (atts, "Inherits", null);
  314. if (inherits != null)
  315. SetBaseType (inherits);
  316. className = GetString (atts, "ClassName", null);
  317. if (className != null && !CodeGenerator.IsValidLanguageIndependentIdentifier (className))
  318. ThrowParseException (String.Format ("'{0}' is not valid for 'className'", className));
  319. if (atts.Count > 0)
  320. ThrowParseException ("Unknown attribute: " + GetOneKey (atts));
  321. }
  322. internal void SetBaseType (string type)
  323. {
  324. if (type == DefaultBaseTypeName)
  325. return;
  326. Type parent = null;
  327. if (srcAssembly != null)
  328. parent = srcAssembly.GetType (type);
  329. if (parent == null)
  330. parent = LoadType (type);
  331. if (parent == null)
  332. ThrowParseException ("Cannot find type " + type);
  333. if (!DefaultBaseType.IsAssignableFrom (parent))
  334. ThrowParseException ("The parent type does not derive from " + DefaultBaseType);
  335. baseType = parent;
  336. }
  337. Assembly GetAssemblyFromSource (string vpath)
  338. {
  339. vpath = UrlUtils.Combine (BaseVirtualDir, vpath);
  340. string realPath = MapPath (vpath, false);
  341. if (!File.Exists (realPath))
  342. ThrowParseException ("File " + vpath + " not found");
  343. AddDependency (realPath);
  344. CompilerResults result = CachingCompiler.Compile (language, realPath, realPath, assemblies);
  345. if (result.NativeCompilerReturnValue != 0) {
  346. StringWriter writer = new StringWriter();
  347. StreamReader reader = new StreamReader (realPath);
  348. throw new CompilationException (realPath, result.Errors, reader.ReadToEnd ());
  349. }
  350. AddAssembly (result.CompiledAssembly, true);
  351. return result.CompiledAssembly;
  352. }
  353. internal abstract Type DefaultBaseType { get; }
  354. internal abstract string DefaultBaseTypeName { get; }
  355. internal abstract string DefaultDirectiveName { get; }
  356. internal string InputFile
  357. {
  358. get { return inputFile; }
  359. set { inputFile = value; }
  360. }
  361. internal string Text
  362. {
  363. get { return text; }
  364. set { text = value; }
  365. }
  366. internal Type BaseType
  367. {
  368. get {
  369. if (baseType == null)
  370. baseType = DefaultBaseType;
  371. return baseType;
  372. }
  373. }
  374. internal string ClassName {
  375. get {
  376. if (className != null)
  377. return className;
  378. className = Path.GetFileName (inputFile).Replace ('.', '_');
  379. className = className.Replace ('-', '_');
  380. className = className.Replace (' ', '_');
  381. if (Char.IsDigit(className[0])) {
  382. className = "_" + className;
  383. }
  384. return className;
  385. }
  386. }
  387. internal string PrivateBinPath {
  388. get {
  389. if (privateBinPath != null)
  390. return privateBinPath;
  391. AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
  392. privateBinPath = Path.Combine (setup.ApplicationBase, setup.PrivateBinPath);
  393. return privateBinPath;
  394. }
  395. }
  396. internal ArrayList Scripts {
  397. get {
  398. if (scripts == null)
  399. scripts = new ArrayList ();
  400. return scripts;
  401. }
  402. }
  403. internal ArrayList Imports {
  404. get { return imports; }
  405. }
  406. internal ArrayList Assemblies {
  407. get {
  408. if (appAssemblyIndex != -1) {
  409. object o = assemblies [appAssemblyIndex];
  410. assemblies.RemoveAt (appAssemblyIndex);
  411. assemblies.Add (o);
  412. appAssemblyIndex = -1;
  413. }
  414. return assemblies;
  415. }
  416. }
  417. internal ArrayList Interfaces {
  418. get { return interfaces; }
  419. }
  420. internal RootBuilder RootBuilder {
  421. get { return rootBuilder; }
  422. set { rootBuilder = value; }
  423. }
  424. internal ArrayList Dependencies {
  425. get { return dependencies; }
  426. }
  427. internal string CompilerOptions {
  428. get { return compilerOptions; }
  429. }
  430. internal string Language {
  431. get { return language; }
  432. }
  433. internal bool Debug {
  434. get { return debug; }
  435. }
  436. internal bool OutputCache {
  437. get { return output_cache; }
  438. }
  439. internal int OutputCacheDuration {
  440. get { return oc_duration; }
  441. }
  442. internal string OutputCacheVaryByHeader {
  443. get { return oc_header; }
  444. }
  445. internal string OutputCacheVaryByCustom {
  446. get { return oc_custom; }
  447. }
  448. internal string OutputCacheVaryByControls {
  449. get { return oc_controls; }
  450. }
  451. internal bool OutputCacheShared {
  452. get { return oc_shared; }
  453. }
  454. internal OutputCacheLocation OutputCacheLocation {
  455. get { return oc_location; }
  456. }
  457. internal string OutputCacheVaryByParam {
  458. get { return oc_param; }
  459. }
  460. internal PagesConfiguration PagesConfig {
  461. get { return PagesConfiguration.GetInstance (Context); }
  462. }
  463. }
  464. }