// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.Serialization; using System.Web.Http.Properties; using System.Xml.Serialization; namespace System.Web.Http.Query { /// /// This class is used to do validation on the query generated by the ODataQueryDeserializer. The default implementation /// validates that the query is not accessing members hidden through attributes like , and /// /// internal class QueryValidator { private static QueryValidator _instance = new QueryValidator(); protected QueryValidator() { } public static QueryValidator Instance { get { return _instance; } } public virtual void Validate(IQueryable query) { QueryValidationVisitor.Validate(query); } private class QueryValidationVisitor : ExpressionVisitor { public static void Validate(IQueryable query) { QueryValidationVisitor visitor = new QueryValidationVisitor(); visitor.Visit(query.Expression); } protected override Expression VisitMember(MemberExpression node) { if (!IsVisible(node.Member)) { throw Error.InvalidOperation(SRResources.InaccessiblePropertyOrField, node.Member.Name, node.Member.DeclaringType.Name); } return base.VisitMember(node); } private static bool IsVisible(MemberInfo member) { switch (member.MemberType) { case MemberTypes.Field: FieldInfo field = member as FieldInfo; if (!field.IsPublic) { return false; } break; case MemberTypes.Property: PropertyInfo property = member as PropertyInfo; MethodInfo propertyGetter = property.GetGetMethod(); if (propertyGetter == null || !propertyGetter.IsPublic) { return false; } break; default: return false; } object[] attributes = member.GetCustomAttributes(inherit: true); object[] parentAttributes = member.ReflectedType.GetCustomAttributes(inherit: true); return !( (HasAttribute(parentAttributes) && !HasAttribute(attributes)) // isDataContractAndNotDataMember || HasAttribute(attributes) || HasAttribute(attributes) || HasAttribute(attributes)); } private static bool HasAttribute(object[] attribs) { return attribs.Length != 0 && attribs.OfType().Any(); } } } }