2008-04-19 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.Compilation / AspGenerator.cs
index 9f03358c23d99c55658c1a306d72e36ad131ba89..2742a8614feaa70acfe283c8d461817fe9f233bd 100644 (file)
@@ -36,6 +36,7 @@ using System.IO;
 using System.Text;
 using System.Web.Caching;
 using System.Web.Configuration;
+using System.Web.Hosting;
 using System.Web.UI;
 using System.Web.UI.HtmlControls;
 using System.Web.Util;
@@ -231,23 +232,47 @@ namespace System.Web.Compilation
 
                        throw new Exception ("Got type: " + type);
                }
-               
-               void InitParser (string filename)
+
+               void InitParser (TextReader reader, string filename)
                {
-                       StreamReader reader = new StreamReader (filename, WebEncoding.FileEncoding);
                        AspParser parser = new AspParser (filename, reader);
-                       reader.Close ();
+                       ((IDisposable)reader).Dispose ();
                        parser.Error += new ParseErrorHandler (ParseError);
                        parser.TagParsed += new TagParsedHandler (TagParsed);
                        parser.TextParsed += new TextParsedHandler (TextParsed);
                        if (!pstack.Push (parser))
                                throw new ParseException (Location, "Infinite recursion detected including file: " + filename);
-                       tparser.AddDependency (filename);
+
+                       if (filename != "@@inner_string@@") {
+                               string arvp = Path.Combine (tparser.BaseVirtualDir, Path.GetFileName (filename));
+                               if (VirtualPathUtility.IsAbsolute (arvp))
+                                       arvp = VirtualPathUtility.ToAppRelative (arvp);
+                               
+                               tparser.AddDependency (arvp);
+                       }
+               }
+               
+               void InitParser (string filename)
+               {
+                       StreamReader reader = new StreamReader (filename, WebEncoding.FileEncoding);
+                       InitParser (reader, filename);
                }
 
                public void Parse (string file)
                {
-                       InitParser (file);
+#if ONLY_1_1
+                       Parse (file, true);
+#else
+                       Parse (file, false);
+#endif
+               }
+               
+               public void Parse (TextReader reader, string filename, bool doInitParser)
+               {
+                       isApplication = tparser.DefaultDirectiveName == "application";
+
+                       if (doInitParser)
+                               InitParser (reader, filename);
 
                        pstack.Parser.Parse ();
                        if (text.Length > 0)
@@ -261,32 +286,81 @@ namespace System.Web.Compilation
 
                        if (stack.Count > 1 && pstack.Count == 0)
                                throw new ParseException (stack.Builder.location,
-                                               "Expecting </" + stack.Builder.TagName + "> " + stack.Builder);
+                                                         "Expecting </" + stack.Builder.TagName + "> " + stack.Builder);
+               }
+
+               public void Parse (Stream stream, string filename, bool doInitParser)
+               {
+                       Parse (new StreamReader (stream, WebEncoding.FileEncoding), filename, doInitParser);
+               }
+               
+               public void Parse (string filename, bool doInitParser)
+               {
+                       StreamReader reader = new StreamReader (filename, WebEncoding.FileEncoding);
+                       Parse (reader, filename, doInitParser);
                }
 
                public void Parse ()
                {
+#if NET_2_0
+                       string inputFile = tparser.InputFile;
+                       TextReader inputReader = tparser.Reader;
+                       
+                       if (String.IsNullOrEmpty (inputFile)) {
+                               StreamReader sr = inputReader as StreamReader;
+                               if (sr != null) {
+                                       FileStream fr = sr.BaseStream as FileStream;
+                                       if (fr != null)
+                                               inputFile = fr.Name;
+                               }
+
+                               if (String.IsNullOrEmpty (inputFile))
+                                       inputFile = "@@inner_string@@";
+                       }
+
+                       if (inputReader != null) {
+                               Parse (inputReader, inputFile, true);
+                       } else {
+                               if (String.IsNullOrEmpty (inputFile))
+                                       throw new HttpException ("Parser input file is empty, cannot continue.");
+                               inputFile = Path.GetFullPath (inputFile);
+                               InitParser (inputFile);
+                               Parse (inputFile);
+                       }
+#else
                        Parse (Path.GetFullPath (tparser.InputFile));
+#endif
                }
 
+               internal static void AddTypeToCache (ArrayList dependencies, string inputFile, Type type)
+               {
+                       string [] deps = (string []) dependencies.ToArray (typeof (string));
+                       HttpContext ctx = HttpContext.Current;
+                       HttpRequest req = ctx != null ? ctx.Request : null;
+
+                       if (req == null)
+                               throw new HttpException ("No current context, cannot compile.");
+
+                       int depLength = deps.Length;
+                       for (int i = 0; i < deps.Length; i++)
+                               deps [i] = req.MapPath (deps [i]);                      
+
+                       HttpRuntime.InternalCache.Insert ("@@Type" + inputFile, type, new CacheDependency (deps));
+               }
+               
                public Type GetCompiledType ()
                {
-                       Type type = (Type) HttpRuntime.Cache.Get ("@@Type" + tparser.InputFile);
+                       Type type = (Type) HttpRuntime.InternalCache.Get ("@@Type" + tparser.InputFile);
                        if (type != null) {
                                return type;
                        }
 
-                       isApplication = tparser.DefaultDirectiveName == "application";
-
                        Parse ();
 
                        BaseCompiler compiler = GetCompilerFromType ();
 
                        type = compiler.GetCompiledType ();
-                       CacheDependency cd = new CacheDependency ((string[])
-                                                       tparser.Dependencies.ToArray (typeof (string)));
-
-                       HttpRuntime.Cache.InsertPrivate ("@@Type" + tparser.InputFile, type, cd);
+                       AddTypeToCache (tparser.Dependencies, tparser.InputFile, type);
                        return type;
                }
 
