Current version of CS use Content-disposition filename header field to set correct filename during download.
This work correctly on IE 7/8 and not work on all other browsers.
This browser not UrlEncode filename field from Content-disposition field.
Simply change next httphandlers (web.config) to support national filenames.
<system.web> ... <httpHandlers> ... <add verb="GET" path="cfs-file.ashx" type="CustomCSHandlers.FileHttpHandler, CustomCSHandlers" /> <add verb="GET" path="cfs-filesystemfile.ashx" type="CustomCSHandlers.FileSystemFileStorageHttpHandler, CustomCSHandlers" /> ... </httpHandlers> ... </system.web>
Create C# class library project CustomCSHandlers and add 2 files.
1.FileHttpHandler.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using CommunityServer.Components;
namespace CustomCSHandlers
{
public class FileHttpHandler : IHttpHandler
{
// Requested URLS are in the format: .../__key/filestorekey/path/filename
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
CSContext.Current.AllowTokenRequests(false);
ICentralizedFile file = CentralizedFileStorageProvider.GetCentralizedFileByUrl(context.Request.Url.ToString());
if (file != null)
{
context.Response.Cache.SetAllowResponseInBrowserHistory(true);
context.Response.Cache.SetValidUntilExpires(true);
context.Response.Cache.SetExpires(DateTime.Now.AddDays(1));
context.Response.Cache.SetLastModified(DateTime.Now);
if (CentralizedFileStorageProvider.HasAccessValidator(file.FileStoreKey))
context.Response.Cache.SetCacheability(HttpCacheability.Private);
else
context.Response.Cache.SetCacheability(HttpCacheability.Public);
if (CentralizedFileStorageProvider.CurrentUserHasAccess(file.FileStoreKey, file.Path, file.FileName))
{
string path = file.GetDownloadUrl();
int i;
if ((i = path.LastIndexOf("/")) > 0)
{
string filename = Globals.UrlDecodeFileComponent(path.Substring(i + 1));
path = path.Substring(0, i + 1) + "N$/" + filename;
}
context.Response.RedirectLocation = Globals.FullPath(path);
context.Response.StatusCode = 301;
}
else
context.Response.StatusCode = 403;
}
else
context.Response.StatusCode = 404;
}
}
}
2. FileSystemFileStorageHttpHandler.cs
using System;
using System.Collections.Generic;
using System.Text;
using CommunityServer.Components;
using System.IO;
using System.Web;
namespace CustomCSHandlers
{
public class FileSystemFileStorageHttpHandler : IHttpHandler
{
// Requested URLS are in the format: ...__key/[filestorekey]/[path]/[filename]
public bool IsReusable
{
get { return true; }
}
protected CommunityServer.Components.FileSystemFileStorageFile GetFileFromPath(string path)
{
int index = path.IndexOf("__key/");
if (index < 0)
return null;
path = path.Substring(index + 6);
index = path.IndexOf('/');
if (index < 0)
return null;
string fileStoreKey = path.Substring(0, index);
index = path.LastIndexOf('/');
if (index < 0)
return null;
string fileName = path.Substring(index + 1);
if (path.Length - (fileStoreKey.Length + fileName.Length + 2) <= 0)
path = string.Empty;
else
path = path.Substring(fileStoreKey.Length + 1, path.Length - (fileStoreKey.Length + fileName.Length + 2));
fileStoreKey = Globals.UrlDecodePathComponent(fileStoreKey);
if (path.EndsWith("/N$"))
path = path.Substring(0, path.Length - 3);
else if (path == "N$")
path = path.Substring(0, path.Length - 2);
else
fileName = Globals.UrlDecodeFileComponent(fileName);
path = Globals.UrlDecodePathComponent(path);
if (string.IsNullOrEmpty(fileStoreKey) || string.IsNullOrEmpty(fileName))
return null;
CommunityServer.Components.FileSystemFileStorageProvider fileProvider = CentralizedFileStorageProvider.Instance(fileStoreKey) as CommunityServer.Components.FileSystemFileStorageProvider;
if (fileProvider != null)
return fileProvider.GetFile(path, fileName) as CommunityServer.Components.FileSystemFileStorageFile;
else
return null;
}
public void ProcessRequest(HttpContext context)
{
CSContext.Current.AllowTokenRequests(false);
CommunityServer.Components.FileSystemFileStorageFile file = GetFileFromPath(context.Request.Path);
if (file == null)
{
context.Response.StatusCode = 404;
return;
}
DateTime lastModified = (new FileInfo(file.FullLocalPath)).LastWriteTime;
DateTime currentLastModifiedDate = DateTime.MinValue;
#region If-Modified-Since
DateTime.TryParse(context.Request.Headers["If-Modified-Since"] ?? "", out currentLastModifiedDate);
if (Math.Abs(((TimeSpan)lastModified.ToUniversalTime().Subtract(currentLastModifiedDate.ToUniversalTime())).TotalSeconds) <= 1)
{
context.Response.StatusCode = 304;
context.Response.Status = "304 Not Modified";
return;
}
#endregion
#region If-None-Match (ETag)
long eTag = 0;
if (long.TryParse(context.Request.Headers["If-None-Match"] ?? "", out eTag))
{
currentLastModifiedDate = new DateTime(eTag);
if (lastModified == currentLastModifiedDate)
{
context.Response.StatusCode = 304;
context.Response.Status = "304 Not Modified";
return;
}
}
#endregion
if (!CentralizedFileStorageProvider.CurrentUserHasAccess(file.FileStoreKey, file.Path, file.FileName))
{
context.Response.StatusCode = 403;
return;
}
context.Response.ContentType = CommunityServer.Configuration.MimeTypeConfiguration.GetMimeType(file.FileName);
context.Response.Cache.SetAllowResponseInBrowserHistory(true);
context.Response.Cache.SetLastModified(lastModified.ToUniversalTime());
context.Response.Cache.SetETag(lastModified.Ticks.ToString());
if (!CentralizedFileStorageProvider.HasAccessValidator(file.FileStoreKey))
context.Response.Cache.SetCacheability(HttpCacheability.Public);
else
context.Response.Cache.SetCacheability(HttpCacheability.Private);
string disposition;
if (context.Response.ContentType == "application/pdf" || context.Response.ContentType == "application/octet-stream")
disposition = "attachment";
else
disposition = "inline";
if (context.Request.Browser.Browser.IndexOf("Netscape") != -1)
context.Response.AddHeader("Content-disposition", disposition + "; filename*0*=" + context.Server.UrlEncode(file.FileName).Replace("+", "%20") + "");
else
{
context.Response.AddHeader("Content-disposition", disposition); // filename=" + context.Server.UrlEncode(file.FileName).Replace("+", "%20") + "");
}
// Send files stored on UNC paths explicitly to avoid a bug with TransmitFile.
if (!file.FullLocalPath.StartsWith("\\"))
context.Response.TransmitFile(file.FullLocalPath);
else
{
context.Response.AddHeader("Content-Length", file.ContentLength.ToString("0"));
using (Stream s = new FileStream(file.FullLocalPath, FileMode.Open, FileAccess.Read))
{
context.Response.Buffer = false;
context.Response.BufferOutput = false;
try
{
byte[] buffer = new byte[64 * 1024];
int read;
while ((read = s.Read(buffer, 0, buffer.Length)) > 0)
{
if (!context.Response.IsClientConnected)
break;
context.Response.OutputStream.Write(buffer, 0, read);
context.Response.OutputStream.Flush();
}
}
catch (HttpException) { }
catch (Exception ex)
{
new CSException(CSExceptionType.UnknownError, "FileSystemFileStorageFile", ex).Log();
}
context.Response.Flush();
context.Response.Close();
s.Close();
}
}
}
}
}
add CustomCSHandlers.dll to bin folder.


0 comment(s) so far