From 774f2015144e894605aea217cdc70dd159af6e59 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 20 Aug 2014 20:09:05 -0600 Subject: [PATCH 1/4] Adds a simple cache mechanism to hold reflected property info when cloning - reduces perf to 10% of what it used to be --- src/Umbraco.Core/Models/DeepCloneHelper.cs | 26 ++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Core/Models/DeepCloneHelper.cs b/src/Umbraco.Core/Models/DeepCloneHelper.cs index ed7a0e802d..796dc6cb12 100644 --- a/src/Umbraco.Core/Models/DeepCloneHelper.cs +++ b/src/Umbraco.Core/Models/DeepCloneHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -27,6 +28,11 @@ namespace Umbraco.Core.Models public static class DeepCloneHelper { + /// + /// Used to avoid constant reflection (perf) + /// + private static readonly ConcurrentDictionary PropCache = new ConcurrentDictionary(); + /// /// Used to deep clone any reference properties on the object (should be done after a MemberwiseClone for which the outcome is 'output') /// @@ -43,16 +49,18 @@ namespace Umbraco.Core.Models throw new InvalidOperationException("Both the input and output types must be the same"); } - var refProperties = inputType.GetProperties() - .Where(x => - //is not attributed with the ignore clone attribute + var refProperties = PropCache.GetOrAdd(inputType, type => + inputType.GetProperties() + .Where(x => + //is not attributed with the ignore clone attribute Attribute.GetCustomAttribute(x, typeof(DoNotCloneAttribute)) == null - //reference type but not string - && x.PropertyType.IsValueType == false && x.PropertyType != typeof (string) - //settable - && x.CanWrite - //non-indexed - && x.GetIndexParameters().Any() == false); + //reference type but not string + && x.PropertyType.IsValueType == false && x.PropertyType != typeof (string) + //settable + && x.CanWrite + //non-indexed + && x.GetIndexParameters().Any() == false) + .ToArray()); foreach (var propertyInfo in refProperties) { From 89b577410630e15f7e6dd265249c33ad5d76697e Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 21 Aug 2014 14:39:06 -0600 Subject: [PATCH 2/4] Fixes: U4-5380 Booting.aspx security issue --- src/umbraco.cms/helpers/url.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/umbraco.cms/helpers/url.cs b/src/umbraco.cms/helpers/url.cs index e32b0333f4..abcaae22cc 100644 --- a/src/umbraco.cms/helpers/url.cs +++ b/src/umbraco.cms/helpers/url.cs @@ -47,7 +47,13 @@ namespace umbraco.cms.helpers if (Uri.TryCreate(callerUrl, UriKind.RelativeOrAbsolute, out localUri)) { // check for local urls - if (!requestUri.IsAbsoluteUri || requestUri.Host == localUri.Host) + + //Cannot start with // since that is not a local url + if (!requestUri.OriginalString.StartsWith("//") + //cannot be non-absolute and also contain the char : since that will indicate a protocol + && (!requestUri.IsAbsoluteUri && !requestUri.OriginalString.Contains(":")) + //needs to be non-absolute or the hosts must match the current request + && (!requestUri.IsAbsoluteUri || requestUri.Host == localUri.Host)) { return true; } @@ -58,6 +64,13 @@ namespace umbraco.cms.helpers throw new ArgumentException("CallerUrl is in a wrong format that couldn't be parsed as a valid URI. If you don't want to evaluate for local urls, but just proxy urls then leave callerUrl empty", "callerUrl"); } } + + //we cannot continue if the url is not absolute + if (!requestUri.IsAbsoluteUri) + { + return false; + } + // check for valid proxy urls var feedProxyXml = XmlHelper.OpenAsXmlDocument(IOHelper.MapPath(SystemFiles.FeedProxyConfig)); if (feedProxyXml != null && From a8b297903d01ba36874beae87a6ec00ee7a9d8f5 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 25 Aug 2014 16:16:42 +1000 Subject: [PATCH 3/4] Ensures we don't get any ysods when changing doc type properties and the content re-creation since it's running on an async thread (U4-5388 , U4-5387 ) --- .../umbraco.presentation/content.cs | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs index 6b3cd50a9f..84d83f709c 100644 --- a/src/Umbraco.Web/umbraco.presentation/content.cs +++ b/src/Umbraco.Web/umbraco.presentation/content.cs @@ -20,6 +20,7 @@ using umbraco.cms.businesslogic.cache; using umbraco.cms.businesslogic.web; using umbraco.DataLayer; using umbraco.presentation.nodeFactory; +using Umbraco.Web; using Action = umbraco.BusinessLogic.Actions.Action; using Node = umbraco.NodeFactory.Node; using Umbraco.Core; @@ -96,13 +97,13 @@ namespace umbraco { get { - if (HttpContext.Current == null) + if (UmbracoContext.Current == null || UmbracoContext.Current.HttpContext == null) return XmlContentInternal; - var content = HttpContext.Current.Items[XmlContextContentItemKey] as XmlDocument; + var content = UmbracoContext.Current.HttpContext.Items[XmlContextContentItemKey] as XmlDocument; if (content == null) { content = XmlContentInternal; - HttpContext.Current.Items[XmlContextContentItemKey] = content; + UmbracoContext.Current.HttpContext.Items[XmlContextContentItemKey] = content; } return content; } @@ -827,24 +828,27 @@ namespace umbraco /// internal void RemoveXmlFilePersistenceQueue() { - HttpContext.Current.Application.Lock(); - HttpContext.Current.Application[PersistenceFlagContextKey] = null; - HttpContext.Current.Application.UnLock(); + if (UmbracoContext.Current != null && UmbracoContext.Current.HttpContext != null) + { + UmbracoContext.Current.HttpContext.Application.Lock(); + UmbracoContext.Current.HttpContext.Application[PersistenceFlagContextKey] = null; + UmbracoContext.Current.HttpContext.Application.UnLock(); + } } internal bool IsXmlQueuedForPersistenceToFile { get { - if (HttpContext.Current != null) + if (UmbracoContext.Current != null && UmbracoContext.Current.HttpContext != null) { - bool val = HttpContext.Current.Application[PersistenceFlagContextKey] != null; + bool val = UmbracoContext.Current.HttpContext.Application[PersistenceFlagContextKey] != null; if (val) { DateTime persistenceTime = DateTime.MinValue; try { - persistenceTime = (DateTime)HttpContext.Current.Application[PersistenceFlagContextKey]; + persistenceTime = (DateTime)UmbracoContext.Current.HttpContext.Application[PersistenceFlagContextKey]; if (persistenceTime > GetCacheFileUpdateTime()) { return true; @@ -893,8 +897,8 @@ namespace umbraco private void ClearContextCache() { // If running in a context very important to reset context cache orelse new nodes are missing - if (HttpContext.Current != null && HttpContext.Current.Items.Contains(XmlContextContentItemKey)) - HttpContext.Current.Items.Remove(XmlContextContentItemKey); + if (UmbracoContext.Current != null && UmbracoContext.Current.HttpContext != null && UmbracoContext.Current.HttpContext.Items.Contains(XmlContextContentItemKey)) + UmbracoContext.Current.HttpContext.Items.Remove(XmlContextContentItemKey); } /// @@ -1192,20 +1196,20 @@ order by umbracoNode.level, umbracoNode.sortOrder"; { //if this is called outside a web request we cannot queue it it will run in the current thread. - if (HttpContext.Current != null) + if (UmbracoContext.Current != null && UmbracoContext.Current.HttpContext != null) { - HttpContext.Current.Application.Lock(); + UmbracoContext.Current.HttpContext.Application.Lock(); try { - if (HttpContext.Current.Application[PersistenceFlagContextKey] != null) + if (UmbracoContext.Current.HttpContext.Application[PersistenceFlagContextKey] != null) { - HttpContext.Current.Application.Add(PersistenceFlagContextKey, null); + UmbracoContext.Current.HttpContext.Application.Add(PersistenceFlagContextKey, null); } - HttpContext.Current.Application[PersistenceFlagContextKey] = DateTime.UtcNow; + UmbracoContext.Current.HttpContext.Application[PersistenceFlagContextKey] = DateTime.UtcNow; } finally { - HttpContext.Current.Application.UnLock(); + UmbracoContext.Current.HttpContext.Application.UnLock(); } } else From 13b57c7638d664527988153f65c87309dcf14b50 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 25 Aug 2014 16:40:45 +1000 Subject: [PATCH 4/4] adds some logging --- src/Umbraco.Web/UmbracoModule.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 86ede93ae1..e618a2ecd0 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -46,6 +46,7 @@ namespace Umbraco.Web { // the keepalive service will use that url ApplicationContext.Current.OriginalRequestUrl = string.Format("{0}:{1}{2}", httpContext.Request.ServerVariables["SERVER_NAME"], httpContext.Request.ServerVariables["SERVER_PORT"], IOHelper.ResolveUrl(SystemDirectories.Umbraco)); + LogHelper.Info("Setting OriginalRequestUrl: " + ApplicationContext.Current.OriginalRequestUrl); } // do not process if client-side request