Exemplo n.º 1
0
        private static IEnumerable <KeyValuePair <string, object> > ParseETagValue(IList <ResourceProperty> etagProperties, string ifMatchHeaderValue)
        {
            bool flag;

            if (ifMatchHeaderValue == "*")
            {
                return(WebUtil.EmptyKeyValuePairStringObject);
            }
            string      stringToUnescape = ifMatchHeaderValue.Substring("W/\"".Length, (ifMatchHeaderValue.Length - "W/\"".Length) - 1);
            KeyInstance instance         = null;
            Exception   innerException   = null;

            try
            {
                flag = KeyInstance.TryParseNullableTokens(Uri.UnescapeDataString(stringToUnescape), out instance);
            }
            catch (DataServiceException exception2)
            {
                flag           = false;
                innerException = exception2;
            }
            if (!flag)
            {
                throw DataServiceException.CreatePreConditionFailedError(System.Data.Services.Strings.Serializer_ETagValueDoesNotMatch, innerException);
            }
            if (instance.PositionalValues.Count != etagProperties.Count)
            {
                throw DataServiceException.CreatePreConditionFailedError(System.Data.Services.Strings.Serializer_ETagValueDoesNotMatch);
            }
            KeyValuePair <string, object>[] pairArray = new KeyValuePair <string, object> [etagProperties.Count];
            for (int i = 0; i < pairArray.Length; i++)
            {
                ResourceProperty property    = etagProperties[i];
                object           targetValue = null;
                string           text        = (string)instance.PositionalValues[i];
                if (text != "null")
                {
                    try
                    {
                        flag = WebConvert.TryKeyStringToPrimitive(text, property.Type, out targetValue);
                    }
                    catch (OverflowException exception3)
                    {
                        flag           = false;
                        innerException = exception3;
                    }
                    if (!flag)
                    {
                        throw DataServiceException.CreatePreConditionFailedError(System.Data.Services.Strings.Serializer_ETagValueDoesNotMatch, innerException);
                    }
                }
                pairArray[i] = new KeyValuePair <string, object>(etagProperties[i].Name, targetValue);
            }
            return(pairArray);
        }
Exemplo n.º 2
0
        internal static string CompareAndGetETag(object parentEntityResource, object parentEntityToken, ResourceSetWrapper container, IDataService service, out bool writeResponseForGetMethods)
        {
            DataServiceHostWrapper host = service.OperationContext.Host;

            writeResponseForGetMethods = true;
            string str = null;

            if (parentEntityResource == null)
            {
                if (!string.IsNullOrEmpty(host.RequestIfMatch))
                {
                    throw DataServiceException.CreatePreConditionFailedError(System.Data.Services.Strings.Serializer_ETagValueDoesNotMatch);
                }
                return(str);
            }
            ResourceType nonPrimitiveResourceType         = GetNonPrimitiveResourceType(service.Provider, parentEntityResource);
            ICollection <ResourceProperty> eTagProperties = service.Provider.GetETagProperties(container.Name, nonPrimitiveResourceType);

            if (eTagProperties.Count == 0)
            {
                if (!string.IsNullOrEmpty(host.RequestIfMatch))
                {
                    throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.Serializer_NoETagPropertiesForType);
                }
            }
            else if ((!string.IsNullOrEmpty(host.RequestIfMatch) || !string.IsNullOrEmpty(host.RequestIfNoneMatch)) && (host.RequestIfMatch != "*"))
            {
                if (host.RequestIfNoneMatch == "*")
                {
                    writeResponseForGetMethods = false;
                }
                else
                {
                    str = GetETagValue(parentEntityToken, nonPrimitiveResourceType, eTagProperties, service, true);
                    if (string.IsNullOrEmpty(host.RequestIfMatch))
                    {
                        if (host.RequestIfNoneMatch == str)
                        {
                            writeResponseForGetMethods = false;
                        }
                    }
                    else if (str != host.RequestIfMatch)
                    {
                        throw DataServiceException.CreatePreConditionFailedError(System.Data.Services.Strings.Serializer_ETagValueDoesNotMatch);
                    }
                }
            }
            if ((str == null) && (eTagProperties.Count != 0))
            {
                str = GetETagValue(parentEntityResource, nonPrimitiveResourceType, eTagProperties, service, true);
            }
            return(str);
        }
