screwturn-4/WebApplication/GetFile.aspx.cs
2009-09-30 13:47:13 +00:00

201 lines
6.6 KiB
C#

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Globalization;
using ScrewTurn.Wiki.PluginFramework;
namespace ScrewTurn.Wiki {
// No BasePage because compression/language selection are not needed
public partial class GetFile : Page {
protected void Page_Load(object sender, EventArgs e) {
string filename = Request["File"];
if(filename == null) {
Response.StatusCode = 404;
Response.Write(Properties.Messages.FileNotFound);
return;
}
// Remove ".." sequences that might be a security issue
filename = filename.Replace("..", "");
bool isPageAttachment = !string.IsNullOrEmpty(Request["Page"]);
PageInfo pageInfo = isPageAttachment ? Pages.FindPage(Request["Page"]) : null;
if(isPageAttachment && pageInfo == null) {
Response.StatusCode = 404;
Response.Write(Properties.Messages.FileNotFound);
return;
}
IFilesStorageProviderV30 provider;
if(!string.IsNullOrEmpty(Request["Provider"])) provider = Collectors.FilesProviderCollector.GetProvider(Request["Provider"]);
else {
if(isPageAttachment) provider = FilesAndAttachments.FindPageAttachmentProvider(pageInfo, filename);
else provider = FilesAndAttachments.FindFileProvider(filename);
}
if(provider == null) {
Response.StatusCode = 404;
Response.Write("File not found.");
return;
}
// Use canonical path format (leading with /)
if(!isPageAttachment) {
if(!filename.StartsWith("/")) filename = "/" + filename;
filename = filename.Replace("\\", "/");
}
bool countHit = CountHit(filename);
// Verify permissions
bool canDownload = false;
if(isPageAttachment) {
canDownload = AuthChecker.CheckActionForPage(pageInfo, Actions.ForPages.DownloadAttachments,
SessionFacade.GetCurrentUsername(), SessionFacade.GetCurrentGroupNames());
}
else {
string dir = Tools.GetDirectoryName(filename);
canDownload = AuthChecker.CheckActionForDirectory(provider, dir,
Actions.ForDirectories.DownloadFiles, SessionFacade.GetCurrentUsername(),
SessionFacade.GetCurrentGroupNames());
}
if(!canDownload) {
Response.StatusCode = 401;
return;
}
long size = -1;
FileDetails details = null;
if(isPageAttachment) details = provider.GetPageAttachmentDetails(pageInfo, filename);
else details = provider.GetFileDetails(filename);
if(details != null) size = details.Size;
else {
Log.LogEntry("Attempted to download an inexistent file/attachment (" + (pageInfo != null ? pageInfo.FullName + "/" : "") + filename + ")", EntryType.Warning, Log.SystemUsername);
Response.StatusCode = 404;
Response.Write("File not found.");
return;
}
string mime = "";
try {
string ext = Path.GetExtension(filename);
if(ext.StartsWith(".")) ext = ext.Substring(1).ToLower(); // Remove trailing dot
mime = GetMimeType(ext);
}
catch {
// ext is null -> no mime type -> abort
Response.Write(filename + "<br />");
Response.StatusCode = 404;
Response.Write("File not found.");
//mime = "application/octet-stream";
return;
}
// Prepare response
Response.Clear();
Response.AddHeader("content-type", mime);
if(Request["AsStreamAttachment"] != null) {
Response.AddHeader("content-disposition", "attachment;filename=\"" + Path.GetFileName(filename) + "\"");
}
else {
Response.AddHeader("content-disposition", "inline;filename=\"" + Path.GetFileName(filename) + "\"");
}
Response.AddHeader("content-length", size.ToString());
bool retrieved = false;
if(isPageAttachment) {
try {
retrieved = provider.RetrievePageAttachment(pageInfo, filename, Response.OutputStream, countHit);
}
catch(ArgumentException ex) {
Log.LogEntry("Attempted to download an inexistent attachment (" + pageInfo.FullName + "/" + filename + ")\n" + ex.ToString(), EntryType.Warning, Log.SystemUsername);
}
}
else {
try {
retrieved = provider.RetrieveFile(filename, Response.OutputStream, countHit);
}
catch(ArgumentException ex) {
Log.LogEntry("Attempted to download an inexistent file/attachment (" + filename + ")\n" + ex.ToString(), EntryType.Warning, Log.SystemUsername);
}
}
if(!retrieved) {
Response.StatusCode = 404;
Response.Write("File not found.");
return;
}
// Set the cache duration accordingly to the file date/time
//Response.AddFileDependency(filename);
//Response.Cache.SetETagFromFileDependencies();
//Response.Cache.SetLastModifiedFromFileDependencies();
Response.Cache.SetETag(filename.GetHashCode().ToString() + "-" + size.ToString());
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetSlidingExpiration(true);
Response.Cache.SetValidUntilExpires(true);
Response.Cache.VaryByParams["File"] = true;
Response.Cache.VaryByParams["Provider"] = true;
Response.Cache.VaryByParams["Page"] = true;
Response.Cache.VaryByParams["IsPageAttachment"] = true;
}
private string GetMimeType(string ext) {
string mime = "";
if(MimeTypes.Types.TryGetValue(ext, out mime)) return mime;
else return "application/octet-stream";
}
/// <summary>
/// Gets a value indicating whether or not to count the hit.
/// </summary>
/// <param name="file">The name of the file.</param>
/// <returns><c>true</c> if the hit must be counted, <c>false</c> otherwise.</returns>
private bool CountHit(string file) {
bool result = Request["NoHit"] != "1";
if(!result) return false;
else {
FileDownloadCountFilterMode mode = Settings.FileDownloadCountFilterMode;
if(mode == FileDownloadCountFilterMode.CountAll) return true;
else {
string[] allowedExtensions = Settings.FileDownloadCountFilter;
string extension = Path.GetExtension(file);
if(string.IsNullOrEmpty(extension)) return false;
else extension = extension.Trim('.').ToLowerInvariant();
bool found = false;
foreach(string ex in allowedExtensions) {
if(ex == extension) {
found = true;
break;
}
}
if(found && mode == FileDownloadCountFilterMode.CountSpecifiedExtensions) return true;
else if(!found && mode == FileDownloadCountFilterMode.ExcludeSpecifiedExtensions) return true;
else return false;
}
}
}
}
}