public void ProcessRequest(HttpContextBase context, FileInfo file)
        {
            var request = context.Request;
            var response = context.Response;

            var fileSettingEntity = _fileEntitySettingProvider.GetSetting(file);

            var fileEntity = new FileEntity(_retryableFileOpener, _mimeTyper, _hasher, MaxFileSizeToServe, BufferSize, file, fileSettingEntity);

            if (_webServerType == WebServerType.NotSet || _httpResponseHeaderHelper == null || _httpRequestResponder == null)
            {
                Initialize(context);
            }

            //We don't want to use up all the servers memory keeping a copy of the file, we just want to stream file to client
            response.BufferOutput = false;

            try
            {
                _httpRequestResponder.ServeRequest(request, response, fileEntity);
            }
            catch (HttpException httpException)
            {
                //Client disconnected half way through us sending data
                if (httpException.ErrorCode != ErrorTheRemoteHostClosedTheConnection)
                    return;

                throw;
            }
        }
        public void ServeRequest(HttpRequestBase request, HttpResponseBase response, FileEntity fileEntity)
        {
            if (!IsHttpMethodAllowed(request))
            {
                //If we are unable to parse url send 405 Method not allowed
                HttpResponseHeaderHelper.SendHttpStatusHeaders(response, HttpStatusCode.MethodNotAllowed);
                return;
            }

            if (!fileEntity.IsAllowedToServeRequestedEntity)
            {
                //If we are unable to parse url send 403 Path Forbidden
                HttpResponseHeaderHelper.SendHttpStatusHeaders(response, HttpStatusCode.Forbidden);
                return;
            }

            var requestHttpMethod = HttpRequestHeaderHelper.GetHttpMethod(request);

            var compressionType = HttpRequestHeaderHelper.GetCompressionMode(request);

            // If this is a binary file like image, then we won't compress it.
            if (!fileEntity.IsCompressable)
            {
                compressionType = ResponseCompressionType.None;
            }

            // If it is a partial request we need to get bytes of orginal entity data, we will compress the byte ranges returned
            var entityStoredWithCompressionType = compressionType;
            var isRangeRequest = HttpRequestHeaderHelper.IsRangeRequest(request);
            if (isRangeRequest)
            {
                entityStoredWithCompressionType = ResponseCompressionType.None;
            }

            FileEntityCacheItem fileEntityCacheItem = null;

            if (!fileEntity.TryGetFileHandlerCacheItem(entityStoredWithCompressionType, out fileEntityCacheItem))
            {
                //File does not exist
                if (!fileEntity.DoesEntityExists)
                {
                    HttpResponseHeaderHelper.SendHttpStatusHeaders(response, HttpStatusCode.NotFound);
                    return;
                }

                //File too large to send
                if (fileEntity.IsEntityLargerThanMaxFileSize)
                {
                    HttpResponseHeaderHelper.SendHttpStatusHeaders(response, HttpStatusCode.RequestEntityTooLarge);
                    return;
                }
            }
            else if (fileEntityCacheItem.EntityData == null && !fileEntity.DoesEntityExists)
            {
                //If we have cached the properties of the file but its to large to serve from memory then we must check that the file exists each time.
                HttpResponseHeaderHelper.SendHttpStatusHeaders(response, HttpStatusCode.NotFound);
                return;
            }

            //Unable to parse request range header
            IEnumerable<RangeItem> ranges = null;
            var requestRange = HttpRequestHeaderHelper.GetRanges(request, fileEntityCacheItem.ContentLength, out ranges);
            if (requestRange.HasValue && !requestRange.Value)
            {
                HttpResponseHeaderHelper.SendHttpStatusHeaders(response, HttpStatusCode.RequestedRangeNotSatisfiable);
                return;
            }

            //Check querystring etag
            var urlEtagHandler = GetUrlEtagHandler(request, response, fileEntity.UrlEtagHandlingMethod, fileEntity.UrlEtagQuerystringName, fileEntityCacheItem.Etag);
            if (urlEtagHandler != null)
            {
                var shouldStopResponse = urlEtagHandler.UpdateEtag(response, request.Url, fileEntityCacheItem.Etag);
                if (shouldStopResponse)
                {
                    return;
                }
            }

            //Check if cached response is valid and if it is send appropriate response headers
            var httpStatus = GetResponseHttpStatus(request, fileEntityCacheItem.LastModified, fileEntityCacheItem.Etag);

            HttpResponseHeaderHelper.SendHttpStatusHeaders(response, httpStatus);

            if (httpStatus == HttpStatusCode.NotModified || httpStatus == HttpStatusCode.PreconditionFailed)
            {
                return;
            }

            //Tell the client it supports resumable requests
            HttpResponseHeaderHelper.SetResponseResumable(response);

            //How the entity should be cached on the client
            HttpResponseHeaderHelper.SetResponseCachable(response, DateTime.Now, fileEntityCacheItem.LastModified, fileEntityCacheItem.Etag, fileEntity.Expires);

            var entityResponseForEntity = GetEntityResponse(response, ranges);
            entityResponseForEntity.SendHeaders(response, compressionType, fileEntityCacheItem);

            var transmitEntity = fileEntity.GetTransmitEntityStrategy(fileEntityCacheItem);
            entityResponseForEntity.SendBody(requestHttpMethod, response, transmitEntity);
        }
