private DataServiceProtocolVersion CalculateDataServiceProtocolVersion(ODataRequest request, ODataResponse response) { DataServiceProtocolVersion dataServiceVersion = VersionHelper.ConvertToDataServiceProtocolVersion(request.GetHeaderValueIfExists(HttpHeaders.DataServiceVersion)); DataServiceProtocolVersion maxDataServiceVersion = VersionHelper.ConvertToDataServiceProtocolVersion(request.GetHeaderValueIfExists(HttpHeaders.MaxDataServiceVersion)); var responseContentType = response.GetHeaderValueIfExists(HttpHeaders.ContentType); if (responseContentType != null) { if (responseContentType.StartsWith(MimeTypes.ApplicationJsonODataLightNonStreaming, StringComparison.OrdinalIgnoreCase) || responseContentType.StartsWith(MimeTypes.ApplicationJsonODataLightStreaming, StringComparison.OrdinalIgnoreCase)) { return DataServiceProtocolVersion.V4; } } if (response.StatusCode.IsError()) { return DataServiceProtocolVersion.V4; } DataServiceProtocolVersion expectedVersion = DataServiceProtocolVersion.V4; // Apply minDsv if MPV > V2 if (maxDataServiceVersion != DataServiceProtocolVersion.Unspecified && this.maxProtocolVersion >= maxDataServiceVersion) { expectedVersion = maxDataServiceVersion; } else { expectedVersion = this.maxProtocolVersion; } // If body of a response is empty, the version is V1 unless it has prefer header. if (!this.IsResponseBodyEmpty(response)) { if (request.Uri.IsMetadata()) { // metadata payloads are not handled by the normal payload element visitor, but the response header will match the model version exactly expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, this.ModelVersionCalculator.CalculateProtocolVersion(this.model)); } else { // GET requests are versioned based on the URI because type information is not known until serialization if (request.GetEffectiveVerb() == HttpVerb.Get || request.Uri.IsServiceOperation() || request.Uri.IsAction()) { expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, this.UriVersionCalculator.CalculateProtocolVersion(request.Uri, response.Headers[HttpHeaders.ContentType], this.maxProtocolVersion, dataServiceVersion, maxDataServiceVersion)); } // Post and update requests are versioned based on the specific instance if (response.RootElement != null) { expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, this.PayloadElementVersionCalculator.CalculateProtocolVersion(response.RootElement, response.Headers[HttpHeaders.ContentType], this.maxProtocolVersion, maxDataServiceVersion)); } } } else { if (request.Uri.IsAction()) { expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, this.UriVersionCalculator.CalculateProtocolVersion(request.Uri, response.GetHeaderValueIfExists(HttpHeaders.ContentType), this.maxProtocolVersion, dataServiceVersion, maxDataServiceVersion)); } } // NOTE: the prefer verifier will ensure that this header is present if it should be, so our only concern here // is that the version is >= V3 if it is present if (response.Headers.ContainsKey(HttpHeaders.PreferenceApplied)) { expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, DataServiceProtocolVersion.V4); } return expectedVersion; }
/// <summary> /// Helper method for getting the error payload from the response. Handles a special case for media-resource operations which may contain errors despite not normally /// being deserialized as such. /// </summary> /// <param name="response">The current response</param> /// <param name="formatSelector">The format selector to use if the response needs to be deserialized</param> /// <param name="errorPayload">The error payload if one was found</param> /// <returns>Whether or not an error payload was found</returns> internal static bool TryGetErrorPayloadFromResponse(ODataResponse response, IProtocolFormatStrategySelector formatSelector, out ODataErrorPayload errorPayload) { ExceptionUtilities.CheckArgumentNotNull(response, "response"); errorPayload = null; var payload = response.RootElement; if (payload == null) { return false; } if (payload.ElementType == ODataPayloadElementType.ODataErrorPayload) { errorPayload = (ODataErrorPayload)payload; return true; } // From here out, try to handle special case for streams which come back with error payloads and are not interpreted if (payload.ElementType != ODataPayloadElementType.PrimitiveValue) { return false; } var body = ((PrimitiveValue)payload).ClrValue as byte[]; if (body == null) { return false; } var contentType = response.GetHeaderValueIfExists(HttpHeaders.ContentType); if (contentType == null) { return false; } // deserialize it ExceptionUtilities.CheckArgumentNotNull(formatSelector, "formatSelector"); var formatForContentType = formatSelector.GetStrategy(contentType, null); var deserializer = formatForContentType.GetDeserializer(); payload = deserializer.DeserializeFromBinary(body, new ODataPayloadContext { EncodingName = HttpUtilities.GetContentTypeCharsetOrNull(contentType) }); errorPayload = payload as ODataErrorPayload; return errorPayload != null; }
/// <summary> /// Verifies the update succeeded /// </summary> /// <param name="request">The request to verify</param> /// <param name="response">The response to verify</param> public override void Verify(ODataRequest request, ODataResponse response) { base.Verify(request, response); var contentType = response.GetHeaderValueIfExists(HttpHeaders.ContentType); var version = response.GetDataServiceVersion(); var options = this.ProtocolImplementationDetails.GetExpectedPayloadOptions(contentType, version, request.Uri); new NextLinkValidatingVisitor(request.Uri, options, this).ValidateNextLinks(response.RootElement); }
/// <summary> /// Returns a value indicating whether this verifier applies to the given response /// </summary> /// <param name="response">The response</param> /// <returns> /// True if it applies, false otherwise /// </returns> public bool Applies(ODataResponse response) { return response.GetHeaderValueIfExists(HttpHeaders.ContentType).IfValid(false, c => c.StartsWith(MimeTypes.ApplicationJsonLight, StringComparison.OrdinalIgnoreCase)); }