internal CachedRawResponse( HttpRawResponse rawResponse, HttpCachePolicySettings settings, CachedVary cachedVary) { _rawResponse = rawResponse; _settings = settings; _cachedVary = cachedVary; }
// // helpers for accessing CacheInternal // // add CachedVary private static CachedVary UtcAdd(String key, CachedVary cachedVary) { return((CachedVary)HttpRuntime.CacheInternal.UtcAdd(key, cachedVary, null /*dependencies*/, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null /*callback*/)); }
public override bool Equals(object obj) { CachedVary vary = obj as CachedVary; if (vary == null) { return(false); } return((((this._varyByAllParams == vary._varyByAllParams) && (this._varyByCustom == vary._varyByCustom)) && (StringUtil.StringArrayEquals(this._contentEncodings, vary._contentEncodings) && StringUtil.StringArrayEquals(this._headers, vary._headers))) && StringUtil.StringArrayEquals(this._params, vary._params)); }
public override bool Equals(Object obj) { if (!(obj is CachedVary)) { return(false); } CachedVary cv = (CachedVary)obj; return(_varyByAllParams == cv._varyByAllParams && StringEquals(_varyByCustom, cv._varyByCustom) && StringArrayEquals(_headers, cv._headers) && StringArrayEquals(_params, cv._params)); }
// insert cached vary or output cache entry internal static void InsertResponse(String cachedVaryKey, CachedVary cachedVary, String rawResponseKey, CachedRawResponse rawResponse, CacheDependency dependencies, DateTime absExp, TimeSpan slidingExp) { // if the provider is undefined or the fragment can't be inserted in the // provider, insert it in the internal cache. OutputCacheProvider provider = GetProvider(HttpContext.Current); // // CachedVary can be serialized. // CachedRawResponse is not always serializable. // bool useProvider = (provider != null); if (useProvider) { bool canUseProvider = (IsSubstBlockSerializable(rawResponse._rawResponse) && rawResponse._settings.IsValidationCallbackSerializable() && slidingExp == Cache.NoSlidingExpiration && (dependencies == null || dependencies.IsFileDependency())); if (useProvider && !canUseProvider) { throw new ProviderException(SR.GetString(SR.Provider_does_not_support_policy_for_responses, provider.Name)); } } #if DBG bool cachedVaryPutInCache = (cachedVary != null); #endif if (cachedVary != null) { /* * Add the CachedVary item so that a request will know * which headers are needed to issue another request. * * Use the Add method so that we guarantee we only use * a single CachedVary and don't overwrite existing ones. */ CachedVary cachedVaryInCache; if (!useProvider) { cachedVaryInCache = OutputCache.UtcAdd(cachedVaryKey, cachedVary); } else { cachedVaryInCache = (CachedVary)provider.Add(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } if (cachedVaryInCache != null) { if (!cachedVary.Equals(cachedVaryInCache)) { if (!useProvider) { HttpRuntime.CacheInternal.UtcInsert(cachedVaryKey, cachedVary); } else { provider.Set(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } } else { cachedVary = cachedVaryInCache; #if DBG cachedVaryPutInCache = false; #endif } } if (!useProvider) { AddCacheKeyToDependencies(ref dependencies, cachedVaryKey); } // not all caches support cache key dependencies, but we can use a "change number" to associate // the ControlCachedVary and the PartialCachingCacheEntry rawResponse._cachedVaryId = cachedVary.CachedVaryId; } // Now insert into the cache (use cache provider if possible, otherwise use internal cache) if (!useProvider) { HttpRuntime.CacheInternal.UtcInsert(rawResponseKey, rawResponse, dependencies, absExp, slidingExp, CacheItemPriority.Normal, s_entryRemovedCallback); IncrementCount(); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_ENTRIES); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_TURNOVER_RATE); } else { string depKey = null; string[] fileDeps = null; if (dependencies != null) { depKey = OUTPUTCACHE_KEYPREFIX_DEPENDENCIES + dependencies.GetUniqueID(); fileDeps = dependencies.GetFileDependencies(); } OutputCacheEntry oce = Convert(rawResponse, depKey, fileDeps); provider.Set(rawResponseKey, oce, absExp); if (dependencies != null) { // use Add and dispose dependencies if there's already one in the cache Object d = HttpRuntime.CacheInternal.UtcAdd(depKey, new DependencyCacheEntry(rawResponseKey, oce.KernelCacheUrl, provider.Name), dependencies, absExp, Cache.NoSlidingExpiration, CacheItemPriority.Normal, s_dependencyRemovedCallback); if (d != null) { dependencies.Dispose(); } } } #if DBG string cachedVaryType = (cachedVaryPutInCache) ? "CachedVary" : ""; string providerUsed = (useProvider) ? provider.Name : "CacheInternal"; Debug.Trace("OutputCache", "InsertResposne(" + cachedVaryKey + ", " + cachedVaryType + ", " + rawResponseKey + ", CachedRawResponse, ...) -->" + providerUsed); #endif }
private static CachedVary UtcAdd(string key, CachedVary cachedVary) { return((CachedVary)HttpRuntime.CacheInternal.UtcAdd(key, cachedVary, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null)); }
internal static void InsertResponse(string cachedVaryKey, CachedVary cachedVary, string rawResponseKey, CachedRawResponse rawResponse, CacheDependency dependencies, DateTime absExp, TimeSpan slidingExp) { OutputCacheProvider provider = GetProvider(HttpContext.Current); bool flag = provider != null; if (flag) { bool flag2 = ((IsSubstBlockSerializable(rawResponse._rawResponse) && rawResponse._settings.IsValidationCallbackSerializable()) && (slidingExp == Cache.NoSlidingExpiration)) && ((dependencies == null) || dependencies.IsFileDependency()); if (flag && !flag2) { throw new ProviderException(System.Web.SR.GetString("Provider_does_not_support_policy_for_responses", new object[] { provider.Name })); } } if (cachedVary != null) { CachedVary vary; if (!flag) { vary = UtcAdd(cachedVaryKey, cachedVary); } else { vary = (CachedVary) provider.Add(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } if (vary != null) { if (!cachedVary.Equals(vary)) { if (!flag) { HttpRuntime.CacheInternal.UtcInsert(cachedVaryKey, cachedVary); } else { provider.Set(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } } else { cachedVary = vary; } } if (!flag) { AddCacheKeyToDependencies(ref dependencies, cachedVaryKey); } rawResponse._cachedVaryId = cachedVary.CachedVaryId; } if (!flag) { HttpRuntime.CacheInternal.UtcInsert(rawResponseKey, rawResponse, dependencies, absExp, slidingExp, CacheItemPriority.Normal, s_entryRemovedCallback); IncrementCount(); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_ENTRIES); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_TURNOVER_RATE); } else { string depKey = null; string[] fileDependencies = null; if (dependencies != null) { depKey = "aD" + dependencies.GetUniqueID(); fileDependencies = dependencies.GetFileDependencies(); } OutputCacheEntry entry = Convert(rawResponse, depKey, fileDependencies); provider.Set(rawResponseKey, entry, absExp); if ((dependencies != null) && (HttpRuntime.CacheInternal.UtcAdd(depKey, new DependencyCacheEntry(rawResponseKey, entry.KernelCacheUrl, provider.Name), dependencies, absExp, Cache.NoSlidingExpiration, CacheItemPriority.Normal, s_dependencyRemovedCallback) != null)) { dependencies.Dispose(); } } }
// // helpers for accessing CacheInternal // // add CachedVary private static CachedVary UtcAdd(String key, CachedVary cachedVary) { return (CachedVary) HttpRuntime.CacheInternal.UtcAdd(key, cachedVary, null /*dependencies*/, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null /*callback*/); }
internal void OnEnter(object source, EventArgs eventArgs) { this._key = null; this._recordedCacheMiss = false; if (OutputCache.InUse) { string[] strArray2 = null; string[] strArray3 = null; HttpApplication application = (HttpApplication)source; HttpContext context = application.Context; context.GetFilePathData(); HttpRequest request = context.Request; HttpResponse response = context.Response; switch (request.HttpVerb) { case HttpVerb.GET: case HttpVerb.HEAD: case HttpVerb.POST: { string str; this._key = str = this.CreateOutputCachedItemKey(context, null); object obj2 = OutputCache.Get(str); if (obj2 != null) { int num; int length; CachedVary cachedVary = obj2 as CachedVary; if (cachedVary != null) { str = this.CreateOutputCachedItemKey(context, cachedVary); if (str == null) { return; } if (cachedVary._contentEncodings == null) { obj2 = OutputCache.Get(str); } else { obj2 = null; bool flag3 = true; string knownRequestHeader = context.WorkerRequest.GetKnownRequestHeader(0x16); if (knownRequestHeader != null) { string[] contentEncodings = cachedVary._contentEncodings; int startIndex = 0; bool flag4 = false; while (!flag4) { flag4 = true; int index = GetAcceptableEncoding(contentEncodings, startIndex, knownRequestHeader); if (index > -1) { flag3 = false; obj2 = OutputCache.Get(str + contentEncodings[index]); if (obj2 == null) { startIndex = index + 1; if (startIndex < contentEncodings.Length) { flag4 = false; } } } else if (index == -2) { flag3 = false; } } } if ((obj2 == null) && flag3) { obj2 = OutputCache.Get(str); } } if ((obj2 == null) || (((CachedRawResponse)obj2)._cachedVaryId != cachedVary.CachedVaryId)) { if (obj2 != null) { OutputCache.Remove(str, context); } return; } } CachedRawResponse response2 = (CachedRawResponse)obj2; HttpCachePolicySettings settings = response2._settings; if ((cachedVary == null) && !settings.IgnoreParams) { if (request.HttpVerb == HttpVerb.POST) { this.RecordCacheMiss(); return; } if (request.HasQueryString) { this.RecordCacheMiss(); return; } } if (settings.IgnoreRangeRequests) { string str8 = request.Headers["Range"]; if (StringUtil.StringStartsWithIgnoreCase(str8, "bytes")) { return; } } if (!settings.HasValidationPolicy()) { string str4 = request.Headers["Cache-Control"]; if (str4 != null) { strArray2 = str4.Split(s_fieldSeparators); for (num = 0; num < strArray2.Length; num++) { string str6 = strArray2[num]; switch (str6) { case "no-cache": case "no-store": this.RecordCacheMiss(); return; } if (StringUtil.StringStartsWith(str6, "max-age=")) { int num4; try { num4 = Convert.ToInt32(str6.Substring(8), CultureInfo.InvariantCulture); } catch { num4 = -1; } if (num4 >= 0) { int num6 = (int)((context.UtcTimestamp.Ticks - settings.UtcTimestampCreated.Ticks) / 0x989680L); if (num6 >= num4) { this.RecordCacheMiss(); return; } } } else if (StringUtil.StringStartsWith(str6, "min-fresh=")) { int num5; try { num5 = Convert.ToInt32(str6.Substring(10), CultureInfo.InvariantCulture); } catch { num5 = -1; } if (((num5 >= 0) && settings.IsExpiresSet) && !settings.SlidingExpiration) { int num7 = (int)((settings.UtcExpires.Ticks - context.UtcTimestamp.Ticks) / 0x989680L); if (num7 < num5) { this.RecordCacheMiss(); return; } } } } } string str5 = request.Headers["Pragma"]; if (str5 != null) { strArray3 = str5.Split(s_fieldSeparators); for (num = 0; num < strArray3.Length; num++) { if (strArray3[num] == "no-cache") { this.RecordCacheMiss(); return; } } } } else if (settings.ValidationCallbackInfo != null) { HttpValidationStatus valid = HttpValidationStatus.Valid; HttpValidationStatus ignoreThisRequest = valid; num = 0; length = settings.ValidationCallbackInfo.Length; while (num < length) { ValidationCallbackInfo info = settings.ValidationCallbackInfo[num]; try { info.handler(context, info.data, ref valid); } catch (Exception exception) { valid = HttpValidationStatus.Invalid; HttpApplicationFactory.RaiseError(exception); } switch (valid) { case HttpValidationStatus.Invalid: OutputCache.Remove(str, context); this.RecordCacheMiss(); return; case HttpValidationStatus.IgnoreThisRequest: ignoreThisRequest = HttpValidationStatus.IgnoreThisRequest; break; case HttpValidationStatus.Valid: break; default: valid = ignoreThisRequest; break; } num++; } if (ignoreThisRequest == HttpValidationStatus.IgnoreThisRequest) { this.RecordCacheMiss(); return; } } HttpRawResponse rawResponse = response2._rawResponse; if ((cachedVary == null) || (cachedVary._contentEncodings == null)) { string acceptEncoding = request.Headers["Accept-Encoding"]; string contentEncoding = null; ArrayList headers = rawResponse.Headers; if (headers != null) { foreach (HttpResponseHeader header in headers) { if (header.Name == "Content-Encoding") { contentEncoding = header.Value; break; } } } if (!IsAcceptableEncoding(contentEncoding, acceptEncoding)) { this.RecordCacheMiss(); return; } } int num3 = -1; if (!rawResponse.HasSubstBlocks) { string ifModifiedSince = request.IfModifiedSince; if (ifModifiedSince != null) { num3 = 0; try { DateTime time = HttpDate.UtcParse(ifModifiedSince); if ((settings.IsLastModifiedSet && (settings.UtcLastModified <= time)) && (time <= context.UtcTimestamp)) { num3 = 1; } } catch { } } if (num3 != 0) { string ifNoneMatch = request.IfNoneMatch; if (ifNoneMatch != null) { num3 = 0; string[] strArray = ifNoneMatch.Split(s_fieldSeparators); num = 0; length = strArray.Length; while (num < length) { if ((num == 0) && strArray[num].Equals("*")) { num3 = 1; break; } if (strArray[num].Equals(settings.ETag)) { num3 = 1; break; } num++; } } } } if (num3 == 1) { response.ClearAll(); response.StatusCode = 0x130; } else { bool sendBody = request.HttpVerb != HttpVerb.HEAD; response.UseSnapshot(rawResponse, sendBody); } response.Cache.ResetFromHttpCachePolicySettings(settings, context.UtcTimestamp); string originalCacheUrl = response2._kernelCacheUrl; if (originalCacheUrl != null) { response.SetupKernelCaching(originalCacheUrl); } PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_RATIO_BASE); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_HITS); this._key = null; this._recordedCacheMiss = false; application.CompleteRequest(); return; } return; } } } }
private string CreateOutputCachedItemKey(HttpContext context, CachedVary cachedVary) { return(CreateOutputCachedItemKey(context.Request.Path, context.Request.HttpVerb, context, cachedVary)); }
/* * Return a key to lookup a cached response. The key contains * the path and optionally, vary parameters, vary headers, custom strings, * and form posted data. */ string CreateOutputCachedItemKey(HttpContext context, CachedVary cachedVary) { return CreateOutputCachedItemKey(context.Request.Path, context.Request.HttpVerb, context, cachedVary); }
internal static string CreateOutputCachedItemKey( string path, HttpVerb verb, HttpContext context, CachedVary cachedVary) { StringBuilder sb; int i, j, n; string name, value; string[] a; byte[] buf; HttpRequest request; NameValueCollection col; int contentLength; bool getAllParams; if (verb == HttpVerb.POST) { sb = new StringBuilder(OUTPUTCACHE_KEYPREFIX_POST, path.Length + OUTPUTCACHE_KEYPREFIX_POST.Length); } else { sb = new StringBuilder(OUTPUTCACHE_KEYPREFIX_GET, path.Length + OUTPUTCACHE_KEYPREFIX_GET.Length); } sb.Append(CultureInfo.InvariantCulture.TextInfo.ToLower(path)); /* key for cached vary item has additional information */ if (cachedVary != null) { request = context.Request; /* params part */ for (j = 0; j <= 2; j++) { a = null; col = null; getAllParams = false; switch (j) { case 0: sb.Append("H"); a = cachedVary._headers; if (a != null) { col = request.GetServerVarsWithoutDemand(); } break; case 1: Debug.Assert(cachedVary._params == null || !cachedVary._varyByAllParams, "cachedVary._params == null || !cachedVary._varyByAllParams"); sb.Append("Q"); a = cachedVary._params; if (request.HasQueryString && (a != null || cachedVary._varyByAllParams)) { col = request.QueryString; getAllParams = cachedVary._varyByAllParams; } break; case 2: default: Debug.Assert(cachedVary._params == null || !cachedVary._varyByAllParams, "cachedVary._params == null || !cachedVary._varyByAllParams"); sb.Append("F"); if (verb == HttpVerb.POST) { a = cachedVary._params; if (request.HasForm && (a != null || cachedVary._varyByAllParams)) { col = request.Form; getAllParams = cachedVary._varyByAllParams; } } break; } Debug.Assert(a == null || !getAllParams, "a == null || !getAllParams"); /* handle all params case (VaryByParams[*] = true) */ if (getAllParams && col.Count > 0) { a = col.AllKeys; for (i = a.Length - 1; i >= 0; i--) { if (a[i] != null) a[i] = CultureInfo.InvariantCulture.TextInfo.ToLower(a[i]); } Array.Sort(a, InvariantComparer.Default); } if (a != null) { for (i = 0, n = a.Length; i < n; i++) { name = a[i]; if (col == null) { value = NULL_VARYBY_VALUE; } else { value = col[name]; if (value == null) { value = NULL_VARYBY_VALUE; } } sb.Append("N"); sb.Append(name); sb.Append("V"); sb.Append(value); } } } /* custom string part */ sb.Append("C"); if (cachedVary._varyByCustom != null) { sb.Append("N"); sb.Append(cachedVary._varyByCustom); sb.Append("V"); try { value = context.ApplicationInstance.GetVaryByCustomString( context, cachedVary._varyByCustom); if (value == null) { value = NULL_VARYBY_VALUE; } } catch (Exception e) { value = ERROR_VARYBY_VALUE; HttpApplicationFactory.RaiseError(e); } sb.Append(value); } /* * if VaryByParms=*, and method is not a form, then * use a cryptographically strong hash of the data as * part of the key. */ sb.Append("D"); if ( verb == HttpVerb.POST && cachedVary._varyByAllParams && request.Form.Count == 0) { contentLength = request.ContentLength; if (contentLength > MAX_POST_KEY_LENGTH || contentLength < 0) { return null; } if (contentLength > 0) { buf = ((HttpInputStream)request.InputStream).GetAsByteArray(); if (buf == null) { return null; } // Use SHA256 to generate a collision-free hash of the input data value = Convert.ToBase64String(CryptoUtil.ComputeSHA256Hash(buf)); sb.Append(value); } } /* * VaryByContentEncoding */ sb.Append("E"); string[] contentEncodings = cachedVary._contentEncodings; if (contentEncodings != null) { string coding = context.Response.GetHttpHeaderContentEncoding(); if (coding != null) { for (int k = 0; k < contentEncodings.Length; k++) { if (contentEncodings[k] == coding) { sb.Append(coding); break; } } } } // The key must end in "E", or the VaryByContentEncoding feature will break. Unfortunately, // there was no good way to encapsulate the logic within this routine. See the code in // OnEnter where we append the result of GetAcceptableEncoding to the key. } return sb.ToString(); }
/* * If the item is cacheable, add it to the cache. */ /// <devdoc> /// <para>Raises the <see langword='Leave'/> event, which causes any cacheable items to /// be put into the output cache.</para> /// </devdoc> internal /*public*/ void OnLeave(Object source, EventArgs eventArgs) { HttpApplication app; HttpContext context; bool cacheable; CachedVary cachedVary; HttpCachePolicy cache; HttpCachePolicySettings settings; string keyRawResponse; string[] varyByContentEncodings; string[] varyByHeaders; string[] varyByParams; bool varyByAllParams; HttpRequest request; HttpResponse response; int i, n; bool cacheAuthorizedPage; Debug.Trace("OutputCacheModuleLeave", "Beginning OutputCacheModule::Leave"); app = (HttpApplication)source; context = app.Context; request = context.Request; response = context.Response; cache = null; #if DBG string reason = null; #endif /* * Determine whether the response is cacheable. */ cacheable = false; do { if (!response.HasCachePolicy) { #if DBG reason = "CachePolicy not created, not modified from non-caching default."; #endif break; } cache = response.Cache; if (!cache.IsModified()) { #if DBG reason = "CachePolicy created, but not modified from non-caching default."; #endif break; } if (response.StatusCode != 200) { #if DBG reason = "response.StatusCode != 200."; #endif break; } if (request.HttpVerb != HttpVerb.GET && request.HttpVerb != HttpVerb.POST) { #if DBG reason = "the cache can only cache responses to GET and POST."; #endif break; } if (!response.IsBuffered()) { #if DBG reason = "the response is not buffered."; #endif break; } /* * Change a response with HttpCacheability.Public to HttpCacheability.Private * if it requires authorization, and allow it to be cached. * * Note that setting Cacheability to ServerAndPrivate would accomplish * the same thing without needing the "cacheAuthorizedPage" variable, * but in RTM we did not have ServerAndPrivate, and setting that value * would change the behavior. */ cacheAuthorizedPage = false; if ( cache.GetCacheability() == HttpCacheability.Public && context.RequestRequiresAuthorization()) { cache.SetCacheability(HttpCacheability.Private); cacheAuthorizedPage = true; } if ( cache.GetCacheability() != HttpCacheability.Public && cache.GetCacheability() != HttpCacheability.ServerAndPrivate && cache.GetCacheability() != HttpCacheability.ServerAndNoCache && !cacheAuthorizedPage) { #if DBG reason = "CachePolicy.Cacheability is not Public, ServerAndPrivate, or ServerAndNoCache."; #endif break; } if (cache.GetNoServerCaching()) { #if DBG reason = "CachePolicy.NoServerCaching is set."; #endif break; } // MSRC 11855 (DevDiv 297240 / 362405) - We should suppress output caching for responses which contain non-shareable cookies. // We already disable the HTTP.SYS and IIS user mode cache when *any* response cookie is present (see IIS7WorkerRequest.SendUnknownResponseHeader) if (response.ContainsNonShareableCookies()) { #if DBG reason = "Non-shareable response cookies were present."; #endif break; } if (!cache.HasExpirationPolicy() && !cache.HasValidationPolicy()) { #if DBG reason = "CachePolicy has no expiration policy or validation policy."; #endif break; } if (cache.VaryByHeaders.GetVaryByUnspecifiedParameters()) { #if DBG reason = "CachePolicy.Vary.VaryByUnspecifiedParameters was called."; #endif break; } if (!cache.VaryByParams.AcceptsParams() && (request.HttpVerb == HttpVerb.POST || request.HasQueryString)) { #if DBG reason = "the cache cannot cache responses to POSTs or GETs with query strings unless Cache.VaryByParams is modified."; #endif break; } if (cache.VaryByContentEncodings.IsModified() && !cache.VaryByContentEncodings.IsCacheableEncoding(context.Response.GetHttpHeaderContentEncoding())) { #if DBG reason = "the cache cannot cache encoded responses that are not listed in the VaryByContentEncodings collection."; #endif break; } cacheable = true; } while (false); /* * Add response to cache. */ if (!cacheable) { #if DBG Debug.Assert(reason != null, "reason != null"); Debug.Trace("OutputCacheModuleLeave", "Item is not output cacheable because " + reason + "\n\tUrl=" + request.Path + "\nReturning from OutputCacheModule::Leave"); #endif return; } RecordCacheMiss(); settings = cache.GetCurrentSettings(response); varyByContentEncodings = settings.VaryByContentEncodings; varyByHeaders = settings.VaryByHeaders; if (settings.IgnoreParams) { varyByParams = null; } else { varyByParams = settings.VaryByParams; } /* Create the key if it was not created in OnEnter */ if (_key == null) { _key = CreateOutputCachedItemKey(context, null); Debug.Assert(_key != null, "_key != null"); } if (varyByContentEncodings == null && varyByHeaders == null && varyByParams == null && settings.VaryByCustom == null) { /* * This is not a varyBy item. */ keyRawResponse = _key; cachedVary = null; } else { /* * There is a vary in the cache policy. We handle this * by adding another item to the cache which contains * a list of the vary headers. A request for the item * without the vary headers in the key will return this * item. From the headers another key can be constructed * to lookup the item with the raw response. */ if (varyByHeaders != null) { for (i = 0, n = varyByHeaders.Length; i < n; i++) { varyByHeaders[i] = "HTTP_" + CultureInfo.InvariantCulture.TextInfo.ToUpper( varyByHeaders[i].Replace('-', '_')); } } varyByAllParams = false; if (varyByParams != null) { varyByAllParams = (varyByParams.Length == 1 && varyByParams[0] == ASTERISK); if (varyByAllParams) { varyByParams = null; } else { for (i = 0, n = varyByParams.Length; i < n; i++) { varyByParams[i] = CultureInfo.InvariantCulture.TextInfo.ToLower(varyByParams[i]); } } } cachedVary = new CachedVary(varyByContentEncodings, varyByHeaders, varyByParams, varyByAllParams, settings.VaryByCustom); keyRawResponse = CreateOutputCachedItemKey(context, cachedVary); if (keyRawResponse == null) { Debug.Trace("OutputCacheModuleLeave", "Couldn't add non-cacheable post.\n\tkey=" + _key); return; } // it is possible that the user code calculating custom vary-by // string would Flush making the response non-cacheable. Check fo it here. if (!response.IsBuffered()) { Debug.Trace("OutputCacheModuleLeave", "Response.Flush() inside GetVaryByCustomString\n\tkey=" + _key); return; } } DateTime utcExpires = Cache.NoAbsoluteExpiration; TimeSpan slidingDelta = Cache.NoSlidingExpiration; if (settings.SlidingExpiration) { slidingDelta = settings.SlidingDelta; } else if (settings.IsMaxAgeSet) { DateTime utcTimestamp = (settings.UtcTimestampCreated != DateTime.MinValue) ? settings.UtcTimestampCreated : context.UtcTimestamp; utcExpires = utcTimestamp + settings.MaxAge; } else if (settings.IsExpiresSet) { utcExpires = settings.UtcExpires; } // Check and ensure that item hasn't expired: if (utcExpires > DateTime.UtcNow) { // Create the response object to be sent on cache hits. HttpRawResponse httpRawResponse = response.GetSnapshot(); string kernelCacheUrl = response.SetupKernelCaching(null); Guid cachedVaryId = (cachedVary != null) ? cachedVary.CachedVaryId : Guid.Empty; CachedRawResponse cachedRawResponse = new CachedRawResponse(httpRawResponse, settings, kernelCacheUrl, cachedVaryId); Debug.Trace("OutputCacheModuleLeave", "Adding response to cache.\n\tkey=" + keyRawResponse); CacheDependency dep = response.CreateCacheDependencyForResponse(); try { OutputCache.InsertResponse(_key, cachedVary, keyRawResponse, cachedRawResponse, dep, utcExpires, slidingDelta); } catch { if (dep != null) { dep.Dispose(); } throw; } } _key = null; Debug.Trace("OutputCacheModuleLeave", "Returning from OutputCacheModule::Leave"); }
private static CachedVary UtcAdd(string key, CachedVary cachedVary) { return (CachedVary) HttpRuntime.CacheInternal.UtcAdd(key, cachedVary, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null); }
internal static string CreateOutputCachedItemKey( string path, CacheRequestMethod method, HttpContext context, CachedVary cachedVary) { StringBuilder sb; int i, j, n; string name, value; string[] a; byte[] buf, hash; HttpRequest request; NameValueCollection col; int contentLength; if (method == CacheRequestMethod.Post) { sb = new StringBuilder("System.Web.Http.HttpRawResponse\nM=3\n"); } else { sb = new StringBuilder("System.Web.Http.HttpRawResponse\nM=2\n"); } sb.Append(CultureInfo.InvariantCulture.TextInfo.ToLower(path)); /* key for cached vary item has additional information */ if (cachedVary != null) { request = context.Request; /* params part */ for (j = 0; j <= 2; j++) { switch (j) { case 0: sb.Append("\nVH"); a = cachedVary._headers; col = request.ServerVariables; break; case 1: sb.Append("\nVPQ"); a = cachedVary._params; col = request.QueryString; break; case 2: default: sb.Append("\nVPF"); a = cachedVary._params; col = request.Form; if (method != CacheRequestMethod.Post) { col = null; } break; } if (col == null) { continue; } /* handle all params case (VaryByParams[*] = true) */ if (a == null && cachedVary._varyByAllParams && j != 0) { a = col.AllKeys; for (i = a.Length - 1; i >= 0; i--) { if (a[i] != null) { a[i] = CultureInfo.InvariantCulture.TextInfo.ToLower(a[i]); } } Array.Sort(a, InvariantComparer.Default); } if (a != null) { for (i = 0, n = a.Length; i < n; i++) { name = a[i]; value = col[name]; if (value == null) { value = NULL_VARYBY_VALUE; } sb.Append("\tPN:"); sb.Append(name); sb.Append("\tPV:"); sb.Append(value); } } } /* custom string part */ sb.Append("\nVC"); if (cachedVary._varyByCustom != null) { sb.Append("\tCN:"); sb.Append(cachedVary._varyByCustom); sb.Append("\tCV:"); try { value = context.ApplicationInstance.GetVaryByCustomString( context, cachedVary._varyByCustom); if (value == null) { value = NULL_VARYBY_VALUE; } } catch (Exception e) { value = ERROR_VARYBY_VALUE; HttpApplicationFactory.RaiseError(e); } sb.Append(value); } /* * if VaryByParms=*, and method is not a form, then * use a cryptographically strong hash of the data as * part of the key. */ sb.Append("\nVPD"); if (method == CacheRequestMethod.Post && cachedVary._varyByAllParams && request.Form.Count == 0) { contentLength = request.ContentLength; if (contentLength > MAX_POST_KEY_LENGTH || contentLength < 0) { return(null); } if (contentLength > 0) { buf = ((HttpInputStream)request.InputStream).Data; if (buf == null) { return(null); } hash = MachineKey.HashData(buf, s_hashModifier, 0, buf.Length); value = Convert.ToBase64String(hash); sb.Append(value); } } sb.Append("\nEOV"); } return(sb.ToString()); }
internal static string CreateOutputCachedItemKey(string path, HttpVerb verb, HttpContext context, CachedVary cachedVary) { StringBuilder builder; if (verb == HttpVerb.POST) { builder = new StringBuilder("a1", path.Length + "a1".Length); } else { builder = new StringBuilder("a2", path.Length + "a2".Length); } builder.Append(CultureInfo.InvariantCulture.TextInfo.ToLower(path)); if (cachedVary != null) { string varyByCustomString; HttpRequest request = context.Request; for (int i = 0; i <= 2; i++) { int num; string[] array = null; NameValueCollection serverVarsWithoutDemand = null; bool flag = false; switch (i) { case 0: builder.Append("H"); array = cachedVary._headers; if (array != null) { serverVarsWithoutDemand = request.GetServerVarsWithoutDemand(); } break; case 1: builder.Append("Q"); array = cachedVary._params; if (request.HasQueryString && ((array != null) || cachedVary._varyByAllParams)) { serverVarsWithoutDemand = request.QueryString; flag = cachedVary._varyByAllParams; } break; default: builder.Append("F"); if (verb == HttpVerb.POST) { array = cachedVary._params; if (request.HasForm && ((array != null) || cachedVary._varyByAllParams)) { serverVarsWithoutDemand = request.Form; flag = cachedVary._varyByAllParams; } } break; } if (flag && (serverVarsWithoutDemand.Count > 0)) { array = serverVarsWithoutDemand.AllKeys; num = array.Length - 1; while (num >= 0) { if (array[num] != null) { array[num] = CultureInfo.InvariantCulture.TextInfo.ToLower(array[num]); } num--; } Array.Sort(array, System.InvariantComparer.Default); } if (array != null) { num = 0; int length = array.Length; while (num < length) { string str = array[num]; if (serverVarsWithoutDemand == null) { varyByCustomString = "+n+"; } else { varyByCustomString = serverVarsWithoutDemand[str]; if (varyByCustomString == null) { varyByCustomString = "+n+"; } } builder.Append("N"); builder.Append(str); builder.Append("V"); builder.Append(varyByCustomString); num++; } } } builder.Append("C"); if (cachedVary._varyByCustom != null) { builder.Append("N"); builder.Append(cachedVary._varyByCustom); builder.Append("V"); try { varyByCustomString = context.ApplicationInstance.GetVaryByCustomString(context, cachedVary._varyByCustom); if (varyByCustomString == null) { varyByCustomString = "+n+"; } } catch (Exception exception) { varyByCustomString = "+e+"; HttpApplicationFactory.RaiseError(exception); } builder.Append(varyByCustomString); } builder.Append("D"); if (((verb == HttpVerb.POST) && cachedVary._varyByAllParams) && (request.Form.Count == 0)) { int contentLength = request.ContentLength; if ((contentLength > 0x3a98) || (contentLength < 0)) { return(null); } if (contentLength > 0) { byte[] asByteArray = ((HttpInputStream)request.InputStream).GetAsByteArray(); if (asByteArray == null) { return(null); } varyByCustomString = Convert.ToBase64String(MachineKeySection.HashData(asByteArray, null, 0, asByteArray.Length)); builder.Append(varyByCustomString); } } builder.Append("E"); string[] strArray2 = cachedVary._contentEncodings; if (strArray2 != null) { string httpHeaderContentEncoding = context.Response.GetHttpHeaderContentEncoding(); if (httpHeaderContentEncoding != null) { for (int j = 0; j < strArray2.Length; j++) { if (strArray2[j] == httpHeaderContentEncoding) { builder.Append(httpHeaderContentEncoding); break; } } } } } return(builder.ToString()); }
/* * Return a key to lookup a cached response. The key contains * the path and optionally, vary parameters, vary headers, custom strings, * and form posted data. */ string CreateOutputCachedItemKey(HttpContext context, CachedVary cachedVary) { return(CreateOutputCachedItemKey(context.Request.Path, _method, context, cachedVary)); }
internal void OnLeave(object source, EventArgs eventArgs) { HttpApplication application = (HttpApplication)source; HttpContext context = application.Context; HttpRequest request = context.Request; HttpResponse response = context.Response; HttpCachePolicy cache = null; bool flag = false; if (response.HasCachePolicy) { cache = response.Cache; if (((cache.IsModified() && (response.Cookies.Count <= 0)) && (response.StatusCode == 200)) && (((request.HttpVerb == HttpVerb.GET) || (request.HttpVerb == HttpVerb.POST)) && response.IsBuffered())) { bool flag3 = false; if ((cache.GetCacheability() == HttpCacheability.Public) && context.RequestRequiresAuthorization()) { cache.SetCacheability(HttpCacheability.Private); flag3 = true; } if (((((cache.GetCacheability() == HttpCacheability.Public) || (cache.GetCacheability() == HttpCacheability.ServerAndPrivate)) || ((cache.GetCacheability() == HttpCacheability.Server) || flag3)) && (!cache.GetNoServerCaching() && (cache.HasExpirationPolicy() || cache.HasValidationPolicy()))) && ((!cache.VaryByHeaders.GetVaryByUnspecifiedParameters() && (cache.VaryByParams.AcceptsParams() || ((request.HttpVerb != HttpVerb.POST) && !request.HasQueryString))) && (!cache.VaryByContentEncodings.IsModified() || cache.VaryByContentEncodings.IsCacheableEncoding(context.Response.GetHttpHeaderContentEncoding())))) { flag = true; } } } if (flag) { CachedVary vary; string str; string[] varyByParams; this.RecordCacheMiss(); HttpCachePolicySettings currentSettings = cache.GetCurrentSettings(response); string[] varyByContentEncodings = currentSettings.VaryByContentEncodings; string[] varyByHeaders = currentSettings.VaryByHeaders; if (currentSettings.IgnoreParams) { varyByParams = null; } else { varyByParams = currentSettings.VaryByParams; } if (this._key == null) { this._key = this.CreateOutputCachedItemKey(context, null); } if (((varyByContentEncodings == null) && (varyByHeaders == null)) && ((varyByParams == null) && (currentSettings.VaryByCustom == null))) { str = this._key; vary = null; } else { int num; int length; if (varyByHeaders != null) { num = 0; length = varyByHeaders.Length; while (num < length) { varyByHeaders[num] = "HTTP_" + CultureInfo.InvariantCulture.TextInfo.ToUpper(varyByHeaders[num].Replace('-', '_')); num++; } } bool varyByAllParams = false; if (varyByParams != null) { varyByAllParams = (varyByParams.Length == 1) && (varyByParams[0] == "*"); if (varyByAllParams) { varyByParams = null; } else { num = 0; length = varyByParams.Length; while (num < length) { varyByParams[num] = CultureInfo.InvariantCulture.TextInfo.ToLower(varyByParams[num]); num++; } } } vary = new CachedVary(varyByContentEncodings, varyByHeaders, varyByParams, varyByAllParams, currentSettings.VaryByCustom); str = this.CreateOutputCachedItemKey(context, vary); if (str == null) { return; } if (!response.IsBuffered()) { return; } } DateTime noAbsoluteExpiration = Cache.NoAbsoluteExpiration; TimeSpan noSlidingExpiration = Cache.NoSlidingExpiration; if (currentSettings.SlidingExpiration) { noSlidingExpiration = currentSettings.SlidingDelta; } else if (currentSettings.IsMaxAgeSet) { DateTime time2 = (currentSettings.UtcTimestampCreated != DateTime.MinValue) ? currentSettings.UtcTimestampCreated : context.UtcTimestamp; noAbsoluteExpiration = time2 + currentSettings.MaxAge; } else if (currentSettings.IsExpiresSet) { noAbsoluteExpiration = currentSettings.UtcExpires; } if (noAbsoluteExpiration > DateTime.UtcNow) { HttpRawResponse snapshot = response.GetSnapshot(); string kernelCacheUrl = response.SetupKernelCaching(null); Guid cachedVaryId = (vary != null) ? vary.CachedVaryId : Guid.Empty; CachedRawResponse rawResponse = new CachedRawResponse(snapshot, currentSettings, kernelCacheUrl, cachedVaryId); CacheDependency dependencies = response.CreateCacheDependencyForResponse(); try { OutputCache.InsertResponse(this._key, vary, str, rawResponse, dependencies, noAbsoluteExpiration, noSlidingExpiration); } catch { if (dependencies != null) { dependencies.Dispose(); } throw; } } this._key = null; } }
/* * If the item is cacheable, add it to the cache. */ /// <include file='doc\OutputCacheModule.uex' path='docs/doc[@for="OutputCacheModule.OnLeave"]/*' /> /// <devdoc> /// <para>Raises the <see langword='Leave'/> event, which causes any cacheable items to /// be put into the output cache.</para> /// </devdoc> internal /*public*/ void OnLeave(Object source, EventArgs eventArgs) { HttpApplication app; HttpContext context; bool cacheable; CachedRawResponse cachedRawResponse; CachedVary cachedVary; CachedVary cachedVaryInCache; HttpCachePolicy cache; HttpCachePolicySettings settings; CacheDependency dependency; CacheDependency dependencyVary; string keyRawResponse; string[] varyByHeaders; string[] varyByParams; bool varyByAllParams; HttpRequest request; HttpResponse response; DateTime utcTimestamp; TimeSpan slidingDelta; HttpRawResponse httpRawResponse; int i, n; DateTime utcExpires; bool cacheAuthorizedPage; CacheInternal cacheInternal; Debug.Trace("OutputCacheModuleLeave", "Beginning OutputCacheModule::Leave"); app = (HttpApplication)source; context = app.Context; request = context.Request; response = context.Response; cache = response.Cache; #if DBG string reason = null; #endif /* * Determine whether the response is cacheable. */ cacheable = false; do { if (!cache.IsModified()) { #if DBG reason = "CachePolicy was not modified from non-caching default."; #endif break; } if (_key == null) { #if DBG reason = "no key was created for Request in Enter method."; #endif break; } if (response.StatusCode != 200) { #if DBG reason = "response.StatusCode != 200."; #endif break; } if (_method == CacheRequestMethod.Head) { #if DBG reason = "the cache cannot cache responses to HEAD requests."; #endif break; } if (!response.IsBuffered()) { #if DBG reason = "the response is not buffered."; #endif break; } /* * Change a response with HttpCacheability.Public to HttpCacheability.Private * if it requires authorization, and allow it to be cached. * * Note that setting Cacheability to ServerAndPrivate would accomplish * the same thing without needing the "cacheAuthorizedPage" variable, * but in RTM we did not have ServerAndPrivate, and setting that value * would change the behavior. */ cacheAuthorizedPage = false; if (cache.GetCacheability() == HttpCacheability.Public && context.RequestRequiresAuthorization()) { cache.SetCacheability(HttpCacheability.Private); cacheAuthorizedPage = true; } if (cache.GetCacheability() != HttpCacheability.Public && cache.GetCacheability() != HttpCacheability.ServerAndPrivate && cache.GetCacheability() != HttpCacheability.ServerAndNoCache && !cacheAuthorizedPage) { #if DBG reason = "CachePolicy.Cacheability is not Public, ServerAndPrivate, or ServerAndNoCache."; #endif break; } if (cache.GetNoServerCaching()) { #if DBG reason = "CachePolicy.NoServerCaching is set."; #endif break; } if (!cache.HasExpirationPolicy() && !cache.HasValidationPolicy()) { #if DBG reason = "CachePolicy has no expiration policy or validation policy."; #endif break; } if (cache.VaryByHeaders.GetVaryByUnspecifiedParameters()) { #if DBG reason = "CachePolicy.Vary.VaryByUnspecifiedParameters was called."; #endif break; } if (!cache.VaryByParams.AcceptsParams() && (_method == CacheRequestMethod.Post || request.QueryStringText != String.Empty)) { #if DBG reason = "the cache cannot cache responses to POSTs or GETs with query strings unless Cache.VaryByParams is modified."; #endif break; } cacheable = true; } while (false); /* * Add response to cache. */ if (!cacheable) { #if DBG Debug.Assert(reason != null, "reason != null"); Debug.Trace("OutputCacheModuleLeave", "Item is not output cacheable because " + reason + "\n\tUrl=" + request.Url.ToString() + "\nReturning from OutputCacheModule::Leave"); #endif return; } RecordCacheMiss(); settings = cache.GetCurrentSettings(response); /* Determine the size of the sliding expiration.*/ utcTimestamp = context.UtcTimestamp; utcExpires = DateTime.MaxValue; if (settings.SlidingExpiration) { slidingDelta = settings.SlidingDelta; utcExpires = Cache.NoAbsoluteExpiration; } else { slidingDelta = Cache.NoSlidingExpiration; if (settings.IsMaxAgeSet) { utcExpires = utcTimestamp + settings.MaxAge; } else if (settings.IsExpiresSet) { utcExpires = settings.UtcExpires; } } varyByHeaders = settings.VaryByHeaders; if (settings.IgnoreParams) { varyByParams = null; } else { varyByParams = settings.VaryByParams; } cacheInternal = HttpRuntime.CacheInternal; if (varyByHeaders == null && varyByParams == null && settings.VaryByCustom == null) { /* * This is not a varyBy item. */ keyRawResponse = _key; cachedVary = null; dependencyVary = null; } else { /* * There is a vary in the cache policy. We handle this * by adding another item to the cache which contains * a list of the vary headers. A request for the item * without the vary headers in the key will return this * item. From the headers another key can be constructed * to lookup the item with the raw response. */ if (varyByHeaders != null) { for (i = 0, n = varyByHeaders.Length; i < n; i++) { varyByHeaders[i] = "HTTP_" + CultureInfo.InvariantCulture.TextInfo.ToUpper( varyByHeaders[i].Replace('-', '_')); } } varyByAllParams = false; if (varyByParams != null) { varyByAllParams = (varyByParams.Length == 1 && varyByParams[0] == "*"); if (varyByAllParams) { varyByParams = null; } else { for (i = 0, n = varyByParams.Length; i < n; i++) { varyByParams[i] = CultureInfo.InvariantCulture.TextInfo.ToLower(varyByParams[i]); } } } cachedVary = new CachedVary(varyByHeaders, varyByParams, varyByAllParams, settings.VaryByCustom); keyRawResponse = CreateOutputCachedItemKey(context, cachedVary); if (keyRawResponse == null) { Debug.Trace("OutputCacheModuleLeave", "Couldn't add non-cacheable post.\n\tkey=" + _key); return; } // it is possible that the user code calculating custom vary-by // string would Flush making the response non-cacheable. Check fo it here. if (!response.IsBuffered()) { Debug.Trace("OutputCacheModuleLeave", "Response.Flush() inside GetVaryByCustomString\n\tkey=" + _key); return; } /* * Add the CachedVary item so that a request will know * which headers are needed to issue another request. * * Use the Add method so that we guarantee we only use * a single CachedVary and don't overwrite existing ones. */ cachedVaryInCache = (CachedVary)cacheInternal.UtcAdd( _key, cachedVary, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Default, null); if (cachedVaryInCache != null) { if (cachedVary.Equals(cachedVaryInCache)) { cachedVary = cachedVaryInCache; } else { Debug.Trace("OutputCacheModuleLeave", "CachedVary definition changed, new CachedVary inserted into cache.\n\tkey=" + _key); cacheInternal.UtcInsert(_key, cachedVary); } } #if DBG else { Debug.Trace("OutputCacheModuleLeave", "Added CachedVary to cache.\n\tkey=" + _key); } #endif dependencyVary = new CacheDependency(false, null, new string[1] { _key }); } Debug.Trace("OutputCacheModuleLeave", "Adding response to cache.\n\tkey=" + keyRawResponse + "\nReturning from OutputCacheModule::Leave"); dependency = response.GetCacheDependency(dependencyVary); /* * Create the response object to be sent on cache hits. */ httpRawResponse = response.GetSnapshot(); cachedRawResponse = new CachedRawResponse(httpRawResponse, settings, cachedVary); Debug.Trace("OutputCacheModuleLeave", "utcExpires=" + utcExpires + "expires=" + DateTimeUtil.ConvertToLocalTime(utcExpires)); cacheInternal.UtcInsert( keyRawResponse, cachedRawResponse, dependency, utcExpires, slidingDelta, CacheItemPriority.Normal, s_cacheItemRemovedCallback); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_ENTRIES); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_TURNOVER_RATE); }
internal static void InsertResponse(string cachedVaryKey, CachedVary cachedVary, string rawResponseKey, CachedRawResponse rawResponse, CacheDependency dependencies, DateTime absExp, TimeSpan slidingExp) { OutputCacheProvider provider = GetProvider(HttpContext.Current); bool flag = provider != null; if (flag) { bool flag2 = ((IsSubstBlockSerializable(rawResponse._rawResponse) && rawResponse._settings.IsValidationCallbackSerializable()) && (slidingExp == Cache.NoSlidingExpiration)) && ((dependencies == null) || dependencies.IsFileDependency()); if (flag && !flag2) { throw new ProviderException(System.Web.SR.GetString("Provider_does_not_support_policy_for_responses", new object[] { provider.Name })); } } if (cachedVary != null) { CachedVary vary; if (!flag) { vary = UtcAdd(cachedVaryKey, cachedVary); } else { vary = (CachedVary)provider.Add(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } if (vary != null) { if (!cachedVary.Equals(vary)) { if (!flag) { HttpRuntime.CacheInternal.UtcInsert(cachedVaryKey, cachedVary); } else { provider.Set(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } } else { cachedVary = vary; } } if (!flag) { AddCacheKeyToDependencies(ref dependencies, cachedVaryKey); } rawResponse._cachedVaryId = cachedVary.CachedVaryId; } if (!flag) { HttpRuntime.CacheInternal.UtcInsert(rawResponseKey, rawResponse, dependencies, absExp, slidingExp, CacheItemPriority.Normal, s_entryRemovedCallback); IncrementCount(); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_ENTRIES); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_TURNOVER_RATE); } else { string depKey = null; string[] fileDependencies = null; if (dependencies != null) { depKey = "aD" + dependencies.GetUniqueID(); fileDependencies = dependencies.GetFileDependencies(); } OutputCacheEntry entry = Convert(rawResponse, depKey, fileDependencies); provider.Set(rawResponseKey, entry, absExp); if ((dependencies != null) && (HttpRuntime.CacheInternal.UtcAdd(depKey, new DependencyCacheEntry(rawResponseKey, entry.KernelCacheUrl, provider.Name), dependencies, absExp, Cache.NoSlidingExpiration, CacheItemPriority.Normal, s_dependencyRemovedCallback) != null)) { dependencies.Dispose(); } } }
// insert cached vary or output cache entry internal static void InsertResponse(String cachedVaryKey, CachedVary cachedVary, String rawResponseKey, CachedRawResponse rawResponse, CacheDependency dependencies, DateTime absExp, TimeSpan slidingExp) { // if the provider is undefined or the fragment can't be inserted in the // provider, insert it in the internal cache. OutputCacheProvider provider = GetProvider(HttpContext.Current); // // CachedVary can be serialized. // CachedRawResponse is not always serializable. // bool useProvider = (provider != null); if (useProvider) { bool canUseProvider = (IsSubstBlockSerializable(rawResponse._rawResponse) && rawResponse._settings.IsValidationCallbackSerializable() && slidingExp == Cache.NoSlidingExpiration && (dependencies == null || dependencies.IsFileDependency())); if (useProvider && !canUseProvider) { throw new ProviderException(SR.GetString(SR.Provider_does_not_support_policy_for_responses, provider.Name)); } } #if DBG bool cachedVaryPutInCache = (cachedVary != null); #endif if (cachedVary != null) { /* * Add the CachedVary item so that a request will know * which headers are needed to issue another request. * * Use the Add method so that we guarantee we only use * a single CachedVary and don't overwrite existing ones. */ CachedVary cachedVaryInCache; if (!useProvider) { cachedVaryInCache = OutputCache.UtcAdd(cachedVaryKey, cachedVary); } else { cachedVaryInCache = (CachedVary) provider.Add(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } if (cachedVaryInCache != null) { if (!cachedVary.Equals(cachedVaryInCache)) { if (!useProvider) { HttpRuntime.CacheInternal.UtcInsert(cachedVaryKey, cachedVary); } else { provider.Set(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } } else { cachedVary = cachedVaryInCache; #if DBG cachedVaryPutInCache = false; #endif } } if (!useProvider) { AddCacheKeyToDependencies(ref dependencies, cachedVaryKey); } // not all caches support cache key dependencies, but we can use a "change number" to associate // the ControlCachedVary and the PartialCachingCacheEntry rawResponse._cachedVaryId = cachedVary.CachedVaryId; } // Now insert into the cache (use cache provider if possible, otherwise use internal cache) if (!useProvider) { HttpRuntime.CacheInternal.UtcInsert(rawResponseKey, rawResponse, dependencies, absExp, slidingExp, CacheItemPriority.Normal, s_entryRemovedCallback); IncrementCount(); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_ENTRIES); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_TURNOVER_RATE); } else { string depKey = null; string[] fileDeps = null; if (dependencies != null) { depKey = OUTPUTCACHE_KEYPREFIX_DEPENDENCIES + dependencies.GetUniqueID(); fileDeps = dependencies.GetFileDependencies(); } OutputCacheEntry oce = Convert(rawResponse, depKey, fileDeps); provider.Set(rawResponseKey, oce, absExp); if (dependencies != null) { // use Add and dispose dependencies if there's already one in the cache Object d = HttpRuntime.CacheInternal.UtcAdd(depKey, new DependencyCacheEntry(rawResponseKey, oce.KernelCacheUrl, provider.Name), dependencies, absExp, Cache.NoSlidingExpiration, CacheItemPriority.Normal, s_dependencyRemovedCallback); if (d != null) { dependencies.Dispose(); } } } #if DBG string cachedVaryType = (cachedVaryPutInCache) ? "CachedVary" : ""; string providerUsed = (useProvider) ? provider.Name : "CacheInternal"; Debug.Trace("OutputCache", "InsertResposne(" + cachedVaryKey + ", " + cachedVaryType + ", " + rawResponseKey + ", CachedRawResponse, ...) -->" + providerUsed); #endif }
// // helpers for accessing InternalCache // // add CachedVary private static CachedVary UtcAdd(String key, CachedVary cachedVary) { return((CachedVary)HttpRuntime.Cache.InternalCache.Add(key, cachedVary, null)); }