Exemplo n.º 3
0
        internal void SetETagValues(object resourceCookie, ResourceSetWrapper container)
        {
            DataServiceHostWrapper host   = this.service.OperationContext.Host;
            object                   obj2 = this.ResolveResource(resourceCookie);
            ResourceType             nonPrimitiveResourceType = WebUtil.GetNonPrimitiveResourceType(this.service.Provider, obj2);
            IList <ResourceProperty> eTagProperties           = this.service.Provider.GetETagProperties(container.Name, nonPrimitiveResourceType);

            if (eTagProperties.Count == 0)
            {
                if (!string.IsNullOrEmpty(host.RequestIfMatch))
                {
                    throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.Serializer_NoETagPropertiesForType);
                }
            }
            else
            {
                IDataServiceUpdateProvider updateProvider = this.updateProvider as IDataServiceUpdateProvider;
                if (updateProvider != null)
                {
                    IEnumerable <KeyValuePair <string, object> > emptyKeyValuePairStringObject;
                    bool?checkForEquality = null;
                    if (!string.IsNullOrEmpty(host.RequestIfMatch))
                    {
                        checkForEquality = true;
                        emptyKeyValuePairStringObject = ParseETagValue(eTagProperties, host.RequestIfMatch);
                    }
                    else
                    {
                        emptyKeyValuePairStringObject = WebUtil.EmptyKeyValuePairStringObject;
                    }
                    updateProvider.SetConcurrencyValues(resourceCookie, checkForEquality, emptyKeyValuePairStringObject);
                }
                else
                {
                    if (string.IsNullOrEmpty(host.RequestIfMatch))
                    {
                        throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.DataService_CannotPerformOperationWithoutETag(nonPrimitiveResourceType.FullName));
                    }
                    if ((host.RequestIfMatch != "*") && (WebUtil.GetETagValue(resourceCookie, nonPrimitiveResourceType, eTagProperties, this.service, false) != host.RequestIfMatch))
                    {
                        throw DataServiceException.CreatePreConditionFailedError(System.Data.Services.Strings.Serializer_ETagValueDoesNotMatch);
                    }
                }
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Parse the given etag value in the If-Match request header.
        /// </summary>
        /// <param name="etagProperties">List of etag properties for the type whose etag values we are parsing.</param>
        /// <param name="ifMatchHeaderValue">value of the If-Match header as specified in the request.</param>
        /// <returns>returns the etag value as a list containing the property name and its corresponding value. If the If-Match header value is '*', then returns an empty collection.</returns>
        private static IEnumerable <KeyValuePair <string, object> > ParseETagValue(IList <ResourceProperty> etagProperties, string ifMatchHeaderValue)
        {
            Debug.Assert(etagProperties != null && etagProperties.Count != 0, "There must be atleast one etag property specified");
            Debug.Assert(!String.IsNullOrEmpty(ifMatchHeaderValue), "IfMatch header cannot be null");

            if (ifMatchHeaderValue == XmlConstants.HttpAnyETag)
            {
                // if the value is '*', then we return an empty IEnumerable.
                return(new KeyValuePair <string, object> [0]);
            }

            Debug.Assert(ifMatchHeaderValue.StartsWith(XmlConstants.HttpWeakETagPrefix, StringComparison.Ordinal), "If-Match header must be properly formatted - this check is done in DataService.CheckETagValues method");
            Debug.Assert(ifMatchHeaderValue.Length >= XmlConstants.HttpWeakETagPrefix.Length + 1, "If-Match header must be properly formatted - this check is done in DataService.CheckETagValues method");

            // Just get the etag value - we need to ignore the 'W/"' and the last '"' character from the etag
            string strippedETag = ifMatchHeaderValue.Substring(XmlConstants.HttpWeakETagPrefix.Length, ifMatchHeaderValue.Length - XmlConstants.HttpWeakETagPrefix.Length - 1);

            KeyInstance keyInstance = null;
            bool        success;
            Exception   innerException = null;

            // In V1, when we didn't have IConcurrencyProvider interface, we always used to compute the
            // latest etag from the entity instance we got from IUpdatable.GetResource and then comparing
            // it with the If-Match request header. Hence all invalid cases always used to throw
            // DataServiceException with 412, since the etags didn't match.
            // In V1.5, we have added the support for IConcurrencyProvider, which means we need to parse
            // the etag values and parse it to the provider, if it has implement this interface. To avoid
            // breaking changes, we need to catch all parsing errors and report them as 412 instead of 400
            // to avoid it from becoming a breaking change.
            try
            {
                success = KeyInstance.TryParseNullableTokens(Uri.UnescapeDataString(strippedETag), out keyInstance);
            }
            catch (DataServiceException e)
            {
                success        = false;
                innerException = e;
            }

            if (!success)
            {
                // We could have throwed BadRequest here since the etag value is not properly formattted. But since
                // we used to do throw 412 in V1, keeping it that way to avoid breaking change.
                throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch, innerException);
            }

            if (keyInstance.PositionalValues.Count != etagProperties.Count)
            {
                // We could have throwed BadRequest here since the etag value is not properly formattted. But since
                // we used to do throw 412 in V1, keeping it that way to avoid breaking change.
                throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch);
            }

            KeyValuePair <string, object>[] etagPropertyInfo = new KeyValuePair <string, object> [etagProperties.Count];
            for (int i = 0; i < etagPropertyInfo.Length; i++)
            {
                ResourceProperty etagProperty  = etagProperties[i];
                object           propertyValue = null;
                string           value         = (string)keyInstance.PositionalValues[i];

                if (value != XmlConstants.NullLiteralInETag)
                {
                    // The reason we need to catch the Overflow Exception here is because of the Bug #679728.
                    // In V1, when we didn't have IConcurrencyProvider interface, we always used to compute the
                    // latest etag from the entity instance we got from IUpdatable.GetResource and then comparing
                    // it with the If-Match request header. Hence all invalid cases always used to throw
                    // DataServiceException with 412, since the etags didn't match.
                    // In V1.5, we have added the support for IConcurrencyProvider, which means we need to parse
                    // the etag values and parse it to the provider, if it has implement this interface. To avoid
                    // breaking changes, we need to catch all parsing errors and report them as 412 instead of 400
                    // to avoid it from becoming a breaking change.
                    try
                    {
                        success = System.Data.Services.Parsing.WebConvert.TryKeyStringToPrimitive(value, etagProperty.Type, out propertyValue);
                    }
                    catch (OverflowException e)
                    {
                        success        = false;
                        innerException = e;
                    }

                    if (!success)
                    {
                        // We could have throwed BadRequest here since the etag value is not properly formattted. But since
                        // we used to do throw 412 in V1, keeping it that way to avoid breaking change.
                        throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch, innerException);
                    }
                }

                etagPropertyInfo[i] = new KeyValuePair <string, object>(etagProperties[i].Name, propertyValue);
            }

            return(etagPropertyInfo);
        }
