DocumentServer/DocService/UploadService.ashx.cs
2015-08-17 17:19:04 +03:00

362 lines
18 KiB
C#

/*
* (c) Copyright Ascensio System SIA 2010-2015
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
* EU, LV-1021.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
using System;
using System.Net;
using System.Configuration;
using System.Web;
using System.IO;
using System.Text;
using System.Xml;
using System.Collections;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using System.Collections.Specialized;
using FileConverterUtils2;
using log4net;
namespace DocService
{
public class UploadService : IHttpAsyncHandler
{
private readonly ILog _log = LogManager.GetLogger(typeof(UploadService));
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
{
TransportClassMainAshx oTransportClassMainAshx = new TransportClassMainAshx(context, cb);
ErrorTypes eError = ErrorTypes.NoError;
try
{
_log.Info("Starting process request...");
_log.Info(context.Request.QueryString.ToString());
string sGuid = context.Request.QueryString["key"];
int nMaxBytes = Convert.ToInt32(ConfigurationSettings.AppSettings["limits.image.size"] ?? "25000000");
if (context.Request.ContentLength <= nMaxBytes)
{
if (context.Request.Files.Count > 0)
{
int nParamsCount = 0;
string sInputParams = "";
for (int i = 0, length = context.Request.QueryString.Count; i < length; ++i)
{
sInputParams += context.Request.QueryString.Get(i) + ":" + context.Request.QueryString.GetKey(i);
if (nParamsCount > 0)
sInputParams += ",";
nParamsCount++;
}
AsyncMediaXmlOperation oAsyncMediaXmlOperation = new AsyncMediaXmlOperation();
List<string> aUrls = new List<string>();
TransportClass1 oTransportClass1 = new TransportClass1(oTransportClassMainAshx, oAsyncMediaXmlOperation, context.Request.QueryString, aUrls, sGuid, Path.Combine(sGuid, @"media/media.xml"), context.Request.Files, context.Request.Files.GetEnumerator());
oAsyncMediaXmlOperation.GetMediaXmlBegin(oTransportClass1.m_sMediaXml, GetMediaXmlCallback, oTransportClass1);
}
else
eError = ErrorTypes.UploadCountFiles;
}
else
eError = ErrorTypes.UploadContentLength;
}
catch(Exception e)
{
eError = ErrorTypes.Upload;
_log.Error(context.Request.QueryString.ToString());
_log.Error("Exeption: ", e);
}
if (ErrorTypes.NoError != eError)
WriteToResponse(oTransportClassMainAshx, eError, null, context.Request.QueryString);
return new AsyncOperationData(extraData);
}
public void EndProcessRequest(IAsyncResult result)
{
}
public void ProcessRequest(HttpContext context)
{
throw new InvalidOperationException();
}
public bool IsReusable
{
get
{
return false;
}
}
#region HelpFunctions
private void WriteToResponse(TransportClassMainAshx oTransportClassMainAshx, ErrorTypes eError, List<string> aUrls, NameValueCollection aNameValueCollection)
{
HttpContext oHttpContext = oTransportClassMainAshx.m_oHttpContext;
AsyncCallback oAsyncCallback = oTransportClassMainAshx.m_oAsyncCallback;
OutputCommand oOutputCommand = new OutputCommand();
if (null != aNameValueCollection)
{
for (int i = 0, length = aNameValueCollection.Count; i < length; ++i)
oOutputCommand.input.Add(aNameValueCollection.GetKey(i), aNameValueCollection.Get(i));
}
oOutputCommand.urls = aUrls;
oOutputCommand.error = (int)eError;
oOutputCommand.type = (int)PostMessageType.UploadImage;
JavaScriptSerializer serializer = new JavaScriptSerializer();
StringBuilder sb = new StringBuilder();
serializer.Serialize(oOutputCommand, sb);
string sJson = sb.ToString();
oHttpContext.Response.Write("<html><head><script type=\"text/javascript\">function load(){ parent.postMessage(\"" + sJson.Replace("\"", "\\\"") + "\", '*'); }</script></head><body onload='load()'></body></html>");
oAsyncCallback.Invoke(new AsyncOperationData(null));
}
#endregion
#region Callbacks
private void GetMediaXmlCallbackProcess(TransportClass1 oTransportClass1, Dictionary<string, string> aMediaXmlMapHash, Dictionary<string, string> aMediaXmlMapFilename)
{
AsyncContextReadOperation oAsyncContextReadOperation = new AsyncContextReadOperation();
TransportClass2 oTransportClass2 = new TransportClass2(oTransportClass1, aMediaXmlMapHash, aMediaXmlMapFilename, oAsyncContextReadOperation);
HttpPostedFile oCurrentFile = (HttpPostedFile)oTransportClass1.m_oFiles[(string)oTransportClass1.m_oFilesEnumerator.Current];
oCurrentFile.InputStream.Position = 0;
oAsyncContextReadOperation.ReadContextBegin(oCurrentFile.InputStream, ReadContextCallback, oTransportClass2);
}
private void GetMediaXmlCallback(IAsyncResult ar)
{
TransportClass1 oTransportClass1 = ar.AsyncState as TransportClass1;
try
{
Dictionary<string, string> aMediaXmlMapHash;
Dictionary<string, string> aMediaXmlMapFilename;
ErrorTypes eError = oTransportClass1.m_oAsyncMediaXmlOperation.GetMediaXmlEnd(ar, out aMediaXmlMapHash, out aMediaXmlMapFilename);
if (ErrorTypes.NoError == eError && oTransportClass1.m_oFilesEnumerator.MoveNext())
{
GetMediaXmlCallbackProcess(oTransportClass1, aMediaXmlMapHash, aMediaXmlMapFilename);
}
else
WriteToResponse(oTransportClass1, eError, null, oTransportClass1.m_aInputParams);
}
catch(Exception e)
{
_log.Error("Exeption: ", e);
WriteToResponse(oTransportClass1, ErrorTypes.Upload, null, oTransportClass1.m_aInputParams);
}
}
private void ReadContextCallback(IAsyncResult ar)
{
TransportClass2 oTransportClass2 = ar.AsyncState as TransportClass2;
try
{
ErrorTypes eError = oTransportClass2.m_oAsyncContextReadOperation.ReadContextEnd(ar);
if (ErrorTypes.NoError == eError)
{
HttpPostedFile oCurrentFile = ((HttpPostedFile)oTransportClass2.m_oFiles[(string)oTransportClass2.m_oFilesEnumerator.Current]);
oCurrentFile.InputStream.Position = 0;
Stream oImageStream = oCurrentFile.InputStream;
byte[] aBuffer = oTransportClass2.m_oAsyncContextReadOperation.m_aOutput.ToArray();
int nImageFormat = FormatChecker.GetFileFormat(aBuffer);
string sSupportedFormats = ConfigurationSettings.AppSettings["limits.image.types.upload"] ?? "jpg";
if (0 != (FileFormats.AVS_OFFICESTUDIO_FILE_IMAGE & nImageFormat) && -1 != sSupportedFormats.IndexOf(FileFormats.ToString(nImageFormat)))
{
if (FileFormats.AVS_OFFICESTUDIO_FILE_IMAGE_GIF == nImageFormat || FileFormats.AVS_OFFICESTUDIO_FILE_IMAGE_ICO == nImageFormat)
{
byte[] aNewBuffer;
if (Utils.ConvertGifIcoToPng(aBuffer, nImageFormat, out aNewBuffer))
{
nImageFormat = FileFormats.AVS_OFFICESTUDIO_FILE_IMAGE_PNG;
aBuffer = aNewBuffer;
oImageStream = new MemoryStream(aBuffer);
}
}
string sImageHash = null;
using (MemoryStream ms = new MemoryStream(aBuffer))
sImageHash = Utils.getMD5HexString(ms);
string sFileName;
if (oTransportClass2.m_oMediaXmlMapHash.TryGetValue(sImageHash, out sFileName))
{
ImageUrlProcess(oTransportClass2, Constants.mc_sResourceServiceUrlRel + Path.Combine(oTransportClass2.m_sKey, @"media\" + sFileName).Replace('\\', '/'));
}
else
{
string sSearchName = "image";
List<int> aIndexes = new List<int>();
foreach (KeyValuePair<string, string> kvp in oTransportClass2.m_oMediaXmlMapFilename)
{
string sFilename = Path.GetFileNameWithoutExtension(kvp.Key);
if (0 == sFilename.IndexOf(sSearchName))
{
int nCurIndex;
if (int.TryParse(sFilename.Substring(sSearchName.Length), out nCurIndex))
aIndexes.Add(nCurIndex);
}
}
int nMaxIndex = -1;
for (int i = 0, length = aIndexes.Count; i < length; ++i)
{
int nCurIndex = aIndexes[i];
if (nMaxIndex < nCurIndex)
nMaxIndex = nCurIndex;
}
int nNewIndex = 1;
if (nMaxIndex >= nNewIndex)
nNewIndex = nMaxIndex + 1;
string sNewName = sSearchName + nNewIndex + "." + FileFormats.ToString(nImageFormat);
string sNewPath = Path.Combine(oTransportClass2.m_sKey, @"media\" + sNewName).Replace('\\', '/');
Storage oStorage = new Storage();
TransportClass3 oTransportClass3 = new TransportClass3(oTransportClass2, sNewName, sImageHash, sNewPath, oStorage);
oTransportClass3.m_oStorage.WriteFileBegin(sNewPath, oImageStream, WriteUploadedFileCallback, oTransportClass3);
}
}
else
WriteToResponse(oTransportClass2, ErrorTypes.UploadExtension, null, oTransportClass2.m_aInputParams);
}
else
WriteToResponse(oTransportClass2, eError, null, oTransportClass2.m_aInputParams);
}
catch (Exception e)
{
_log.Error("Exeption: ", e);
WriteToResponse(oTransportClass2, ErrorTypes.Upload, null, oTransportClass2.m_aInputParams);
}
}
private void ImageUrlProcess(TransportClass2 oTransportClass2, string sUrl)
{
oTransportClass2.m_aUrls.Add(sUrl);
if (oTransportClass2.m_oFilesEnumerator.MoveNext())
GetMediaXmlCallbackProcess(oTransportClass2, oTransportClass2.m_oMediaXmlMapHash, oTransportClass2.m_oMediaXmlMapFilename);
else
oTransportClass2.m_oAsyncMediaXmlOperation.WriteMediaXmlBegin(oTransportClass2.m_sMediaXml, oTransportClass2.m_oMediaXmlMapHash, WriteMediaXmlCallback, oTransportClass2);
}
private void WriteUploadedFileCallback(IAsyncResult ar)
{
TransportClass3 oTransportClass3 = ar.AsyncState as TransportClass3;
try
{
int nReadWriteBytes;
ErrorTypes eError = oTransportClass3.m_oStorage.WriteFileEnd(ar, out nReadWriteBytes);
if (ErrorTypes.NoError == eError)
{
oTransportClass3.m_oMediaXmlMapHash.Add(oTransportClass3.m_sHash, oTransportClass3.m_sFilename);
oTransportClass3.m_oMediaXmlMapFilename.Add(oTransportClass3.m_sFilename, oTransportClass3.m_sHash);
ImageUrlProcess(oTransportClass3, Constants.mc_sResourceServiceUrlRel + oTransportClass3.m_sPath.Replace('\\', '/'));
}
else
WriteToResponse(oTransportClass3, eError, null, oTransportClass3.m_aInputParams);
}
catch (Exception e)
{
_log.Error("Exeption: ", e);
WriteToResponse(oTransportClass3, ErrorTypes.Upload, null, oTransportClass3.m_aInputParams);
}
}
private void WriteMediaXmlCallback(IAsyncResult ar)
{
TransportClass1 oTransportClass1 = ar.AsyncState as TransportClass1;
try
{
ErrorTypes eError = oTransportClass1.m_oAsyncMediaXmlOperation.WriteMediaXmlEnd(ar);
if (ErrorTypes.NoError == eError)
WriteToResponse(oTransportClass1, ErrorTypes.NoError, oTransportClass1.m_aUrls, oTransportClass1.m_aInputParams);
else
WriteToResponse(oTransportClass1, eError, null, oTransportClass1.m_aInputParams);
}
catch (Exception e)
{
_log.Error("Exeption: ", e);
WriteToResponse(oTransportClass1, ErrorTypes.Upload, null, oTransportClass1.m_aInputParams);
}
}
#endregion
#region TransportClass
private class TransportClass1 : TransportClassMainAshx
{
public AsyncMediaXmlOperation m_oAsyncMediaXmlOperation;
public NameValueCollection m_aInputParams;
public List<string> m_aUrls = new List<string>();
public string m_sKey;
public string m_sMediaXml;
public HttpFileCollection m_oFiles;
public IEnumerator m_oFilesEnumerator;
public TransportClass1(TransportClassMainAshx oTransportClassMainAshx, AsyncMediaXmlOperation oAsyncMediaXmlOperation, NameValueCollection aInputParams, List<string> aUrls, string sKey, string sMediaXml, HttpFileCollection oFiles, IEnumerator oFilesEnumerator)
: base(oTransportClassMainAshx.m_oHttpContext, oTransportClassMainAshx.m_oAsyncCallback)
{
m_oAsyncMediaXmlOperation = oAsyncMediaXmlOperation;
m_aInputParams = aInputParams;
m_sKey = sKey;
m_oFiles = oFiles;
m_oFilesEnumerator = oFilesEnumerator;
m_sMediaXml = sMediaXml;
m_aUrls = aUrls;
}
}
private class TransportClass2 : TransportClass1
{
public Dictionary<string, string> m_oMediaXmlMapHash = new Dictionary<string, string>();
public Dictionary<string, string> m_oMediaXmlMapFilename = new Dictionary<string, string>();
public AsyncContextReadOperation m_oAsyncContextReadOperation;
public TransportClass2(TransportClass1 oTransportClass1, Dictionary<string, string> oMediaXmlMapHash, Dictionary<string, string> oMediaXmlMapFilename, AsyncContextReadOperation oAsyncContextReadOperation)
: base(oTransportClass1, oTransportClass1.m_oAsyncMediaXmlOperation, oTransportClass1.m_aInputParams, oTransportClass1.m_aUrls, oTransportClass1.m_sKey, oTransportClass1.m_sMediaXml, oTransportClass1.m_oFiles, oTransportClass1.m_oFilesEnumerator)
{
m_oMediaXmlMapHash = oMediaXmlMapHash;
m_oMediaXmlMapFilename = oMediaXmlMapFilename;
m_oAsyncContextReadOperation = oAsyncContextReadOperation;
}
}
private class TransportClass3 : TransportClass2
{
public string m_sFilename;
public string m_sHash;
public string m_sPath;
public Storage m_oStorage;
public TransportClass3(TransportClass2 oTransportClass2, string sFilename, string sHash, string sPath, Storage oStorage)
: base(oTransportClass2, oTransportClass2.m_oMediaXmlMapHash, oTransportClass2.m_oMediaXmlMapFilename, oTransportClass2.m_oAsyncContextReadOperation)
{
m_sFilename = sFilename;
m_sHash = sHash;
m_sPath = sPath;
m_oStorage = oStorage;
}
}
public class OutputCommand
{
public int type;
public List<string> urls = new List<string>();
public int error;
public Dictionary<string, object> input = new Dictionary<string,object>();
}
#endregion
}
}