Exemplo n.º 1
0
        public void ProcessRequest(HttpContext context)
        {
            try
            {
                if (!SecurityContext.IsAuthenticated && !CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsAdmin())
                {
                    throw new HttpException(403, "Access denied.");
                }

                var pid = context.Request.QueryString["pid"];
                if (string.IsNullOrEmpty(pid))
                {
                    throw new HttpException(400, "Bad request.");
                }

                if (CoreContext.PaymentManager.GetTariffPayments(TenantProvider.CurrentTenantID).All(p => p.CartId != pid))
                {
                    throw new HttpException(403, "Access denied.");
                }

                var invoice = CoreContext.PaymentManager.GetPaymentInvoice(pid);
                if (invoice == null || string.IsNullOrEmpty(invoice.Sale))
                {
                    throw new HttpException(404, "Not found.");
                }

                var pdf = Convert.FromBase64String(invoice.Sale);

                context.Response.Clear();
                context.Response.ContentType = MimeMapping.GetMimeMapping(".pdf");
                context.Response.AddHeader("Content-Disposition", "inline; filename=\"" + pid + ".pdf\"");
                context.Response.AddHeader("Content-Length", pdf.Length.ToString());

                for (int i = 0, count = 1024; i < pdf.Length; i += count)
                {
                    context.Response.OutputStream.Write(pdf, i, Math.Min(count, pdf.Length - i));
                }
                context.Response.Flush();
            }
            catch (HttpException he)
            {
                context.Response.StatusCode = he.GetHttpCode();
                context.Response.Write(HttpUtility.HtmlEncode(he.Message));
            }
            catch (Exception error)
            {
                log.ErrorFormat("Url: {0} {1}", context.Request.Url, error);
                context.Response.StatusCode = 500;
                context.Response.Write(HttpUtility.HtmlEncode(error.Message));
            }
        }
Exemplo n.º 2
0
        private static void TempFile(HttpContext context)
        {
            var fileName = context.Request[FilesLinkUtility.FileTitle];
            var auth     = context.Request[FilesLinkUtility.AuthKey];

            var validateResult = EmailValidationKeyProvider.ValidateEmailKey(fileName, auth ?? "", Global.StreamUrlExpire);

            if (validateResult != EmailValidationKeyProvider.ValidationResult.Ok)
            {
                var exc = new HttpException((int)HttpStatusCode.Forbidden, FilesCommonResource.ErrorMassage_SecurityException);

                Global.Logger.Error(string.Format("{0} {1}: {2}", FilesLinkUtility.AuthKey, validateResult, context.Request.Url), exc);

                context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
                context.Response.Write(FilesCommonResource.ErrorMassage_SecurityException);
                return;
            }

            context.Response.Clear();
            context.Response.ContentType = MimeMapping.GetMimeMapping(fileName);
            context.Response.AddHeader("Content-Disposition", ContentDispositionUtil.GetHeaderValue(fileName));

            var store = Global.GetStore();

            var path = Path.Combine("temp_stream", fileName);

            if (!store.IsFile(FileConstant.StorageDomainTmp, path))
            {
                context.Response.StatusCode = (int)HttpStatusCode.NotFound;
                context.Response.Write(FilesCommonResource.ErrorMassage_FileNotFound);
                return;
            }

            using (var readStream = store.GetReadStream(FileConstant.StorageDomainTmp, path))
            {
                context.Response.AddHeader("Content-Length", readStream.Length.ToString());
                readStream.StreamCopyTo(context.Response.OutputStream);
            }

            store.Delete(FileConstant.StorageDomainTmp, path);

            try
            {
                context.Response.Flush();
                context.Response.End();
            }
            catch (HttpException)
            {
            }
        }