Exemplo n.º 5
0
        /// <summary>
        /// If the provider implements IConcurrencyProvider, then this method passes the etag values
        /// to the provider, otherwise compares the etag itself.
        /// </summary>
        /// <param name="resourceCookie">etag values for the given resource.</param>
        /// <param name="container">container for the given resource.</param>
        internal void SetETagValues(object resourceCookie, ResourceSetWrapper container)
        {
            Debug.Assert(resourceCookie != null, "resourceCookie != null");
            Debug.Assert(container != null, "container != null");
            DataServiceHostWrapper host = this.service.OperationContext.Host;

            Debug.Assert(String.IsNullOrEmpty(host.RequestIfNoneMatch), "IfNoneMatch header cannot be specified for Update/Delete operations");

            // Resolve the cookie first to the actual resource type
            object actualEntity = this.ResolveResource(resourceCookie);

            Debug.Assert(actualEntity != null, "actualEntity != null");

            ResourceType resourceType = WebUtil.GetNonPrimitiveResourceType(this.service.Provider, actualEntity);

            Debug.Assert(resourceType != null, "resourceType != null");

            IList <ResourceProperty> etagProperties = this.service.Provider.GetETagProperties(container.Name, resourceType);

            if (etagProperties.Count == 0)
            {
                if (!String.IsNullOrEmpty(host.RequestIfMatch))
                {
                    throw DataServiceException.CreateBadRequestError(Strings.Serializer_NoETagPropertiesForType);
                }

                // If the type has no etag properties, then we do not need to do any etag checks
                return;
            }

            // If the provider implements IConcurrencyProvider, then we need to call the provider
            // and pass the etag values. Else, we need to compare the etag values ourselves.
            IDataServiceUpdateProvider concurrencyProvider = this.updateProvider as IDataServiceUpdateProvider;

            if (concurrencyProvider != null)
            {
                bool?checkForEquality = null;
                IEnumerable <KeyValuePair <string, object> > etagValues = null;
                if (!String.IsNullOrEmpty(host.RequestIfMatch))
                {
                    checkForEquality = true;
                    etagValues       = ParseETagValue(etagProperties, host.RequestIfMatch);
                }
                else
                {
                    etagValues = new KeyValuePair <string, object> [0];
                }

                concurrencyProvider.SetConcurrencyValues(resourceCookie, checkForEquality, etagValues);
            }
            else if (String.IsNullOrEmpty(host.RequestIfMatch))
            {
                throw DataServiceException.CreateBadRequestError(Strings.DataService_CannotPerformOperationWithoutETag(resourceType.FullName));
            }
            else if (host.RequestIfMatch != XmlConstants.HttpAnyETag)
            {
                // Compare If-Match header value with the current etag value, if the If-Match header value is not equal to '*'
                string etagValue = WebUtil.GetETagValue(resourceCookie, resourceType, etagProperties, this.service, false /*getMethod*/);
                Debug.Assert(!String.IsNullOrEmpty(etagValue), "etag value can never be null");

                if (etagValue != host.RequestIfMatch)
                {
                    throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch);
                }
            }
        }