// finds and matches a tracker (this a or sub-tracker in varyby cases) for a HttpRequest public Tracker FindTrackerForRequest(HttpRequest request) { // path if (String.Compare(_path, request.FilePath, StringComparison.OrdinalIgnoreCase) != 0) { return null; } // verbs bool verbMatchFound = String.Compare(_verbs[0], request.HttpMethod, StringComparison.OrdinalIgnoreCase) == 0; if (!verbMatchFound && _verbs.Length > 1) { for (int i = 1; i < _verbs.Length; i++) { if (String.Compare(_verbs[i], request.HttpMethod, StringComparison.OrdinalIgnoreCase) == 0) { verbMatchFound = true; break; } } } if (!verbMatchFound) { return null; } // path info if (_emptyPathInfoOnly && !string.IsNullOrEmpty(request.PathInfo)) { return null; } // query string if (_emptyQueryStringOnly && request.QueryString.Count > 0) { return null; } // in non-vary-by case return this tracker if (_varyBy == null || _varyBy.Length == 0) { return this; } // get the child tracker corresponding to vary-by key for this request Tracker childTracker = null; string varyByKey = CalculateVaryByKey(_varyBy, request); lock (_varyByTrackers) { if (!_varyByTrackers.TryGetValue(varyByKey, out childTracker)) { // create a new child tracker if not exceeding the limit already if (_varyByTrackers.Count < HttpModule.OutputCache.VaryByLimit) { childTracker = new Tracker(this, varyByKey); _varyByTrackers.Add(varyByKey, childTracker); } } } return childTracker; }
// private ctor to create a child tracker for a specific vary-by value Tracker(Tracker parent, string varyById) { _parent = parent; _path = parent._path; _duration = parent._duration; _verbs = parent._verbs; _varyBy = parent._varyBy; _serveFromMemory = parent._serveFromMemory; _varyById = varyById; _filenamePrefix = string.Format("{0}_q_{1:x8}", parent._filenamePrefix, varyById.GetHashCode()); _capturingEvent = new ManualResetEvent(true); _varyByTrackers = null; // no need for sub-sub-trackers }
void OnResolveRequestCache(object sender, EventArgs e) { // start clean _trackerCapturingResponse = null; Tracker tracker = HttpModule.OutputCache.Lookup(_app.Context); if (tracker == null) { // this request is not subject to cache return; } // try to send response or start capture // (use 'finally' because starting capture would lock) try { } finally { if (tracker.TrySendResponseOrStartResponseCapture(_app.Response)) { // successfully sent current response _app.CompleteRequest(); } else { // started capturing _trackerCapturingResponse = tracker; } } }
void OnEndRequest(object sender, EventArgs e) { if (_trackerCapturingResponse != null) { // if still capturing, abandon the process try { _trackerCapturingResponse.CancelCapture(_app.Response); } finally { _trackerCapturingResponse = null; } } }
void OnUpdateRequestCache(object sender, EventArgs e) { if (_trackerCapturingResponse != null) { // if capturing, finish the capture and save the file _trackerCapturingResponse.FinishCaptureAndSaveResponse(_app.Response); _trackerCapturingResponse = null; } }
bool Startup() { DiskOutputCacheSettingsSection config = (DiskOutputCacheSettingsSection) WebConfigurationManager.GetWebApplicationSection("diskOutputCacheSettings"); if (config == null) { // no config - the list of URLs is empty return false; } if (string.IsNullOrEmpty(config.Location)) { // the default location is in temporary asp.net files _location = Path.Combine(HttpRuntime.CodegenDir, "DiskOutputCache"); if (!Directory.Exists(_location)) { Directory.CreateDirectory(_location); } } else { _location = config.Location; if (!Directory.Exists(_location)) { throw new InvalidDataException(string.Format("Invalid location '{0}'", _location)); } } _varyByLimit = config.VaryByLimitPerUrl; _fileValidationDelay = config.FileValidationDelay; foreach (CachedUrlsElement e in config.CachedUrls) { string path = e.Path; if (!VirtualPathUtility.IsAppRelative(path) && !VirtualPathUtility.IsAbsolute(path)) { throw new InvalidDataException(string.Format("Invalid path '{0}', absolute or app-relative path expected", path)); } path = VirtualPathUtility.ToAbsolute(path); // create file path prefix for this path string relPathPrefix = VirtualPathUtility.ToAppRelative(path); if (relPathPrefix.StartsWith("~/")) { relPathPrefix = relPathPrefix.Substring(2); } relPathPrefix = relPathPrefix.Replace('.', '_'); relPathPrefix = relPathPrefix.Replace('/', '_'); // list of verbs string[] verbs = ParseStringList(e.Verbs); if (verbs.Length == 0) { throw new InvalidDataException(string.Format("Invalid list of verbs '{0}'", e.Verbs)); } // vary-by string[] varyBy = ParseStringList(e.VaryBy); // remember the tracker object _trackers[path] = new Tracker(path, Path.Combine(_location, relPathPrefix), e.Duration, verbs, varyBy, e.EmptyQueryStringOnly, e.EmptyPathInfoOnly, e.ServeFromMemory); } return true; }