* OutputCacheModule.cs: Make raw repsonse entries dependent on
[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
12 namespace System.Web.Caching {
13         
14         internal sealed class OutputCacheModule : IHttpModule {
15
16                 public OutputCacheModule ()
17                 {
18                 }
19
20                 public void Dispose ()
21                 {
22                 }
23
24                 public void Init (HttpApplication app)
25                 {
26                         app.AddOnResolveRequestCacheAsync (
27                                 new BeginEventHandler (OnBeginRequestCache),
28                                 new EndEventHandler (OnEndRequestCache));
29
30                         app.AddOnUpdateRequestCacheAsync (
31                                 new BeginEventHandler (OnBeginUpdateCache),
32                                 new EndEventHandler (OnEndUpdateCache));
33                 }
34
35                 IAsyncResult OnBeginRequestCache (object o, EventArgs args, AsyncCallback cb, object data)
36                 {
37                         HttpApplication app = (HttpApplication) o;
38                         HttpContext context = app.Context;
39                         
40                         string vary_key = context.Request.FilePath;
41                         CachedVaryBy varyby = context.Cache [vary_key] as CachedVaryBy;
42                         string key;
43                         CachedRawResponse c;
44
45                         if (varyby == null)
46                                 goto leave;
47
48                         key = varyby.CreateKey (vary_key, context);
49                         c = context.Cache [key] as CachedRawResponse;
50                         
51                         if (c != null && context.Timestamp < c.Policy.Expires) {
52                                 
53                                 context.Response.ClearContent ();
54                                 context.Response.BinaryWrite (c.GetData (), 0, c.ContentLength);
55
56                                 context.Response.ClearHeaders ();
57                                 context.Response.SetCachedHeaders (c.Headers);
58                                 context.Response.StatusCode = c.StatusCode;
59                                 context.Response.StatusDescription = c.StatusDescription;
60                                 
61                                 app.CompleteRequest ();
62                         } else if (c != null) {
63                                 context.Cache.Remove (key);
64                         }
65
66                 leave:
67                         HttpAsyncResult result = new HttpAsyncResult (cb,this);
68                         result.Complete (true, o, null);
69                         
70                         return result;
71                 }
72
73                 void OnEndRequestCache (IAsyncResult result)
74                 {
75                 }
76
77                 IAsyncResult OnBeginUpdateCache (object o, EventArgs args, AsyncCallback cb, object data)
78                 {
79                         HttpApplication app = (HttpApplication) o;
80                         HttpContext context = app.Context;
81                         HttpAsyncResult result;
82
83                         if (context.Response.IsCached && context.Response.StatusCode == 200)
84                                 DoCacheInsert (context);
85
86                         result = new HttpAsyncResult (cb, this);
87                         result.Complete (true, o, null);
88                         return result;
89                 }
90
91                 void OnEndUpdateCache (IAsyncResult result)
92                 {
93                 }
94
95                 private void DoCacheInsert (HttpContext context)
96                 {
97                         string vary_key = context.Request.FilePath;
98                         string key;
99                         CachedVaryBy varyby = context.Cache [vary_key] as CachedVaryBy;
100                         CachedRawResponse prev = null;
101                         bool lookup = true;
102                         
103                         if (varyby == null) {
104                                 varyby = new CachedVaryBy (context.Response.Cache);
105                                 context.Cache.InsertPrivate (vary_key, varyby, null,
106                                                 Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
107                                                 CacheItemPriority.Normal, null);
108                                 lookup = false;
109                         } 
110                         
111                         key = varyby.CreateKey (vary_key, context);
112
113                         if (lookup)
114                                 prev = context.Cache [key] as CachedRawResponse;
115                         
116                         if (IsExpired (context, prev)) {
117                                 CachedRawResponse c = context.Response.GetCachedResponse ();
118                                 string [] files = new string [0];
119                                 string [] keys = new string [] { vary_key };
120
121                                 context.Cache.InsertPrivate (key, c, new CacheDependency (files, keys),
122                                                 context.Response.Cache.Expires,
123                                                 Cache.NoSlidingExpiration,
124                                                 CacheItemPriority.Normal, null);
125                         } 
126                 }
127
128                 private bool IsExpired (HttpContext context, CachedRawResponse crr)
129                 {
130                         if (crr == null || context.Timestamp > crr.Policy.Expires)
131                                 return true;
132                         return false;
133                 }
134         }
135 }
136