示例#3
0
        public void ServeRequest(HttpRequestBase request, HttpResponseBase response, FileEntity fileEntity)
        {
            if (!IsHttpMethodAllowed(request))
            {
                //If we are unable to parse url send 405 Method not allowed
                HttpResponseHeaderHelper.SendHttpStatusHeaders(response, HttpStatusCode.MethodNotAllowed);
                return;
            }

            if (!fileEntity.IsAllowedToServeRequestedEntity)
            {
                //If we are unable to parse url send 403 Path Forbidden
                HttpResponseHeaderHelper.SendHttpStatusHeaders(response, HttpStatusCode.Forbidden);
                return;
            }

            var requestHttpMethod = HttpRequestHeaderHelper.GetHttpMethod(request);

            var compressionType = HttpRequestHeaderHelper.GetCompressionMode(request);

            // If this is a binary file like image, then we won't compress it.
            if (!fileEntity.IsCompressable)
            {
                compressionType = ResponseCompressionType.None;
            }

            // If it is a partial request we need to get bytes of orginal entity data, we will compress the byte ranges returned
            var entityStoredWithCompressionType = compressionType;
            var isRangeRequest = HttpRequestHeaderHelper.IsRangeRequest(request);

            if (isRangeRequest)
            {
                entityStoredWithCompressionType = ResponseCompressionType.None;
            }

            FileEntityCacheItem fileEntityCacheItem = null;

            if (!fileEntity.TryGetFileHandlerCacheItem(entityStoredWithCompressionType, out fileEntityCacheItem))
            {
                //File does not exist
                if (!fileEntity.DoesEntityExists)
                {
                    HttpResponseHeaderHelper.SendHttpStatusHeaders(response, HttpStatusCode.NotFound);
                    return;
                }

                //File too large to send
                if (fileEntity.IsEntityLargerThanMaxFileSize)
                {
                    HttpResponseHeaderHelper.SendHttpStatusHeaders(response, HttpStatusCode.RequestEntityTooLarge);
                    return;
                }
            }
            else if (fileEntityCacheItem.EntityData == null && !fileEntity.DoesEntityExists)
            {
                //If we have cached the properties of the file but its to large to serve from memory then we must check that the file exists each time.
                HttpResponseHeaderHelper.SendHttpStatusHeaders(response, HttpStatusCode.NotFound);
                return;
            }

            //Unable to parse request range header
            IEnumerable <RangeItem> ranges = null;
            var requestRange = HttpRequestHeaderHelper.GetRanges(request, fileEntityCacheItem.ContentLength, out ranges);

            if (requestRange.HasValue && !requestRange.Value)
            {
                HttpResponseHeaderHelper.SendHttpStatusHeaders(response, HttpStatusCode.RequestedRangeNotSatisfiable);
                return;
            }

            //Check querystring etag
            var urlEtagHandler = GetUrlEtagHandler(request, response, fileEntity.UrlEtagHandlingMethod, fileEntity.UrlEtagQuerystringName, fileEntityCacheItem.Etag);

            if (urlEtagHandler != null)
            {
                var shouldStopResponse = urlEtagHandler.UpdateEtag(response, request.Url, fileEntityCacheItem.Etag);
                if (shouldStopResponse)
                {
                    return;
                }
            }

            //Check if cached response is valid and if it is send appropriate response headers
            var httpStatus = GetResponseHttpStatus(request, fileEntityCacheItem.LastModified, fileEntityCacheItem.Etag);

            HttpResponseHeaderHelper.SendHttpStatusHeaders(response, httpStatus);

            if (httpStatus == HttpStatusCode.NotModified || httpStatus == HttpStatusCode.PreconditionFailed)
            {
                return;
            }

            //Tell the client it supports resumable requests
            HttpResponseHeaderHelper.SetResponseResumable(response);

            //How the entity should be cached on the client
            HttpResponseHeaderHelper.SetResponseCachable(response, DateTime.Now, fileEntityCacheItem.LastModified, fileEntityCacheItem.Etag, fileEntity.Expires);

            var entityResponseForEntity = GetEntityResponse(response, ranges);

            entityResponseForEntity.SendHeaders(response, compressionType, fileEntityCacheItem);

            var transmitEntity = fileEntity.GetTransmitEntityStrategy(fileEntityCacheItem);

            entityResponseForEntity.SendBody(requestHttpMethod, response, transmitEntity);
        }