/// <summary>Handles an exception when processing a batch response.</summary> /// <param name='service'>Data service doing the processing.</param> /// <param name="host">host to which we need to write the exception message</param> /// <param name='exception'>Exception thrown.</param> /// <param name='writer'>Output writer for the batch.</param> internal static void HandleBatchProcessException(IDataService service, DataServiceHostWrapper host, Exception exception, StreamWriter writer) { Debug.Assert(service != null, "service != null"); Debug.Assert(host != null, "host != null"); Debug.Assert(exception != null, "exception != null"); Debug.Assert(writer != null, "writer != null"); Debug.Assert(service.Configuration != null, "service.Configuration != null"); Debug.Assert(WebUtil.IsCatchableExceptionType(exception), "WebUtil.IsCatchableExceptionType(exception)"); string contentType; Encoding encoding; TryGetResponseFormatForError(host, out contentType, out encoding); HandleExceptionArgs args = new HandleExceptionArgs(exception, false, contentType, service.Configuration.UseVerboseErrors); service.InternalHandleException(args); host.ResponseVersion = XmlConstants.DataServiceVersion1Dot0 + ";"; host.ProcessException(args); writer.Flush(); Action<Stream> errorWriter = ProcessBenignException(exception, service); if (errorWriter == null) { errorWriter = CreateErrorSerializer(args, encoding); } errorWriter(writer.BaseStream); writer.WriteLine(); }
internal void InitializeAndCacheHeaders(IDataService dataService) { this.hostWrapper = new DataServiceHostWrapper(this.hostInterface); this.CurrentDataService = dataService; if (this.hostInterface is IDataServiceHost2) { this.ResponseHeaders.Add("X-Content-Type-Options", "nosniff"); } }
internal ODataResponseMessage(DataServiceHostWrapper host) { this.host = host; }
private static object[] ReadOperationParameters(DataServiceHostWrapper host, OperationWrapper operation) { object[] objArray = new object[operation.Parameters.Count]; for (int i = 0; i < operation.Parameters.Count; i++) { Type instanceType = operation.Parameters[i].ParameterType.InstanceType; string queryStringItem = host.GetQueryStringItem(operation.Parameters[i].Name); Type underlyingType = Nullable.GetUnderlyingType(instanceType); if (string.IsNullOrEmpty(queryStringItem)) { WebUtil.CheckSyntaxValid(instanceType.IsClass || (underlyingType != null)); objArray[i] = null; } else { queryStringItem = queryStringItem.Trim(); Type type = underlyingType ?? instanceType; if (WebConvert.IsKeyTypeQuoted(type)) { WebUtil.CheckSyntaxValid(WebConvert.IsKeyValueQuoted(queryStringItem)); } WebUtil.CheckSyntaxValid(WebConvert.TryKeyStringToPrimitive(queryStringItem, type, out objArray[i])); } } return objArray; }
internal static void HandleBatchOperationError(IDataService service, DataServiceHostWrapper host, Exception exception, ODataBatchWriter batchWriter, Stream responseStream, Version defaultResponseVersion) { string str; Encoding encoding; string str2; Version version; TryGetResponseFormatForError(service, host, defaultResponseVersion, out str, out encoding, out str2, out version); HandleExceptionArgs args = new HandleExceptionArgs(exception, false, str2, service.Configuration.UseVerboseErrors); service.InternalHandleException(args); Action<Stream> action = null; if (host != null) { host.ResponseVersion = version.ToString(2) + ";"; host.ProcessException(args); action = ProcessBenignException(exception, service); } if (action == null) { ODataBatchOperationResponseMessage operationResponseMessage; if (host != null) { operationResponseMessage = host.BatchServiceHost.GetOperationResponseMessage(); WebUtil.SetResponseHeadersForBatchRequests(operationResponseMessage, host.BatchServiceHost); } else { operationResponseMessage = batchWriter.CreateOperationResponseMessage(); operationResponseMessage.StatusCode = args.ResponseStatusCode; } using (ODataMessageWriter writer = ResponseBodyWriter.CreateMessageWriter(null, service, version, operationResponseMessage, str, null)) { SerializeODataError(args, writer, responseStream, encoding); } } }
private static void TryGetResponseFormatForError(IDataService service, DataServiceHostWrapper host, Version defaultResponseVersion, out string contentType, out Encoding encoding, out string contentTypeWithCharsetAppended, out Version responseVersion) { if (host == null) { responseVersion = defaultResponseVersion; TryGetResponseFormatForError(null, null, null, out contentType, out encoding, out contentTypeWithCharsetAppended); } else { Version maxProtocolVersion = service.Configuration.DataServiceBehavior.MaxProtocolVersion.ToVersion(); if (!TryGetMinResponseVersionForError(host, maxProtocolVersion, out responseVersion)) { responseVersion = defaultResponseVersion; } TryGetResponseFormatForError(host.RequestAccept, host.RequestAcceptCharSet, responseVersion, out contentType, out encoding, out contentTypeWithCharsetAppended); } }
internal static bool TryGetMinResponseVersionForError(DataServiceHostWrapper host, Version maxProtocolVersion, out Version responseVersion) { responseVersion = null; try { Version version; if (((maxProtocolVersion > RequestDescription.Version2Dot0) && (host.RequestMaxVersion > RequestDescription.Version2Dot0)) && WebUtil.ResponseMediaTypeWouldBeJsonLight(host.RequestAccept, false)) { responseVersion = RequestDescription.Version3Dot0; } if (!host.TryGetMinDataServiceVersionFromWrappedHost(out version)) { return (responseVersion != null); } if ((responseVersion == null) || (version > responseVersion)) { responseVersion = version; } if (maxProtocolVersion < RequestDescription.Version3Dot0) { responseVersion = RequestDescription.DataServiceDefaultResponseVersion; return true; } if (!RequestDescription.IsKnownRequestVersion(responseVersion) || (responseVersion > maxProtocolVersion)) { return false; } return true; } catch (Exception exception) { if (!CommonUtil.IsCatchableExceptionType(exception)) { throw; } } return false; }
/// <summary>Gets content type and encoding information from the host if possible; defaults otherwise.</summary> /// <param name="host">Host to get headers from (possibly null).</param> /// <param name="contentType">After invocation, content type for the exception.</param> /// <param name="encoding">After invocation, encoding for the exception.</param> private static void TryGetResponseFormatForError(DataServiceHostWrapper host, out string contentType, out Encoding encoding) { TryGetResponseFormatForError( (host != null) ? host.RequestAccept : null, (host != null) ? host.RequestAcceptCharSet : null, out contentType, out encoding); }
/// <summary> /// Creates a new instance of the host wrapper to cache the request headers and to validate the data from the host interface. /// </summary> internal void InitializeAndCacheHeaders() { Debug.Assert(this.hostInterface != null, "this.hostInterface != null"); this.hostWrapper = new DataServiceHostWrapper(this.hostInterface); }
/// <summary>Reads the current object from the <paramref name="item"/>.</summary> /// <param name="segmentInfo">segmentinfo containing information about the current element that is getting processes</param> /// <param name="topLevel">true if the element currently pointed by the xml reader refers to a top level element</param> /// <param name="item">Item to read from.</param> /// <returns>returns the clr object with the data populated</returns> private object CreateObject(SegmentInfo segmentInfo, bool topLevel, SyndicationItem item) { Debug.Assert(item != null, "item != null"); Debug.Assert(topLevel || !this.Update, "deep updates not supported"); this.RecurseEnter(); object result; // update the object count everytime you encounter a new resource this.CheckAndIncrementObjectCount(); // Process the type annotation. ResourceType currentResourceType = this.GetResourceType(item, segmentInfo.TargetResourceType); if (currentResourceType.ResourceTypeKind != ResourceTypeKind.EntityType) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_OnlyEntityTypesMustBeSpecifiedInEntryElement(currentResourceType.FullName)); } // We have the actual type info from the payload. Update the request/response DSV if any property is FF mapped with KeepInContent=false. this.UpdateAndCheckEpmRequestResponseDSV(currentResourceType, topLevel); // Get a resource cookie from the provider. ResourceSetWrapper container; if (segmentInfo.TargetKind == RequestTargetKind.OpenProperty) { // Open navigation properties are not supported on OpenTypes. throw DataServiceException.CreateBadRequestError(Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(segmentInfo.Identifier)); } else { Debug.Assert(segmentInfo.TargetKind == RequestTargetKind.Resource, "segmentInfo.TargetKind == RequestTargetKind.Resource"); container = segmentInfo.TargetContainer; } DataServiceHostWrapper host = this.Service.OperationContext.Host; if (this.Update) { Debug.Assert(currentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "only expecting entity types"); // Only verify ETag if there is going to be some update applied (that's the idea) // In reality: // - for normal entities (V1 compatible) - don't check ETags if there is no content element. (Same as in V1) // - for V2 stuff - check ETags always as we can't tell if there's going to be something modified or not // with EPM properties can be anywhere in the payload and thus even without content there still can be updates // with MLE the properties are not in the content element but in their own element // It's hard to recognize if there's going to be update up front and so this below is an approximation // which seems to be good enough. Note that if we add new ways of handling properties in the content // the condition below might need to change. bool verifyETag = topLevel && (HasContent(item) || currentResourceType.HasEntityPropertyMappings || currentResourceType.IsMediaLinkEntry); bool replaceResource = topLevel && host.AstoriaHttpVerb == AstoriaVerbs.PUT; // if its a top level resource, then it cannot be null result = this.GetObjectFromSegmentInfo(currentResourceType, segmentInfo, verifyETag, topLevel /*checkForNull*/, replaceResource); if (this.Tracker != null) { this.Tracker.TrackAction(result, container, UpdateOperations.Change); } } else { if (segmentInfo.TargetKind == RequestTargetKind.Resource) { DataServiceConfiguration.CheckResourceRights(segmentInfo.TargetContainer, EntitySetRights.WriteAppend); } result = this.Updatable.CreateResource(container.Name, currentResourceType.FullName); if (this.Tracker != null) { this.Tracker.TrackAction(result, container, UpdateOperations.Add); } } // Process the content in the entry. EpmContentDeSerializer.EpmAppliedPropertyInfo propertiesApplied = new EpmContentDeSerializer.EpmAppliedPropertyInfo(); this.ApplyProperties(item, currentResourceType, propertiesApplied, result); // Perform application of epm properties here if (currentResourceType.HasEntityPropertyMappings) { new EpmContentDeSerializer(currentResourceType, result).DeSerialize( item, new EpmContentDeSerializer.EpmContentDeserializerState { IsUpdateOperation = this.Update, Updatable = this.Updatable, Service = this.Service, PropertiesApplied = propertiesApplied }); } // Process the links in the entry. foreach (SyndicationLink link in item.Links) { string navigationPropertyName = UriUtil.GetNameFromAtomLinkRelationAttribute(link.RelationshipType); if (null == navigationPropertyName) { continue; } Deserializer.CheckForBindingInPutOperations(host.AstoriaHttpVerb); Debug.Assert(segmentInfo.TargetContainer != null, "segmentInfo.TargetContainer != null"); this.ApplyLink(link, segmentInfo.TargetContainer, currentResourceType, result, navigationPropertyName); } this.RecurseLeave(); return(result); }