2009-10-20 Marek Habersack <mhabersack@novell.com>
authorMarek Habersack <grendel@twistedcode.net>
Tue, 20 Oct 2009 19:21:39 +0000 (19:21 -0000)
committerMarek Habersack <grendel@twistedcode.net>
Tue, 20 Oct 2009 19:21:39 +0000 (19:21 -0000)
* OutputCacheModule.cs: keysCache and entriesToInvalidate
dictionaries are allocated only when they are
required. BuildManager's RemoveEntry envent is subscribed to only
if cache actually has some entries.
Added support for post-cache substitution.

* CachedRawResponse.cs: data is stored in a list of DataItem
instances instead of just in a single buffer. This enables support
for post-cache substitution.

2009-10-20  Marek Habersack  <mhabersack@novell.com>

* HttpResponse.cs: implemented the WriteSubstitution method,
thus enabling post-cache substitution.

svn path=/trunk/mcs/; revision=144487

mcs/class/System.Web/System.Web.Caching/CachedRawResponse.cs
mcs/class/System.Web/System.Web.Caching/ChangeLog
mcs/class/System.Web/System.Web.Caching/OutputCacheModule.cs
mcs/class/System.Web/System.Web/ChangeLog
mcs/class/System.Web/System.Web/HttpResponse.cs

index 70c1f72af0ee8a5d19cbe824a8b7c40b4719211f..d512070d02f9afa0a3b312d4ce91d23fac0d7f25 100644 (file)
@@ -3,8 +3,9 @@
 //
 // Author(s):
 //  Jackson Harper (jackson@ximian.com)
+//  Marek Habersack <mhabersack@novell.com>
 //
-// (C) 2003 Novell, Inc (http://www.novell.com)
+// (C) 2003-2009 Novell, Inc (http://www.novell.com)
 //
 
 //
 
 
 using System;
-using System.Text;
 using System.Collections;
 using System.Collections.Specialized;
+using System.IO;
+using System.Text;
 
