2009-02-28 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.UI / SimpleWebHandlerParser.cs
index 8555938cc7c7d4264a52011383946426f523227f..24fc0bd89f61c6a54e3570012b3eddbb9b6bf417 100644 (file)
@@ -55,27 +55,50 @@ namespace System.Web.UI
                ArrayList assemblies;
                ArrayList dependencies;
                Hashtable anames;
-               string privateBinPath;
                string baseDir;
                string baseVDir;
 #if !NET_2_0
                CompilationConfiguration compilationConfig;
-#else
+#endif
+
+#if NET_2_0
                TextReader reader;
 #endif
+               
                int appAssemblyIndex = -1;
                Type cachedType;
 
                protected SimpleWebHandlerParser (HttpContext context, string virtualPath, string physicalPath)
+               : this (context, virtualPath, physicalPath, null)
+               {}
+               
+               internal SimpleWebHandlerParser (HttpContext context, string virtualPath, string physicalPath, TextReader reader)
                {
+#if NET_2_0
+                       this.reader = reader;
+#endif
                        cachedType = CachingCompiler.GetTypeFromCache (physicalPath);
                        if (cachedType != null)
                                return; // We don't need anything else.
 
-                       this.context = context;
+                       // context is obsolete in 2.0+ - MSDN recommends passing null, so we need to
+                       // take that into account
+                       if (context != null)
+                               this.context = context;
+                       else
+                               this.context = HttpContext.Current;
+                       
                        this.vPath = virtualPath;
-                       this.physPath = physicalPath;
-                       AddDependency (physicalPath);
+                       AddDependency (virtualPath);
+                       
+                       // physicalPath is obsolete in 2.0+ - same note what for context applies here
+                       if (physicalPath != null && physicalPath.Length > 0)
+                               this.physPath = physicalPath;
+                       else {
+                               HttpRequest req = this.context != null ? context.Request : null;
+                               if (req != null)
+                                       this.physPath = req.MapPath (virtualPath);
+                       }
 
                        assemblies = new ArrayList ();
                        string location = Context.ApplicationInstance.AssemblyLocation;
@@ -102,13 +125,6 @@ namespace System.Web.UI
 
                        GetDirectivesAndContent ();
                }
