/// <summary>
        /// Adds the correct response headers for a file download request.
        /// </summary>
        /// <param name="context">HttpContext</param>
        /// <param name="fileHeadObject">The file object representing the file to stream.</param>
        public static void AddDownloadHeaders(HttpContext context, FileHeadObject fileHeadObject)
        {
            HttpContext httpContext = context as HttpContext;

            string requestLanguage = string.Empty;
            if (httpContext.Request.UserLanguages.Length > 0)
                requestLanguage = httpContext.Request.UserLanguages[0];

            httpContext.Response.AppendHeader("Content-Length", fileHeadObject.BytesCount.ToString(CultureInfo.InvariantCulture));
            httpContext.Response.ContentType = GetMimeType(fileHeadObject.FileName);

            string disposition = BuildContentDispositionHeader(fileHeadObject, requestLanguage,
                httpContext.Request.Browser.Type,
                httpContext.Request.Browser.MajorVersion,
                httpContext.Request.Browser.Platform);
            httpContext.Response.AppendHeader("Content-Disposition", disposition);  // gives save-as dialog and filename
        }
        private static string TruncateHeaderLine(FileHeadObject fileHeadObject, string text, int firstLineLen)
        {
            int maxLen = firstLineLen;
            int pos = 0;
            if (pos + maxLen < text.Length)
            {
                int lastByteCount = 0;
                while (pos < maxLen)
                {
                    if (text[pos] == '%')  // we don't want a filename to end with '%'.
                        lastByteCount = 3;
                    else
                        lastByteCount = 1;
                    pos += lastByteCount;
                }

                pos = pos - lastByteCount;
                string ext = fileHeadObject.FileExtensionName;
                text = text.Substring(0, pos);
                int dotPos = text.LastIndexOf(".", StringComparison.Ordinal);
                if (dotPos > 0)
                    text = text.Substring(0, dotPos);

                text += ext;
            }

            return text;
        }
 /// <summary>
 /// If the filename contains high ASCII and client is non-English, the filename to use (w/o extension).
 /// </summary>
 /// <param name="fileHeadObject"></param>
 private static string GetPlaceholderFileName(FileHeadObject fileHeadObject)
 {
     return string.Format(CultureInfo.InvariantCulture, "Download_{0}", fileHeadObject.Id.ToString());
 }
        private static string GetDownloadFilename(FileHeadObject fileHeadObject, string userLanguage, bool requestIsFromXPIE6Japanese)
        {
            bool isUsePlaceholder = false;
            string origFileName = fileHeadObject.FileName;
            string fileName;
            // if the request from WINXP IE6 and Japanese
            if (requestIsFromXPIE6Japanese)
            {
                fileName = BuildDownloadNameForXPIE6Japanese(fileHeadObject);
            }
            else
            {
                if (StringContainsHighAscii(origFileName))
                {
                    isUsePlaceholder = true;
                    if (userLanguage.StartsWith("en", StringComparison.OrdinalIgnoreCase))
                        isUsePlaceholder = false;
                }

                string nameToUse = origFileName;
                if (isUsePlaceholder)
                {
                    string extension = fileHeadObject.FileExtensionName;
                    nameToUse = GetPlaceholderFileName(fileHeadObject) + extension;
                }

                fileName = HttpUtility.UrlPathEncode(nameToUse);
                fileName = fileName.Replace("#", "%23");
            }

            return fileName;
        }
        /// <summary>
        /// Builds the optimum file name that can be displayed without exceeeding
        /// header limit.
        /// </summary>
        /// <param name="fileHeadObject">original file head</param>
        /// <returns></returns>
        private static string BuildDownloadNameForXPIE6Japanese(FileHeadObject fileHeadObject)
        {
            //To DO Krishna: We can change this logic to use ability of UTF8 encoded byte  to determine the truncation point.
            string nameToUse = fileHeadObject.FileName;
            string ext = fileHeadObject.FileExtensionName;
            if (ext.Length > 0)
                nameToUse = nameToUse.Substring(0, nameToUse.Length - ext.Length);

            char[] charArr = nameToUse.ToCharArray();
            string holderStr;
            StringBuilder fileName = new StringBuilder();
            int nCurrentLength = 0;

            foreach (char c in charArr)
            {

                holderStr = HttpUtility.UrlEncode(c.ToString());
                if ((holderStr.Length + nCurrentLength) > 155)
                    break;

                nCurrentLength += holderStr.Length;
                fileName.Append(holderStr);
                holderStr = null;
            }

            if (ext.Length > 0)
                fileName.Append(ext);

            return fileName.ToString();
        }
        /// <summary>
        /// Note that the httpContext param can legally be null.  See callers.
        /// </summary>
        /// <remarks>
        /// The Content-Disposition HTTP response header gives us some control over how the client will react
        /// to the file download.  In particular, whether or not the client will launch a "Save As" dialog when a file
        /// is requested for dowload.  See RFC 1806 for detials.</remarks>
        /// <remarks>We tried excluding "attachment" from the contentDisposition header for IE 5.5 to avoid
        /// getting a double download prompt.  Except, this causes a problem for the case
        /// where Office2K is installed on IE5.5 -- for that case we don't get any download prompt
        /// unless we have the header.  So on IE5.5 we get a double download prompt.
        /// </remarks>
        /// <param name="fileHeadObject"></param>
        /// <param name="userLanguage"></param>
        /// <param name="capabilitiesType"></param>
        /// <param name="majorVersion"></param>
        /// <param name="platform"></param>
        /// <returns></returns>
        private static string BuildContentDispositionHeader(FileHeadObject fileHeadObject, string userLanguage, string capabilitiesType, int majorVersion, string platform)
        {
            // To build and hold the Content-Disposition header.
            StringBuilder dispositionBuilder = new StringBuilder();

            dispositionBuilder.Append("attachment;");

            // Note that we cannot determine browser details from a WebOperationContext,
            // so we simply ignore this check in that case.  See callers.
            bool requestIsFromXPIE6Japanese = false;
            if ((!string.IsNullOrEmpty(capabilitiesType)) && majorVersion > -1 && (!string.IsNullOrEmpty(platform)))
                requestIsFromXPIE6Japanese = IfRequestIsFromXPIE6Japanese(userLanguage, capabilitiesType, majorVersion, platform);

            dispositionBuilder.AppendFormat("filename=\"{0}\"", GetDownloadFilename(fileHeadObject, userLanguage, requestIsFromXPIE6Japanese));

            string disposition = dispositionBuilder.ToString();

            // Max line length is 78 characters, including header name; we'll limit the first line to less characters
            // to make sure we have space for the header and the line terminators
            if (!requestIsFromXPIE6Japanese)
                disposition = TruncateHeaderLine(fileHeadObject, disposition, 100);

            return disposition;
        }