Exemplo n.º 3
0
        private static void DownloadTry(HttpContext context)
        {
            FileType tryType;

            try
            {
                tryType = (FileType)Enum.Parse(typeof(FileType), context.Request[CommonLinkUtility.TryParam]);
            }
            catch
            {
                tryType = FileType.Document;
            }

            var title = string.IsNullOrEmpty(context.Request[CommonLinkUtility.FileTitle]) ? "Demo" : "new";

            title += FileUtility.InternalExtension[tryType];

            context.Response.Clear();
            context.Response.ContentType = MimeMapping.GetMimeMapping(title);
            context.Response.Charset     = "utf-8";

            var browser = context.Request.Browser.Browser;
            var format  = browser == "IE" || browser == "Safari"
                             ? "{0}; filename=\"{1}\""
                             : "{0}; filename*=utf-8''{1}";

            var filename           = browser == "Safari" ? title : HttpUtility.UrlPathEncode(title);
            var contentDisposition = string.Format(format, "attachment", filename);

            context.Response.AddHeader("Content-Disposition", contentDisposition);

            //NOTE: always pass files through handler
            using (var readStream = Global.GetStoreTemplate().IronReadStream("", title, 10))
            {
                context.Response.AddHeader("Content-Length", readStream.Length.ToString()); //BUG:Can be bugs
                readStream.StreamCopyTo(context.Response.OutputStream);
            }

            try
            {
                context.Response.Flush();
                context.Response.End();
            }
            catch (HttpException)
            {
            }
        }
