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 24ed031f6..80434ed19 100644 Binary files a/thirdparty/HttpServer/HttpServer.dll and b/thirdparty/HttpServer/HttpServer.dll differ diff --git a/thirdparty/HttpServer/Upgrade-readme.txt b/thirdparty/HttpServer/Upgrade-readme.txt deleted file mode 100644 index bc152592d..000000000 --- a/thirdparty/HttpServer/Upgrade-readme.txt +++ /dev/null @@ -1,4 +0,0 @@ -The file HttpServer.dll has been patched from the tags/v1.1 version, -to prevent a crash where multiple threads access the file collection on a form. - -If you upgrade, make sure to apply the patch. \ No newline at end of file diff --git a/thirdparty/HttpServer/fix-filemodule-crash.patch b/thirdparty/HttpServer/fix-filemodule-crash.patch deleted file mode 100644 index 6704a53eb..000000000 --- a/thirdparty/HttpServer/fix-filemodule-crash.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 4ef5d02d06c5297469d814462daf6aa449628467 Mon Sep 17 00:00:00 2001 -From: Kenneth Skovhede -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(); -+ } - } - } - } -