Legacy upload processor implemented in ImportConsole; LegacyUploadHandler and UploadHandler (read) are implemented in IISMainHandler; IISUploadHandler implemented; IISUploadHandler package implemented; some fixes in util

main
Inga 🏳‍🌈 15 years ago
parent 1138bcc831
commit d5447a1ba3
  1. 2
      Builder/IISMainHandler/build.txt
  2. 1
      Builder/IISUploadHandler/build.txt
  3. 1
      Builder/IISUploadHandler/postbuild.bat
  4. 1
      Builder/IISUploadHandler/prebuild.bat
  5. 48
      Builder/IISUploadHandler/product.wxs
  6. 2
      Common/Common.csproj
  7. 22
      Common/Config.cs
  8. 113
      Common/UploadManager.cs
  9. 83
      Common/dataobjects/Upload.cs
  10. 47
      Core/Util.cs
  11. 8
      FLocal.sln
  12. 9
      IISMainHandler/HandlersFactory.cs
  13. 3
      IISMainHandler/IISMainHandler.csproj
  14. 10
      IISMainHandler/MainHandler.cs
  15. 16
      IISMainHandler/exceptions/RedirectException.cs
  16. 23
      IISMainHandler/handlers/StaticHandler.cs
  17. 43
      IISMainHandler/handlers/response/LegacyUploadHandler.cs
  18. 26
      IISMainHandler/handlers/response/UploadHandler.cs
  19. 22
      IISUploadHandler/Config.cs
  20. 68
      IISUploadHandler/IISUploadHandler.csproj
  21. 36
      IISUploadHandler/Properties/AssemblyInfo.cs
  22. 79
      IISUploadHandler/UploadHandler.cs
  23. 60
      ImportConsole/Program.cs
  24. 4
      build-all.bat

@ -0,0 +1,48 @@
<?xml version='1.0'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product Id='*' Name='FLocal IISUploadHandler' Language='1033'
Version='1.{rev}.{build}.0' Manufacturer='inga-lovinde' UpgradeCode='1311A47C-18A2-47CB-AB1C-85C7FF020D68' >
<Package Description='FLocal IISUploadHandler' Comments='FLocal IISUploadHandler' Manufacturer='inga-lovinde' InstallerVersion='300' Compressed='yes' Platform="x64" />
<Upgrade Id="1311A47C-18A2-47CB-AB1C-85C7FF020D68">
<UpgradeVersion Minimum="1.0.0" IncludeMinimum="yes" Maximum="1.{rev}.{build}" IncludeMaximum="no" Property="OLDERVERSIONBEINGUPGRADED" />
</Upgrade>
<Upgrade Id="1311A47C-18A2-47CB-AB1C-85C7FF020D68">
<UpgradeVersion Minimum="1.{rev}.{build}" IncludeMinimum="no" Property="NEWERVERSIONDETECTED" />
</Upgrade>
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallInitialize"/>
</InstallExecuteSequence>
<Media Id='1' Cabinet='product.cab' EmbedCab='yes' />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INETPUBROOTDIRECTORY" Name="inetpub">
<Directory Id="INETPUBMAINDIRECTORY" Name="flocal-upload">
<Directory Id="BINARIESROOTDIRECTORY" Name="Bin"/>
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="BINARIESROOTDIRECTORY">
<Component Id="Core.dll" Guid="4770412D-CAFE-469B-AD39-993832D43380">
<File Id="Core.dll" Source="..\..\Core\bin\Release\Core.dll" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="Core.pdb" Guid="D48AA0FF-F559-475B-BF27-C2BD537F7DD4">
<File Id="Core.pdb" Source="..\..\Core\bin\Release\Core.pdb" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="IISUploadHandler.dll" Guid="285FB9C5-A16F-4C4A-885C-8743AF66A43E">
<File Id="IISUploadHandler.dll" Source="..\..\IISUploadHandler\bin\Release\IISUploadHandler.dll" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="IISUploadHandler.pdb" Guid="DD8F0AA8-0F14-4D97-83E8-4F623921B602">
<File Id="IISUploadHandler.pdb" Source="..\..\IISUploadHandler\bin\Release\IISUploadHandler.pdb" KeyPath="yes" Checksum="yes"/>
</Component>
</DirectoryRef>
<Feature Id='IISUploadHandler' Title='IISUploadHandler' Level='1'>
<ComponentRef Id='IISUploadHandler.dll' />
<ComponentRef Id='IISUploadHandler.pdb' />
</Feature>
<Feature Id='Core' Title='Core library' Level='1'>
<ComponentRef Id='Core.dll' />
<ComponentRef Id='Core.pdb' />
</Feature>
</Product>
</Wix>