Exemplo n.º 4
0
        private static void DownloadFile(HttpContext context)
        {
            var flushed = false;

            try
            {
                var id  = context.Request[FilesLinkUtility.FileId];
                var doc = context.Request[FilesLinkUtility.DocShareKey] ?? "";

                using (var fileDao = Global.DaoFactory.GetFileDao())
                {
                    File file;
                    var  readLink = FileShareLink.Check(doc, true, fileDao, out file);
                    if (!readLink && file == null)
                    {
                        fileDao.InvalidateCache(id);

                        int version;
                        file = int.TryParse(context.Request[FilesLinkUtility.Version], out version) && version > 0
                                   ? fileDao.GetFile(id, version)
                                   : fileDao.GetFile(id);
                    }

                    if (file == null)
                    {
                        context.Response.StatusCode = (int)HttpStatusCode.NotFound;

                        return;
                    }

                    if (!readLink && !Global.GetFilesSecurity().CanRead(file))
                    {
                        context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
                        return;
                    }

                    if (!string.IsNullOrEmpty(file.Error))
                    {
                        throw new Exception(file.Error);
                    }

                    if (!fileDao.IsExistOnStorage(file))
                    {
                        Global.Logger.ErrorFormat("Download file error. File is not exist on storage. File id: {0}.", file.ID);
                        context.Response.StatusCode = (int)HttpStatusCode.NotFound;

                        return;
                    }

                    FileMarker.RemoveMarkAsNew(file);

                    context.Response.Clear();
                    context.Response.ClearHeaders();
                    context.Response.Charset = "utf-8";

                    var title = file.Title.Replace(',', '_');

                    var ext = FileUtility.GetFileExtension(file.Title);

                    var outType = context.Request[FilesLinkUtility.OutType];

                    if (!string.IsNullOrEmpty(outType))
                    {
                        outType = outType.Trim();
                        if (FileUtility.ExtsConvertible[ext].Contains(outType))
                        {
                            ext = outType;

                            title = FileUtility.ReplaceFileExtension(title, ext);
                        }
                    }

                    context.Response.AddHeader("Content-Disposition", ContentDispositionUtil.GetHeaderValue(title));
                    context.Response.ContentType = MimeMapping.GetMimeMapping(title);

                    //// Download file via nginx
                    //if (CoreContext.Configuration.Standalone &&
                    //    WorkContext.IsMono &&
                    //    Global.GetStore() is DiscDataStore &&
                    //    !file.ProviderEntry &&
                    //    !FileConverter.EnableConvert(file, ext)
                    //    )
                    //{
                    //    var diskDataStore = (DiscDataStore)Global.GetStore();

                    //    var pathToFile = diskDataStore.GetPhysicalPath(String.Empty, FileDao.GetUniqFilePath(file));

                    //    context.Response.Headers.Add("X-Accel-Redirect", "/filesData" + pathToFile);

                    //    FilesMessageService.Send(file, context.Request, MessageAction.FileDownloaded, file.Title);

                    //    return;
                    //}

                    if (string.Equals(context.Request.Headers["If-None-Match"], GetEtag(file)))
                    {
                        //Its cached. Reply 304
                        context.Response.StatusCode = (int)HttpStatusCode.NotModified;
                        context.Response.Cache.SetETag(GetEtag(file));
                    }
                    else
                    {
                        context.Response.CacheControl = "public";
                        context.Response.Cache.SetETag(GetEtag(file));
                        context.Response.Cache.SetCacheability(HttpCacheability.Public);

                        Stream fileStream = null;

                        try
                        {
                            if (file.ContentLength <= SetupInfo.AvailableFileSize)
                            {
                                if (!FileConverter.EnableConvert(file, ext))
                                {
                                    if (!readLink && fileDao.IsSupportedPreSignedUri(file))
                                    {
                                        context.Response.Redirect(fileDao.GetPreSignedUri(file, TimeSpan.FromHours(1)).ToString(), true);

                                        return;
                                    }

                                    fileStream = fileDao.GetFileStream(file);
                                    context.Response.AddHeader("Content-Length", file.ContentLength.ToString(CultureInfo.InvariantCulture));
                                }
                                else
                                {
                                    fileStream = FileConverter.Exec(file, ext);
                                    context.Response.AddHeader("Content-Length", fileStream.Length.ToString(CultureInfo.InvariantCulture));
                                }

                                fileStream.StreamCopyTo(context.Response.OutputStream);

                                if (!context.Response.IsClientConnected)
                                {
                                    Global.Logger.Warn(String.Format("Download file error {0} {1} Connection is lost. Too long to buffer the file", file.Title, file.ID));
                                }

                                FilesMessageService.Send(file, context.Request, MessageAction.FileDownloaded, file.Title);

                                context.Response.Flush();
                                flushed = true;
                            }
                            else
                            {
                                context.Response.Buffer = false;

                                context.Response.ContentType = "application/octet-stream";

                                long offset = 0;

                                if (context.Request.Headers["Range"] != null)
                                {
                                    context.Response.StatusCode = 206;
                                    var range = context.Request.Headers["Range"].Split(new[] { '=', '-' });
                                    offset = Convert.ToInt64(range[1]);
                                }

                                if (offset > 0)
                                {
                                    Global.Logger.Info("Starting file download offset is " + offset);
                                }

                                context.Response.AddHeader("Connection", "Keep-Alive");
                                context.Response.AddHeader("Accept-Ranges", "bytes");

                                if (offset > 0)
                                {
                                    context.Response.AddHeader("Content-Range", String.Format(" bytes {0}-{1}/{2}", offset, file.ContentLength - 1, file.ContentLength));
                                }

                                var       dataToRead = file.ContentLength;
                                const int bufferSize = 8 * 1024; // 8KB
                                var       buffer     = new Byte[bufferSize];

                                if (!FileConverter.EnableConvert(file, ext))
                                {
                                    if (!readLink && fileDao.IsSupportedPreSignedUri(file))
                                    {
                                        context.Response.Redirect(fileDao.GetPreSignedUri(file, TimeSpan.FromHours(1)).ToString(), true);

                                        return;
                                    }

                                    fileStream = fileDao.GetFileStream(file, offset);
                                    context.Response.AddHeader("Content-Length", (file.ContentLength - offset).ToString(CultureInfo.InvariantCulture));
                                }
                                else
                                {
                                    fileStream = FileConverter.Exec(file, ext);

                                    if (offset > 0)
                                    {
                                        var startBytes = offset;

                                        while (startBytes > 0)
                                        {
                                            long readCount;

                                            if (bufferSize >= startBytes)
                                            {
                                                readCount = startBytes;
                                            }
                                            else
                                            {
                                                readCount = bufferSize;
                                            }

                                            var length = fileStream.Read(buffer, 0, (int)readCount);

                                            startBytes -= length;
                                        }
                                    }
                                }

                                while (dataToRead > 0)
                                {
                                    int length;

                                    try
                                    {
                                        length = fileStream.Read(buffer, 0, bufferSize);
                                    }
                                    catch (HttpException exception)
                                    {
                                        Global.Logger.Error(
                                            String.Format("Read from stream is error. Download file {0} {1}. Maybe Connection is lost.?? Error is {2} ",
                                                          file.Title,
                                                          file.ID,
                                                          exception
                                                          ));

                                        throw;
                                    }

                                    if (context.Response.IsClientConnected)
                                    {
                                        context.Response.OutputStream.Write(buffer, 0, length);
                                        context.Response.Flush();
                                        flushed    = true;
                                        dataToRead = dataToRead - length;
                                    }
                                    else
                                    {
                                        dataToRead = -1;
                                        Global.Logger.Warn(String.Format("IsClientConnected is false. Why? Download file {0} {1} Connection is lost. ", file.Title, file.ID));
                                    }
                                }
                            }
                        }
                        catch (ThreadAbortException)
                        {
                        }
                        catch (HttpException e)
                        {
                            throw new HttpException((int)HttpStatusCode.BadRequest, e.Message);
                        }
                        finally
                        {
                            if (fileStream != null)
                            {
                                fileStream.Close();
                                fileStream.Dispose();
                            }
                        }

                        try
                        {
                            context.Response.End();
                            flushed = true;
                        }
                        catch (HttpException)
                        {
                        }
                    }
                }
            }
            catch (ThreadAbortException)
            {
            }
            catch (Exception ex)
            {
                // Get stack trace for the exception with source file information
                var st = new StackTrace(ex, true);
                // Get the top stack frame
                var frame = st.GetFrame(0);
                // Get the line number from the stack frame
                var line = frame.GetFileLineNumber();

                Global.Logger.ErrorFormat("Url: {0} {1} IsClientConnected:{2}, line number:{3} frame:{4}", context.Request.Url, ex, context.Response.IsClientConnected, line, frame);
                if (!flushed && context.Response.IsClientConnected)
                {
                    context.Response.StatusCode = 400;
                    context.Response.Write(HttpUtility.HtmlEncode(ex.Message));
                }
            }
        }
