diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj index a1bca62e03..97d04cff46 100644 --- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj +++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj @@ -37,10 +37,6 @@ ..\ThirdParty\emby\Emby.Server.Core.dll - - ..\packages\ini-parser.2.3.0\lib\net20\INIFileParser.dll - True - ..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.1\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll True @@ -79,28 +75,6 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -136,175 +110,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MediaBrowser.Server.Startup.Common/packages.config b/MediaBrowser.Server.Startup.Common/packages.config index b12895000b..d329f2ccee 100644 --- a/MediaBrowser.Server.Startup.Common/packages.config +++ b/MediaBrowser.Server.Startup.Common/packages.config @@ -1,5 +1,4 @@  - \ No newline at end of file diff --git a/ServiceStack/Host/RestHandler.cs b/ServiceStack/Host/RestHandler.cs index 1eae6be389..abc3468695 100644 --- a/ServiceStack/Host/RestHandler.cs +++ b/ServiceStack/Host/RestHandler.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Threading.Tasks; +using MediaBrowser.Model.Logging; using MediaBrowser.Model.Services; namespace ServiceStack.Host @@ -54,11 +55,11 @@ namespace ServiceStack.Host return requestFactoryFn != null ? requestFactoryFn(httpReq) : null; } - public static RestPath FindMatchingRestPath(string httpMethod, string pathInfo, out string contentType) + public static RestPath FindMatchingRestPath(string httpMethod, string pathInfo, ILogger logger, out string contentType) { pathInfo = GetSanitizedPathInfo(pathInfo, out contentType); - return ServiceStackHost.Instance.ServiceController.GetRestPathForRequest(httpMethod, pathInfo); + return ServiceStackHost.Instance.ServiceController.GetRestPathForRequest(httpMethod, pathInfo, logger); } public static string GetSanitizedPathInfo(string pathInfo, out string contentType) @@ -93,7 +94,7 @@ namespace ServiceStack.Host if (this.RestPath == null) { string contentType; - this.RestPath = FindMatchingRestPath(httpMethod, pathInfo, out contentType); + this.RestPath = FindMatchingRestPath(httpMethod, pathInfo, new NullLogger(), out contentType); if (contentType != null) ResponseContentType = contentType; diff --git a/ServiceStack/Host/RestPath.cs b/ServiceStack/Host/RestPath.cs index 5bbd03a21e..3f896beaed 100644 --- a/ServiceStack/Host/RestPath.cs +++ b/ServiceStack/Host/RestPath.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; +using MediaBrowser.Model.Logging; using ServiceStack.Serialization; namespace ServiceStack.Host @@ -46,11 +47,11 @@ namespace ServiceStack.Host public string[] Verbs { - get - { - return allowsAllVerbs - ? new[] { ActionContext.AnyAction } - : AllowedVerbs.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); + get + { + return allowsAllVerbs + ? new[] { ActionContext.AnyAction } + : AllowedVerbs.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); } } @@ -75,31 +76,36 @@ namespace ServiceStack.Host return parts; } - public static IEnumerable GetFirstMatchHashKeys(string[] pathPartsForMatching) + public static List GetFirstMatchHashKeys(string[] pathPartsForMatching) { var hashPrefix = pathPartsForMatching.Length + PathSeperator; return GetPotentialMatchesWithPrefix(hashPrefix, pathPartsForMatching); } - public static IEnumerable GetFirstMatchWildCardHashKeys(string[] pathPartsForMatching) + public static List GetFirstMatchWildCardHashKeys(string[] pathPartsForMatching) { const string hashPrefix = WildCard + PathSeperator; return GetPotentialMatchesWithPrefix(hashPrefix, pathPartsForMatching); } - private static IEnumerable GetPotentialMatchesWithPrefix(string hashPrefix, string[] pathPartsForMatching) + private static List GetPotentialMatchesWithPrefix(string hashPrefix, string[] pathPartsForMatching) { + var list = new List(); + foreach (var part in pathPartsForMatching) { - yield return hashPrefix + part; + list.Add(hashPrefix + part); + var subParts = part.Split(ComponentSeperator); if (subParts.Length == 1) continue; foreach (var subPart in subParts) { - yield return hashPrefix + subPart; + list.Add(hashPrefix + subPart); } } + + return list; } public RestPath(Type requestType, string path, string verbs, string summary = null, string notes = null) @@ -220,16 +226,14 @@ namespace ServiceStack.Host private readonly Dictionary propertyNamesMap = new Dictionary(); - public static Func CalculateMatchScore { get; set; } - - public int MatchScore(string httpMethod, string[] withPathInfoParts) + public int MatchScore(string httpMethod, string[] withPathInfoParts, ILogger logger) { - if (CalculateMatchScore != null) - return CalculateMatchScore(this, httpMethod, withPathInfoParts); - int wildcardMatchCount; - var isMatch = IsMatch(httpMethod, withPathInfoParts, out wildcardMatchCount); - if (!isMatch) return -1; + var isMatch = IsMatch(httpMethod, withPathInfoParts, logger, out wildcardMatchCount); + if (!isMatch) + { + return -1; + } var score = 0; @@ -255,19 +259,33 @@ namespace ServiceStack.Host /// For performance withPathInfoParts should already be a lower case string /// to minimize redundant matching operations. /// - /// - /// - /// - /// - public bool IsMatch(string httpMethod, string[] withPathInfoParts, out int wildcardMatchCount) + public bool IsMatch(string httpMethod, string[] withPathInfoParts, ILogger logger, out int wildcardMatchCount) { wildcardMatchCount = 0; - if (withPathInfoParts.Length != this.PathComponentsCount && !this.IsWildCardPath) return false; - if (!this.allowsAllVerbs && !StringContains(this.allowedVerbs, httpMethod)) return false; + if (withPathInfoParts.Length != this.PathComponentsCount && !this.IsWildCardPath) + { + //logger.Info("withPathInfoParts mismatch for {0} for {1}", httpMethod, string.Join("/", withPathInfoParts)); + return false; + } - if (!ExplodeComponents(ref withPathInfoParts)) return false; - if (this.TotalComponentsCount != withPathInfoParts.Length && !this.IsWildCardPath) return false; + if (!this.allowsAllVerbs && !StringContains(this.allowedVerbs, httpMethod)) + { + //logger.Info("allowsAllVerbs mismatch for {0} for {1} allowedverbs {2}", httpMethod, string.Join("/", withPathInfoParts), this.allowedVerbs); + return false; + } + + if (!ExplodeComponents(ref withPathInfoParts)) + { + //logger.Info("ExplodeComponents mismatch for {0} for {1}", httpMethod, string.Join("/", withPathInfoParts)); + return false; + } + + if (this.TotalComponentsCount != withPathInfoParts.Length && !this.IsWildCardPath) + { + //logger.Info("TotalComponentsCount mismatch for {0} for {1}", httpMethod, string.Join("/", withPathInfoParts)); + return false; + } int pathIx = 0; for (var i = 0; i < this.TotalComponentsCount; i++) @@ -277,7 +295,7 @@ namespace ServiceStack.Host if (i < this.TotalComponentsCount - 1) { // Continue to consume up until a match with the next literal - while (pathIx < withPathInfoParts.Length && withPathInfoParts[pathIx] != this.literalsToMatch[i + 1]) + while (pathIx < withPathInfoParts.Length && !LiteralsEqual(withPathInfoParts[pathIx], this.literalsToMatch[i + 1])) { pathIx++; wildcardMatchCount++; @@ -286,6 +304,7 @@ namespace ServiceStack.Host // Ensure there are still enough parts left to match the remainder if ((withPathInfoParts.Length - pathIx) < (this.TotalComponentsCount - i - 1)) { + //logger.Info("withPathInfoParts length mismatch for {0} for {1}", httpMethod, string.Join("/", withPathInfoParts)); return false; } } @@ -306,7 +325,11 @@ namespace ServiceStack.Host continue; } - if (withPathInfoParts.Length <= pathIx || withPathInfoParts[pathIx] != literalToMatch) return false; + if (withPathInfoParts.Length <= pathIx || !LiteralsEqual(withPathInfoParts[pathIx], literalToMatch)) + { + //logger.Info("withPathInfoParts2 length mismatch for {0} for {1}. not equals: {2} != {3}.", httpMethod, string.Join("/", withPathInfoParts), withPathInfoParts[pathIx], literalToMatch); + return false; + } pathIx++; } } @@ -314,6 +337,22 @@ namespace ServiceStack.Host return pathIx == withPathInfoParts.Length; } + private bool LiteralsEqual(string str1, string str2) + { + // Most cases + if (string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + // Handle turkish i + str1 = str1.ToUpperInvariant(); + str2 = str2.ToUpperInvariant(); + + // Invariant IgnoreCase would probably be better but it's not available in PCL + return string.Equals(str1, str2, StringComparison.CurrentCultureIgnoreCase); + } + private bool ExplodeComponents(ref string[] withPathInfoParts) { var totalComponents = new List(); @@ -374,9 +413,9 @@ namespace ServiceStack.Host if (string.Equals("ignore", variableName, StringComparison.OrdinalIgnoreCase)) { pathIx++; - continue; + continue; } - + throw new ArgumentException("Could not find property " + variableName + " on " + RequestType.GetOperationName()); } diff --git a/ServiceStack/Host/ServiceController.cs b/ServiceStack/Host/ServiceController.cs index 378c21d5d9..158097dd00 100644 --- a/ServiceStack/Host/ServiceController.cs +++ b/ServiceStack/Host/ServiceController.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; +using MediaBrowser.Model.Logging; using MediaBrowser.Model.Services; namespace ServiceStack.Host @@ -135,7 +136,7 @@ namespace ServiceStack.Host appHost.RestPaths.AddRange(RestPathMap.Values.SelectMany(x => x)); } - public RestPath GetRestPathForRequest(string httpMethod, string pathInfo) + public RestPath GetRestPathForRequest(string httpMethod, string pathInfo, ILogger logger) { var matchUsingPathParts = RestPath.GetPathPartsForMatching(pathInfo); @@ -144,19 +145,23 @@ namespace ServiceStack.Host var yieldedHashMatches = RestPath.GetFirstMatchHashKeys(matchUsingPathParts); foreach (var potentialHashMatch in yieldedHashMatches) { - if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches)) continue; + if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches)) + { + continue; + } var bestScore = -1; foreach (var restPath in firstMatches) { - var score = restPath.MatchScore(httpMethod, matchUsingPathParts); + var score = restPath.MatchScore(httpMethod, matchUsingPathParts, logger); if (score > bestScore) bestScore = score; } + if (bestScore > 0) { foreach (var restPath in firstMatches) { - if (bestScore == restPath.MatchScore(httpMethod, matchUsingPathParts)) + if (bestScore == restPath.MatchScore(httpMethod, matchUsingPathParts, logger)) return restPath; } } @@ -170,14 +175,14 @@ namespace ServiceStack.Host var bestScore = -1; foreach (var restPath in firstMatches) { - var score = restPath.MatchScore(httpMethod, matchUsingPathParts); + var score = restPath.MatchScore(httpMethod, matchUsingPathParts, logger); if (score > bestScore) bestScore = score; } if (bestScore > 0) { foreach (var restPath in firstMatches) { - if (bestScore == restPath.MatchScore(httpMethod, matchUsingPathParts)) + if (bestScore == restPath.MatchScore(httpMethod, matchUsingPathParts, logger)) return restPath; } } diff --git a/ServiceStack/HttpHandlerFactory.cs b/ServiceStack/HttpHandlerFactory.cs index 5f4892d51c..3a3f5b3485 100644 --- a/ServiceStack/HttpHandlerFactory.cs +++ b/ServiceStack/HttpHandlerFactory.cs @@ -22,10 +22,19 @@ namespace ServiceStack } string contentType; - var restPath = RestHandler.FindMatchingRestPath(httpReq.HttpMethod, pathInfo, out contentType); - if (restPath != null) - return new RestHandler { RestPath = restPath, RequestName = restPath.RequestType.GetOperationName(), ResponseContentType = contentType }; + var restPath = RestHandler.FindMatchingRestPath(httpReq.HttpMethod, pathInfo, logger, out contentType); + if (restPath != null) + { + return new RestHandler + { + RestPath = restPath, + RequestName = restPath.RequestType.GetOperationName(), + ResponseContentType = contentType + }; + } + + logger.Error("Could not find handler for {0}", pathInfo); return null; } }