@@ -331,13 +405,6 @@ namespace System.Web.Compilation
                        if (tparser != null)
                                tparser.Location = location;
 
-                       // MS ignores tbody/thead
-                       if ((attributes == null || !attributes.IsRunAtServer ())) {
-                               if (String.Compare (tagid, "tbody", true, CultureInfo.InvariantCulture) == 0 ||
-                                   String.Compare (tagid, "thead", true, CultureInfo.InvariantCulture) == 0)
-                               return;
-                       }
-
                        if (text.Length != 0)
                                FlushText ();
 
@@ -404,12 +471,23 @@ namespace System.Web.Compilation
                                        file = attributes ["file"] as string;
 
                                if (isvirtual) {
-                                       file = tparser.MapPath (file);
-                               } else {
-                                       file = GetIncludeFilePath (tparser.BaseDir, file);
-                               }
+                                       bool parsed = false;
+#if NET_2_0
+                                       VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
 
-                               Parse (file);
+                                       if (vpp.FileExists (file)) {
+                                               VirtualFile vf = vpp.GetFile (file);
+                                               if (vf != null) {
+                                                       Parse (vf.Open (), file, true);
+                                                       parsed = true;
+                                               }
+                                       }
+#endif
+                                       
+                                       if (!parsed)
+                                               Parse (tparser.MapPath (file), true);
+                               } else
+                                       Parse (GetIncludeFilePath (tparser.BaseDir, file), true);
                                break;
                        default:
                                break;
@@ -464,8 +542,7 @@ namespace System.Web.Compilation
                        string t = text.ToString ();
                        text.Length = 0;
                        if (inScript) {
-                               // TODO: store location
-                               tparser.Scripts.Add (t);
+                               tparser.Scripts.Add (new ServerSideScript (t, new System.Web.Compilation.Location (tparser.Location)));
                                return;
                        }
 
@@ -479,6 +556,56 @@ namespace System.Web.Compilation
                        }
                }
 
+#if NET_2_0
+               bool BuilderHasOtherThan (Type type, ControlBuilder cb)
+               {
+                       ArrayList al = cb.OtherTags;
+                       if (al != null && al.Count > 0)
+                               return true;
+                       
+                       al = cb.Children;
+                       if (al != null) {
+                               ControlBuilder tmp;
+                               
+                               foreach (object o in al) {
+                                       if (o == null)
+                                               continue;
+                                       
+                                       tmp = o as ControlBuilder;
+                                       if (tmp == null) {
+                                               string s = o as string;
+                                               if (s != null && String.IsNullOrEmpty (s.Trim ()))
+                                                       continue;
+                                               
+                                               return true;
+                                       }
+                                       
+                                       if (tmp is System.Web.UI.WebControls.ContentBuilderInternal)
+                                               continue;
+                                       
+                                       if (!(tmp.ControlType is System.Web.UI.WebControls.Content))
+                                               return true;                                    
+                               }
+                       }
+
+                       return false;
+               }
+               
+               bool OtherControlsAllowed (ControlBuilder cb)
+               {
+                       if (cb == null)
+                               return true;
+                       
+                       if (!typeof (System.Web.UI.WebControls.Content).IsAssignableFrom (cb.ControlType))
+                               return true;
+
+                       if (BuilderHasOtherThan (typeof (System.Web.UI.WebControls.Content), rootBuilder))
+                               return false;
+                       
+                       return true;
+               }
+#endif
+               
                bool ProcessTag (string tagid, TagAttributes atts, TagType tagtype)
                {
                        if (isApplication) {
@@ -516,6 +643,11 @@ namespace System.Web.Compilation
                        if (builder == null)
                                return false;
 
+#if NET_2_0
+                       if (!OtherControlsAllowed (builder))
+                               throw new ParseException (Location, "Only Content controls are allowed directly in a content page that contains Content controls.");
+#endif
+                       
                        builder.location = location;
                        builder.ID = htable ["id"] as string;
                        if (typeof (HtmlForm).IsAssignableFrom (builder.ControlType)) {
@@ -562,7 +694,10 @@ namespace System.Web.Compilation
                {
                        if (tagtype != TagType.Close) {
                                if (attributes != null && attributes.IsRunAtServer ()) {
-                                       CheckLanguage ((string) attributes ["language"]);
+                                       string language = (string) attributes ["language"];
+                                       if (language != null && language.Length > 0 && tparser.ImplicitLanguage)
+                                               tparser.SetLanguage (language);
+                                       CheckLanguage (language);
                                        string src = (string) attributes ["src"];
                                        if (src != null) {
                                                if (src == "")