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";

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

                    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
                        {
                            var title = file.Title;

                            if (file.ContentLength <= SetupInfo.AvailableFileSize)
                            {
                                var ext = FileUtility.GetFileExtension(file.Title);

                                var outType = (context.Request[FilesLinkUtility.OutType] ?? "").Trim();
                                if (!string.IsNullOrEmpty(outType) &&
                                    FileUtility.ExtsConvertible.Keys.Contains(ext) &&
                                    FileUtility.ExtsConvertible[ext].Contains(outType))
                                {
                                    ext = outType;
                                }

                                long offset = 0;
                                long length;
                                if (!file.ProviderEntry &&
                                    string.Equals(context.Request["convpreview"], "true", StringComparison.InvariantCultureIgnoreCase) &&
                                    FFmpegService.IsConvertable(ext))
                                {
                                    const string mp4Name = "content.mp4";
                                    var          mp4Path = FileDao.GetUniqFilePath(file, mp4Name);
                                    var          store   = Global.GetStore();
                                    if (!store.IsFile(mp4Path))
                                    {
                                        fileStream = fileDao.GetFileStream(file);

                                        Global.Logger.InfoFormat("Converting {0} (fileId: {1}) to mp4", file.Title, file.ID);
                                        var stream = FFmpegService.Convert(fileStream, ext);
                                        store.Save(string.Empty, mp4Path, stream, mp4Name);
                                    }

                                    var fullLength = store.GetFileSize(string.Empty, mp4Path);

                                    length     = ProcessRangeHeader(context, fullLength, ref offset);
                                    fileStream = store.GetReadStream(string.Empty, mp4Path, (int)offset);

                                    title = FileUtility.ReplaceFileExtension(title, ".mp4");
                                }
                                else
                                {
                                    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); // getStream to fix file.ContentLength

                                        if (fileStream.CanSeek)
                                        {
                                            var fullLength = file.ContentLength;
                                            length = ProcessRangeHeader(context, fullLength, ref offset);
                                            fileStream.Seek(offset, SeekOrigin.Begin);
                                        }
                                        else
                                        {
                                            length = file.ContentLength;
                                        }
                                    }
                                    else
                                    {
                                        title      = FileUtility.ReplaceFileExtension(title, ext);
                                        fileStream = FileConverter.Exec(file, ext);

                                        length = fileStream.Length;
                                    }
                                }

                                SendStreamByChunks(context, length, title, fileStream, ref flushed);
                            }
                            else
                            {
                                if (!readLink && fileDao.IsSupportedPreSignedUri(file))
                                {
                                    context.Response.Redirect(fileDao.GetPreSignedUri(file, TimeSpan.FromHours(1)).ToString(), true);

                                    return;
                                }

                                fileStream = fileDao.GetFileStream(file); // getStream to fix file.ContentLength

                                long offset = 0;
                                var  length = file.ContentLength;
                                if (fileStream.CanSeek)
                                {
                                    length = ProcessRangeHeader(context, file.ContentLength, ref offset);
                                    fileStream.Seek(offset, SeekOrigin.Begin);
                                }

                                SendStreamByChunks(context, length, title, fileStream, ref flushed);
                            }
                        }
                        catch (ThreadAbortException tae)
                        {
                            Global.Logger.Error("DownloadFile", tae);
                        }
                        catch (HttpException e)
                        {
                            Global.Logger.Error("DownloadFile", e);
                            throw new HttpException((int)HttpStatusCode.BadRequest, e.Message);
                        }
                        finally
                        {
                            if (fileStream != null)
                            {
                                fileStream.Close();
                                fileStream.Dispose();
                            }
                        }

                        try
                        {
                            context.Response.Flush();
                            context.Response.SuppressContent = true;
                            context.ApplicationInstance.CompleteRequest();
                            flushed = true;
                        }
                        catch (HttpException ex)
                        {
                            Global.Logger.Error("DownloadFile", ex);
                        }
                    }
                }
            }
            catch (ThreadAbortException tae)
            {
                Global.Logger.Error("DownloadFile", tae);
            }
            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));
                }
            }
        }