-namespace System.Web.Caching {
+#if NET_2_0
+using System.Collections.Generic;
+#endif
 
-       internal sealed class CachedRawResponse {
-               static readonly byte[] emptyBuffer = new byte[0];
+namespace System.Web.Caching
+{
+       sealed class CachedRawResponse
+       {
+               public sealed class DataItem
+               {
+                       public readonly byte[] Buffer;
+                       public readonly long Length;
+#if NET_2_0
+                       public readonly HttpResponseSubstitutionCallback Callback;
+#endif
+                       
+                       public DataItem (byte[] buffer, long length)
+                       {
+                               Buffer = buffer;
+                               Length = length;
+                       }
+
+#if NET_2_0
+                       public DataItem (HttpResponseSubstitutionCallback callback) : this (null, 0)
+                       {
+                               Callback = callback;
+                       }
+#endif
+               }
+               
                HttpCachePolicy policy;
                CachedVaryBy varyby;
                int status_code;
                string status_desc;
                int content_length;
                NameValueCollection headers;
-               byte[] buffer;
+#if NET_2_0
+               List <DataItem> data;
+#else
+               ArrayList data;
+#endif
+
+               IList Data {
+                       get {
+                               if (data == null) {
+#if NET_2_0
+                                       data = new List <DataItem> ();
+#else
+                                       data = new ArrayList ();
+#endif
+                               }
+
+                               return data;
+                       }
+               }
                
-               internal CachedRawResponse (HttpCachePolicy policy)
+               public CachedRawResponse (HttpCachePolicy policy)
                {
                        this.policy = policy;
-                       this.buffer = emptyBuffer;
                }
 
-               internal HttpCachePolicy Policy {
+               public HttpCachePolicy Policy {
                        get { return policy; }
                        set { policy = value; }
                }
 
-               internal CachedVaryBy VaryBy {
+               public CachedVaryBy VaryBy {
                        get { return varyby; }
                        set { varyby = value; }
                }
                
-               internal int StatusCode {
+               public int StatusCode {
                        get { return status_code; }
                        set { status_code = value; }
                }
 
-               internal string StatusDescription {
+               public string StatusDescription {
                        get { return status_desc; }
                        set { status_desc = value; }
                }
 
-               internal int ContentLength {
-                       get { return content_length; }
-                       set { content_length = value; }
-               }
-               
-               internal NameValueCollection Headers {
+               public NameValueCollection Headers {
                        get { return headers; }
                }
 
-               internal void SetHeaders (NameValueCollection headers) {
+               public void SetHeaders (NameValueCollection headers)
+               {
                        this.headers = headers;
                }
 
-               internal void SetData (byte[] buffer)
+               public void SetData (MemoryStream ms)
+               {
+                       if (ms == null)
+                               return;
+                       
+                       Data.Add (new DataItem (ms.GetBuffer (), ms.Length));
+               }
+
+#if NET_2_0
+               public void SetData (HttpResponseSubstitutionCallback callback)
                {
-                       this.buffer = buffer;
+                       if (callback == null)
+                               return;
+
+                       Data.Add (new DataItem (callback));
                }
+#endif
                
-               internal byte[] GetData ()
+               public IList GetData ()
                {
-                       return buffer;
+                       int count = data != null ? data.Count :0;
+                       if (count == 0)
+                               return null;
+
+                       return data;
                }
        }
 }
index b6cac9bd14fe1934c8204cf2ec532b8ec2dcbfe8..a6a015750aac61dc7b7ccade183a0856748be54d 100644 (file)
@@ -1,3 +1,15 @@
+2009-10-20  Marek Habersack  <mhabersack@novell.com>
+
+       * OutputCacheModule.cs: keysCache and entriesToInvalidate
+       dictionaries are allocated only when they are
+       required. BuildManager's RemoveEntry envent is subscribed to only
+       if cache actually has some entries.
+       Added support for post-cache substitution.
+
+       * CachedRawResponse.cs: data is stored in a list of DataItem
+       instances instead of just in a single buffer. This enables support
+       for post-cache substitution.
+
 2009-10-05  Marek Habersack  <mhabersack@novell.com>
 
        * Cache.cs: if item expiration time exceeds the maximum value
index 59a1d4dc18efc09be08d45552a0f31b976585176..af6afe555e4b73dc102af8858ca2d238b3c9935d 100644 (file)
@@ -3,8 +3,9 @@
 //
 // Authors:
 //  Jackson Harper (jackson@ximian.com)
+//  Marek Habersack <mhabersack@novell.com>
 //
-// (C) 2003 Novell, Inc (http://www.novell.com)
+// (C) 2003-2009 Novell, Inc (http://www.novell.com)
 //
 
 //
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+using System.Collections;
 using System.IO;
+using System.Text;
 using System.Web;
 using System.Web.UI;
 using System.Web.Util;
-using System.Collections;
 using System.Web.Compilation;
 
 #if NET_2_0
@@ -63,11 +65,6 @@ namespace System.Web.Caching {
                {
                        context.ResolveRequestCache += new EventHandler(OnResolveRequestCache);
                        context.UpdateRequestCache += new EventHandler(OnUpdateRequestCache);
-#if NET_2_0
-                       keysCache = new Dictionary <string, string> ();
-                       entriesToInvalidate = new Dictionary <string, string> ();
-                       BuildManager.RemoveEntry += new BuildManagerRemoveEntryEventHandler (OnBuildManagerRemoveEntry);
-#endif
                        response_removed = new CacheItemRemovedCallback (OnRawResponseRemoved);
                }
 
@@ -83,9 +80,15 @@ namespace System.Web.Caching {
                                        return;
                                
                                keysCache.Remove (entry);
-                               if (context == null && !entriesToInvalidate.ContainsKey (entry)) {
-                                       entriesToInvalidate.Add (entry, cacheValue);
-                                       return;
+                               if (context == null) {
+                                       if (entriesToInvalidate == null) {
+                                               entriesToInvalidate = new Dictionary <string, string> (StringComparer.Ordinal);
+                                               entriesToInvalidate.Add (entry, cacheValue);
+                                               return;
+                                       } else if (!entriesToInvalidate.ContainsKey (entry)) {
+                                               entriesToInvalidate.Add (entry, cacheValue);
+                                               return;
+                                       }
                                }
                        }
 
@@ -116,7 +119,7 @@ namespace System.Web.Caching {
 #if NET_2_0
                        lock (keysCacheLock) {
                                string invValue;
-                               if (entriesToInvalidate.TryGetValue (vary_key, out invValue) && String.Compare (invValue, key, StringComparison.Ordinal) == 0) {
+                               if (entriesToInvalidate != null && entriesToInvalidate.TryGetValue (vary_key, out invValue) && String.Compare (invValue, key, StringComparison.Ordinal) == 0) {
                                        context.Cache.Remove (vary_key);
                                        context.InternalCache.Remove (key);
                                        entriesToInvalidate.Remove (vary_key);
@@ -158,15 +161,37 @@ namespace System.Web.Caching {
                                        return;
                                }
                        }
-                       
-                       context.Response.ClearContent ();
-                       context.Response.BinaryWrite (c.GetData (), 0, c.ContentLength);
 
-                       context.Response.ClearHeaders ();
-                       context.Response.SetCachedHeaders (c.Headers);
+                       HttpResponse response = context.Response;                       
+                       response.ClearContent ();
+                       IList cachedData = c.GetData ();
+                       if (cachedData != null) {
+                               Encoding outEnc = WebEncoding.ResponseEncoding;
+                               
+                               foreach (CachedRawResponse.DataItem d in cachedData) {
+                                       if (d.Length > 0) {
+                                               response.BinaryWrite (d.Buffer, 0, (int)d.Length);
+                                               continue;
+                                       }
+
+#if NET_2_0
+                                       if (d.Callback == null)
+                                               continue;
+
+                                       string s = d.Callback (context);
+                                       if (s == null || s.Length == 0)
+                                               continue;
 
-                       context.Response.StatusCode = c.StatusCode;
-                       context.Response.StatusDescription = c.StatusDescription;
+                                       byte[] bytes = outEnc.GetBytes (s);
+                                       response.BinaryWrite (bytes, 0, bytes.Length);
+#endif
+                               }
+                       }
+                       
+                       response.ClearHeaders ();
+                       response.SetCachedHeaders (c.Headers);
+                       response.StatusCode = c.StatusCode;
+                       response.StatusDescription = c.StatusDescription;
                                
                        app.CompleteRequest ();
                }
@@ -179,7 +204,6 @@ namespace System.Web.Caching {
                        if (context.Response.IsCached && context.Response.StatusCode == 200 && 
                            !context.Trace.IsEnabled)
                                DoCacheInsert (context);
-
                }
 
                void DoCacheInsert (HttpContext context)
@@ -239,7 +263,11 @@ namespace System.Web.Caching {
 #if NET_2_0
                        if (cacheKey != null) {
                                lock (keysCacheLock) {
-                                       if (!keysCache.ContainsKey (cacheKey))
+                                       if (keysCache == null) {
+                                               BuildManager.RemoveEntry += new BuildManagerRemoveEntryEventHandler (OnBuildManagerRemoveEntry);
+                                               keysCache = new Dictionary <string, string> (StringComparer.Ordinal);
+                                               keysCache.Add (cacheKey, cacheValue);
+                                       } else if (!keysCache.ContainsKey (cacheKey))
                                                keysCache.Add (cacheKey, cacheValue);
                                }
                        }
index aba48e25cf849bca04546d8f391d54e80001a2cd..a1d13f441963b1531e4437270249a93871ec3d24 100644 (file)
@@ -1,3 +1,8 @@
+2009-10-20  Marek Habersack  <mhabersack@novell.com>
+
+       * HttpResponse.cs: implemented the WriteSubstitution method,
+       thus enabling post-cache substitution.
+
 2009-10-12  Marek Habersack  <mhabersack@novell.com>
 
        * HttpResponse.cs: actually _use_ the url passed to Redirect when
index 24b5f28be54c01c101587ac27a6e6d75ef5ce4b8..cd6debafa23c93864314b88488dd3c0d071bd9f6 100644 (file)
@@ -843,11 +843,8 @@ namespace System.Web {
                                        app_instance.TriggerPreSendRequestContent ();
                        }
 
-                       if (IsCached) {
-                               MemoryStream ms = output_stream.GetData ();
-                               cached_response.ContentLength = (int) ms.Length;
-                               cached_response.SetData (ms.GetBuffer ());
-                       }
+                       if (IsCached)
+                               cached_response.SetData (output_stream.GetData ());
 
                        if (WorkerRequest != null)
                                output_stream.Flush (WorkerRequest, final_flush);
@@ -1037,10 +1034,32 @@ namespace System.Web {
                        Flush ();
                }
 #if NET_2_0
-               [MonoTODO ("Not implemented")]
                public void WriteSubstitution (HttpResponseSubstitutionCallback callback)
                {
-                       throw new NotImplementedException ();
+                       // Emulation of .NET behavior
+                       if (callback == null)
+                               throw new NullReferenceException ();
+
+                       object target = callback.Target;
+                       if (target != null && target.GetType () == typeof (Control))
+                               throw new ArgumentException ("callback");
+
+                       string s = callback (context);
+                       if (!IsCached) {
+                               Write (s);
+                               return;
+                       }
+
+                       Cache.Cacheability = HttpCacheability.Server;
+                       Flush ();
+                       if (WorkerRequest == null)
+                               Write (s); // better this than nothing
+                       else {
+                               byte[] bytes = WebEncoding.ResponseEncoding.GetBytes (s);
+                               WorkerRequest.SendResponseFromMemory (bytes, bytes.Length);
+                       }
+                       
+                       cached_response.SetData (callback);
                }
 #endif
                //