/// <summary> /// Sets the output cache parameters and also the client side caching parameters /// </summary> /// <param name="context"></param> private void SetCaching(HttpContext context, string fileName) { //This ensures OutputCaching is set for this handler and also controls //client side caching on the browser side. Default is 10 days. TimeSpan duration = TimeSpan.FromDays(10); HttpCachePolicy cache = context.Response.Cache; cache.SetCacheability(HttpCacheability.Public); cache.SetExpires(DateTime.Now.Add(duration)); cache.SetMaxAge(duration); cache.SetValidUntilExpires(true); cache.SetLastModified(DateTime.Now); cache.SetETag(Guid.NewGuid().ToString()); //set server OutputCache to vary by our params cache.VaryByParams["t"] = true; cache.VaryByParams["s"] = true; //don't allow varying by wildcard cache.SetOmitVaryStar(true); //ensure client browser maintains strict caching rules cache.AppendCacheExtension("must-revalidate, proxy-revalidate"); //This is the only way to set the max-age cachability header in ASP.Net! FieldInfo maxAgeField = cache.GetType().GetField("_maxAge", BindingFlags.Instance | BindingFlags.NonPublic); maxAgeField.SetValue(cache, duration); //make this output cache dependent on the file if there is one. if (!string.IsNullOrEmpty(fileName)) { context.Response.AddFileDependency(fileName); } }
/// <summary> /// Set the response cache headers for WebResource /// </summary> /// <param name="cache"></param> /// <param name="etag"></param> /// <param name="maxAge"></param> protected static void SetCachingHeadersForWebResource(HttpCachePolicy cache, string etag, TimeSpan maxAge) { cache.SetCacheability(HttpCacheability.Public); cache.VaryByParams["d"] = true; cache.SetOmitVaryStar(true); cache.SetExpires(DateTime.Now.Add(maxAge)); cache.SetValidUntilExpires(true); cache.VaryByHeaders["Accept-Encoding"] = true; cache.SetETag(string.Concat("\"", etag, "\"")); }
public void ProcessRequest(HttpContext context) { string[] jsFiles = context.Request.QueryString["jsfiles"].Split(','); List <string> files = new List <string>(); StringBuilder response = new StringBuilder(); foreach (string jsFile in jsFiles) { if (!jsFile.EndsWith(".js", StringComparison.OrdinalIgnoreCase)) { //log custom exception context.Response.StatusCode = 403; return; } try { JavaScriptCompressor javaScriptCompressor = new JavaScriptCompressor(); string filePath = context.Server.MapPath(jsFile); string js = File.ReadAllText(filePath); string compressedJS = javaScriptCompressor.Compress(js); response.Append(compressedJS); } catch (Exception ex) { //log exception context.Response.StatusCode = 500; return; } } context.Response.Write(response.ToString()); string version = "1.0"; //your dynamic version number here context.Response.ContentType = "application/javascript"; context.Response.AddFileDependencies(files.ToArray()); HttpCachePolicy cache = context.Response.Cache; cache.SetCacheability(HttpCacheability.Public); cache.VaryByParams["jsfiles"] = true; cache.VaryByParams["version"] = true; cache.SetETag(version); cache.SetLastModifiedFromFileDependencies(); cache.SetMaxAge(TimeSpan.FromDays(14)); cache.SetRevalidation(HttpCacheRevalidation.AllCaches); }
/// <summary> /// Sets the ETag HTTP header to the specified string. /// </summary> /// <param name="etag">The text to use for the ETag header. </param> /// <exception cref="T:System.ArgumentNullException"><paramref name="etag" /> is null. </exception> /// <exception cref="T:System.InvalidOperationException"> /// The ETag header has already been set. - or -The /// <see cref="M:System.Web.HttpCachePolicy.SetETagFromFileDependencies" /> has already been called. /// </exception> public void SetETag(string etag) { policy.SetETag(etag); }
internal static void ProcessRequestInternal(HttpContext context, string pathOverride) { HttpRequest request = context.Request; HttpResponse response = context.Response; string virtualPathWithPathInfo; string physicalPath; FileInfo fileInfo; long fileLength; DateTime lastModifiedInUtc; string etag; string rangeHeader; // custom virtual path providers that don't yeild a MapPathBasedVirtualFile // are a special case, and do not support TransmitFile, WriteFile, Range requests, // or the cache policy that we apply below /* * if (ProcessRequestForNonMapPathBasedVirtualFile(request, response, overrideVirtualPath)) { * return; * } * * if (overrideVirtualPath == null) * { * virtualPathWithPathInfo = request.Path; * physicalPath = request.PhysicalPath; * } * else { * virtualPathWithPathInfo = overrideVirtualPath; * physicalPath = request.MapPath(overrideVirtualPath); * } */ if (pathOverride != null) { physicalPath = pathOverride; } else { physicalPath = context.Request.PhysicalPath; } // Debug.Trace("StaticFileHandler", "Path= " + virtualPathWithPathInfo + ", PhysicalPath= " + physicalPath); try { fileInfo = GetFileInfo(physicalPath); } catch (HttpException hex) { int httpCode = hex.GetHttpCode(); string httpError = String.Format("{0} ({1})", hex.Message, physicalPath); throw new HttpException(httpCode, httpError, hex); } // Determine Last Modified Time. We might need it soon // if we encounter a Range: and If-Range header // Using UTC time to avoid daylight savings time bug 83230 lastModifiedInUtc = new DateTime(fileInfo.LastWriteTimeUtc.Year, fileInfo.LastWriteTimeUtc.Month, fileInfo.LastWriteTimeUtc.Day, fileInfo.LastWriteTimeUtc.Hour, fileInfo.LastWriteTimeUtc.Minute, fileInfo.LastWriteTimeUtc.Second, 0, DateTimeKind.Utc); // Because we can't set a "Last-Modified" header to any time // in the future, check the last modified time and set it to // DateTime.Now if it's in the future. // This is to fix VSWhidbey #402323 DateTime utcNow = DateTime.UtcNow; if (lastModifiedInUtc > utcNow) { // use 1 second resolution lastModifiedInUtc = new DateTime(utcNow.Ticks - (utcNow.Ticks % TimeSpan.TicksPerSecond), DateTimeKind.Utc); } etag = GenerateETag(lastModifiedInUtc, utcNow); fileLength = fileInfo.Length; // is this a Range request? rangeHeader = request.Headers["Range"]; if (rangeHeader != null && rangeHeader.StartsWith("bytes", StringComparison.OrdinalIgnoreCase) && ProcessRangeRequest(context, physicalPath, fileLength, rangeHeader, etag, lastModifiedInUtc)) { return; } // if we get this far, we're sending the entire file SendFile(physicalPath, 0, fileLength, fileLength, context); // Specify content type. Use extension to do the mapping response.ContentType = MimeMapping.GetMapping(physicalPath); // Static file handler supports byte ranges response.AppendHeader("Accept-Ranges", "bytes"); // We want to flush cache entry when static file has changed response.AddFileDependency(physicalPath); /* * NOTE: This was the code originally in the handler: * // Set an expires in the future. * response.Cache.SetExpires(utcNow.AddMinutes(5)); * // always set Last-Modified * response.Cache.SetLastModified(lastModifiedInUtc); * // always set ETag * response.Cache.SetETag(etag); * // always set Cache-Control to public * response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate); */ // set cache headers HttpCachePolicy cachePolicy = response.Cache; SetCachingPolicy(cachePolicy); // set cache file info cachePolicy.SetETag(etag); cachePolicy.SetLastModified(lastModifiedInUtc); }
public override void SetETag(string etag) { _httpCachePolicy.SetETag(etag); }
void IHttpHandler.ProcessRequest(HttpContext context) { Image image; ImageFormat imageFormat; string contentType = null; MemoryStream memStream = null; ImageCache imageCache; bool enableCaching = true; bool cacheValid = false; int minutes = Null.NullInteger; string cacheKey = null; string eTag = null; // Get params string imagePath = context.Request.QueryString["IP"]; string thumbWidth = context.Request.QueryString["IW"]; string background = context.Request.QueryString["BC"]; string duration = context.Request.QueryString["CD"]; // Get Header Etag string headerEtag = context.Request.Headers["If-None-Match"]; // When image param start by http or https, // it's probably an external image! ImageTypeName imageType; if (imagePath.IndexOf("http://") > -1 || imagePath.IndexOf("https://") > -1) { // Image will be get from an http request imageType = ImageTypeName.URI; } else { // Image will be read from disk imageType = ImageTypeName.FilePath; imagePath = context.Server.MapPath(imagePath); } // Default image if not found string defaultImage = context.Server.MapPath("~/images/thumbnail.jpg"); try { if (string.IsNullOrEmpty(imagePath) == false) { // Initializations if (string.IsNullOrEmpty(thumbWidth)) { thumbWidth = "175"; } if (string.IsNullOrEmpty(duration)) { enableCaching = false; } else { minutes = Convert.ToInt32(duration); } // Get cached image thumbnail if (enableCaching) { cacheKey = string.Format("Store_{0}_{1}_{2}", imagePath, thumbWidth, background); eTag = cacheKey.GetHashCode().ToString("X"); imageCache = (ImageCache)DataCache.GetCache(cacheKey); if (imageCache != null) { contentType = imageCache.ContentType; memStream = new MemoryStream(imageCache.Data); cacheValid = true; } } // If cache is null, create the thumbnail if (!cacheValid) { image = GetImage(imageType, imagePath, defaultImage); imageFormat = image.RawFormat; contentType = GetContentType(imageFormat); Size thumbSize = ThumbSize(image.Width, image.Height, Convert.ToInt16(thumbWidth)); Bitmap thumb = new Bitmap(thumbSize.Width, thumbSize.Height); Graphics g = Graphics.FromImage(thumb); g.CompositingQuality = CompositingQuality.HighQuality; g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.SmoothingMode = SmoothingMode.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; // Fill background with specified color // to mimics original GIF transparency if (imageFormat.Equals(ImageFormat.Gif)) { Brush bgBrush = GetBrush(GetHexDigits(background)); g.FillRectangle(bgBrush, 0, 0, thumbSize.Width, thumbSize.Height); } g.DrawImage(image, 0, 0, thumbSize.Width, thumbSize.Height); // Create memory stream from thumbnail memStream = new MemoryStream(); thumb.Save(memStream, imageFormat); image.Dispose(); thumb.Dispose(); // Save thumbnail to cache if (enableCaching) { imageCache = new ImageCache(contentType, memStream.ToArray()); TimeSpan sliding = new TimeSpan(0, Convert.ToInt32(duration), 0); DataCache.SetCache(cacheKey, imageCache, sliding); } } // If an Etag is present and valid if (string.IsNullOrEmpty(headerEtag) == false && headerEtag == eTag) { // Return 304 Not Modified context.Response.Clear(); context.Response.StatusCode = (int)HttpStatusCode.NotModified; context.Response.SuppressContent = true; } else { // Return thumbnail to browser context.Response.StatusCode = (int)HttpStatusCode.OK; context.Response.ContentType = contentType; if (enableCaching) { HttpCachePolicy contextCache = context.Response.Cache; contextCache.SetCacheability(HttpCacheability.ServerAndPrivate); contextCache.SetExpires(DateTime.Now.AddMinutes(minutes).ToUniversalTime()); contextCache.SetLastModified(DateTime.Now.ToUniversalTime()); contextCache.SetETag(eTag); } memStream.WriteTo(context.Response.OutputStream); } memStream.Close(); memStream.Dispose(); } } catch { context.Response.StatusCode = (int)HttpStatusCode.NotFound; } }
public void Deny_Unrestricted() { HttpCachePolicy cache = response.Cache; Assert.IsNotNull(cache.VaryByHeaders, "VaryByHeaders"); Assert.IsNotNull(cache.VaryByParams, "VaryByParams"); cache.AddValidationCallback(new HttpCacheValidateHandler(Validate), null); cache.AppendCacheExtension("mono"); cache.SetCacheability(HttpCacheability.NoCache); cache.SetCacheability(HttpCacheability.NoCache, "mono"); cache.SetETag("etag"); try { cache.SetETagFromFileDependencies(); } catch (TypeInitializationException) { // 1.1 tries to initialize HttpRuntime } catch (InvalidOperationException) { // expected } cache.SetExpires(DateTime.MinValue); cache.SetLastModified(DateTime.Now); try { cache.SetLastModifiedFromFileDependencies(); } catch (InvalidOperationException) { // expected } catch (NotImplementedException) { // mono } cache.SetMaxAge(TimeSpan.FromTicks(1000)); try { cache.SetNoServerCaching(); } catch (NotImplementedException) { // mono } try { cache.SetNoStore(); } catch (NotImplementedException) { // mono } try { cache.SetNoTransforms(); } catch (NotImplementedException) { // mono } cache.SetProxyMaxAge(TimeSpan.FromTicks(2000)); cache.SetRevalidation(HttpCacheRevalidation.None); cache.SetSlidingExpiration(true); try { cache.SetValidUntilExpires(true); } catch (NotImplementedException) { // mono } cache.SetVaryByCustom("custom"); cache.SetAllowResponseInBrowserHistory(true); #if NET_2_0 try { cache.SetOmitVaryStar(false); } catch (NotImplementedException) { // mono } #endif }
internal static void ProcessRequestInternal(HttpContext context, string pathOverride) { HttpRequest request = context.Request; HttpResponse response = context.Response; string physicalPath = context.Request.PhysicalPath; string fileName = Path.GetFileName(physicalPath); if (pathOverride != null) { physicalPath = pathOverride; } FileInfo info; if (!FileExists(physicalPath)) { string error = "File does not exist"; if (context.IsDebuggingEnabled) { error += String.Format(": {0}", physicalPath); } throw new HttpException(404, error); } try { info = new FileInfo(physicalPath); } catch (IOException exception) { throw new HttpException(404, "Error trying to enumerate files", exception); } catch (SecurityException exception2) { throw new HttpException(401, "File enumerator access denied", exception2); } if (info.Length == 0) { throw new HttpException(404, "File is empty"); } if ((info.Attributes & FileAttributes.Hidden) != 0) { throw new HttpException(404, "File is hidden"); } if (physicalPath[physicalPath.Length - 1] == '.') { throw new HttpException(404, "File does not exist"); } if ((info.Attributes & FileAttributes.Directory) != 0) { if (request.Path.EndsWith("/")) { throw new HttpException(403, SR.GetString("Missing star mapping")); } response.Redirect(request.Path + "/"); } else { DateTime lastModTime = new DateTime(info.LastWriteTime.Year, info.LastWriteTime.Month, info.LastWriteTime.Day, info.LastWriteTime.Hour, info.LastWriteTime.Minute, info.LastWriteTime.Second, 0); if (lastModTime > DateTime.Now) { lastModTime = DateTime.Now; } string strETag = GenerateETag(context, lastModTime); try { BuildFileItemResponse(context, physicalPath, info.Length, lastModTime, strETag); } catch (Exception exception3) { if ((exception3 is ExternalException) && IsSecurityError(((ExternalException)exception3).ErrorCode)) { throw new HttpException(401, "Resource access forbidden"); } } // set cache headers HttpCachePolicy cachePolicy = context.Response.Cache; SetCachingPolicy(cachePolicy); // set cache file info cachePolicy.SetETag(strETag); cachePolicy.SetLastModified(lastModTime); } }
/// <summary> /// This will make the browser and server keep the output /// in its cache and thereby improve performance. /// See http://en.wikipedia.org/wiki/HTTP_ETag /// </summary> /// <param name="path"> /// The combined path to the items. /// </param> /// <param name="context"> /// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides /// references to the intrinsic server objects /// </param> /// <param name="responseType"> /// The HTTP MIME type to to send. /// </param> /// <param name="futureExpire"> /// Whether the response headers should be set to expire in the future. /// </param> /// <param name="fileMonitors"> /// The file Monitors. /// </param> protected void SetHeaders(string path, HttpContext context, ResponseType responseType, bool futureExpire, IList <string> fileMonitors) { // Generate a hash from the combined last write times of any monitors and // the path. StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(path); if (fileMonitors != null) { foreach (string fileMonitor in fileMonitors) { FileInfo fileInfo = new FileInfo(fileMonitor); stringBuilder.AppendFormat("{0}", fileInfo.LastWriteTimeUtc); } } int hash = stringBuilder.ToString().GetHashCode(); HttpResponse response = context.Response; HttpCachePolicy cache = response.Cache; response.ContentType = responseType.ToDescription(); cache.VaryByHeaders["Accept-Encoding"] = true; if (futureExpire) { int maxCacheDays = CruncherConfiguration.Instance.MaxCacheDays; cache.SetExpires(DateTime.UtcNow.AddDays(maxCacheDays)); cache.SetMaxAge(new TimeSpan(maxCacheDays, 0, 0, 0)); if (fileMonitors != null) { response.AddFileDependencies(fileMonitors.ToArray()); cache.SetLastModifiedFromFileDependencies(); } cache.SetValidUntilExpires(false); } else { cache.SetExpires(DateTime.UtcNow.AddDays(-1)); cache.SetMaxAge(new TimeSpan(0, 0, 0, 0)); } cache.SetRevalidation(HttpCacheRevalidation.AllCaches); string etag = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", hash); string incomingEtag = context.Request.Headers["If-None-Match"]; cache.SetETag(etag); cache.SetCacheability(HttpCacheability.Public); if (string.Compare(incomingEtag, etag, StringComparison.Ordinal) != 0) { return; } response.Clear(); response.StatusCode = (int)HttpStatusCode.NotModified; response.SuppressContent = true; }
/// <summary> /// Configures ASP.Net's Cache policy based on properties set /// </summary> /// <param name="policy">cache policy to set</param> void ICachePolicyConfigurer.Configure(HttpCachePolicy policy) { policy.SetAllowResponseInBrowserHistory(allowInHistory); policy.SetCacheability(cacheability); policy.SetOmitVaryStar(omitVaryStar); policy.SetRevalidation(revalidation); policy.SetSlidingExpiration(slidingExpiration); policy.SetValidUntilExpires(validUntilExpires); if (duration != 0) { policy.SetExpires(DateTime.Now.AddSeconds(duration)); } if (varyByContentEncodings != null) { foreach (var header in varyByContentEncodings.Split(',')) { policy.VaryByContentEncodings[header.Trim()] = true; } } if (varyByCustom != null) { policy.SetVaryByCustom(varyByCustom); } if (varyByHeaders != null) { foreach (var header in varyByHeaders.Split(',')) { policy.VaryByHeaders[header.Trim()] = true; } } if (varyByParams != null) { foreach (var param in varyByParams.Split(',')) { policy.VaryByParams[param.Trim()] = true; } } if (cacheExtension != null) { policy.AppendCacheExtension(cacheExtension); } if (setEtagFromFileDependencies) { policy.SetETagFromFileDependencies(); } if (setLastModifiedFromFileDependencies) { policy.SetLastModifiedFromFileDependencies(); } if (setNoServerCaching) { policy.SetNoServerCaching(); } if (setNoStore) { policy.SetNoStore(); } if (setNoTransforms) { policy.SetNoTransforms(); } if (etag != null) { policy.SetETag(etag); } if (isLastModifiedSet) { policy.SetLastModified(lastModified); } if (isMaxAgeSet) { policy.SetMaxAge(TimeSpan.FromSeconds(maxAge)); } if (isProxyMaxAgeSet) { policy.SetProxyMaxAge(TimeSpan.FromSeconds(proxyMaxAge)); } }
public override void SetETag(string etag) { _policy.SetETag(etag); }
public void ProcessRequest(HttpContext context) { HttpRequest request = context.Request; string phyFilePath = request.PhysicalPath; if (!File.Exists(phyFilePath)) { string phyDirPath = Path.GetDirectoryName(phyFilePath); if (!string.IsNullOrWhiteSpace(phyDirPath)) { string fileName = Path.GetFileNameWithoutExtension(phyFilePath); if (!string.IsNullOrWhiteSpace(fileName)) { string fileExtension = Path.GetExtension(phyFilePath); if (!string.IsNullOrWhiteSpace(fileExtension)) { string[] fileNames = fileName.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries); if (fileNames != null) { int length = fileNames.Length; if (length > 1) { fileName = string.Join("_", fileNames, 0, length - 1); phyFilePath = Path.Combine(phyDirPath, string.Concat(fileName, fileExtension)); } Array.Clear(fileNames, 0, length); fileNames = null; } fileExtension = null; } fileName = null; } phyDirPath = null; } } if (File.Exists(phyFilePath)) { HttpResponse response = context.Response; ECacheType cacheType = ECacheType.None; string subfix = Path.GetExtension(phyFilePath); if (".css".Equals(subfix, StringComparison.CurrentCultureIgnoreCase)) { cacheType = ECacheType.Css; response.ContentType = "text/css"; } else if (".js".Equals(subfix, StringComparison.CurrentCultureIgnoreCase)) { cacheType = ECacheType.Js; response.ContentType = "application/x-javascript"; } #if !DEBUG if (cacheType != ECacheType.None) { //http://www.cnblogs.com/shanyou/archive/2012/05/01/2477500.html const int DAYS = 30; string ifModifiedSince = request.Headers["If-Modified-Since"]; if (!string.IsNullOrEmpty(ifModifiedSince) && TimeSpan.FromTicks(DateTime.Now.Ticks - DateTime.Parse(ifModifiedSince).Ticks).Days < DAYS) { response.StatusCode = (int)System.Net.HttpStatusCode.NotModified; response.StatusDescription = "Not Modified"; response.End(); return; } else { string fileContent = null; string ifNoneMatch = request.Headers["If-None-Match"]; string eTag = string.Format("\"{0}\"", this.GetFileMd5(string.Concat(phyFilePath, fileContent = this.GetFileContent(phyFilePath)))); if (!string.IsNullOrEmpty(ifNoneMatch) && ifNoneMatch.Equals(eTag)) { response.StatusCode = (int)System.Net.HttpStatusCode.NotModified; response.StatusDescription = "Not Modified"; response.End(); return; } else { HttpCachePolicy cache = response.Cache; //cache.SetLastModifiedFromFileDependencies();//程序自动读取文件的LastModified cache.SetLastModified(context.Timestamp); //因为静态文件的URL是特殊处理过,所以程序自动读取文件是在磁盘上找不到的,故改成手工代码设置文件的LastModified的方式。wangyunpeng,2016-4-12 //cache.SetETagFromFileDependencies();//程序自动读取文件的ETag cache.SetETag(eTag); //因为静态文件的URL是特殊处理过,所以程序自动读取文件是在磁盘上找不到的,故改成手工代码设置文件的ETag的方式。wangyunpeng,2016-4-12 cache.SetCacheability(HttpCacheability.Public); cache.SetExpires(DateTime.Now.AddDays(DAYS)); TimeSpan timeSpan = TimeSpan.FromDays(DAYS); cache.SetMaxAge(timeSpan); cache.SetProxyMaxAge(timeSpan); cache.SetValidUntilExpires(true); cache.SetSlidingExpiration(true); #region 压缩js和css文件 if (!string.IsNullOrWhiteSpace(fileContent)) { if (cacheType == ECacheType.Js) { string fileName = Path.GetFileName(phyFilePath); if (_MiniJsFiles.Contains(fileName, new StringComparer())) { fileContent = this.PackJavascript(fileContent);//ECMAScript压缩 } } //输出内容 response.ContentEncoding = _GlobalizationSection == null ? Encoding.UTF8 : _GlobalizationSection.ResponseEncoding; response.Write(fileContent); } #endregion } } } else {//直接输出文件 response.WriteFile(phyFilePath); } #else //直接输出文件 response.WriteFile(phyFilePath); #endif //取消GZIP压缩,IE7,IE8,Safari支持GZIP压缩显示css和js有问题。wangyunpeng if (this.IsAcceptEncoding(request, GZIP)) { response.Filter = new GZipStream(response.Filter, CompressionMode.Compress); this.SetResponseEncoding(response, GZIP); } else if (this.IsAcceptEncoding(request, DEFLATE)) { response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress); this.SetResponseEncoding(response, DEFLATE); } response.End(); } }