From b8199ad1c44e2c4ab558cf90cfde5fdd17ed9d73 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Wed, 13 Aug 2014 23:42:26 +0200 Subject: [PATCH] Fixed handling of multi-byte characters in both HttpServer and Duplicati. This fixes issue #1085 and issue #1063. --- Duplicati/Library/Utility/Uri.cs | 36 +-- Duplicati/Library/Utility/Utility.cs | 58 +--- .../Server/WebServer/IndexHtmlHandler.cs | 2 +- Duplicati/Server/WebServer/Server.cs | 5 +- thirdparty/HttpServer/Homepage.txt | 2 +- thirdparty/HttpServer/HttpServer.dll | Bin 132096 -> 131584 bytes thirdparty/HttpServer/Upgrade-readme.txt | 4 - .../HttpServer/fix-filemodule-crash.patch | 31 -- thirdparty/HttpServer/licensedata.json | 4 +- .../HttpServer/removed-urlencode-usage.diff | 266 ------------------ thirdparty/HttpServer/sign-key-fix.patch | 196 ------------- thirdparty/HttpServer/tempfolder-fix.patch | 70 ----- .../HttpServer/webserver-thread-fix.patch | 92 ------ 13 files changed, 30 insertions(+), 736 deletions(-) delete mode 100644 thirdparty/HttpServer/Upgrade-readme.txt delete mode 100644 thirdparty/HttpServer/fix-filemodule-crash.patch delete mode 100644 thirdparty/HttpServer/removed-urlencode-usage.diff delete mode 100644 thirdparty/HttpServer/sign-key-fix.patch delete mode 100644 thirdparty/HttpServer/tempfolder-fix.patch delete mode 100644 thirdparty/HttpServer/webserver-thread-fix.patch diff --git a/Duplicati/Library/Utility/Uri.cs b/Duplicati/Library/Utility/Uri.cs index e6505f57d..d5e02686c 100644 --- a/Duplicati/Library/Utility/Uri.cs +++ b/Duplicati/Library/Utility/Uri.cs @@ -328,7 +328,7 @@ namespace Duplicati.Library.Utility /// /// The regular expression that matches %20 type values in a querystring /// - private static System.Text.RegularExpressions.Regex RE_ESCAPECHAR = new System.Text.RegularExpressions.Regex(@"[^0-9a-zA-Z]", System.Text.RegularExpressions.RegexOptions.Compiled); + private static System.Text.RegularExpressions.Regex RE_ESCAPECHAR = new System.Text.RegularExpressions.Regex(@"[^0-9a-zA-Z\-\_]", System.Text.RegularExpressions.RegexOptions.Compiled); /// /// Encodes a URL, like System.Web.HttpUtility.UrlEncode @@ -356,9 +356,8 @@ namespace Duplicati.Library.Utility var encoder = encoding.GetEncoder(); var inbuf = new char[1]; - var outbuf = new byte[2]; - var shortout = new byte[1]; - + var outbuf = new byte[4]; + return RE_ESCAPECHAR.Replace(value, (m) => { if (m.Value == " ") return spacevalue; @@ -368,13 +367,7 @@ namespace Duplicati.Library.Utility try { var len = encoder.GetBytes(inbuf, 0, 1, outbuf, 0, true); - if (len == 1) - { - shortout[0] = outbuf[0]; - return "%" + Utility.ByteArrayAsHexString(shortout).ToLower(); - } - else if (len == 2) - return "%u" + Utility.ByteArrayAsHexString(outbuf).ToLower(); + return "%" + BitConverter.ToString(outbuf, 0, len).Replace("-", "%"); } catch { @@ -389,12 +382,7 @@ namespace Duplicati.Library.Utility /// /// The regular expression that matches %20 type values in a querystring /// - private static System.Text.RegularExpressions.Regex RE_NUMBER = new System.Text.RegularExpressions.Regex(@"(\%(?([0-9]|[a-z]|[A-Z]){2}))|(\+)|(\%u(?([0-9]|[a-z]|[A-Z]){4}))", System.Text.RegularExpressions.RegexOptions.Compiled); - - /// - /// A helper for converting byte arrays to hex, vice versa - /// - private const string HEX_DIGITS_UPPER = "0123456789ABCDEF"; + private static System.Text.RegularExpressions.Regex RE_NUMBER = new System.Text.RegularExpressions.Regex(@"(\%(?([0-9]|[a-f]|[A-F]){2}))|(\+)|(\%u(?([0-9]|[a-f]|[A-F]){2,4,6,8}))", System.Text.RegularExpressions.RegexOptions.Compiled); /// /// Encodes a URL, like System.Web.HttpUtility.UrlEncode @@ -410,20 +398,20 @@ namespace Duplicati.Library.Utility encoding = encoding ?? System.Text.Encoding.UTF8; var decoder = encoding.GetDecoder(); - var inbuf = new byte[2]; - var outbuf = new char[1]; - - return RE_NUMBER.Replace(value, (m) => { + var inbuf = new byte[8]; + var outbuf = new char[8]; + + return RE_NUMBER.Replace(value, (m) => { if (m.Value == "+") return " "; try { var hex = m.Groups["number"].Value; + var bytelen = hex.Length / 2; Utility.HexStringAsByteArray(hex, inbuf); - - decoder.GetChars(inbuf, 0, hex.Length / 2, outbuf, 0); - return outbuf[0].ToString(); + var c = decoder.GetChars(inbuf, 0, bytelen, outbuf, 0); + return new string(outbuf, 0, c); } catch { diff --git a/Duplicati/Library/Utility/Utility.cs b/Duplicati/Library/Utility/Utility.cs index 8ba07889b..d84e89fe8 100644 --- a/Duplicati/Library/Utility/Utility.cs +++ b/Duplicati/Library/Utility/Utility.cs @@ -626,67 +626,29 @@ namespace Duplicati.Library.Utility } /// - /// A helper for converting byte arrays to hex, vice versa - /// - private const string HEX_DIGITS_UPPER = "0123456789ABCDEF"; - - /// - /// Converts the byte array to hex digits + /// Converts a sequence of bytes to a hex string /// + /// The array as hex string. /// The data to convert - /// The data as a string of hex digits public static string ByteArrayAsHexString(byte[] data) { - if (data == null || data.Length == 0) - return ""; - - StringBuilder sb = new StringBuilder(); - foreach(byte b in data) - { - sb.Append(HEX_DIGITS_UPPER[(b >> 4) & 0xF]); - sb.Append(HEX_DIGITS_UPPER[b & 0xF]); - } - - return sb.ToString(); + return BitConverter.ToString(data).Replace("-", string.Empty); } - /// - /// Converts the given hex string into a byte array + /// Converts a hex string to a byte array /// + /// The string as byte array. /// The hex string - /// A pre-allocated output data array, or null - /// The byte array - public static byte[] HexStringAsByteArray(string hex, byte[] data = null) + /// The parsed data + public static byte[] HexStringAsByteArray(string hex, byte[] data) { - if (string.IsNullOrEmpty(hex)) - return new byte[0]; - - hex = hex.Trim().ToUpper(); - - if (hex.Length % 2 != 0) - throw new Exception(Strings.Utility.InvalidHexStringLengthError); - - if (data == null) - data = new byte[hex.Length / 2]; - else if (data.Length < hex.Length / 2) - throw new ArgumentOutOfRangeException("data"); - - for(int i = 0; i < hex.Length; i+= 2) - { - int upper = HEX_DIGITS_UPPER.IndexOf(hex[i]); - int lower = HEX_DIGITS_UPPER.IndexOf(hex[i + 1]); - - if (upper < 0) - throw new Exception(string.Format(Strings.Utility.InvalidHexDigitError, hex[i])); - if (lower < 0) - throw new Exception(string.Format(Strings.Utility.InvalidHexDigitError, hex[i + 1])); - - data[i % 2] = (byte)((upper << 4) | lower); - } + for (var i = 0; i < hex.Length; i += 2) + data[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); return data; } + public static bool Which(string appname) { diff --git a/Duplicati/Server/WebServer/IndexHtmlHandler.cs b/Duplicati/Server/WebServer/IndexHtmlHandler.cs index d1481f9c6..0cd3f8ffe 100644 --- a/Duplicati/Server/WebServer/IndexHtmlHandler.cs +++ b/Duplicati/Server/WebServer/IndexHtmlHandler.cs @@ -33,7 +33,7 @@ namespace Duplicati.Server.WebServer { response.Status = System.Net.HttpStatusCode.OK; response.Reason = "OK"; - response.ContentType = "text/html"; + response.ContentType = "text/html; charset=utf-8"; using (var fs = System.IO.File.OpenRead(m_defaultdoc)) { diff --git a/Duplicati/Server/WebServer/Server.cs b/Duplicati/Server/WebServer/Server.cs index a159d2731..19ce81fd5 100644 --- a/Duplicati/Server/WebServer/Server.cs +++ b/Duplicati/Server/WebServer/Server.cs @@ -174,6 +174,8 @@ namespace Duplicati.Server.WebServer customized_files.MimeTypes.Add("htc", "text/x-component"); customized_files.MimeTypes.Add("json", "application/json"); customized_files.MimeTypes.Add("map", "application/json"); + customized_files.MimeTypes["htm"] = "text/html; charset=utf-8"; + customized_files.MimeTypes["html"] = "text/html; charset=utf-8"; server.Add(customized_files); } @@ -182,13 +184,14 @@ namespace Duplicati.Server.WebServer fh.MimeTypes.Add("htc", "text/x-component"); fh.MimeTypes.Add("json", "application/json"); fh.MimeTypes.Add("map", "application/json"); + fh.MimeTypes["htm"] = "text/html; charset=utf-8"; + fh.MimeTypes["html"] = "text/html; charset=utf-8"; server.Add(fh); server.Add(new IndexHtmlHandler(System.IO.Path.Combine(webroot, "index.html"))); #if DEBUG //For debugging, it is nice to know when we get a 404 server.Add(new DebugReportHandler()); #endif - return server; } diff --git a/thirdparty/HttpServer/Homepage.txt b/thirdparty/HttpServer/Homepage.txt index c0d8fec2b..43b623b1f 100644 --- a/thirdparty/HttpServer/Homepage.txt +++ b/thirdparty/HttpServer/Homepage.txt @@ -1 +1 @@ -http://webserver.codeplex.com/ \ No newline at end of file +https://github.com/duplicati/httpserver \ No newline at end of file diff --git a/thirdparty/HttpServer/HttpServer.dll b/thirdparty/HttpServer/HttpServer.dll index 24ed031f6703eb3d147d395ec1560c0cf6d2c0d9..80434ed194142c172e14e5c95c7ed07d34075e68 100644 GIT binary patch delta 30237 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 -Date: Tue, 5 Aug 2014 10:06:31 +0200 -Subject: [PATCH] Fixed bug that causes FileModule to crash - ---- - HttpServer/HttpModules/FileModule.cs | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/HttpServer/HttpModules/FileModule.cs b/HttpServer/HttpModules/FileModule.cs -index 071fd01..8efa5a4 100755 ---- a/HttpServer/HttpModules/FileModule.cs -+++ b/HttpServer/HttpModules/FileModule.cs -@@ -120,10 +120,12 @@ namespace HttpServer.HttpModules - { - if (Contains(uri.AbsolutePath, _forbiddenChars)) - return false; -- -+ -+ if (!uri.AbsolutePath.StartsWith(_baseUri)) -+ return false; -+ - string path = GetPath(uri); - return -- uri.AbsolutePath.StartsWith(_baseUri) && // Correct directory - File.Exists(path) && // File exists - (File.GetAttributes(path) & FileAttributes.ReparsePoint) == 0; // Not a symlink - } --- -1.8.4.2 - diff --git a/thirdparty/HttpServer/licensedata.json b/thirdparty/HttpServer/licensedata.json index 2eba21b2d..e0fb5de03 100644 --- a/thirdparty/HttpServer/licensedata.json +++ b/thirdparty/HttpServer/licensedata.json @@ -1,7 +1,7 @@ { "name": "C# WebServer", "description": "A HTTP Compliant WebServer in C#", - "link": "http://webserver.codeplex.com/", + "link": "https://github.com/duplicati/httpserver", "license": "Apache 2.0", - "notes": "Patched to fix a crash" + "notes": "Patched from http://webserver.codeplex.com/" } \ No newline at end of file diff --git a/thirdparty/HttpServer/removed-urlencode-usage.diff b/thirdparty/HttpServer/removed-urlencode-usage.diff deleted file mode 100644 index 1ebd818de..000000000 --- a/thirdparty/HttpServer/removed-urlencode-usage.diff +++ /dev/null @@ -1,266 +0,0 @@ -From 4e4239cf74e23e13c3bee808104d8d213e40fe39 Mon Sep 17 00:00:00 2001 -From: Kenneth Skovhede -Date: Wed, 23 Jul 2014 15:04:20 +0200 -Subject: [PATCH] Removed usage of HttpUtility UrlEncode and - HttpUtility.UrlDecode as these has issues on Mono. - ---- - HttpServer/HttpHelper.cs | 2 +- - HttpServer/HttpRequest.cs | 4 +- - HttpServer/HttpServer.csproj | 1 + - HttpServer/HttpUtilityHelper.cs | 171 ++++++++++++++++++++++++++++++++++++++++ - HttpServer/RequestCookie.cs | 2 +- - HttpServer/ResponseCookie.cs | 2 +- - 6 files changed, 177 insertions(+), 5 deletions(-) - create mode 100644 HttpServer/HttpUtilityHelper.cs - -diff --git a/HttpServer/HttpHelper.cs b/HttpServer/HttpHelper.cs -index 8d11daa..a0d286f 100755 ---- a/HttpServer/HttpHelper.cs -+++ b/HttpServer/HttpHelper.cs -@@ -165,7 +165,7 @@ namespace HttpServer - - private static void Add(IHttpInput input, string name, string value) - { -- input.Add(HttpUtility.UrlDecode(name), HttpUtility.UrlDecode(value)); -+ input.Add(HttpUtilityHelper.UrlDecode(name), HttpUtilityHelper.UrlDecode(value)); - } - } - } -diff --git a/HttpServer/HttpRequest.cs b/HttpServer/HttpRequest.cs -index a52dbed..cacbb7d 100755 ---- a/HttpServer/HttpRequest.cs -+++ b/HttpServer/HttpRequest.cs -@@ -54,12 +54,12 @@ namespace HttpServer - _queryString = HttpHelper.ParseQueryString(_uriPath.Substring(pos + 1)); - _param.SetQueryString(_queryString); - string path = _uriPath.Substring(0, pos); -- _uriPath = System.Web.HttpUtility.UrlDecode(path) + "?" + _uriPath.Substring(pos + 1); -+ _uriPath = HttpUtilityHelper.UrlDecode(path) + "?" + _uriPath.Substring(pos + 1); - UriParts = value.Substring(0, pos).Split(UriSplitters, StringSplitOptions.RemoveEmptyEntries); - } - else - { -- _uriPath = System.Web.HttpUtility.UrlDecode(_uriPath); -+ _uriPath = HttpUtilityHelper.UrlDecode(_uriPath); - UriParts = value.Split(UriSplitters, StringSplitOptions.RemoveEmptyEntries); - } - } -diff --git a/HttpServer/HttpServer.csproj b/HttpServer/HttpServer.csproj -index 81bb2eb..431c406 100644 ---- a/HttpServer/HttpServer.csproj -+++ b/HttpServer/HttpServer.csproj -@@ -134,6 +134,7 @@ - - - -+ - - - -+ -+ -+ - -\ No newline at end of file -diff --git a/HttpServer/httpserver.pfx b/HttpServer/httpserver.pfx -deleted file mode 100755 -index 2ba33088b51785a8dbf88106abf0ec3dd7a54994..0000000000000000000000000000000000000000 -GIT binary patch -literal 0 -HcmV?d00001 - -literal 1756 -zcmY+DeK^zm8^^!juNgM-Sou+mQu2`R6k2pLTIFH;$?!W!GUGT()AF!n7l!$fB&?QB -zO((|DD33*XN`<2(x$4;RkVeaM#Zt1<`POwFu5*2^`*Yv->%Q;L_4(s|!yNP=1ggLs -zbP-y^io2h?qy?&hB^-1nii1u=FdOEmH2$lkQjX%NTtlz`u}f&|pHrF`5Gvt7jW7qQ -zh1a1me_`bDRVei*dsTfO@!?4bQhS2pK>4v(nvZ(m->x{ukuARbs-5CAvx~Odw=Us@ -zHHEuWyb>e4zy4H7c`2i!-x8iqIy^cuzWrRWu*hd((}SF*$Nm{IVU0tGPkA1w}DKewdTx{k#_6FH6@`-P~O49^#UuQPTYF49;krZ}UN5r8U?pbQha{Ql@L+|pl9S#M=Z6t|l -zKfk`Z>B8FVa}m1_-sb1O;+*dBvGAnt&{XLq=Ybi;wV~B{E`1?K(s5F^`p#Lr$Yz5* -zv~RO?e1K50Q01G7;jbO>(TqBWdoZ9LZN)aSiuLC;FWQaq!(}Nt^3p81R#97UOyy4R -z-|_p`ujAtGbYm6*xn^Bt_7myNajS^Wk&}Zq_qB{q6V2!5MLo+kH#;_(v)k-auM2B~ -zoyxv9o=-d@KGrU-pbw=RB%EvsVq9Q|Kz;bUB7LOUmGJPuchG#0JI*0jlXlq4HQ4@XV({ZoJ=U&0hV$rxrSp>4``XckDKS%DSoRxUvs`Z5O>nQJP4B-X -z{rPhPUZ=uJK~_F_B!gIYilUFZUFI|dkS;zaJe$N)Sm#Y=&RvB0kI`jWyoN8Hy_t7qb)s=9~$lsGw^cGlUQ@s4-Zu(r!KKQo@;7@vFUS4i=p -zTrB3{)B0ikzt>!2H6D#ZfdBx&!T&%5JjKKtI0e9fJ>ZBOJm3zv0R+GnAR^2i$!&q{ -zh$jGhzp?FzCnAwOLiZx(fZUG2HlzbaJPBaKA!rS2G>8H@PP!o8$AkiqfggczfC(^w -z6Np6uaR3gWBKKEv4EO=b+>!Vs5Q{Jdk~4uYB#!zvg#&!P^(7z~9f$y!h!WfW{=FI+ -z5$8<=i69U_T-iSr@LzI8f0ZlW(-L$2=g-Ms<(kTYSS!?c5AsuitcZL2~DGuaURhGUU)idEHbtKpL$yYq3UbK -z%KO&A&o#83L$m7wNSk2GjKRck7xs-?_yF_Frmc+djXVb_Gq72G%wcQGdDFVlf%myn -z?Jc_40Q!NHlq+rQL?YSl04s8#-zl!Dmz5mR>ovZo+~Priuko_mE%12erZ1+ts)JOV -zOi|UX|9?JxC`%CPQ{mFh-*`6u1hYHlRfwb4yCLwdf}rOe?P=rRlx)VG;3eHFHVFxx|79-3m_y}N9mQY1 -zaD#X6P)EGKl6);zmysusr$?tSm0hh#f@-R^gQB%oF;kWeJHw{18d}wQl?r5pGDzzU -wttb-R{;yd~$(5O1HS>f0S=&(t-0ZzaPrWSnZT7qu`SceL-kH&*xUY-*2gkbk^#A|> - -diff --git a/HttpServer/test.snk b/HttpServer/test.snk -deleted file mode 100755 -index 8da3182b4ebfb542507eb7ef48ffbfce2bf3995b..0000000000000000000000000000000000000000 -GIT binary patch -literal 0 -HcmV?d00001 - -literal 596 -zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50097bzgeh{8PZA&elL^}7m-6lG|{kbaa9P5 -z6e@YDGh=|GP9%|kZDq^AxDp8i8ol~tW*zyPCUH^Y0q!HZ`nqyF+b?rNIuOl6sJ%lW -zlMb&1^h=-twO35$90By~P4G-7iifzzpVSD}Bs+gQv@iL2u8^ioiXa*UMGvLryokaD -zUd}+4OdXNRIong?<<6!9K$)!7 -zByqNO1qp1^_%$`#e+>@`pd;RK{7uWBj<2KCFZnO%#TTJDxSw+v(~D(u#{CaVH$Nxr -zzyiIV;fL=Bs+Gq!@zn0M*%Ne)SNZFA@!M-ZJ$2Q%g3NUhR!8qA0#} -zSJY#IGkNYv4L$XLA)9v59%3fY#qPdXYvdKy)H -iTkg*w>*3ZPja^HsjVZRb -Date: Sat, 28 Jun 2014 16:52:33 +0200 -Subject: [PATCH] Fixed Tempfolder to use the system tempfolder instead of - hardcoded /var/tmp - ---- - HttpServer/FormDecoders/MultipartDecoder.cs | 12 +++++++----- - HttpServer/HttpServer.cs | 10 ++++++---- - 2 files changed, 13 insertions(+), 9 deletions(-) - -diff --git a/HttpServer/FormDecoders/MultipartDecoder.cs b/HttpServer/FormDecoders/MultipartDecoder.cs -index b4a6dbb..6da4967 100755 ---- a/HttpServer/FormDecoders/MultipartDecoder.cs -+++ b/HttpServer/FormDecoders/MultipartDecoder.cs -@@ -22,6 +22,12 @@ namespace HttpServer.FormDecoders - /// form-data - /// - public const string FormData = "form-data"; -+ -+ /// -+ /// Gets the temp folder used to store multi-part uploads -+ /// -+ public static readonly string Tempfolder = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "HttpServer"); -+ - #region IFormDecoder Members - - /// -@@ -73,11 +79,7 @@ namespace HttpServer.FormDecoders - - // Generate a filename - string filename = element.Filename; -- string internetCache = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache); -- // if the internet path doesn't exist, assume mono and /var/tmp -- string path = string.IsNullOrEmpty(internetCache) -- ? Path.Combine("var", "tmp") -- : Path.Combine(internetCache.Replace("\\\\", "\\"), "tmp"); -+ string path = Tempfolder; - element.Filename = Path.Combine(path, Math.Abs(element.Filename.GetHashCode()) + ".tmp"); - - // If the file exists generate a new filename -diff --git a/HttpServer/HttpServer.cs b/HttpServer/HttpServer.cs -index 9dd4215..4ecf16a 100755 ---- a/HttpServer/HttpServer.cs -+++ b/HttpServer/HttpServer.cs -@@ -476,15 +476,17 @@ namespace HttpServer - _components.AddInstance(new HttpContextFactory(LogWriter, 16384, - _components.Get())); - -- // the special folder does not exist on mono -- string tempPath = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache); -- if (string.IsNullOrEmpty(tempPath)) -- tempPath = "/var/tmp/"; -+ string tempPath = System.IO.Path.GetTempPath(); - if (!Directory.Exists(tempPath)) - { - WriteLog(this, LogPrio.Warning, "Temp path do not exist: " + tempPath); - return; - } -+ -+ tempPath = MultipartDecoder.Tempfolder; -+ if (!Directory.Exists(tempPath)) -+ Directory.CreateDirectory(tempPath); -+ - DirectoryInfo info = new DirectoryInfo(tempPath); - foreach (FileInfo file in info.GetFiles("*.tmp")) - file.Delete(); --- -1.8.4.2 - diff --git a/thirdparty/HttpServer/webserver-thread-fix.patch b/thirdparty/HttpServer/webserver-thread-fix.patch deleted file mode 100644 index 2b1dd0b98..000000000 --- a/thirdparty/HttpServer/webserver-thread-fix.patch +++ /dev/null @@ -1,92 +0,0 @@ -diff -urN webserver-clean/HttpServer/HttpForm.cs webserver-modified/HttpServer/HttpForm.cs ---- webserver-clean/HttpServer/HttpForm.cs 2014-01-10 12:08:32.000000000 +0100 -+++ webserver-modified/HttpServer/HttpForm.cs 2014-01-18 23:32:04.000000000 +0100 -@@ -10,6 +10,9 @@ - public static readonly HttpForm EmptyForm = new HttpForm("EmptyForm", true); - - private readonly Dictionary _files = new Dictionary(); -+ -+ // A lock to prevent concurrent access to the _files dict -+ private object _lock = new object(); - - /// Initializes a form container with the specified name - public HttpForm() : base("form") -@@ -45,7 +48,8 @@ - if(_files.ContainsKey(file.Name)) - throw new ArgumentException("File named '" + file.Name + "' already exists!"); - -- _files.Add(file.Name, file); -+ lock(_lock) -+ _files.Add(file.Name, file); - } - - /// -@@ -72,16 +76,19 @@ - /// If name is null or empty - /// If the instance is HttpForm.EmptyForm which cannot be modified - public HttpFile GetFile(string name) -- { -- if (_ignoreChanges) -- throw new InvalidOperationException("Cannot retrieve files from instance HttpForm.EmptyForm."); -- if(string.IsNullOrEmpty(name)) -- throw new ArgumentNullException("name"); -+ { -+ if (_ignoreChanges) -+ throw new InvalidOperationException("Cannot retrieve files from instance HttpForm.EmptyForm."); -+ if (string.IsNullOrEmpty(name)) -+ throw new ArgumentNullException("name"); - -- if(!_files.ContainsKey(name)) -- return null; -+ lock(_lock) -+ { -+ if (!_files.ContainsKey(name)) -+ return null; - -- return _files[name]; -+ return _files[name]; -+ } - } - - /// -@@ -95,10 +102,13 @@ - if (_files.Count == 0) - return EmptyFileCollection; - -- List files = new List(); -- foreach (HttpFile file in _files.Values) -- files.Add(file); -- return files.AsReadOnly(); -+ lock(_lock) -+ { -+ List files = new List(); -+ foreach(HttpFile file in _files.Values) -+ files.Add(file); -+ return files.AsReadOnly(); -+ } - } - } - -@@ -106,13 +116,16 @@ - - /// Disposes all held HttpFile's and resets values - public override void Clear() -- { -- base.Clear(); -+ { -+ base.Clear(); - -- foreach (KeyValuePair pair in _files) -- pair.Value.Dispose(); -+ lock(_lock) -+ { -+ foreach(KeyValuePair pair in _files) -+ pair.Value.Dispose(); - -- _files.Clear(); -+ _files.Clear(); -+ } - } - } - } -