@ -64,11 +64,13 @@
<Compile Include="dataobjects\Post.cs" /> <Compile Include="dataobjects\Post.cs" />
<Compile Include="dataobjects\Session.cs" /> <Compile Include="dataobjects\Session.cs" />
<Compile Include="dataobjects\Thread.cs" /> <Compile Include="dataobjects\Thread.cs" />
<Compile Include="dataobjects\Upload.cs" />
<Compile Include="dataobjects\User.cs" /> <Compile Include="dataobjects\User.cs" />
<Compile Include="IOutputParams.cs" /> <Compile Include="IOutputParams.cs" />
<Compile Include="ISqlObjectTableSpec.cs" /> <Compile Include="ISqlObjectTableSpec.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SqlObject.cs" /> <Compile Include="SqlObject.cs" />
<Compile Include="UploadManager.cs" />
<Compile Include="UserContext.cs" /> <Compile Include="UserContext.cs" />
<Compile Include="UserSettingsGateway.cs" /> <Compile Include="UserSettingsGateway.cs" />
</ItemGroup> </ItemGroup>

@ -3,10 +3,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Collections.Specialized; using System.Collections.Specialized;
using FLocal.Core;
namespace FLocal.Common { namespace FLocal.Common {
public class Config : FLocal.Core.Config<Config> { public class Config : Config<Config> {
public readonly string InitTime; public readonly string InitTime;
@ -20,6 +21,10 @@ namespace FLocal.Common {
public readonly string SaltPasswords; public readonly string SaltPasswords;
public readonly string SaltUploader;
public readonly string UploaderUrl;
protected Config(NameValueCollection data) : base(data) { protected Config(NameValueCollection data) : base(data) {
this.InitTime = DateTime.Now.ToLongTimeString(); this.InitTime = DateTime.Now.ToLongTimeString();
this.mainConnection = new MySQLConnector.Connection(data["ConnectionString"], MySQLConnector.PostgresDBTraits.instance); this.mainConnection = new MySQLConnector.Connection(data["ConnectionString"], MySQLConnector.PostgresDBTraits.instance);
@ -27,6 +32,8 @@ namespace FLocal.Common {
this.DirSeparator = System.IO.Path.DirectorySeparatorChar.ToString(); this.DirSeparator = System.IO.Path.DirectorySeparatorChar.ToString();
this.SaltMigration = data["SaltMigration"]; this.SaltMigration = data["SaltMigration"];
this.SaltPasswords = data["SaltPasswords"]; this.SaltPasswords = data["SaltPasswords"];
this.SaltUploader = data["SaltUploader"];
this.UploaderUrl = data["UploaderUrl"];
} }
public static void Init(NameValueCollection data) { public static void Init(NameValueCollection data) {
@ -44,8 +51,17 @@ namespace FLocal.Common {
public static void Transactional(Action<Core.DB.Transaction> action) { public static void Transactional(Action<Core.DB.Transaction> action) {
using(Core.DB.Transaction transaction = Core.DB.IDBConnectionExtensions.beginTransaction(instance.mainConnection)) { using(Core.DB.Transaction transaction = Core.DB.IDBConnectionExtensions.beginTransaction(instance.mainConnection)) {
action(transaction); bool success = false;
transaction.Commit(); try {
action(transaction);
success = true;
transaction.Commit();
} catch(FLocalException) {
if(!success) {
transaction.Rollback();
}
throw;
}
} }
} }

@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using FLocal.Core;
using FLocal.Common.dataobjects;
using FLocal.Core.DB;
using FLocal.Core.DB.conditions;
using System.Net;
namespace FLocal.Common {
public static class UploadManager {
private class _AlreadyUploadedException : FLocalException {
public _AlreadyUploadedException() : base("Already uploaded") {
}
}
public class AlreadyUploadedException : FLocalException {
public readonly int uploadId;
public AlreadyUploadedException(int uploadId) : base("Already uploaded " + uploadId) {
this.uploadId = uploadId;
}
}
private const int MAX_UPLOAD_FILESIZE = 1024*1024;
private static HashSet<string> allowedExtensions = new HashSet<string>() {
"jpg",
"gif",
"png",
};
public static void UploadFile(Stream fileStream, string _extension, DateTime uploadDate, User uploader, int? id) {
string extension = _extension.ToLower();
if(!allowedExtensions.Contains(extension)) throw new FLocalException("Unsupported extension");
if(fileStream.Length > MAX_UPLOAD_FILESIZE) throw new FLocalException("File is too big");
byte[] data = new byte[fileStream.Length];
if(fileStream.Read(data, 0, (int)fileStream.Length) != fileStream.Length) {
throw new FLocalException("File is incomplete");
}
string file_md5 = Util.md5(fileStream);
AbstractCondition condition = new ComparisonCondition(
Upload.TableSpec.instance.getColumnSpec(Upload.TableSpec.FIELD_HASH),
ComparisonType.EQUAL,
file_md5
);
try {
if(Config.instance.mainConnection.GetCountByConditions(Upload.TableSpec.instance, condition, new JoinSpec[0]) > 0) {
throw new _AlreadyUploadedException();
}
Config.Transactional(transaction => {
Config.instance.mainConnection.lockTable(transaction, Upload.TableSpec.instance);
/*if(Config.instance.mainConnection.GetCountByConditions(Upload.TableSpec.instance, condition, new JoinSpec[0]) > 0) {
throw new _AlreadyUploadedException();
}*/
//TODO: ???
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Config.instance.UploaderUrl + "Upload/?extension=" + extension + "&signature=" + Util.md5(file_md5 + " " + Config.instance.SaltUploader));
request.Method = "POST";
request.ContentLength = data.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(data, 0, data.Length);
requestStream.Close();
HttpWebResponse response;
try {
response = (HttpWebResponse)request.GetResponse();
} catch(WebException e) {
response = (HttpWebResponse)e.Response;
}
using(StreamReader reader = new StreamReader(response.GetResponseStream())) {
string result = reader.ReadToEnd();
if(result != "OK") {
throw new CriticalException("Cannot upload file to upload service: " + result);
}
}
Dictionary<string, string> row = new Dictionary<string,string>();
if(id.HasValue) row[Upload.TableSpec.FIELD_ID] = id.ToString();
row[Upload.TableSpec.FIELD_HASH] = file_md5;
row[Upload.TableSpec.FIELD_EXTENSION] = extension;
row[Upload.TableSpec.FIELD_UPLOADDATE] = uploadDate.ToUTCString();
row[Upload.TableSpec.FIELD_USERID] = uploader.id.ToString();
row[Upload.TableSpec.FIELD_SIZE] = data.Length.ToString();
Config.instance.mainConnection.insert(transaction, Upload.TableSpec.instance, row);
});
} catch(_AlreadyUploadedException) {
throw new AlreadyUploadedException(
int.Parse(
Config.instance.mainConnection.LoadIdsByConditions(
Upload.TableSpec.instance,
condition,
Diapasone.unlimited,
new JoinSpec[0]
)[0]
)
);
}
}
}
}

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using FLocal.Core;
using FLocal.Core.DB;
using FLocal.Core.DB.conditions;
namespace FLocal.Common.dataobjects {
public class Upload : SqlObject<Upload> {
public class TableSpec : ISqlObjectTableSpec {
public const string TABLE = "Uploads";
public const string FIELD_ID = "Id";
public const string FIELD_HASH = "MD5";
public const string FIELD_EXTENSION = "Extension";
public const string FIELD_SIZE = "Size";
public const string FIELD_UPLOADDATE = "UploadDate";
public const string FIELD_USERID = "UserId";
public static readonly TableSpec instance = new TableSpec();
public string name { get { return TABLE; } }
public string idName { get { return FIELD_ID; } }
public void refreshSqlObject(int id) { Refresh(id); }
}
protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } }
private string _hash;
public string hash {
get {
this.LoadIfNotLoaded();
return this._hash;
}
}
private string _extension;
public string extension {
get {
this.LoadIfNotLoaded();
return this._extension;
}
}
private int _size;
public int size {
get {
this.LoadIfNotLoaded();
return this._size;
}
}
private DateTime _uploadDate;
public DateTime uploadDate {
get {
this.LoadIfNotLoaded();
return this._uploadDate;
}
}
private int? _userId;
public int? userId {
get {
this.LoadIfNotLoaded();
return this._userId;
}
}
public User user {
get {
return User.LoadById(this.userId.Value);
}
}
protected override void doFromHash(Dictionary<string, string> data) {
this._hash = data[TableSpec.FIELD_HASH];
this._extension = data[TableSpec.FIELD_EXTENSION];
this._size = int.Parse(data[TableSpec.FIELD_SIZE]);
this._uploadDate = Util.ParseDateTimeFromTimestamp(data[TableSpec.FIELD_UPLOADDATE]).Value;
this._userId = Util.ParseInt(data[TableSpec.FIELD_USERID]);
}
}
}

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.IO;
namespace FLocal.Core { namespace FLocal.Core {
@ -165,6 +166,34 @@ namespace FLocal.Core {
return sBuilder.ToString(); return sBuilder.ToString();
} }
/// <summary>
/// Code sample from http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5.aspx
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string md5(Stream inputStream) {
inputStream.Position = 0;
System.Security.Cryptography.HashAlgorithm md5Hasher = System.Security.Cryptography.MD5.Create();
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hasher.ComputeHash(inputStream);
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}
public static bool throws<TException>(Action action) where TException : Exception { public static bool throws<TException>(Action action) where TException : Exception {
try { try {
action(); action();
@ -174,6 +203,24 @@ namespace FLocal.Core {
} }
} }
private static Dictionary<string, string> extension2mime = new Dictionary<string,string>();
public static string getMimeByExtension(string extension) {
if(!extension.StartsWith(".")) extension = "." + extension;
if(!extension2mime.ContainsKey(extension)) {
lock(extension2mime) {
if(!extension2mime.ContainsKey(extension)) {
Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(extension);
if (regKey != null && regKey.GetValue("Content Type") != null) {
extension2mime[extension] = regKey.GetValue("Content Type").ToString();
} else {
return null;
}
}
}
}
return extension2mime[extension];
}
} }
} }

@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Importer", "Importer\Import
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImportConsole", "ImportConsole\ImportConsole.csproj", "{208B84AF-A5DD-4C20-83D5-160EA243BA43}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImportConsole", "ImportConsole\ImportConsole.csproj", "{208B84AF-A5DD-4C20-83D5-160EA243BA43}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IISUploadHandler", "IISUploadHandler\IISUploadHandler.csproj", "{09F13185-3B2A-4FCB-AB6A-750112FFF920}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -73,6 +75,12 @@ Global
{208B84AF-A5DD-4C20-83D5-160EA243BA43}.Release|Any CPU.ActiveCfg = Release|Any CPU {208B84AF-A5DD-4C20-83D5-160EA243BA43}.Release|Any CPU.ActiveCfg = Release|Any CPU
{208B84AF-A5DD-4C20-83D5-160EA243BA43}.Release|Any CPU.Build.0 = Release|Any CPU {208B84AF-A5DD-4C20-83D5-160EA243BA43}.Release|Any CPU.Build.0 = Release|Any CPU
{208B84AF-A5DD-4C20-83D5-160EA243BA43}.Release|x86.ActiveCfg = Release|Any CPU {208B84AF-A5DD-4C20-83D5-160EA243BA43}.Release|x86.ActiveCfg = Release|Any CPU
{09F13185-3B2A-4FCB-AB6A-750112FFF920}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09F13185-3B2A-4FCB-AB6A-750112FFF920}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09F13185-3B2A-4FCB-AB6A-750112FFF920}.Debug|x86.ActiveCfg = Debug|Any CPU
{09F13185-3B2A-4FCB-AB6A-750112FFF920}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09F13185-3B2A-4FCB-AB6A-750112FFF920}.Release|Any CPU.Build.0 = Release|Any CPU
{09F13185-3B2A-4FCB-AB6A-750112FFF920}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

@ -14,6 +14,13 @@ namespace FLocal.IISHandler {
// throw new FLocalException("Malformed url"); // throw new FLocalException("Malformed url");
// } // }
if(context.requestParts.Length < 1) return new handlers.RootHandler(); if(context.requestParts.Length < 1) return new handlers.RootHandler();
#region legacy
if(context.httprequest.Path.ToLower().StartsWith("/user/upload/")) {
return new handlers.response.LegacyUploadHandler();
}
#endregion
switch(context.requestParts[0].ToLower()) { switch(context.requestParts[0].ToLower()) {
case "boards": case "boards":
return new handlers.BoardsHandler(); return new handlers.BoardsHandler();
@ -33,6 +40,8 @@ namespace FLocal.IISHandler {
return new handlers.response.UserListHandler(); return new handlers.response.UserListHandler();
case "user": case "user":
return new handlers.response.UserInfoHandler(); return new handlers.response.UserInfoHandler();
case "uploads":
return new handlers.response.UploadHandler();
case "static": case "static":
return new handlers.StaticHandler(context.requestParts); return new handlers.StaticHandler(context.requestParts);
case "do": case "do":

@ -50,6 +50,7 @@
<Compile Include="designs\Classic.cs" /> <Compile Include="designs\Classic.cs" />
<Compile Include="designs\IDesign.cs" /> <Compile Include="designs\IDesign.cs" />
<Compile Include="designs\Lite.cs" /> <Compile Include="designs\Lite.cs" />
<Compile Include="exceptions\RedirectException.cs" />
<Compile Include="Extensions.cs" /> <Compile Include="Extensions.cs" />
<Compile Include="HandlersFactory.cs" /> <Compile Include="HandlersFactory.cs" />
<Compile Include="handlers\AbstractGetHandler.cs" /> <Compile Include="handlers\AbstractGetHandler.cs" />
@ -62,8 +63,10 @@
<Compile Include="handlers\request\LogoutHandler.cs" /> <Compile Include="handlers\request\LogoutHandler.cs" />
<Compile Include="handlers\request\MigrateAccountHandler.cs" /> <Compile Include="handlers\request\MigrateAccountHandler.cs" />
<Compile Include="handlers\response\BoardAsThread.cs" /> <Compile Include="handlers\response\BoardAsThread.cs" />
<Compile Include="handlers\response\LegacyUploadHandler.cs" />
<Compile Include="handlers\response\LoginHandler.cs" /> <Compile Include="handlers\response\LoginHandler.cs" />
<Compile Include="handlers\response\MigrateAccountHandler.cs" /> <Compile Include="handlers\response\MigrateAccountHandler.cs" />
<Compile Include="handlers\response\UploadHandler.cs" />
<Compile Include="handlers\response\UserInfoHandler.cs" /> <Compile Include="handlers\response\UserInfoHandler.cs" />
<Compile Include="handlers\RootHandler.cs" /> <Compile Include="handlers\RootHandler.cs" />
<Compile Include="handlers\StaticHandler.cs" /> <Compile Include="handlers\StaticHandler.cs" />

@ -12,7 +12,7 @@ namespace FLocal.IISHandler {
get { return true; } get { return true; }
} }
public void ProcessRequest(HttpContext httpcontext) { private void doProcessRequest(HttpContext httpcontext) {
Uri referer = httpcontext.Request.UrlReferrer; Uri referer = httpcontext.Request.UrlReferrer;
if(referer != null && referer.PathAndQuery.StartsWith("/static")) { if(referer != null && referer.PathAndQuery.StartsWith("/static")) {
@ -32,5 +32,13 @@ namespace FLocal.IISHandler {
handler.Handle(context); handler.Handle(context);
} }
public void ProcessRequest(HttpContext context) {
try {
this.doProcessRequest(context);
} catch(RedirectException e) {
context.Response.Redirect(e.newUrl);
}
}
} }
} }

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FLocal.IISHandler {
class RedirectException : FLocal.Core.FLocalException {
public readonly string newUrl;
public RedirectException(string newUrl) : base("Redirect to " + newUrl + " is being performed") {
this.newUrl = newUrl;
}
}
}

@ -5,7 +5,7 @@ using System.Text;
using System.Web; using System.Web;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.IO; using System.IO;
using Microsoft.Win32; using FLocal.Core;
namespace FLocal.IISHandler.handlers { namespace FLocal.IISHandler.handlers {
class StaticHandler : ISpecificHandler { class StaticHandler : ISpecificHandler {
@ -16,23 +16,6 @@ namespace FLocal.IISHandler.handlers {
this.requestParts = requestParts; this.requestParts = requestParts;
} }
private static Dictionary<string, string> extension2mime = new Dictionary<string,string>();
private static string getMimeByExtension(string extension) {
if(!extension2mime.ContainsKey(extension)) {
lock(extension2mime) {
if(!extension2mime.ContainsKey(extension)) {
RegistryKey regKey = Registry.ClassesRoot.OpenSubKey(extension);
if (regKey != null && regKey.GetValue("Content Type") != null) {
extension2mime[extension] = regKey.GetValue("Content Type").ToString();
} else {
return null;
}
}
}
}
return extension2mime[extension];
}
public void Handle(WebContext context) { public void Handle(WebContext context) {
if(this.requestParts.Length < 2) { if(this.requestParts.Length < 2) {
throw new HttpException(403, "listing not allowed"); throw new HttpException(403, "listing not allowed");
@ -56,7 +39,7 @@ namespace FLocal.IISHandler.handlers {
throw new HttpException(403, "forbidden"); throw new HttpException(403, "forbidden");
} }
string mime = getMimeByExtension(fileinfo.Extension); string mime = Util.getMimeByExtension(fileinfo.Extension);
if(mime != null) { if(mime != null) {
context.httpresponse.ContentType = mime; context.httpresponse.ContentType = mime;
} else { } else {
@ -66,7 +49,7 @@ namespace FLocal.IISHandler.handlers {
context.httpresponse.CacheControl = HttpCacheability.Public.ToString(); context.httpresponse.CacheControl = HttpCacheability.Public.ToString();
context.httpresponse.Expires = 1440; context.httpresponse.Expires = 1440;
context.httpresponse.WriteFile(fileinfo.FullName); context.httpresponse.TransmitFile(fileinfo.FullName);
} }
} }

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FLocal.Core;
using FLocal.Common;
using System.Xml.Linq;
using FLocal.Common.dataobjects;
namespace FLocal.IISHandler.handlers.response {
class LegacyUploadHandler : AbstractGetHandler {
protected override string templateName {
get {
return null;
}
}
protected override System.Xml.Linq.XElement[] getSpecificData(WebContext context) {
if(context.requestParts.Length != 3) throw new FLocalException("wrong url");
string[] parts = context.requestParts[2].Split('.');
if(parts.Length != 2) throw new FLocalException("wrong url");
if(parts[0].PHPSubstring(0, 4).ToLower() != "file") throw new FLocalException("wrong url");
int rawFileNum = int.Parse(parts[0].PHPSubstring(4));
int fileNum;
switch(parts[1].ToLower()) {
case "jpg":
fileNum = rawFileNum;
break;
case "gif":
fileNum = 500000 + rawFileNum;
break;
case "png":
fileNum = 600000 + rawFileNum;
break;
default:
throw new FLocalException("wrong url");
}
throw new RedirectException("/Uploads/" + fileNum + "/");
}
}
}

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FLocal.Core;
using FLocal.Common;
using System.Xml.Linq;
using FLocal.Common.dataobjects;
namespace FLocal.IISHandler.handlers.response {
class UploadHandler : AbstractGetHandler {
protected override string templateName {
get {
return null;
}
}
protected override System.Xml.Linq.XElement[] getSpecificData(WebContext context) {
if(context.requestParts.Length != 2) throw new FLocalException("wrong url");
Upload upload = Upload.LoadById(int.Parse(context.requestParts[1]));
throw new RedirectException(Config.instance.UploaderUrl + "Data/" + upload.hash + "." + upload.extension);
}
}
}

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
namespace FLocal.IISUploadHandler {
class Config {
public static readonly Config instance = new Config();
public readonly string salt;
public readonly string storageDir;
private Config() {
var appSettings = ConfigurationManager.AppSettings;
this.salt = appSettings["salt"];
this.storageDir = appSettings["storageDir"];
}
}
}

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{09F13185-3B2A-4FCB-AB6A-750112FFF920}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FLocal.IISUploadHandler</RootNamespace>
<AssemblyName>IISUploadHandler</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Config.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UploadHandler.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Core\Core.csproj">
<Project>{6F532626-E9F8-498E-9683-1538E7CD62CB}</Project>
<Name>Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("IISUploadHandler")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("IISUploadHandler")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("15bb5131-77d1-4703-bded-bbf9a7ffae50")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using FLocal.Core;
namespace FLocal.IISUploadHandler {
class UploadHandler : IHttpHandler {
public bool IsReusable {
get {
return true;
}
}
public void ProcessRequest(HttpContext httpcontext) {
if(httpcontext.Request.Path.ToLower() == "/upload/") {
this.ProcessUpload(httpcontext);
} else if(httpcontext.Request.Path.ToLower().StartsWith("/data/")) {
this.ProcessRetrieve(httpcontext);
} else {
throw new HttpException(403, "wrong url");
}
}
private static string getFilePath(string md5, string extension) {
foreach(char chr in (md5 + extension)) {
if(!Char.IsLetterOrDigit(chr)) throw new HttpException(403, "wrong md5 or extension");
}
return Config.instance.storageDir + md5.PHPSubstring(0, 2) + Path.DirectorySeparatorChar + md5.PHPSubstring(2, 2) + Path.DirectorySeparatorChar + md5.PHPSubstring(4) + "." + extension;
}
private static void CreateDirectoryIfNotExists(DirectoryInfo directoryInfo) {
if(!directoryInfo.Exists) {
CreateDirectoryIfNotExists(directoryInfo.Parent);
directoryInfo.Create();
}
}
private void ProcessUpload(HttpContext context) {
byte[] data = new byte[context.Request.InputStream.Length];
if(context.Request.InputStream.Read(data, 0, (int)context.Request.InputStream.Length) != context.Request.InputStream.Length) {
throw new FLocalException("File is not uploaded correctly");
}
string file_md5 = Util.md5(context.Request.InputStream);
string md5 = Util.md5(file_md5 + " " + Config.instance.salt);
if(md5 != context.Request.QueryString["signature"]) {
throw new HttpException(403, "signature mismatch");
}
string filePath = getFilePath(file_md5, context.Request.QueryString["extension"]);
CreateDirectoryIfNotExists((new FileInfo(filePath)).Directory);
using(FileStream stream = new FileStream(filePath, FileMode.CreateNew)) {
stream.Write(data, 0, data.Length);
}
context.Response.Write("OK");
}
private void ProcessRetrieve(HttpContext context) {
string[] requestParts = context.Request.Path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(requestParts.Length != 2) throw new HttpException(403, "wrong url");
string[] fileParts = requestParts[1].Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
if(fileParts.Length != 2) throw new HttpException(403, "wrong url");
string mime = Util.getMimeByExtension(fileParts[1]);
if(mime == null) throw new FLocalException("unknown extension '" + fileParts[1] + "'");
context.Response.ContentType = mime;
context.Response.TransmitFile(getFilePath(fileParts[0], fileParts[1]));
}
}
}

@ -8,6 +8,8 @@ using FLocal.Common.dataobjects;
using FLocal.Core; using FLocal.Core;
using System.Configuration; using System.Configuration;
using NConsoler; using NConsoler;
using System.IO;
using FLocal.Common;
namespace FLocal.ImportConsole { namespace FLocal.ImportConsole {
class Program { class Program {
@ -66,7 +68,63 @@ namespace FLocal.ImportConsole {
[Action] [Action]
public static void ProcessUpload(string pathToUpload) { public static void ProcessUpload(string pathToUpload) {
throw new NotImplementedException(); User uploader = User.LoadByName("Guest 127.0.0.1");
DirectoryInfo directoryInfo = new DirectoryInfo(pathToUpload);
int i=0;
foreach(FileSystemInfo _info in directoryInfo.GetFiles()) {
if(i%100 == 0) {
Console.Write("[" + (int)(i/100) + "]");
}
FileInfo info = _info as FileInfo;
//Console.WriteLine("Processing " + info.FullName);
if(!info.Name.StartsWith("file")) {
Console.Write("!");
} else {
string[] parts = info.Name.Split('.');
if(parts.Length != 2) throw new FLocalException("wrong file name");
int raw = int.Parse(parts[0].PHPSubstring(4));
int id;
switch(parts[1].ToLower()) {
case "jpg":
id = raw;
break;
case "gif":
id = 500000 + raw;
break;
case "png":
id = 600000 + raw;
break;
default:
throw new FLocalException("wrong extension");
}
if(info != null) {
try {
Upload.LoadById(id);
Console.Write("-");
} catch(NotFoundInDBException) {
try {
UploadManager.UploadFile(
info.OpenRead(),
parts[1],
info.LastWriteTime,
uploader,
id
);
} catch(UploadManager.AlreadyUploadedException e) {
Console.WriteLine(id + " md5 is equal to that of " + e.uploadId);
Console.ReadLine();
} catch(Exception e) {
Console.WriteLine(e.GetType().FullName + ": " + e.Message);
Console.WriteLine(e.StackTrace);
throw;
}
Console.Write("+");
//Console.WriteLine("Processed " + info.FullName);
}
}
}
i++;
}
} }
} }
} }

@ -2,4 +2,6 @@
@rem Note that this script will only produce a .msi packet of your binaries and data. It will not compile your sources. @rem Note that this script will only produce a .msi packet of your binaries and data. It will not compile your sources.
cd Builder cd Builder
Builder IISMainHandler Builder IISMainHandler
move /Y IISMainHandler\product.msi ..\IISMainHandler.msi move /Y IISMainHandler\product.msi ..\IISMainHandler.msi
Builder IISUploadHandler
move /Y IISUploadHandler\product.msi ..\IISUploadHandler.msi
Loading…
Cancel
Save