/// <summary> /// Sends headers required to send an entity. /// </summary> /// <param name="response">An HTTP response.</param> /// <param name="compressionType">The compression type that request wants it sent back in.</param> /// <param name="entity"></param> public void SendHeaders(HttpResponseBase response, ResponseCompressionType compressionType, IEntity entity) { if (!(entity.CompressionType == ResponseCompressionType.None || entity.CompressionType == compressionType)) { throw new NotImplementedException("Need to decode in memory, and then stream it"); } HttpResponseHeaderHelper.SetContentEncoding(response, compressionType); //How should data be compressed if (entity.CompressionType == compressionType) { //We have the entity stored in the correct compression format so just stream it HttpResponseHeaderHelper.AppendHeader(response, HttpHeaderContentLength, entity.ContentLength.ToString()); } else if (entity.CompressionType == ResponseCompressionType.None) { switch (compressionType) { case ResponseCompressionType.GZip: response.Filter = new GZipStream(response.Filter, CompressionMode.Compress); //This means that the output stream will be chunked, so we don't have to worry about content length break; case ResponseCompressionType.Deflate: response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress); //This means that the output stream will be chunked, so we don't have to worry about content length break; } } response.ContentType = entity.ContentType; }
public void SendHeaders(HttpResponseBase response, ResponseCompressionType compressionType, IEntity entity) { //Data must be in uncompressed format when responding partially if (entity.CompressionType != ResponseCompressionType.None) { //TODO: perhaps we could uncompress object, but for now we don't worry about it throw new Exception("Cannot do a partial response on compressed data"); } HttpResponseHeaderHelper.SetContentEncoding(response, compressionType); switch (compressionType) { case ResponseCompressionType.None: var contentLength = Range.EndRange - Range.StartRange + 1; HttpResponseHeaderHelper.AppendHeader(response, HTTP_HEADER_CONTENT_LENGTH, contentLength.ToString()); break; case ResponseCompressionType.GZip: response.Filter = new GZipStream(response.Filter, CompressionMode.Compress); //This means that the output stream will be chunked, so we don't have to worry about content length break; case ResponseCompressionType.Deflate: response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress); //This means that the output stream will be chunked, so we don't have to worry about content length break; } response.ContentType = entity.ContentType; HttpResponseHeaderHelper.AppendHeader(response, HTTP_HEADER_CONTENT_RANGE, BYTES + " " + Range.StartRange + "-" + Range.EndRange + "/" + entity.ContentLength); }
public void SendHeaders(HttpResponseBase response, ResponseCompressionType compressionType, IEntity entity) { //Data must be in uncompressed format when responding partially if (entity.CompressionType != ResponseCompressionType.None) { //TODO: perhaps we could uncompress object, but for now we don't worry about it throw new Exception("Cannot do a partial response on compressed data"); } HttpResponseHeaderHelper.SetContentEncoding(response, compressionType); switch (compressionType) { case ResponseCompressionType.None: var contentLength = Range.EndRange - Range.StartRange + 1; HttpResponseHeaderHelper.AppendHeader(response, HttpHeaderContentLength, contentLength.ToString()); break; case ResponseCompressionType.GZip: response.Filter = new GZipStream(response.Filter, CompressionMode.Compress); //This means that the output stream will be chunked, so we don't have to worry about content length break; case ResponseCompressionType.Deflate: response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress); //This means that the output stream will be chunked, so we don't have to worry about content length break; } response.ContentType = entity.ContentType; HttpResponseHeaderHelper.AppendHeader(response, HttpHeaderContentRange, Bytes + " " + Range.StartRange + "-" + Range.EndRange + "/" + entity.ContentLength); }
/// <summary> /// Setups the headers required to send a partial response. /// </summary> /// <param name="response">An HTTP response.</param> /// <param name="compressionType">The compression type that request wants it sent back in.</param> /// <param name="entity"></param> public void SendHeaders(HttpResponseBase response, ResponseCompressionType compressionType, IEntity entity) { //Data must be in uncompressed format when responding partially if (entity.CompressionType != ResponseCompressionType.None) { //TODO: perhaps we could uncompress object, but for now we don't worry about it throw new Exception("Cannot do a partial response on compressed data"); } HttpResponseHeaderHelper.SetContentEncoding(response, compressionType); switch (compressionType) { case ResponseCompressionType.None: ByteRangeResponse.SetContentLength(response, entity); break; case ResponseCompressionType.GZip: response.Filter = new GZipStream(response.Filter, CompressionMode.Compress); //This means that the output stream will be chunked, so we don't have to worry about content length break; case ResponseCompressionType.Deflate: response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress); //This means that the output stream will be chunked, so we don't have to worry about content length break; } ByteRangeResponse.SetOtherHeaders(response, entity); }
protected override void When() { Entity.Stub(x => x.ContentLength).Return(EntityContentLength); Entity.Stub(x => x.CompressionType).Return(EntityCompressionType); Entity.Stub(x => x.ContentType).Return(EntityContentType); HttpResponseHeaderHelper .Stub(x => x.SetContentEncoding(HttpResponse, ResponseCompressionType)) .Callback((HttpResponseBase httpResponse, ResponseCompressionType responseCompressionType) => { ResponseCompressionTypeSet = responseCompressionType; return(true); }); HttpResponseHeaderHelper .Stub(x => x.AppendHeader(HttpResponse, EntityResponseFull.HttpHeaderContentLength, EntityContentLength.ToString())) .Callback((HttpResponseBase httpResponse, string httpResponseHeader, string headerValue) => { ContentLengthSet = headerValue; return(true); }); HttpResponse.Stub(x => x.ContentType).PropertyBehavior(); HttpResponse.Stub(x => x.Filter).PropertyBehavior(); HttpResponse.Filter = new MemoryStream(); SystemUnderTest.SendHeaders(HttpResponse, ResponseCompressionType, Entity); }
/// <summary> /// Set the compression type used in the response. /// </summary> /// <param name="response">An HTTP response.</param> /// <param name="responseCompressionType">The compression type to use in the response.</param> public void SetContentEncoding(HttpResponseBase response, ResponseCompressionType responseCompressionType) { if (responseCompressionType != ResponseCompressionType.None) { AppendHeader(response, HttpResponseHeader.ContentEncoding, responseCompressionType.ToString().ToLower()); } }
private static void ReadFileData(ResponseCompressionType compressionType, FileInfo file, MemoryStream memoryStream) { using (Stream outputStream = (compressionType == ResponseCompressionType.None ? memoryStream : (compressionType == ResponseCompressionType.GZip ? (Stream) new GZipStream(memoryStream, CompressionMode.Compress, true) : (Stream) new DeflateStream(memoryStream, CompressionMode.Compress)))) { // We can compress and cache this file using (FileStream fs = file.Open(FileMode.Open, FileAccess.Read, FileShare.Read)) { int bufSize = Convert.ToInt32(Math.Min(file.Length, 8 * 1024)); byte[] buffer = new byte[bufSize]; int bytesRead; while ((bytesRead = fs.Read(buffer, 0, bufSize)) > 0) { outputStream.Write(buffer, 0, bytesRead); } } outputStream.Flush(); } }
public void SendHeaders(HttpResponseBase response, ResponseCompressionType compressionType, IEntity entity) { //Data must be in uncompressed format when responding partially if (entity.CompressionType != ResponseCompressionType.None) { //TODO: perhaps we could uncompress object, but for now we don't worry about it throw new Exception("Cannot do a partial response on compressed data"); } HttpResponseHeaderHelper.SetContentEncoding(response, compressionType); switch (compressionType) { case ResponseCompressionType.None: var partialContentLength = GetMultipartPartialRequestLength(Ranges, entity.ContentType, entity.ContentLength); HttpResponseHeaderHelper.AppendHeader(response, HttpHeaderContentLength, partialContentLength.ToString()); break; case ResponseCompressionType.GZip: response.BufferOutput = true; response.Filter = new GZipStream(response.Filter, CompressionMode.Compress); //This means that the output stream will be chunked, so we don't have to worry about content length break; case ResponseCompressionType.Deflate: response.BufferOutput = true; response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress); //This means that the output stream will be chunked, so we don't have to worry about content length break; } response.ContentType = MultipartContenttype; }
private void CacheAndDeliver(HttpContext context, HttpRequest request, HttpResponse response, string physicalFilePath, ResponseCompressionType compressionType, string cacheKey, MemoryStream memoryStream, FileInfo file) { // Cache the content in ASP.NET Cache byte[] responseBytes = memoryStream.ToArray(); context.Cache.Insert(cacheKey, new CachedContent(responseBytes, file.LastWriteTimeUtc), new CacheDependency(physicalFilePath), DateTime.Now.Add(DEFAULT_CACHE_DURATION), Cache.NoSlidingExpiration); this.ProduceResponseHeader(response, responseBytes.Length, compressionType, physicalFilePath, file.LastWriteTimeUtc); this.WriteResponse(response, responseBytes, compressionType, physicalFilePath); Debug.WriteLine("StaticFileHandler: NonCached: " + request.FilePath); }
private void TransmitFileUsingHttpResponse(HttpRequest request, HttpResponse response, string physicalFilePath, ResponseCompressionType compressionType, FileInfo file) { if (file.Exists) { // We don't cache/compress such file types. Must be some binary file that's better // to let IIS handle this.ProduceResponseHeader(response, Convert.ToInt32(file.Length), compressionType, physicalFilePath, file.LastWriteTimeUtc); response.TransmitFile(physicalFilePath); Debug.WriteLine("TransmitFile: " + request.FilePath); } else { throw new HttpException((int)HttpStatusCode.NotFound, request.FilePath + " Not Found"); } }
private static void ProduceResponseHeader(HttpResponse response, int count, ResponseCompressionType mode, string physicalFilePath, DateTime lastModified) { response.Buffer = false; response.BufferOutput = false; response.ContentType = MimeMapping.GetMimeMapping(physicalFilePath); if (mode != ResponseCompressionType.None) { response.AppendHeader("Content-Encoding", mode.ToString().ToLower()); } response.AppendHeader("Content-Length", count.ToString(CultureInfo.InvariantCulture)); response.Cache.SetCacheability(HttpCacheability.Public); response.Cache.AppendCacheExtension("must-revalidate, proxy-revalidate"); response.Cache.SetMaxAge(_defaultCacheDuration); response.Cache.SetExpires(DateTime.Now.Add(_defaultCacheDuration)); response.Cache.SetLastModified(lastModified); }
//方法执行前 public override void OnActionExecuted(ActionExecutedContext filterContext) { //压缩 string EncodingString = filterContext.HttpContext.Request.Headers["Accept-Encoding"].ToString();; if (string.IsNullOrWhiteSpace(EncodingString)) { return; } else { //if (EncodingString.ToLower().Contains("gzip")) //{ // var responses = filterContext.HttpContext.Response; // responses.AddHeader("context-encoding", "gzip"); // responses.Filter = new GZipStream(responses.Filter, CompressionMode.Compress); //} #region 压缩有关(百度方式,页面压缩) var context = HttpContext.Current; var request = context.Request; var response = context.Response; ResponseCompressionType compressionType = this.GetCompressionMode(request); if (compressionType != ResponseCompressionType.None) { response.AppendHeader("Content-Encoding", compressionType.ToString().ToLower()); if (compressionType == ResponseCompressionType.GZip) { response.Filter = new GZipStream(response.Filter, CompressionMode.Compress); } else { response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress); } } #endregion } base.OnActionExecuted(filterContext); }
/// <summary> /// Read a files contents into a stream /// </summary> /// <param name="compressionType">The compression type to use.</param> /// <param name="stream">The stream to write to.</param> private void GetEntityData(ResponseCompressionType compressionType, Stream stream) { using (var outputStream = (compressionType == ResponseCompressionType.None ? stream : (compressionType == ResponseCompressionType.GZip ? (Stream) new GZipStream(stream, CompressionMode.Compress, true) : (Stream) new DeflateStream(stream, CompressionMode.Compress)))) { // We can compress and cache this file using (var resourceStream = _assembly.GetManifestResourceStream(ResourcePath)) { var bufferSize = Convert.ToInt32(Math.Min(ResourceSize, BufferSize)); var buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = resourceStream.Read(buffer, 0, bufferSize)) > 0) { outputStream.Write(buffer, 0, bytesRead); } } outputStream.Flush(); } }
/// <summary> /// Read a files contents into a stream /// </summary> /// <param name="compressionType">The compression type to use.</param> /// <param name="stream">The stream to write to.</param> private void GetEntityData(ResponseCompressionType compressionType, Stream stream) { using (var outputStream = (compressionType == ResponseCompressionType.None ? stream : (compressionType == ResponseCompressionType.GZip ? (Stream) new GZipStream(stream, CompressionMode.Compress, true) : (Stream) new DeflateStream(stream, CompressionMode.Compress)))) { // We can compress and cache this file using (var fileStream = RetryableFileOpener.OpenFileStream(FileInfo, 5, FileMode.Open, FileAccess.Read, FileShare.Read)) { var bufferSize = Convert.ToInt32(Math.Min(FileInfo.Length, BufferSize)); var buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = fileStream.Read(buffer, 0, bufferSize)) > 0) { outputStream.Write(buffer, 0, bytesRead); } } outputStream.Flush(); } }
private bool DeliverFromCache(HttpContext context, HttpRequest request, HttpResponse response, string cacheKey, string physicalFilePath, ResponseCompressionType compressionType) { CachedContent cachedContent = context.Cache[cacheKey] as CachedContent; if (null != cachedContent) { byte[] cachedBytes = cachedContent.ResponseBytes; // We have it cached this.ProduceResponseHeader(response, cachedBytes.Length, compressionType, physicalFilePath, cachedContent.LastModified); this.WriteResponse(response, cachedBytes, compressionType, physicalFilePath); Debug.WriteLine("StaticFileHandler: Cached: " + request.FilePath); return(true); } else { return(false); } }
private void ProduceResponseHeader(HttpResponse response, int count, ResponseCompressionType mode, string physicalFilePath, DateTime lastModified) { response.Buffer = false; response.BufferOutput = false; // Emit content type and encoding based on the file extension and // whether the response is compressed response.ContentType = MimeMapping.GetMimeMapping(physicalFilePath); if (mode != ResponseCompressionType.None) { response.AppendHeader("Content-Encoding", mode.ToString().ToLower()); } response.AppendHeader("Content-Length", count.ToString()); // Emit proper cache headers that will cache the response in browser's // cache for the default cache duration response.Cache.SetCacheability(HttpCacheability.Public); response.Cache.AppendCacheExtension("must-revalidate, proxy-revalidate"); response.Cache.SetMaxAge(DEFAULT_CACHE_DURATION); response.Cache.SetExpires(DateTime.Now.Add(DEFAULT_CACHE_DURATION)); response.Cache.SetLastModified(lastModified); }
/// <summary> /// Get a fileHanderCacheItem for the requested file. /// </summary> /// <param name="entityStoredWithCompressionType">The compression type to use for the file.</param> /// <param name="entityCacheItem">The fileHandlerCacheItem </param> /// <returns>Returns true if a fileHandlerCacheItem can be created; otherwise false.</returns> public bool TryGetFileHandlerCacheItem(ResponseCompressionType entityStoredWithCompressionType, out EntityCacheItem entityCacheItem) { entityCacheItem = null; // If the response bytes are already cached, then deliver the bytes directly from cache var cacheKey = EmbeddedResourceEntityResponderType + ":" + entityStoredWithCompressionType + ":" + ResourcePath; var cachedValue = CacheManager.Get<EntityCacheItem>(cacheKey); if (cachedValue != null) { entityCacheItem = cachedValue; } else { //File does not exist if (!DoesEntityExists) { return false; } //File too large to send if (ResourceSize > MaxFileSizeToServe) { return false; } var etag = string.Empty; var lastModifiedFileTime = ResourceLastModified; //When a browser sets the If-Modified-Since field to 13-1-2010 10:30:58, another DateTime instance is created, but this one has a Ticks value of 633989754580000000 //But the time from the file system is accurate to a tick. So it might be 633989754586086250. var lastModified = new DateTime(lastModifiedFileTime.Year, lastModifiedFileTime.Month, lastModifiedFileTime.Day, lastModifiedFileTime.Hour, lastModifiedFileTime.Minute, lastModifiedFileTime.Second); var contentType = MimeTyper.GetMimeType(ResourceExtension); var contentLength = ResourceSize; //ETAG is always calculated from uncompressed entity data switch (MimeSetting.EtagMethod) { case EtagMethodType.MD5: using (var resourceStream = _assembly.GetManifestResourceStream(ResourcePath)) { etag = Hasher.Hash(resourceStream); } break; case EtagMethodType.LastModified: etag = lastModified.ToString("r"); break; default: throw new Exception("Unknown etag method generation"); } entityCacheItem = new EntityCacheItem { Etag = etag, LastModified = lastModified, ContentLength = contentLength, ContentType = contentType, CompressionType = ResponseCompressionType.None }; if (MimeSetting.ServeFromMemory && (contentLength <= MimeSetting.MaxMemorySize)) { // When not compressed, buffer is the size of the file but when compressed, // initial buffer size is one third of the file size. Assuming, compression // will give us less than 1/3rd of the size using (var memoryStream = new MemoryStream( entityStoredWithCompressionType == ResponseCompressionType.None ? Convert.ToInt32(ResourceSize) : Convert.ToInt32((double)ResourceSize / 3))) { GetEntityData(entityStoredWithCompressionType, memoryStream); var entityData = memoryStream.ToArray(); var entityDataLength = entityData.LongLength; entityCacheItem.EntityData = entityData; entityCacheItem.ContentLength = entityDataLength; entityCacheItem.CompressionType = entityStoredWithCompressionType; } } //Put fileHandlerCacheItem into cache with 30 min sliding expiration, also if file changes then remove fileHandlerCacheItem from cache CacheManager.Insert( cacheKey, entityCacheItem, null, Cache.NoAbsoluteExpiration, MimeSetting.MemorySlidingExpiration, CacheItemPriority.BelowNormal, null); } return true; }
/// <summary> /// Read a files contents into a stream /// </summary> /// <param name="compressionType">The compression type to use.</param> /// <param name="stream">The stream to write to.</param> private void GetEntityData(ResponseCompressionType compressionType, Stream stream) { using (var outputStream = (compressionType == ResponseCompressionType.None ? stream : (compressionType == ResponseCompressionType.GZip ? (Stream)new GZipStream(stream, CompressionMode.Compress, true) : (Stream)new DeflateStream(stream, CompressionMode.Compress)))) { // We can compress and cache this file using (var resourceStream = _assembly.GetManifestResourceStream(ResourcePath)) { var bufferSize = Convert.ToInt32(Math.Min(ResourceSize, BufferSize)); var buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = resourceStream.Read(buffer, 0, bufferSize)) > 0) { outputStream.Write(buffer, 0, bytesRead); } } outputStream.Flush(); } }
/// <summary> /// Get a fileHanderCacheItem for the requested file. /// </summary> /// <param name="entityStoredWithCompressionType">The compression type to use for the file.</param> /// <param name="entityCacheItem">The fileHandlerCacheItem </param> /// <returns>Returns true if a fileHandlerCacheItem can be created; otherwise false.</returns> public bool TryGetFileHandlerCacheItem(ResponseCompressionType entityStoredWithCompressionType, out EntityCacheItem entityCacheItem) { entityCacheItem = null; // If the response bytes are already cached, then deliver the bytes directly from cache var cacheKey = EmbeddedResourceEntityResponderType + ":" + entityStoredWithCompressionType + ":" + ResourcePath; var cachedValue = CacheManager.Get <EntityCacheItem>(cacheKey); if (cachedValue != null) { entityCacheItem = cachedValue; } else { //File does not exist if (!DoesEntityExists) { return(false); } //File too large to send if (ResourceSize > MaxFileSizeToServe) { return(false); } var etag = string.Empty; var lastModifiedFileTime = ResourceLastModified; //When a browser sets the If-Modified-Since field to 13-1-2010 10:30:58, another DateTime instance is created, but this one has a Ticks value of 633989754580000000 //But the time from the file system is accurate to a tick. So it might be 633989754586086250. var lastModified = new DateTime(lastModifiedFileTime.Year, lastModifiedFileTime.Month, lastModifiedFileTime.Day, lastModifiedFileTime.Hour, lastModifiedFileTime.Minute, lastModifiedFileTime.Second); var contentType = MimeTyper.GetMimeType(ResourceExtension); var contentLength = ResourceSize; //ETAG is always calculated from uncompressed entity data switch (MimeSetting.EtagMethod) { case EtagMethodType.MD5: using (var resourceStream = _assembly.GetManifestResourceStream(ResourcePath)) { etag = Hasher.CalculateMd5Etag(resourceStream); } break; case EtagMethodType.LastModified: etag = lastModified.ToString("r"); break; default: throw new Exception("Unknown etag method generation"); } entityCacheItem = new EntityCacheItem { Etag = etag, LastModified = lastModified, ContentLength = contentLength, ContentType = contentType, CompressionType = ResponseCompressionType.None }; if (MimeSetting.ServeFromMemory && (contentLength <= MimeSetting.MaxMemorySize)) { // When not compressed, buffer is the size of the file but when compressed, // initial buffer size is one third of the file size. Assuming, compression // will give us less than 1/3rd of the size using (var memoryStream = new MemoryStream( entityStoredWithCompressionType == ResponseCompressionType.None ? Convert.ToInt32(ResourceSize) : Convert.ToInt32((double)ResourceSize / 3))) { GetEntityData(entityStoredWithCompressionType, memoryStream); var entityData = memoryStream.ToArray(); var entityDataLength = entityData.LongLength; entityCacheItem.EntityData = entityData; entityCacheItem.ContentLength = entityDataLength; entityCacheItem.CompressionType = entityStoredWithCompressionType; } } //Put fileHandlerCacheItem into cache with 30 min sliding expiration, also if file changes then remove fileHandlerCacheItem from cache CacheManager.Insert( cacheKey, entityCacheItem, null, Cache.NoAbsoluteExpiration, MimeSetting.MemorySlidingExpiration, CacheItemPriority.BelowNormal, null); } return(true); }
private void WriteResponse(HttpResponse response, byte[] bytes, ResponseCompressionType mode, string physicalFilePath) { response.OutputStream.Write(bytes, 0, bytes.Length); response.OutputStream.Flush(); }
private void ProduceResponseHeader(HttpResponse response, int count, ResponseCompressionType mode, string physicalFilePath, DateTime lastModified) { response.Buffer = false; response.BufferOutput = false; // Emit content type and encoding based on the file extension and // whether the response is compressed response.ContentType = MimeMapping.GetMimeMapping(physicalFilePath); if (mode != ResponseCompressionType.None) response.AppendHeader("Content-Encoding", mode.ToString().ToLower()); response.AppendHeader("Content-Length", count.ToString()); // Emit proper cache headers that will cache the response in browser's // cache for the default cache duration response.Cache.SetCacheability(HttpCacheability.Public); response.Cache.AppendCacheExtension("must-revalidate, proxy-revalidate"); response.Cache.SetMaxAge(DEFAULT_CACHE_DURATION); response.Cache.SetExpires(DateTime.Now.Add(DEFAULT_CACHE_DURATION)); response.Cache.SetLastModified(lastModified); }
private bool DeliverFromCache(HttpContext context, HttpRequest request, HttpResponse response, string cacheKey, string physicalFilePath, ResponseCompressionType compressionType) { CachedContent cachedContent = context.Cache[cacheKey] as CachedContent; if (null != cachedContent) { byte[] cachedBytes = cachedContent.ResponseBytes; // We have it cached this.ProduceResponseHeader(response, cachedBytes.Length, compressionType, physicalFilePath, cachedContent.LastModified); this.WriteResponse(response, cachedBytes, compressionType, physicalFilePath); Debug.WriteLine("StaticFileHandler: Cached: " + request.FilePath); return true; } else { return false; } }
private static void ReadFileData(ResponseCompressionType compressionType, FileInfo file, MemoryStream memoryStream) { using (Stream outputStream = (compressionType == ResponseCompressionType.None ? memoryStream : (compressionType == ResponseCompressionType.GZip ? (Stream)new GZipStream(memoryStream, CompressionMode.Compress, true) : (Stream)new DeflateStream(memoryStream, CompressionMode.Compress)))) { // We can compress and cache this file using (FileStream fs = file.Open(FileMode.Open, FileAccess.Read, FileShare.Read)) { int bufSize = Convert.ToInt32(Math.Min(file.Length, 8 * 1024)); byte[] buffer = new byte[bufSize]; int bytesRead; while ((bytesRead = fs.Read(buffer, 0, bufSize)) > 0) { outputStream.Write(buffer, 0, bytesRead); } } outputStream.Flush(); } }
/// <summary> /// Read a files contents into a stream /// </summary> /// <param name="compressionType">The compression type to use.</param> /// <param name="stream">The stream to write to.</param> private void GetEntityData(ResponseCompressionType compressionType, Stream stream) { using (var outputStream = (compressionType == ResponseCompressionType.None ? stream : (compressionType == ResponseCompressionType.GZip ? (Stream)new GZipStream(stream, CompressionMode.Compress, true) : (Stream)new DeflateStream(stream, CompressionMode.Compress)))) { // We can compress and cache this file using (var fileStream = RetryableFileOpener.OpenFileStream(FileInfo, 5, FileMode.Open, FileAccess.Read, FileShare.Read)) { var bufferSize = Convert.ToInt32(Math.Min(FileInfo.Length, BufferSize)); var buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = fileStream.Read(buffer, 0, bufferSize)) > 0) { outputStream.Write(buffer, 0, bytesRead); } } outputStream.Flush(); } }
/// <summary> /// Get a fileHanderCacheItem for the requested file. /// </summary> /// <param name="entityStoredWithCompressionType">The compression type to use for the file.</param> /// <param name="fileEntityCacheItem">The fileHandlerCacheItem </param> /// <returns>Returns true if a fileHandlerCacheItem can be created; otherwise false.</returns> public bool TryGetFileHandlerCacheItem(ResponseCompressionType entityStoredWithCompressionType, out FileEntityCacheItem fileEntityCacheItem) { fileEntityCacheItem = null; // If the response bytes are already cached, then deliver the bytes directly from cache var cacheKey = FileInfoEntityType + ":" + entityStoredWithCompressionType + ":" + FileInfo.FullName; var cachedValue = HttpRuntime.Cache.Get(cacheKey); if (cachedValue != null) { fileEntityCacheItem = (FileEntityCacheItem)cachedValue; } else { //File does not exist if (!FileInfo.Exists) { return false; } //File too large to send if (FileInfo.Length > MaxFileSizeToServe) { return false; } var etag = string.Empty; var lastModifiedFileTime = FileInfo.LastWriteTime.ToUniversalTime(); //When a browser sets the If-Modified-Since field to 13-1-2010 10:30:58, another DateTime instance is created, but this one has a Ticks value of 633989754580000000 //But the time from the file system is accurate to a tick. So it might be 633989754586086250. var lastModified = new DateTime(lastModifiedFileTime.Year, lastModifiedFileTime.Month, lastModifiedFileTime.Day, lastModifiedFileTime.Hour, lastModifiedFileTime.Minute, lastModifiedFileTime.Second); var contentType = MimeTyper.GetMimeType(FileInfo.Extension); var contentLength = FileInfo.Length; //ETAG is always calculated from uncompressed entity data switch (FileEntitySetting.EtagMethod) { case EtagMethodType.MD5: etag = Hasher.CalculateMd5Etag(FileInfo); break; case EtagMethodType.LastModified: etag = lastModified.ToString(); break; default: throw new Exception("Unknown etag method generation"); } fileEntityCacheItem = new FileEntityCacheItem { Etag = etag, LastModified = lastModified, ContentLength = contentLength, ContentType = contentType, CompressionType = entityStoredWithCompressionType }; if (FileEntitySetting.ServeFromMemory && (contentLength <= FileEntitySetting.MaxMemorySize)) { // When not compressed, buffer is the size of the file but when compressed, // initial buffer size is one third of the file size. Assuming, compression // will give us less than 1/3rd of the size using (var memoryStream = new MemoryStream( entityStoredWithCompressionType == ResponseCompressionType.None ? Convert.ToInt32(FileInfo.Length) : Convert.ToInt32((double)FileInfo.Length / 3))) { GetEntityData(entityStoredWithCompressionType, memoryStream); var entityData = memoryStream.ToArray(); var entityDataLength = entityData.LongLength; fileEntityCacheItem.EntityData = entityData; fileEntityCacheItem.ContentLength = entityDataLength; } } //Put fileHandlerCacheItem into cache with 30 min sliding expiration, also if file changes then remove fileHandlerCacheItem from cache HttpRuntime.Cache.Insert( cacheKey, fileEntityCacheItem, new CacheDependency(FileInfo.FullName), Cache.NoAbsoluteExpiration, FileEntitySetting.MemorySlidingExpiration, CacheItemPriority.BelowNormal, null); } return true; }
private static void CacheAndDeliver(HttpContext context, HttpRequest request, HttpResponse response, string physicalFilePath, ResponseCompressionType compressionType, string cacheKey, MemoryStream memoryStream, FileSystemInfo file) { var responseBytes = memoryStream.ToArray(); context.Cache.Insert(cacheKey, new CachedContent(responseBytes, file.LastWriteTimeUtc), new CacheDependency(physicalFilePath), DateTime.Now.Add(_defaultCacheDuration), Cache.NoSlidingExpiration); ProduceResponseHeader(response, responseBytes.Length, compressionType, physicalFilePath, file.LastWriteTimeUtc); WriteResponse(response, responseBytes); Debug.WriteLine("StaticFileHandler: NonCached: " + request.FilePath); }
public virtual IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback callback, object state) { this._context = context; HttpResponse response = context.Response; HttpRequest request = context.Request; try { EnsureProperRequest(request); string physicalFilePath = request.PhysicalPath; ResponseCompressionType compressionType = this.GetCompressionMode(request); FileInfo file = new FileInfo(physicalFilePath); string fileExtension = file.Extension.ToLower(); // Do we handle such file types? if (Array.BinarySearch <string>(FILE_TYPES, fileExtension) >= 0) { // Yes we do. // If this is a binary file like image, then we won't compress it. if (Array.BinarySearch <string>(COMPRESS_FILE_TYPES, fileExtension) < 0) { compressionType = ResponseCompressionType.None; } // If the response bytes are already cached, then deliver the bytes directly from cache string cacheKey = typeof(StaticFileHandler).ToString() + ":" + compressionType.ToString() + ":" + physicalFilePath; if (DeliverFromCache(context, request, response, cacheKey, physicalFilePath, compressionType)) { // Delivered from cache } else { if (file.Exists) { // When not compressed, buffer is the size of the file but when compressed, // initial buffer size is one third of the file size. Assuming, compression // will give us less than 1/3rd of the size using (MemoryStream memoryStream = new MemoryStream( compressionType == ResponseCompressionType.None ? Convert.ToInt32(file.Length) : Convert.ToInt32((double)file.Length / 3))) { ReadFileData(compressionType, file, memoryStream); this.CacheAndDeliver(context, request, response, physicalFilePath, compressionType, cacheKey, memoryStream, file); } } else { throw new HttpException((int)HttpStatusCode.NotFound, request.FilePath + " Not Found"); } } } else { this.TransmitFileUsingHttpResponse(request, response, physicalFilePath, compressionType, file); } return(new HttpAsyncResult(callback, state, true, null, null)); } catch (Exception x) { if (x is HttpException) { HttpException h = x as HttpException; response.StatusCode = h.GetHttpCode(); Debug.WriteLine(h.Message); } return(new HttpAsyncResult(callback, state, true, null, x)); } }
private static void TransmitFileUsingHttpResponse(HttpRequest request, HttpResponse response, string physicalFilePath, ResponseCompressionType compressionType, FileInfo file) { if (!file.Exists) { throw new HttpException((int)HttpStatusCode.NotFound, request.FilePath + " Not Found"); } ProduceResponseHeader(response, Convert.ToInt32(file.Length), compressionType, physicalFilePath, file.LastWriteTimeUtc); response.TransmitFile(physicalFilePath); Debug.WriteLine("TransmitFile: " + request.FilePath); }