SimpleWebHandlerParser.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. //
  2. // System.Web.UI.SimpleWebHandlerParser
  3. //
  4. // Authors:
  5. // Gonzalo Paniagua Javier ([email protected])
  6. //
  7. // (C) 2002,2003 Ximian, Inc (http://www.ximian.com)
  8. //
  9. using System;
  10. using System.CodeDom.Compiler;
  11. using System.Collections;
  12. using System.IO;
  13. using System.Reflection;
  14. using System.Text;
  15. using System.Web;
  16. using System.Web.Compilation;
  17. using System.Web.Util;
  18. using TagType = System.Web.Compilation.TagType;
  19. namespace System.Web.UI
  20. {
  21. public abstract class SimpleWebHandlerParser
  22. {
  23. HttpContext context;
  24. string vPath;
  25. string physPath;
  26. string className;
  27. string codeBehind;
  28. bool debug;
  29. string language;
  30. string program;
  31. bool gotDefault;
  32. ArrayList assemblies;
  33. ArrayList dependencies;
  34. Hashtable anames;
  35. string privateBinPath;
  36. string baseDir;
  37. string baseVDir;
  38. protected SimpleWebHandlerParser (HttpContext context, string virtualPath, string physicalPath)
  39. {
  40. this.context = context;
  41. this.vPath = virtualPath;
  42. this.physPath = physicalPath;
  43. assemblies = new ArrayList ();
  44. assemblies.Add ("System.dll");
  45. assemblies.Add ("System.Drawing.dll");
  46. assemblies.Add ("System.Data.dll");
  47. assemblies.Add ("System.Web.dll");
  48. assemblies.Add ("System.Web.Services.dll");
  49. assemblies.Add ("System.Xml.dll");
  50. AddAssembliesInBin ();
  51. GetDirectivesAndContent ();
  52. }
  53. void GetDirectivesAndContent ()
  54. {
  55. StreamReader reader = new StreamReader (File.OpenRead (physPath));
  56. string line;
  57. bool directiveFound = false;
  58. StringBuilder content = new StringBuilder ();
  59. while ((line = reader.ReadLine ()) != null) {
  60. string trimmed = line.Trim ();
  61. if (!directiveFound && trimmed == String.Empty)
  62. continue;
  63. if (trimmed.StartsWith ("<")) {
  64. ParseDirective (trimmed);
  65. directiveFound = true;
  66. continue;
  67. }
  68. content.Append (line + "\n");
  69. content.Append (reader.ReadToEnd ());
  70. }
  71. if (!gotDefault)
  72. throw new ParseException (null, "No @WebService directive found");
  73. this.program = content.ToString ();
  74. reader.Close ();
  75. }
  76. void TagParsed (ILocation location, TagType tagtype, string tagid, TagAttributes attributes)
  77. {
  78. if (tagtype != TagType.Directive)
  79. throw new ParseException (location, "Unexpected tag");
  80. if (String.Compare (tagid, DefaultDirectiveName, true) == 0) {
  81. AddDefaultDirective (location, attributes);
  82. } else if (String.Compare (tagid, "Assembly", true) == 0) {
  83. AddAssemblyDirective (location, attributes);
  84. } else {
  85. throw new ParseException (location, "Unexpected directive: " + tagid);
  86. }
  87. }
  88. void TextParsed (ILocation location, string text)
  89. {
  90. if (text.Trim () != "")
  91. throw new ParseException (location, "Text not allowed here");
  92. }
  93. void ParseError (ILocation location, string message)
  94. {
  95. throw new ParseException (location, message);
  96. }
  97. static string GetAndRemove (Hashtable table, string key)
  98. {
  99. string o = table [key] as string;
  100. table.Remove (key);
  101. return o;
  102. }
  103. void ParseDirective (string line)
  104. {
  105. AspParser parser = new AspParser (physPath, new StringReader (line));
  106. parser.Error += new ParseErrorHandler (ParseError);
  107. parser.TagParsed += new TagParsedHandler (TagParsed);
  108. parser.TextParsed += new TextParsedHandler (TextParsed);
  109. parser.Parse ();
  110. }
  111. internal virtual void AddDefaultDirective (ILocation location, TagAttributes attrs)
  112. {
  113. if (gotDefault)
  114. throw new ParseException (location, "duplicate " + DefaultDirectiveName + " directive");
  115. gotDefault = true;
  116. Hashtable attributes = attrs.GetDictionary (null);
  117. className = GetAndRemove (attributes, "class");
  118. if (className == null)
  119. throw new ParseException (null, "No Class attribute found.");
  120. string d = GetAndRemove (attributes, "debug");
  121. if (d != null) {
  122. debug = (String.Compare (d, "true", true) == 0);
  123. if (debug == false && String.Compare (d, "false", true) != 0)
  124. throw new ParseException (null, "Invalid value for Debug attribute");
  125. }
  126. language = GetAndRemove (attributes, "language");
  127. if (language != null) {
  128. if (0 != String.Compare (language, "C#", true))
  129. throw new ParseException (null, "Only C# language is supported by now.");
  130. }
  131. codeBehind = GetAndRemove (attributes, "codebehind");
  132. if (attributes.Count > 0)
  133. throw new ParseException (location, "Unrecognized attribute in " +
  134. DefaultDirectiveName + " directive");
  135. }
  136. internal virtual void AddAssemblyDirective (ILocation location, TagAttributes attrs)
  137. {
  138. Hashtable tbl = attrs.GetDictionary (null);
  139. string name = GetAndRemove (tbl, "Name");
  140. string src = GetAndRemove (tbl, "Src");
  141. if (name == null && src == null)
  142. throw new ParseException (location, "You gotta specify Src or Name");
  143. if (name != null && src != null)
  144. throw new ParseException (location, "Src and Name cannot be used together");
  145. if (name != null) {
  146. AddAssemblyByName (name, location);
  147. } else {
  148. GetAssemblyFromSource (src, location);
  149. }
  150. if (tbl.Count > 0)
  151. throw new ParseException (location, "Unrecognized attribute in Assembly directive");
  152. }
  153. internal virtual void AddAssembly (Assembly assembly, bool fullPath)
  154. {
  155. if (anames == null)
  156. anames = new Hashtable ();
  157. string name = assembly.GetName ().Name;
  158. string loc = assembly.Location;
  159. if (fullPath) {
  160. if (!assemblies.Contains (loc)) {
  161. assemblies.Add (loc);
  162. }
  163. anames [name] = loc;
  164. anames [loc] = assembly;
  165. } else {
  166. if (!assemblies.Contains (name)) {
  167. assemblies.Add (name);
  168. }
  169. anames [name] = assembly;
  170. }
  171. }
  172. internal virtual Assembly AddAssemblyByName (string name, ILocation location)
  173. {
  174. if (anames == null)
  175. anames = new Hashtable ();
  176. if (anames.Contains (name)) {
  177. object o = anames [name];
  178. if (o is string)
  179. o = anames [o];
  180. return (Assembly) o;
  181. }
  182. bool fullpath = true;
  183. Assembly assembly = LoadAssemblyFromBin (name);
  184. if (assembly != null) {
  185. AddAssembly (assembly, fullpath);
  186. return assembly;
  187. }
  188. try {
  189. assembly = Assembly.Load (name);
  190. string loc = assembly.Location;
  191. fullpath = (Path.GetDirectoryName (loc) == PrivateBinPath);
  192. } catch (Exception e) {
  193. throw new ParseException (location, "Assembly " + name + " not found", e);
  194. }
  195. AddAssembly (assembly, fullpath);
  196. return assembly;
  197. }
  198. void AddAssembliesInBin ()
  199. {
  200. if (!Directory.Exists (PrivateBinPath))
  201. return;
  202. string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
  203. foreach (string dll in binDlls) {
  204. Assembly assembly = Assembly.LoadFrom (dll);
  205. AddAssembly (assembly, true);
  206. }
  207. }
  208. Assembly LoadAssemblyFromBin (string name)
  209. {
  210. Assembly assembly;
  211. if (!Directory.Exists (PrivateBinPath))
  212. return null;
  213. string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
  214. foreach (string dll in binDlls) {
  215. string fn = Path.GetFileName (dll);
  216. fn = Path.ChangeExtension (fn, null);
  217. if (fn != name)
  218. continue;
  219. assembly = Assembly.LoadFrom (dll);
  220. return assembly;
  221. }
  222. return null;
  223. }
  224. Assembly GetAssemblyFromSource (string vpath, ILocation location)
  225. {
  226. vpath = UrlUtils.Combine (BaseVirtualDir, vpath);
  227. string realPath = context.Request.MapPath (vpath);
  228. if (!File.Exists (realPath))
  229. throw new ParseException (location, "File " + vpath + " not found");
  230. AddDependency (realPath);
  231. CompilerResults result = CachingCompiler.Compile (realPath, realPath, assemblies);
  232. if (result.NativeCompilerReturnValue != 0) {
  233. StreamReader reader = new StreamReader (realPath);
  234. throw new CompilationException (realPath, result.Errors, reader.ReadToEnd ());
  235. }
  236. AddAssembly (result.CompiledAssembly, true);
  237. return result.CompiledAssembly;
  238. }
  239. internal Type GetTypeFromBin (string typeName)
  240. {
  241. if (!Directory.Exists (PrivateBinPath))
  242. throw new HttpException (String.Format ("Type {0} not found.", typeName));
  243. string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
  244. Type result = null;
  245. foreach (string dll in binDlls) {
  246. Assembly assembly = Assembly.LoadFrom (dll);
  247. Type type = assembly.GetType (typeName, false);
  248. if (type != null) {
  249. if (result != null)
  250. throw new HttpException (String.Format ("Type {0} is not unique.", typeName));
  251. result = type;
  252. }
  253. }
  254. if (result == null)
  255. throw new HttpException (String.Format ("Type {0} not found.", typeName));
  256. return result;
  257. }
  258. internal virtual void AddDependency (string filename)
  259. {
  260. if (dependencies == null)
  261. dependencies = new ArrayList ();
  262. if (!dependencies.Contains (filename))
  263. dependencies.Add (filename);
  264. }
  265. // Properties
  266. protected abstract string DefaultDirectiveName { get; }
  267. internal HttpContext Context {
  268. get { return context; }
  269. }
  270. internal string VirtualPath {
  271. get { return vPath; }
  272. }
  273. internal string PhysicalPath {
  274. get { return physPath; }
  275. }
  276. internal string ClassName {
  277. get { return className; }
  278. }
  279. internal string CodeBehind {
  280. get { return codeBehind; }
  281. }
  282. internal bool Debug {
  283. get { return debug; }
  284. }
  285. internal string Language {
  286. get { return language; }
  287. }
  288. internal string Program {
  289. get { return program; }
  290. }
  291. internal ArrayList Assemblies {
  292. get { return assemblies; }
  293. }
  294. internal ArrayList Dependencies {
  295. get { return dependencies; }
  296. }
  297. internal string PrivateBinPath {
  298. get {
  299. if (privateBinPath != null)
  300. return privateBinPath;
  301. AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
  302. privateBinPath = setup.PrivateBinPath;
  303. if (!Path.IsPathRooted (privateBinPath)) {
  304. string appbase = setup.ApplicationBase;
  305. if (appbase.StartsWith ("file://")) {
  306. appbase = appbase.Substring (7);
  307. if (Path.DirectorySeparatorChar != '/')
  308. appbase = appbase.Replace ('/', Path.DirectorySeparatorChar);
  309. }
  310. privateBinPath = Path.Combine (appbase, privateBinPath);
  311. }
  312. return privateBinPath;
  313. }
  314. }
  315. internal string BaseDir {
  316. get {
  317. if (baseDir == null)
  318. baseDir = context.Request.MapPath (BaseVirtualDir);
  319. return baseDir;
  320. }
  321. }
  322. internal virtual string BaseVirtualDir {
  323. get {
  324. if (baseVDir == null)
  325. baseVDir = UrlUtils.GetDirectory (context.Request.FilePath);
  326. return baseVDir;
  327. }
  328. }
  329. }
  330. }