Exemplo n.º 5
0
        private static void DownloadFile(HttpContext context, bool inline)
        {
            if (!string.IsNullOrEmpty(context.Request[CommonLinkUtility.TryParam]))
            {
                DownloadTry(context);
                return;
            }

            try
            {
                var id           = context.Request[CommonLinkUtility.FileId];
                var shareLinkKey = context.Request[CommonLinkUtility.DocShareKey] ?? "";

                using (var fileDao = Global.DaoFactory.GetFileDao())
                {
                    File file;
                    var  checkLink = FileShareLink.Check(shareLinkKey, true, fileDao, out file);
                    if (!checkLink && file == null)
                    {
                        int version;
                        file = int.TryParse(context.Request[CommonLinkUtility.Version], out version) && version > 0
                                   ? fileDao.GetFile(id, version)
                                   : fileDao.GetFile(id);
                    }

                    if (file == null)
                    {
                        context.Response.Redirect("~/404.htm");

                        return;
                    }

                    if (!checkLink && !Global.GetFilesSecurity().CanRead(file))
                    {
                        context.Response.Redirect((context.Request.UrlReferrer != null
                                                       ? context.Request.UrlReferrer.ToString()
                                                       : PathProvider.StartURL)
                                                  + "#" + UrlConstant.Error + "/" +
                                                  HttpUtility.UrlEncode(FilesCommonResource.ErrorMassage_SecurityException_ReadFile));
                        return;
                    }

                    if (!fileDao.IsExistOnStorage(file))
                    {
                        Global.Logger.ErrorFormat("Download file error. File is not exist on storage. File id: {0}.", file.ID);
                        context.Response.Redirect("~/404.htm");

                        return;
                    }

                    FileMarker.RemoveMarkAsNew(file);

                    context.Response.Clear();
                    context.Response.ContentType = MimeMapping.GetMimeMapping(file.Title);
                    context.Response.Charset     = "utf-8";

                    var browser = context.Request.Browser.Browser;
                    var title   = file.Title.Replace(',', '_');

                    var ext = FileUtility.GetFileExtension(file.Title);

                    var outType  = string.Empty;
                    var curQuota = TenantExtra.GetTenantQuota();
                    if (curQuota.DocsEdition || FileUtility.InternalExtension.Values.Contains(ext))
                    {
                        outType = context.Request[CommonLinkUtility.OutType];
                    }

                    if (!string.IsNullOrEmpty(outType) && !inline)
                    {
                        outType = outType.Trim();
                        if (FileUtility.ExtsConvertible[ext].Contains(outType))
                        {
                            ext = outType;

                            title = FileUtility.ReplaceFileExtension(title, ext);
                        }
                    }

                    context.Response.AddHeader("Content-Disposition", ContentDispositionUtil.GetHeaderValue(title, inline));

                    if (inline && string.Equals(context.Request.Headers["If-None-Match"], GetEtag(file)))
                    {
                        //Its cached. Reply 304
                        context.Response.StatusCode = (int)HttpStatusCode.NotModified;
                        context.Response.Cache.SetETag(GetEtag(file));
                    }
                    else
                    {
                        context.Response.CacheControl = "public";
                        context.Response.Cache.SetETag(GetEtag(file));
                        context.Response.Cache.SetCacheability(HttpCacheability.Public);

                        Stream fileStream = null;

                        try
                        {
                            if (file.ContentLength <= SetupInfo.AvailableFileSize)
                            {
                                if (file.ConvertedType == null && (string.IsNullOrEmpty(outType) || inline))
                                {
                                    context.Response.AddHeader("Content-Length", file.ContentLength.ToString(CultureInfo.InvariantCulture));

                                    if (fileDao.IsSupportedPreSignedUri(file))
                                    {
                                        context.Response.Redirect(fileDao.GetPreSignedUri(file, TimeSpan.FromHours(1)).ToString(), true);

                                        return;
                                    }

                                    fileStream = fileDao.GetFileStream(file);
                                }
                                else
                                {
                                    fileStream = FileConverter.Exec(file, ext);
                                }

                                fileStream.StreamCopyTo(context.Response.OutputStream);

                                if (!context.Response.IsClientConnected)
                                {
                                    Global.Logger.Error(String.Format("Download file error {0} {1} Connection is lost. Too long to buffer the file", file.Title, file.ID));
                                }

                                context.Response.Flush();
                            }
                            else
                            {
                                long offset = 0;

                                if (context.Request.Headers["Range"] != null)
                                {
                                    context.Response.StatusCode = 206;
                                    var range = context.Request.Headers["Range"].Split(new[] { '=', '-' });
                                    offset = Convert.ToInt64(range[1]);
                                }

                                if (offset > 0)
                                {
                                    Global.Logger.Info("Starting file download offset is " + offset);
                                }

                                context.Response.AddHeader("Connection", "Keep-Alive");
                                context.Response.AddHeader("Accept-Ranges", "bytes");

                                if (offset > 0)
                                {
                                    context.Response.AddHeader("Content-Range", String.Format(" bytes {0}-{1}/{2}", offset, file.ContentLength - 1, file.ContentLength));
                                }

                                var       dataToRead = file.ContentLength;
                                const int bufferSize = 1024;
                                var       buffer     = new Byte[bufferSize];

                                if (file.ConvertedType == null && (string.IsNullOrEmpty(outType) || inline))
                                {
                                    if (fileDao.IsSupportedPreSignedUri(file))
                                    {
                                        context.Response.Redirect(fileDao.GetPreSignedUri(file, TimeSpan.FromHours(1)).ToString(), true);

                                        return;
                                    }

                                    fileStream = fileDao.GetFileStream(file, offset);
                                    context.Response.AddHeader("Content-Length", (file.ContentLength - offset).ToString(CultureInfo.InvariantCulture));
                                }
                                else
                                {
                                    fileStream = FileConverter.Exec(file, ext);

                                    if (offset > 0)
                                    {
                                        var startBytes = offset;

                                        while (startBytes > 0)
                                        {
                                            long readCount;

                                            if (bufferSize >= startBytes)
                                            {
                                                readCount = startBytes;
                                            }
                                            else
                                            {
                                                readCount = bufferSize;
                                            }

                                            var length = fileStream.Read(buffer, 0, (int)readCount);

                                            startBytes -= length;
                                        }
                                    }
                                }

                                while (dataToRead > 0)
                                {
                                    int length;

                                    try
                                    {
                                        length = fileStream.Read(buffer, 0, bufferSize);
                                    }
                                    catch (HttpException exception)
                                    {
                                        Global.Logger.Error(
                                            String.Format("Read from stream is error. Download file {0} {1}. Maybe Connection is lost.?? Error is {2} ",
                                                          file.Title,
                                                          file.ID,
                                                          exception
                                                          ));

                                        throw;
                                    }

                                    if (context.Response.IsClientConnected)
                                    {
                                        context.Response.OutputStream.Write(buffer, 0, length);
                                        dataToRead = dataToRead - length;
                                    }
                                    else
                                    {
                                        dataToRead = -1;
                                        Global.Logger.Error(String.Format("IsClientConnected is false. Why? Download file {0} {1} Connection is lost. ", file.Title, file.ID));
                                    }
                                }
                            }
                        }
                        catch (HttpException e)
                        {
                            throw new HttpException((int)HttpStatusCode.BadRequest, e.Message);
                        }
                        finally
                        {
                            if (fileStream != null)
                            {
                                fileStream.Flush();
                                fileStream.Close();
                                fileStream.Dispose();
                            }
                        }

                        try
                        {
                            context.Response.End();
                        }
                        catch (HttpException)
                        {
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // Get stack trace for the exception with source file information
                var st = new StackTrace(ex, true);
                // Get the top stack frame
                var frame = st.GetFrame(0);
                // Get the line number from the stack frame
                var line = frame.GetFileLineNumber();

                Global.Logger.ErrorFormat("Url: {0} {1} IsClientConnected:{2}, line number:{3} frame:{4}", context.Request.Url, ex, context.Response.IsClientConnected, line, frame);
                context.Response.StatusCode = 400;
                context.Response.Write(HttpUtility.HtmlEncode(ex.Message));
            }
        }
        internal static void ProcessRequestInternal(HttpContext context, string overrideVirtualPath)
        {
            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);
            }

            Debug.Trace("StaticFileHandler", "Path= " + virtualPathWithPathInfo + ", PhysicalPath= " + physicalPath);

            fileInfo = GetFileInfo(virtualPathWithPathInfo, physicalPath, response);

            // 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(context, lastModifiedInUtc, utcNow);
            fileLength = fileInfo.Length;

            // is this a Range request?
            rangeHeader = request.Headers["Range"];
            if (StringUtil.StringStartsWithIgnoreCase(rangeHeader, "bytes") &&
                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.GetMimeMapping(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);
            // Set IgnoreRangeRequests to avoid serving Range requests from the output cache.
            // Note that the kernel cache always ignores Range requests.
            response.Cache.SetIgnoreRangeRequests();
            // Set an expires in the future.
            response.Cache.SetExpires(utcNow.AddDays(1));
            // 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.Public);
        }
        internal static bool ProcessRangeRequest(HttpContext context,
                                                 string physicalPath,
                                                 long fileLength,
                                                 string rangeHeader,
                                                 string etag,
                                                 DateTime lastModified)
        {
            HttpRequest  request  = context.Request;
            HttpResponse response = context.Response;
            bool         handled  = false;

            // return "416 Requested range not satisfiable" if the file length is zero.
            if (fileLength <= 0)
            {
                SendRangeNotSatisfiable(response, fileLength);
                handled = true;
                return(handled);
            }

            string ifRangeHeader = request.Headers["If-Range"];

            if (ifRangeHeader != null && ifRangeHeader.Length > 1)
            {
                // Is this an ETag or a Date? We only need to check two
                // characters; an ETag either begins with W/ or it is quoted.
                if (ifRangeHeader[0] == '"')
                {
                    // it's a strong ETag
                    if (ifRangeHeader != etag)
                    {
                        // the etags do not match, and we will therefore return the entire response
                        return(handled);
                    }
                }
                else if (ifRangeHeader[0] == 'W' && ifRangeHeader[1] == '/')
                {
                    // it's a weak ETag, and is therefore not usable for sub-range retrieval and
                    // we will return the entire response
                    return(handled);
                }
                else
                {
                    // It's a date. If it is greater than or equal to the last-write time of the file, we can send the range.
                    if (IsOutDated(ifRangeHeader, lastModified))
                    {
                        return(handled);
                    }
                }
            }

            // the expected format is "bytes = <range1>[, <range2>, ...]"
            // where <range> is "<first_byte_pos>-[<last_byte_pos>]" or "-<last_n_bytes>".
            int indexOfEquals = rangeHeader.IndexOf('=');

            if (indexOfEquals == -1 || indexOfEquals == rangeHeader.Length - 1)
            {
                //invalid syntax
                return(handled);
            }

            // iterate through the byte ranges and write each satisfiable range to the response
            int  startIndex = indexOfEquals + 1;
            bool isRangeHeaderSyntacticallyValid = true;
            long offset;
            long length;
            bool isSatisfiable;
            bool exceededMax = false;

            ByteRange[] byteRanges      = null;
            int         byteRangesCount = 0;
            long        totalBytes      = 0;

            while (startIndex < rangeHeader.Length && isRangeHeaderSyntacticallyValid)
            {
                isRangeHeaderSyntacticallyValid = GetNextRange(rangeHeader, ref startIndex, fileLength, out offset, out length, out isSatisfiable);
                if (!isRangeHeaderSyntacticallyValid)
                {
                    break;
                }
                if (!isSatisfiable)
                {
                    continue;
                }
                if (byteRanges == null)
                {
                    byteRanges = new ByteRange[16];
                }
                if (byteRangesCount >= byteRanges.Length)
                {
                    // grow byteRanges array
                    ByteRange[] buffer    = new ByteRange[byteRanges.Length * 2];
                    int         byteCount = byteRanges.Length * Marshal.SizeOf(byteRanges[0]);
                    unsafe
                    {
                        fixed(ByteRange *src = byteRanges, dst = buffer)
                        {
                            StringUtil.memcpyimpl((byte *)src, (byte *)dst, byteCount);
                        }
                    }
                    byteRanges = buffer;
                }
                byteRanges[byteRangesCount].Offset = offset;
                byteRanges[byteRangesCount].Length = length;
                byteRangesCount++;
                // IIS imposes this limitation too, and sends "400 Bad Request" if exceeded
                totalBytes += length;
                if (totalBytes > fileLength * MAX_RANGE_ALLOWED)
                {
                    exceededMax = true;
                    break;
                }
            }

            if (!isRangeHeaderSyntacticallyValid)
            {
                return(handled);
            }

            if (exceededMax)
            {
                SendBadRequest(response);
                handled = true;
                return(handled);
            }

            if (byteRangesCount == 0)
            {
                // we parsed the Range header and found no satisfiable byte ranges, so return "416 Requested Range Not Satisfiable"
                SendRangeNotSatisfiable(response, fileLength);
                handled = true;
                return(handled);
            }

            string contentType = MimeMapping.GetMimeMapping(physicalPath);

            if (byteRangesCount == 1)
            {
                offset = byteRanges[0].Offset;
                length = byteRanges[0].Length;
                response.ContentType = contentType;
                string contentRange = String.Format(CultureInfo.InvariantCulture, CONTENT_RANGE_FORMAT, offset, offset + length - 1, fileLength);
                response.AppendHeader("Content-Range", contentRange);

                SendFile(physicalPath, offset, length, fileLength, context);
            }
            else
            {
                response.ContentType = MULTIPART_CONTENT_TYPE;
                string contentRange;
                string partialContentType = "Content-Type: " + contentType + "\r\n";
                for (int i = 0; i < byteRangesCount; i++)
                {
                    offset = byteRanges[i].Offset;
                    length = byteRanges[i].Length;
                    response.Write(MULTIPART_RANGE_DELIMITER);
                    response.Write(partialContentType);
                    response.Write("Content-Range: ");
                    contentRange = String.Format(CultureInfo.InvariantCulture, CONTENT_RANGE_FORMAT, offset, offset + length - 1, fileLength);
                    response.Write(contentRange);
                    response.Write("\r\n\r\n");
                    SendFile(physicalPath, offset, length, fileLength, context);
                    response.Write("\r\n");
                }
                response.Write(MULTIPART_RANGE_END);
            }

            // if we make it here, we're sending a "206 Partial Content" status
            response.StatusCode = 206;
            response.AppendHeader("Last-Modified", HttpUtility.FormatHttpDateTime(lastModified));
            response.AppendHeader("Accept-Ranges", "bytes");
            response.AppendHeader("ETag", etag);
            response.AppendHeader("Cache-Control", "public");

            handled = true;
            return(handled);
        }