* OutputCacheModule.cs: We can use file dependancies now.
[mono.git] / mcs / class / System.Web / System.Web.Caching / OutputCacheModule.cs
1 //
2 // System.Web.Caching.OutputCacheModule
3 //
4 // Authors:
5 //  Jackson Harper (jackson@ximian.com)
6 //
7 // (C) 2003 Novell, Inc (http://www.novell.com)
8 //
9
10 using System.Web;
11 using System.Web.Util;
12 using System.Collections;
13
14 namespace System.Web.Caching {
15         
16         internal sealed class OutputCacheModule : IHttpModule {
17
18                 private CacheItemRemovedCallback response_removed;
19                 
20                 public OutputCacheModule ()
21                 {
22                 }
23
24                 public void Dispose ()
25                 {
26                 }
27
28                 public void Init (HttpApplication app)
29                 {
30                         app.AddOnResolveRequestCacheAsync (
31                                 new BeginEventHandler (OnBeginRequestCache),
32                                 new EndEventHandler (OnEndRequestCache));
33
34                         app.AddOnUpdateRequestCacheAsync (
35                                 new BeginEventHandler (OnBeginUpdateCache),
36                                 new EndEventHandler (OnEndUpdateCache));
37  
38                         response_removed = new CacheItemRemovedCallback (OnRawResponseRemoved);
39                 }
40
41                 IAsyncResult OnBeginRequestCache (object o, EventArgs args, AsyncCallback cb, object data)
42                 {
43                         HttpApplication app = (HttpApplication) o;
44                         HttpContext context = app.Context;
45                         
46                         string vary_key = context.Request.FilePath;
47                         CachedVaryBy varyby = context.Cache [vary_key] as CachedVaryBy;
48                         string key;
49                         CachedRawResponse c;
50
51                         if (varyby == null)
52                                 goto leave;
53
54                         key = varyby.CreateKey (vary_key, context);
55                         c = context.Cache [key] as CachedRawResponse;
56                         
57                         if (c != null) {
58                                 
59                                 context.Response.ClearContent ();
60                                 context.Response.BinaryWrite (c.GetData (), 0, c.ContentLength);
61
62                                 context.Response.ClearHeaders ();
63                                 c.DateHeader.Value = TimeUtil.ToUtcTimeString (DateTime.Now);
64                                 context.Response.SetCachedHeaders (c.Headers);
65
66                                 context.Response.StatusCode = c.StatusCode;
67                                 context.Response.StatusDescription = c.StatusDescription;
68                                 
69                                 app.CompleteRequest ();
70                         } else if (c != null) {
71                                 context.Cache.Remove (key);
72                         }
73
74                 leave:
75                         HttpAsyncResult result = new HttpAsyncResult (cb,this);
76                         result.Complete (true, o, null);
77                         
78                         return result;
79                 }
80
81                 void OnEndRequestCache (IAsyncResult result)
82                 {
83                 }
84
85                 IAsyncResult OnBeginUpdateCache (object o, EventArgs args, AsyncCallback cb, object data)
86                 {
87                         HttpApplication app = (HttpApplication) o;
88                         HttpContext context = app.Context;
89                         HttpAsyncResult result;
90
91                         if (context.Response.IsCached && context.Response.StatusCode == 200 && 
92                             !context.Trace.IsEnabled)
93                                 DoCacheInsert (context);
94
95                         result = new HttpAsyncResult (cb, this);
96                         result.Complete (true, o, null);
97                         return result;
98                 }
99
100                 void OnEndUpdateCache (IAsyncResult result)
101                 {
102                 }
103
104                 private void DoCacheInsert (HttpContext context)
105                 {
106                         string vary_key = context.Request.FilePath;
107                         string key;
108                         CachedVaryBy varyby = context.Cache [vary_key] as CachedVaryBy;
109                         CachedRawResponse prev = null;
110                         bool lookup = true;
111                         
112                         if (varyby == null) {
113                                 varyby = new CachedVaryBy (context.Response.Cache, vary_key);
114                                 context.Cache.InsertPrivate (vary_key, varyby, null,
115                                                 Cache.NoAbsoluteExpiration,
116                                                 Cache.NoSlidingExpiration,
117                                                 CacheItemPriority.Normal, null);
118                                 lookup = false;
119                         } 
120                         
121                         key = varyby.CreateKey (vary_key, context);
122
123                         if (lookup)
124                                 prev = context.Cache [key] as CachedRawResponse;
125                         
126                         if (prev == null) {
127                                 CachedRawResponse c = context.Response.GetCachedResponse ();
128                                 string [] files = new string [] { vary_key };
129                                 string [] keys = new string [] { vary_key };
130                                 bool sliding = context.Response.Cache.Sliding;
131
132                                 context.Cache.InsertPrivate (key, c, new CacheDependency (files, keys),
133                                                 (sliding ? Cache.NoAbsoluteExpiration :
134                                                                 context.Response.Cache.Expires),
135                                                 (sliding ? TimeSpan.FromSeconds (
136                                                         context.Response.Cache.Duration) :
137                                                                 Cache.NoSlidingExpiration),
138                                                 CacheItemPriority.Normal, response_removed);
139                                 c.VaryBy = varyby;
140                                 varyby.ItemList.Add (key);
141                         } 
142                 }
143
144                 private void OnRawResponseRemoved (string key, object value, CacheItemRemovedReason reason)
145                 {
146                         CachedRawResponse c = (CachedRawResponse) value;
147
148                         c.VaryBy.ItemList.Remove (key);                 
149                         if (c.VaryBy.ItemList.Count != 0)
150                                 return;
151                         
152                         Cache cache = HttpRuntime.Cache;
153                         cache.Remove (c.VaryBy.Key);
154                 }
155         }
156 }
157