-#if NET_2_0
-               internal SimpleWebHandlerParser (HttpContext context, string virtualPath, string physicalPath, TextReader reader)
-                       : this (context, virtualPath, physicalPath)
-               {
-                       this.reader = reader;
-               }
-#endif
 
                protected Type GetCompiledTypeFromCache ()
                {
@@ -117,32 +133,84 @@ namespace System.Web.UI
 
                void GetDirectivesAndContent ()
                {
-                       StreamReader reader = new StreamReader (File.OpenRead (physPath));
                        string line;
                        bool directiveFound = false;
+                       bool inDirective = false;
+                       StringBuilder directive = null;
                        StringBuilder content = new StringBuilder ();
+                       int idxStart, idxEnd, length;
+                       StreamReader sr;
 
-                       while ((line = reader.ReadLine ()) != null && cachedType == null) {
-                               string trimmed = line.Trim ();
-                               if (!directiveFound && trimmed == String.Empty)
-                                       continue;
-                               
-                               if (trimmed.StartsWith ("<")) {
-                                       ParseDirective (trimmed);
-                                       directiveFound = true;
-                                       if (gotDefault) {
-                                               cachedType = CachingCompiler.GetTypeFromCache (physPath);
-                                               if (cachedType != null)
-                                                       break;
+#if NET_2_0
+                       if (reader != null)
+                               sr = reader as StreamReader;
+                       else
+#endif
+                               sr = new StreamReader (File.OpenRead (physPath), WebEncoding.FileEncoding);
+                       
+                       using (sr) {
+                               while ((line = sr.ReadLine ()) != null && cachedType == null) {
+                                       length = line.Length;
+                                       if (length == 0) {
+                                               content.Append ("\n");
+                                               continue;
+                                       }
+                                       
+                                       idxStart = line.IndexOf ("<%");
+                                       if (idxStart > -1) {
+                                               idxEnd = line.IndexOf ("%>");                                           
+                                               if (idxStart > 0)
+                                                       content.Append (line.Substring (0, idxStart));
+
+                                               if (directive == null)
+                                                       directive = new StringBuilder ();
+                                               else
+                                                       directive.Length = 0;
+                                               
+                                               if (idxEnd > -1) {
+                                                       directiveFound = true;
+                                                       inDirective = false;
+                                                       directive.Append (line.Substring (idxStart, idxEnd - idxStart + 2));
+                                                       if (idxEnd < length - 2)
+                                                               content.Append (line.Substring (idxEnd + 2, length - idxEnd - 2));
+                                               } else {
+                                                       inDirective = true;
+                                                       directiveFound = false;
+                                                       directive.Append (line.Substring (idxStart));
+                                                       continue;
+                                               }
                                        }
 
-                                       continue;
-                               }
+                                       if (inDirective) {
+                                               int idx = line.IndexOf ("%>");
+                                               if (idx > -1) {
+                                                       directive.Append (line.Substring (0, idx + 2));
+                                                       if (idx < length)
+                                                               content.Append (line.Substring (idx + 2) + "\n");
+                                                       inDirective = false;
+                                                       directiveFound = true;
+                                               } else {
+                                                       directive.Append (line);
+                                                       continue;
+                                               }
+                                       }
+                                       
+                                       if (directiveFound) {
+                                               ParseDirective (directive.ToString ());
+                                               directiveFound = false;
+                                               if (gotDefault) {
+                                                       cachedType = CachingCompiler.GetTypeFromCache (physPath);
+                                                       if (cachedType != null)
+                                                               break;
+                                               }
+
+                                               continue;
+                                       }
 
-                               content.Append (line + "\n");
-                               content.Append (reader.ReadToEnd ());
+                                       content.Append (line + "\n");
+                               }
+                               directive = null;
                        }
-                       reader.Close ();
 
                        if (!gotDefault)
                                throw new ParseException (null, "No @" + DefaultDirectiveName +
@@ -157,7 +225,7 @@ namespace System.Web.UI
                        if (tagtype != System.Web.Compilation.TagType.Directive)
                                throw new ParseException (location, "Unexpected tag");
 
-                       if (String.Compare (tagid, DefaultDirectiveName, true) == 0) {
+                       if (tagid == null || tagid.Length == 0 || String.Compare (tagid, DefaultDirectiveName, true) == 0) {
                                AddDefaultDirective (location, attributes);
                        } else if (String.Compare (tagid, "Assembly", true) == 0) {
                                AddAssemblyDirective (location, attributes);
@@ -186,7 +254,12 @@ namespace System.Web.UI
                
                void ParseDirective (string line)
                {
-                       AspParser parser = new AspParser (physPath, new StringReader (line));
+                       AspParser parser;
+
+                       using (StringReader input = new StringReader (line)) {
+                               parser = new AspParser (physPath, input);
+                       }
+                       
                        parser.Error += new ParseErrorHandler (ParseError);
                        parser.TagParsed += new TagParsedHandler (TagParsed);
                        parser.TextParsed += new TextParsedHandler (TextParsed);
@@ -196,6 +269,13 @@ namespace System.Web.UI
 
                internal virtual void AddDefaultDirective (ILocation location, TagAttributes attrs)
                {
+#if NET_2_0
+                       CompilationSection compConfig;
+#else
+                       CompilationConfiguration compConfig;
+#endif
+                       compConfig = CompilationConfig;
+                       
                        if (gotDefault)
                                throw new ParseException (location, "duplicate " + DefaultDirectiveName + " directive");
 
@@ -210,11 +290,12 @@ namespace System.Web.UI
                                debug = (String.Compare (d, "true", true) == 0);
                                if (debug == false && String.Compare (d, "false", true) != 0)
                                        throw new ParseException (null, "Invalid value for Debug attribute");
-                       }
+                       } else
+                               debug = compConfig.Debug;
 
                        language = GetAndRemove (attributes, "language");
                        if (language == null)
-                               language = CompilationConfig.DefaultLanguage;
+                               language = compConfig.DefaultLanguage;
 
                        GetAndRemove (attributes, "codebehind");
                        if (attributes.Count > 0)
@@ -245,6 +326,9 @@ namespace System.Web.UI
 
                internal virtual void AddAssembly (Assembly assembly, bool fullPath)
                {
+                       if (assembly == null)
+                               throw new ArgumentNullException ("assembly");
+                       
                        if (anames == null)
                                anames = new Hashtable ();
 
@@ -285,40 +369,37 @@ namespace System.Web.UI
                                return assembly;
                        }
 
+                       Exception ex = null;
                        try {
                                assembly = Assembly.LoadWithPartialName (name);
                        } catch (Exception e) {
-                               throw new ParseException (location, "Assembly " + name + " not found", e);
+                               ex = e;
+                               assembly = null;
                        }
 
+                       if (assembly == null)
+                               throw new ParseException (location, String.Format ("Assembly '{0}' not found", name), ex);
+                       
                        AddAssembly (assembly, true);
                        return assembly;
                }
 
                void AddAssembliesInBin ()
                {
-                       if (!Directory.Exists (PrivateBinPath))
-                               return;
-
-                       string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
-                       foreach (string dll in binDlls) {
+                       foreach (string s in HttpApplication.BinDirectoryAssemblies) {
                                try {
-                                       Assembly assembly = Assembly.LoadFrom (dll);
+                                       Assembly assembly = Assembly.LoadFrom (s);
                                        AddAssembly (assembly, true);
                                } catch (Exception e) {
-                                       throw new Exception ("Error while loading " + dll, e);
+                                       throw new Exception ("Error while loading " + s, e);
                                }
                        }
                }
 
                Assembly LoadAssemblyFromBin (string name)
                {
-                       Assembly assembly;
-                       if (!Directory.Exists (PrivateBinPath))
-                               return null;
-
-                       string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
-                       foreach (string dll in binDlls) {
+                       Assembly assembly = null;
+                       foreach (string dll in HttpApplication.BinDirectoryAssemblies) {
                                string fn = Path.GetFileName (dll);
                                fn = Path.ChangeExtension (fn, null);
                                if (fn != name)
@@ -327,7 +408,7 @@ namespace System.Web.UI
                                assembly = Assembly.LoadFrom (dll);
                                return assembly;
                        }
-
+                       
                        return null;
                }
 
@@ -338,36 +419,73 @@ namespace System.Web.UI
                        if (!File.Exists (realPath))
                                throw new ParseException (location, "File " + vpath + " not found");
 
-                       AddDependency (realPath);
+                       AddDependency (vpath);
 
                        CompilerResults result = CachingCompiler.Compile (language, realPath, realPath, assemblies);
                        if (result.NativeCompilerReturnValue != 0) {
-                               StreamReader reader = new StreamReader (realPath);
-                               throw new CompilationException (realPath, result.Errors, reader.ReadToEnd ());
+                               using (StreamReader sr = new StreamReader (realPath)) {
+                                       throw new CompilationException (realPath, result.Errors, sr.ReadToEnd ());
+                               }
                        }
 
                        AddAssembly (result.CompiledAssembly, true);
                        return result.CompiledAssembly;
                }
                
-               internal Type GetTypeFromBin (string typeName)
+               internal Type GetTypeFromBin (string tname)
                {
-                       if (!Directory.Exists (PrivateBinPath))
-                               throw new HttpException (String.Format ("Type {0} not found.", typeName));
-
-                       string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
+                       if (tname == null || tname.Length == 0)
+                               throw new ArgumentNullException ("tname");
+                       
                        Type result = null;
-                       foreach (string dll in binDlls) {
-                               Assembly assembly = Assembly.LoadFrom (dll);
-                               Type type = assembly.GetType (typeName, false);
+                       string typeName;
+                       string assemblyName;
+                       int comma = tname.IndexOf (',');
+                       
+                       if (comma != -1) {
+                               typeName = tname.Substring (0, comma).Trim ();
+                               assemblyName = tname.Substring (comma + 1).Trim ();
+                       } else {
+                               typeName = tname;
+                               assemblyName = null;
+                       }
+
+                       Type type = null;
+                       Assembly assembly = null;
+                       if (assemblyName != null) {
+                               assembly = Assembly.Load (assemblyName);
+                               if (assembly != null)
+                                       type = assembly.GetType (typeName, false);
+                               if (type != null)
+                                       return type;
+                       }
+                       
+#if NET_2_0
+                       IList toplevelAssemblies = BuildManager.TopLevelAssemblies;
+                       if (toplevelAssemblies != null && toplevelAssemblies.Count > 0) {
+                               foreach (Assembly asm in toplevelAssemblies) {
+                                       type = asm.GetType (typeName, false);
+                                       if (type != null) {
+                                               if (result != null)
+                                                       throw new HttpException (String.Format ("Type {0} is not unique.", typeName));
+                                               result = type;
+                                       }
+                               }
+                       }
+#endif
+
+                       foreach (string dll in HttpApplication.BinDirectoryAssemblies) {
+                               assembly = Assembly.LoadFrom (dll);
+                               type = assembly.GetType (typeName, false);
                                if (type != null) {
                                        if (result != null) 
                                                throw new HttpException (String.Format ("Type {0} is not unique.", typeName));
-
+                                               
                                        result = type;
-                               } 
+                               }
                        }
 
+                       
                        if (result == null)
                                throw new HttpException (String.Format ("Type {0} not found.", typeName));
 
@@ -411,7 +529,12 @@ namespace System.Web.UI
                }
 
                internal string Program {
-                       get { return program; }
+                       get {
+                               if (program != null)
+                                       return program;
+
+                               return String.Empty;
+                       }
                }
 
                internal ArrayList Assemblies {
@@ -431,28 +554,6 @@ namespace System.Web.UI
                        get { return dependencies; }
                }
 
-               internal string PrivateBinPath {
-                       get {
-                               if (privateBinPath != null)
-                                       return privateBinPath;
-
-                               AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
-                               privateBinPath = setup.PrivateBinPath;
-                                       
-                               if (!Path.IsPathRooted (privateBinPath)) {
-                                       string appbase = setup.ApplicationBase;
-                                       if (appbase.StartsWith ("file://")) {
-                                               appbase = appbase.Substring (7);
-                                               if (Path.DirectorySeparatorChar != '/')
-                                                       appbase = appbase.Replace ('/', Path.DirectorySeparatorChar);
-                                       }
-                                       privateBinPath = Path.Combine (appbase, privateBinPath);
-                               }
-
-                               return privateBinPath;
-                       }
-               }
-
                internal string BaseDir {
                        get {
                                if (baseDir == null)