2 // System.Web.HttpCachePolicy
5 // Tim Coleman (tim@timcoleman.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections;
31 using System.Globalization;
32 using System.Security.Permissions;
35 using System.Web.Util;
37 namespace System.Web {
39 class CacheabilityUpdatedEventArgs : EventArgs {
41 public readonly HttpCacheability Cacheability;
43 public CacheabilityUpdatedEventArgs (HttpCacheability cacheability)
45 Cacheability = cacheability;
49 internal delegate void CacheabilityUpdatedCallback (object sender, CacheabilityUpdatedEventArgs args);
51 // CAS - no InheritanceDemand here as the class is sealed
52 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
53 public sealed class HttpCachePolicy {
55 internal HttpCachePolicy ()
61 HttpCacheVaryByHeaders vary_by_headers = new HttpCacheVaryByHeaders ();
62 HttpCacheVaryByParams vary_by_params = new HttpCacheVaryByParams ();
63 ArrayList validation_callbacks;
64 StringBuilder cache_extension;
65 internal HttpCacheability Cacheability;
67 bool etag_from_file_dependencies;
72 internal bool have_expire_date;
73 internal DateTime expire_date;
74 internal bool have_last_modified;
75 internal DateTime last_modified;
77 //bool LastModifiedFromFileDependencies;
78 HttpCacheRevalidation revalidation;
79 string vary_by_custom;
85 bool sliding_expiration;
87 bool allow_response_in_browser_history;
88 bool allow_server_caching = true;
89 bool set_no_store = false;
90 bool set_no_transform = false;
91 bool valid_until_expires = false;
93 // always false in 1.x
94 bool omit_vary_star = false;
98 internal event CacheabilityUpdatedCallback CacheabilityUpdated;
102 public HttpCacheVaryByHeaders VaryByHeaders {
103 get { return vary_by_headers; }
106 public HttpCacheVaryByParams VaryByParams {
107 get { return vary_by_params; }
110 internal bool AllowServerCaching {
111 get { return allow_server_caching; }
114 internal int Duration {
115 get { return duration; }
116 set { duration = value; }
119 internal bool Sliding {
120 get { return sliding_expiration; }
123 internal DateTime Expires {
124 get { return expire_date; }
127 internal ArrayList ValidationCallbacks {
128 get { return validation_callbacks; }
131 // always false in 1.x
132 internal bool OmitVaryStar {
133 get { return omit_vary_star; }
136 internal bool ValidUntilExpires {
137 get { return valid_until_expires; }
140 #endregion // Properties
144 internal int ExpireMinutes ()
146 if (!have_expire_date)
149 return (expire_date - DateTime.Now).Minutes;
152 public void AddValidationCallback (HttpCacheValidateHandler handler, object data)
155 throw new ArgumentNullException ("handler");
157 if (validation_callbacks == null)
158 validation_callbacks = new ArrayList ();
160 validation_callbacks.Add (new Pair (handler, data));
163 public void AppendCacheExtension (string extension)
165 if (extension == null)
166 throw new ArgumentNullException ("extension");
168 if (cache_extension == null)
169 cache_extension = new StringBuilder (extension);
171 cache_extension.Append (", " + extension);
175 // This one now allows the full range of Cacheabilities.
177 public void SetCacheability (HttpCacheability cacheability)
179 if (cacheability < HttpCacheability.NoCache || cacheability > HttpCacheability.ServerAndPrivate)
180 throw new ArgumentOutOfRangeException ("cacheability");
182 if (Cacheability > 0 && cacheability > Cacheability)
185 Cacheability = cacheability;
187 if (CacheabilityUpdated != null)
188 CacheabilityUpdated (this, new CacheabilityUpdatedEventArgs (cacheability));
191 public void SetCacheability (HttpCacheability cacheability, string field)
194 throw new ArgumentNullException ("field");
196 if (cacheability != HttpCacheability.NoCache && cacheability != HttpCacheability.Private)
197 throw new ArgumentException ("Must be NoCache or Private", "cacheability");
200 fields = new ArrayList ();
202 fields.Add (new Pair (cacheability, field));
205 public void SetETag (string etag)
208 throw new ArgumentNullException ("etag");
210 if (this.etag != null)
211 throw new InvalidOperationException ("The ETag header has already been set");
213 if (etag_from_file_dependencies)
214 throw new InvalidOperationException ("SetEtagFromFileDependencies has already been called");
219 public void SetETagFromFileDependencies ()
221 if (this.etag != null)
222 throw new InvalidOperationException ("The ETag header has already been set");
224 etag_from_file_dependencies = true;
227 public void SetExpires (DateTime date)
229 if (have_expire_date && date > expire_date)
232 have_expire_date = true;
236 public void SetLastModified (DateTime date)
238 if (date > DateTime.Now)
239 throw new ArgumentOutOfRangeException ("date");
241 if (have_last_modified && date < last_modified)
244 have_last_modified = true;
245 last_modified = date;
248 [MonoTODO ("Not implemented")]
249 public void SetLastModifiedFromFileDependencies ()
251 throw new NotImplementedException ();
254 public void SetMaxAge (TimeSpan date)
256 if (date < TimeSpan.Zero)
257 throw new ArgumentOutOfRangeException ("date");
259 if (HaveMaxAge && MaxAge < date)
266 public void SetNoServerCaching ()
268 allow_server_caching = false;
271 public void SetNoStore ()
276 public void SetNoTransforms ()
278 set_no_transform = true;
281 public void SetProxyMaxAge (TimeSpan delta)
283 if (delta < TimeSpan.Zero)
284 throw new ArgumentOutOfRangeException ("delta");
286 if (HaveProxyMaxAge && ProxyMaxAge < delta)
292 public void SetRevalidation (HttpCacheRevalidation revalidation)
294 if (revalidation < HttpCacheRevalidation.AllCaches ||
295 revalidation > HttpCacheRevalidation.None)
296 throw new ArgumentOutOfRangeException ("revalidation");
298 if (this.revalidation > revalidation)
299 this.revalidation = revalidation;
302 public void SetSlidingExpiration (bool slide)
304 sliding_expiration = slide;
307 public void SetValidUntilExpires (bool validUntilExpires)
309 valid_until_expires = validUntilExpires;
312 public void SetVaryByCustom (string custom)
315 throw new ArgumentNullException ("custom");
317 if (vary_by_custom != null)
318 throw new InvalidOperationException ("VaryByCustom has already been set.");
320 vary_by_custom = custom;
323 internal string GetVaryByCustom ()
325 return vary_by_custom;
328 public void SetAllowResponseInBrowserHistory (bool allow)
330 if (Cacheability == HttpCacheability.NoCache || Cacheability == HttpCacheability.ServerAndNoCache)
331 allow_response_in_browser_history = allow;
334 internal void SetHeaders (HttpResponse response, ArrayList headers)
336 bool noCache = false;
339 switch (Cacheability) {
340 case HttpCacheability.Public:
344 case HttpCacheability.Private:
345 case HttpCacheability.ServerAndPrivate:
349 case HttpCacheability.NoCache:
350 case HttpCacheability.ServerAndNoCache:
358 response.CacheControl = cc;
359 if (!allow_response_in_browser_history) {
360 headers.Add (new UnknownResponseHeader ("Expires", "-1"));
361 headers.Add (new UnknownResponseHeader ("Pragma", "no-cache"));
364 if (MaxAge.TotalSeconds != 0)
365 cc = String.Format ("{0}, max-age={1}", cc, (long) MaxAge.TotalSeconds);
367 string expires = TimeUtil.ToUtcTimeString (expire_date);
368 headers.Add (new UnknownResponseHeader ("Expires", expires));
372 cc = String.Format ("{0}, no-store", cc);
373 if (set_no_transform)
374 cc = String.Format ("{0}, no-transform", cc);
376 headers.Add (new UnknownResponseHeader ("Cache-Control", cc));
379 headers.Add (new UnknownResponseHeader ("ETag", etag));
381 if (have_last_modified)
382 headers.Add (new UnknownResponseHeader ("Last-Modified",
383 TimeUtil.ToUtcTimeString (last_modified)));
385 if (!vary_by_params.IgnoreParams) {
386 BaseResponseHeader vb = vary_by_params.GetResponseHeader ();
393 public void SetOmitVaryStar (bool omit)
395 omit_vary_star = omit;
399 #endregion // Methods