This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.IO;
32 using System.Web;
33 using System.Web.Util;
34 using System.Collections;
35
36 namespace System.Web.Caching {
37         
38         internal sealed class OutputCacheModule : IHttpModule {
39
40                 private CacheItemRemovedCallback response_removed;
41                 
42                 public OutputCacheModule ()
43                 {
44                 }
45
46                 public void Dispose ()
47                 {
48                 }
49
50                 public void Init (HttpApplication app)
51                 {
52                         app.AddOnResolveRequestCacheAsync (
53                                 new BeginEventHandler (OnBeginRequestCache),
54                                 new EndEventHandler (OnEndRequestCache));
55
56                         app.AddOnUpdateRequestCacheAsync (
57                                 new BeginEventHandler (OnBeginUpdateCache),
58                                 new EndEventHandler (OnEndUpdateCache));
59  
60                         response_removed = new CacheItemRemovedCallback (OnRawResponseRemoved);
61                 }
62
63                 IAsyncResult OnBeginRequestCache (object o, EventArgs args, AsyncCallback cb, object data)
64                 {
65                         HttpApplication app = (HttpApplication) o;
66                         HttpContext context = app.Context;
67                         
68                         string vary_key = context.Request.FilePath;
69                         CachedVaryBy varyby = context.Cache [vary_key] as CachedVaryBy;
70                         string key;
71                         CachedRawResponse c;
72
73                         if (varyby == null)
74                                 goto leave;
75
76                         key = varyby.CreateKey (vary_key, context);
77                         c = context.Cache [key] as CachedRawResponse;
78                         
79                         if (c != null) {
80                                 
81                                 context.Response.ClearContent ();
82                                 context.Response.BinaryWrite (c.GetData (), 0, c.ContentLength);
83
84                                 context.Response.ClearHeaders ();
85                                 c.DateHeader.Value = TimeUtil.ToUtcTimeString (DateTime.Now);
86                                 context.Response.SetCachedHeaders (c.Headers);
87
88                                 context.Response.StatusCode = c.StatusCode;
89                                 context.Response.StatusDescription = c.StatusDescription;
90                                 
91                                 app.CompleteRequest ();
92                         } 
93
94                 leave:
95                         HttpAsyncResult result = new HttpAsyncResult (cb,this);
96                         result.Complete (true, o, null);
97                         
98                         return result;
99                 }
100
101                 void OnEndRequestCache (IAsyncResult result)
102                 {
103                 }
104
105                 IAsyncResult OnBeginUpdateCache (object o, EventArgs args, AsyncCallback cb, object data)
106                 {
107                         HttpApplication app = (HttpApplication) o;
108                         HttpContext context = app.Context;
109                         HttpAsyncResult result;
110
111                         if (context.Response.IsCached && context.Response.StatusCode == 200 && 
112                             !context.Trace.IsEnabled)
113                                 DoCacheInsert (context);
114
115                         result = new HttpAsyncResult (cb, this);
116                         result.Complete (true, o, null);
117                         return result;
118                 }
119
120                 void OnEndUpdateCache (IAsyncResult result)
121                 {
122                 }
123
124                 private void DoCacheInsert (HttpContext context)
125                 {
126                         string vary_key = context.Request.FilePath;
127                         string key;
128                         CachedVaryBy varyby = context.Cache [vary_key] as CachedVaryBy;
129                         CachedRawResponse prev = null;
130                         bool lookup = true;
131                         
132                         if (varyby == null) {
133                                 string path = context.Request.MapPath (vary_key);
134                                 string [] files = new string [] { path };
135                                 string [] keys = new string [0];
136                                 varyby = new CachedVaryBy (context.Response.Cache, vary_key);
137                                 context.Cache.InsertPrivate (vary_key, varyby,
138                                                 new CacheDependency (files, keys),
139                                                 Cache.NoAbsoluteExpiration,
140                                                 Cache.NoSlidingExpiration,
141                                                 CacheItemPriority.Normal, null);
142                                 lookup = false;
143                         } 
144                         
145                         key = varyby.CreateKey (vary_key, context);
146
147                         if (lookup)
148                                 prev = context.Cache [key] as CachedRawResponse;
149                         
150                         if (prev == null) {
151                                 CachedRawResponse c = context.Response.GetCachedResponse ();
152                                 string [] files = new string [] { };
153                                 string [] keys = new string [] { vary_key };
154                                 bool sliding = context.Response.Cache.Sliding;
155
156                                 context.Cache.InsertPrivate (key, c, new CacheDependency (files, keys),
157                                                 (sliding ? Cache.NoAbsoluteExpiration :
158                                                                 context.Response.Cache.Expires),
159                                                 (sliding ? TimeSpan.FromSeconds (
160                                                         context.Response.Cache.Duration) :
161                                                                 Cache.NoSlidingExpiration),
162                                                 CacheItemPriority.Normal, response_removed);
163                                 c.VaryBy = varyby;
164                                 varyby.ItemList.Add (key);
165                         } 
166                 }
167
168                 private void OnRawResponseRemoved (string key, object value, CacheItemRemovedReason reason)
169                 {
170                         CachedRawResponse c = (CachedRawResponse) value;
171
172                         c.VaryBy.ItemList.Remove (key);                 
173                         if (c.VaryBy.ItemList.Count != 0)
174                                 return;
175                         
176                         Cache cache = HttpRuntime.Cache;
177                         cache.Remove (c.VaryBy.Key);
178                 }
179         }
180 }
181