SimpleWebHandlerParser.cs 10 KB

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