|
@@ -21,8 +21,6 @@ namespace Emby.Server.Implementations.Services
|
|
|
readonly bool[] componentsWithSeparators;
|
|
|
|
|
|
private readonly string restPath;
|
|
|
- private readonly string allowedVerbs;
|
|
|
- private readonly bool allowsAllVerbs;
|
|
|
public bool IsWildCardPath { get; private set; }
|
|
|
|
|
|
private readonly string[] literalsToMatch;
|
|
@@ -46,15 +44,7 @@ namespace Emby.Server.Implementations.Services
|
|
|
/// </summary>
|
|
|
public int TotalComponentsCount { get; set; }
|
|
|
|
|
|
- public string[] Verbs
|
|
|
- {
|
|
|
- get
|
|
|
- {
|
|
|
- return allowsAllVerbs
|
|
|
- ? new[] { "ANY" }
|
|
|
- : AllowedVerbs.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
- }
|
|
|
- }
|
|
|
+ public string[] Verbs { get; private set; }
|
|
|
|
|
|
public Type RequestType { get; private set; }
|
|
|
|
|
@@ -62,19 +52,11 @@ namespace Emby.Server.Implementations.Services
|
|
|
|
|
|
public string Summary { get; private set; }
|
|
|
|
|
|
- public string Notes { get; private set; }
|
|
|
-
|
|
|
- public bool AllowsAllVerbs { get { return this.allowsAllVerbs; } }
|
|
|
-
|
|
|
- public string AllowedVerbs { get { return this.allowedVerbs; } }
|
|
|
-
|
|
|
public int Priority { get; set; } //passed back to RouteAttribute
|
|
|
|
|
|
public static string[] GetPathPartsForMatching(string pathInfo)
|
|
|
{
|
|
|
- var parts = pathInfo.ToLower().Split(PathSeperatorChar)
|
|
|
- .Where(x => !String.IsNullOrEmpty(x)).ToArray();
|
|
|
- return parts;
|
|
|
+ return pathInfo.ToLower().Split(new[] { PathSeperatorChar }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
}
|
|
|
|
|
|
public static List<string> GetFirstMatchHashKeys(string[] pathPartsForMatching)
|
|
@@ -109,18 +91,13 @@ namespace Emby.Server.Implementations.Services
|
|
|
return list;
|
|
|
}
|
|
|
|
|
|
- public RestPath(Func<Type, object> createInstanceFn, Func<Type, Func<string, object>> getParseFn, Type requestType, string path, string verbs, string summary = null, string notes = null)
|
|
|
+ public RestPath(Func<Type, object> createInstanceFn, Func<Type, Func<string, object>> getParseFn, Type requestType, string path, string verbs, string summary = null)
|
|
|
{
|
|
|
this.RequestType = requestType;
|
|
|
this.Summary = summary;
|
|
|
- this.Notes = notes;
|
|
|
this.restPath = path;
|
|
|
|
|
|
- this.allowsAllVerbs = verbs == null || String.Equals(verbs, WildCard, StringComparison.OrdinalIgnoreCase);
|
|
|
- if (!this.allowsAllVerbs)
|
|
|
- {
|
|
|
- this.allowedVerbs = verbs.ToUpper();
|
|
|
- }
|
|
|
+ this.Verbs = string.IsNullOrWhiteSpace(verbs) ? ServiceExecExtensions.AllVerbs : verbs.ToUpper().Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
|
|
var componentsList = new List<string>();
|
|
|
|
|
@@ -153,7 +130,6 @@ namespace Emby.Server.Implementations.Services
|
|
|
this.PathComponentsCount = this.componentsWithSeparators.Length;
|
|
|
string firstLiteralMatch = null;
|
|
|
|
|
|
- var sbHashKey = new StringBuilder();
|
|
|
for (var i = 0; i < components.Length; i++)
|
|
|
{
|
|
|
var component = components[i];
|
|
@@ -172,7 +148,6 @@ namespace Emby.Server.Implementations.Services
|
|
|
else
|
|
|
{
|
|
|
this.literalsToMatch[i] = component.ToLower();
|
|
|
- sbHashKey.Append(i + PathSeperatorChar.ToString() + this.literalsToMatch);
|
|
|
|
|
|
if (firstLiteralMatch == null)
|
|
|
{
|
|
@@ -198,9 +173,6 @@ namespace Emby.Server.Implementations.Services
|
|
|
? this.PathComponentsCount + PathSeperator + firstLiteralMatch
|
|
|
: WildCardChar + PathSeperator + firstLiteralMatch;
|
|
|
|
|
|
- this.IsValid = sbHashKey.Length > 0;
|
|
|
- this.UniqueMatchHashKey = sbHashKey.ToString();
|
|
|
-
|
|
|
this.typeDeserializer = new StringMapTypeDeserializer(createInstanceFn, getParseFn, this.RequestType);
|
|
|
RegisterCaseInsenstivePropertyNameMappings();
|
|
|
}
|
|
@@ -220,26 +192,46 @@ namespace Emby.Server.Implementations.Services
|
|
|
};
|
|
|
|
|
|
|
|
|
- private static List<Type> _excludeTypes = new List<Type> { typeof(Stream) };
|
|
|
+ private static Type excludeType = typeof(Stream);
|
|
|
|
|
|
- internal static PropertyInfo[] GetSerializableProperties(Type type)
|
|
|
+ internal static List<PropertyInfo> GetSerializableProperties(Type type)
|
|
|
{
|
|
|
- var properties = GetPublicProperties(type);
|
|
|
- var readableProperties = properties.Where(x => x.GetMethod != null);
|
|
|
+ var list = new List<PropertyInfo>();
|
|
|
+ var props = GetPublicProperties(type);
|
|
|
|
|
|
- // else return those properties that are not decorated with IgnoreDataMember
|
|
|
- return readableProperties
|
|
|
- .Where(prop => prop.GetCustomAttributes(true)
|
|
|
- .All(attr =>
|
|
|
+ foreach (var prop in props)
|
|
|
+ {
|
|
|
+ if (prop.GetMethod == null)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (excludeType == prop.PropertyType)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ var ignored = false;
|
|
|
+ foreach (var attr in prop.GetCustomAttributes(true))
|
|
|
+ {
|
|
|
+ if (IgnoreAttributesNamed.Contains(attr.GetType().Name))
|
|
|
{
|
|
|
- var name = attr.GetType().Name;
|
|
|
- return !IgnoreAttributesNamed.Contains(name);
|
|
|
- }))
|
|
|
- .Where(prop => !_excludeTypes.Contains(prop.PropertyType))
|
|
|
- .ToArray();
|
|
|
+ ignored = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!ignored)
|
|
|
+ {
|
|
|
+ list.Add(prop);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // else return those properties that are not decorated with IgnoreDataMember
|
|
|
+ return list;
|
|
|
}
|
|
|
|
|
|
- private static PropertyInfo[] GetPublicProperties(Type type)
|
|
|
+ private static List<PropertyInfo> GetPublicProperties(Type type)
|
|
|
{
|
|
|
if (type.GetTypeInfo().IsInterface)
|
|
|
{
|
|
@@ -269,12 +261,19 @@ namespace Emby.Server.Implementations.Services
|
|
|
propertyInfos.InsertRange(0, newPropertyInfos);
|
|
|
}
|
|
|
|
|
|
- return propertyInfos.ToArray(propertyInfos.Count);
|
|
|
+ return propertyInfos;
|
|
|
}
|
|
|
|
|
|
- return GetTypesPublicProperties(type)
|
|
|
- .Where(t => t.GetIndexParameters().Length == 0) // ignore indexed properties
|
|
|
- .ToArray();
|
|
|
+ var list = new List<PropertyInfo>();
|
|
|
+
|
|
|
+ foreach (var t in GetTypesPublicProperties(type))
|
|
|
+ {
|
|
|
+ if (t.GetIndexParameters().Length == 0)
|
|
|
+ {
|
|
|
+ list.Add(t);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return list;
|
|
|
}
|
|
|
|
|
|
private static PropertyInfo[] GetTypesPublicProperties(Type subType)
|
|
@@ -289,16 +288,11 @@ namespace Emby.Server.Implementations.Services
|
|
|
return pis.ToArray(pis.Count);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- public bool IsValid { get; set; }
|
|
|
-
|
|
|
/// <summary>
|
|
|
/// Provide for quick lookups based on hashes that can be determined from a request url
|
|
|
/// </summary>
|
|
|
public string FirstMatchHashKey { get; private set; }
|
|
|
|
|
|
- public string UniqueMatchHashKey { get; private set; }
|
|
|
-
|
|
|
private readonly StringMapTypeDeserializer typeDeserializer;
|
|
|
|
|
|
private readonly Dictionary<string, string> propertyNamesMap = new Dictionary<string, string>();
|
|
@@ -321,8 +315,14 @@ namespace Emby.Server.Implementations.Services
|
|
|
score += Math.Max((10 - VariableArgsCount), 1) * 100;
|
|
|
|
|
|
//Exact verb match is better than ANY
|
|
|
- var exactVerb = String.Equals(httpMethod, AllowedVerbs, StringComparison.OrdinalIgnoreCase);
|
|
|
- score += exactVerb ? 10 : 1;
|
|
|
+ if (Verbs.Length == 1 && string.Equals(httpMethod, Verbs[0], StringComparison.OrdinalIgnoreCase))
|
|
|
+ {
|
|
|
+ score += 10;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ score += 1;
|
|
|
+ }
|
|
|
|
|
|
return score;
|
|
|
}
|
|
@@ -346,7 +346,7 @@ namespace Emby.Server.Implementations.Services
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- if (!this.allowsAllVerbs && !StringContains(this.allowedVerbs, httpMethod))
|
|
|
+ if (!Verbs.Contains(httpMethod, StringComparer.OrdinalIgnoreCase))
|
|
|
{
|
|
|
//logger.Info("allowsAllVerbs mismatch for {0} for {1} allowedverbs {2}", httpMethod, string.Join("/", withPathInfoParts), this.allowedVerbs);
|
|
|
return false;
|
|
@@ -457,8 +457,7 @@ namespace Emby.Server.Implementations.Services
|
|
|
|
|
|
public object CreateRequest(string pathInfo, Dictionary<string, string> queryStringAndFormData, object fromInstance)
|
|
|
{
|
|
|
- var requestComponents = pathInfo.Split(PathSeperatorChar)
|
|
|
- .Where(x => !String.IsNullOrEmpty(x)).ToArray();
|
|
|
+ var requestComponents = pathInfo.Split(new[] { PathSeperatorChar }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
|
|
ExplodeComponents(ref requestComponents);
|
|
|
|
|
@@ -555,10 +554,5 @@ namespace Emby.Server.Implementations.Services
|
|
|
|
|
|
return this.typeDeserializer.PopulateFromMap(fromInstance, requestKeyValuesMap);
|
|
|
}
|
|
|
-
|
|
|
- public override int GetHashCode()
|
|
|
- {
|
|
|
- return UniqueMatchHashKey.GetHashCode();
|
|
|
- }
|
|
|
}
|
|
|
}
|