/// <summary> /// Factory method to create the light-weight online service context (without fetching service document and metadata document which are known already) /// </summary> /// <param name="target">The target resource to be crawled</param> /// <param name="acceptHeaderValue">The accept header value defined in the Http header</param> /// <param name="serviceRoot">The URI pointing to the service document resource</param> /// <param name="serviceDocument">The content of service document</param> /// <param name="metadataDocument">The content of metadata document</param> /// <param name="jobId">The validation job identifier</param> /// <param name="maximumPayloadSize">The maximum number of bytes allowed to retrieve from the target resource</param> /// <param name="reqHeaders">Http headers sent as part of request</param> /// <returns>The constructed service context</returns> /// <exception cref="CrawlRuntimeException">Throws exception when target resource exceeds the maximum size allowed</exception> public static ServiceContext Create(Uri target, string acceptHeaderValue, Uri serviceRoot, string serviceDocument, string metadataDocument, Guid jobId, int maximumPayloadSize, IEnumerable <KeyValuePair <string, string> > reqHeaders, string category = "core") { Response response = WebHelper.Get(target, acceptHeaderValue, maximumPayloadSize, reqHeaders); ODataMetadataType odataMetadata = ServiceContextFactory.MapAcceptHeaderToMetadataType(acceptHeaderValue); var payloadFormat = response.ResponsePayload.GetFormatFromPayload(); var payloadType = response.ResponsePayload.GetTypeFromPayload(payloadFormat); string entityType = response.ResponsePayload.GetFullEntityType(payloadType, payloadFormat, metadataDocument); return(new ServiceContext(target, jobId, response.StatusCode, response.ResponseHeaders, response.ResponsePayload, entityType, serviceRoot, serviceDocument, metadataDocument, false, reqHeaders, odataMetadata, null, category)); }
/// <summary> /// Parse the metadata type of offline payload from header. /// </summary> /// <param name="offlineHeader">The string offline header.</param> /// <returns>The metadata type of offline payload.</returns> public static ODataMetadataType GetMetadataTypeFromOfflineHeader(this string offlineHeader) { ODataMetadataType metadata = ODataMetadataType.MinOnly; if (offlineHeader.Contains(Constants.V3AcceptHeaderJsonFullMetadata) || offlineHeader.Contains(Constants.V4AcceptHeaderJsonFullMetadata)) { metadata = ODataMetadataType.FullOnly; } return(metadata); }
/// <summary> /// Creates an instance of ServiceContext. /// </summary> /// <param name="destination">request Uri of the service context</param> /// <param name="jobId">Job identifier</param> /// <param name="statusCode">Http status code of the response</param> /// <param name="responseHttpHeaders">Header text of the response</param> /// <param name="responsePayload">Payload content of the response</param> /// <param name="entityType">Fully-qualified name of entity type the repsonse payload is about</param> /// <param name="serviceBaseUri">Uri of service document</param> /// <param name="serviceDocument">Content of service document</param> /// <param name="metadataDocument">Content of metadata document</param> /// <param name="offline">Flag of conetxt being offline(true) or live(false)</param> /// <param name="reqHeaders">Http headers used as part of header</param> /// <param name="odataMetadata">Odata metadata type</param> public ServiceContext( Uri destination, Guid jobId, HttpStatusCode?statusCode, string responseHttpHeaders, string responsePayload, string entityType, Uri serviceBaseUri, string serviceDocument, string metadataDocument, bool offline, IEnumerable <KeyValuePair <string, string> > reqHeaders, ODataMetadataType odataMetadata = ODataMetadataType.MinOnly, string jsonFullmetadataPayload = null, string category = "core") { if (destination == null) { throw new ArgumentNullException("destination"); } // TODO: uncomment this to enable uri canonicalization // this.Destination = destination.Canonicalize(); this.Destination = destination; this.DestinationBasePath = this.Destination.GetLeftPart(UriPartial.Path).TrimEnd('/'); AnnotationDVsManager.Instance(this.DestinationBasePath); if (!string.IsNullOrEmpty(this.DestinationBasePath)) { string lastLeg = this.DestinationBasePath.Substring(this.DestinationBasePath.LastIndexOf('/')); if (!string.IsNullOrEmpty(lastLeg)) { this.DestinationBaseLastSegment = lastLeg.TrimStart('/'); } } this.Projection = this.Destination.Query.IndexOf("$select=", StringComparison.OrdinalIgnoreCase) >= 0; this.JobId = jobId; this.HttpStatusCode = statusCode; this.ResponseHttpHeaders = responseHttpHeaders; this.OdataMetadataType = odataMetadata; this.JsonFullMetadataPayload = jsonFullmetadataPayload; this.MetadataDocument = metadataDocument; int test = responsePayload.Length; this.ResponsePayload = responsePayload; this.EntityTypeFullName = entityType; this.ServiceBaseUri = serviceBaseUri; this.ServiceDocument = serviceDocument; this.IsOffline = offline; this.RequestHeaders = reqHeaders; this.Category = category; this.ServiceType = ConformanceServiceType.ReadWrite; this.LevelTypes = new ConformanceLevelType[] { ConformanceLevelType.Minimal }; if (category.Contains(";")) { string[] array = category.Split(';'); this.Category = array[0]; this.ServiceType = (ConformanceServiceType)Enum.Parse(typeof(ConformanceServiceType), array[1]); if (array.Length > 2 && array[2].Contains(",")) { string[] levelArray = array[2].Split(','); this.LevelTypes = new ConformanceLevelType[levelArray.Length]; for (int i = 0; i < levelArray.Length; i++) { ConformanceLevelType level; if (Enum.TryParse(levelArray[i], out level)) { this.LevelTypes[i] = level; } } } } }
/// <summary> /// Filters rules based on odata metadata type /// </summary> /// <param name="rules">The collection of input rules</param> /// <param name="ODataMetadataType">OData metadata type</param> /// <returns>The subset of input rules that applies to the context</returns> private static IEnumerable<Rule> SelectRulesByMetadataFlag(this IEnumerable<Rule> rules, ODataMetadataType odataMetadataType) { return from r in rules where !r.OdataMetadataType.HasValue || r.OdataMetadataType.Value == odataMetadataType select r; }
/// <summary> /// Factory method to set up the OData Interop context based on uri, desired format and job id /// </summary> /// <param name="destination">uri string pointing to a OData service endpoint</param> /// <param name="format">format preference, could be either "atom" or "json" - default and falling back to atom</param> /// <param name="jobId">unique identifier to tag this context</param> /// <param name="maximumPayloadSize">the maximum number of bytes rule engine is willing to retrieve from the Uri provided</param> /// <param name="reqHeaders">Http headers sent as part of request</param> /// <returns>context object representing the interop request session</returns> public static ServiceContext Create(string destination, string format, Guid jobId, int maximumPayloadSize, IEnumerable <KeyValuePair <string, string> > reqHeaders, string category = "core") { Uri inputUri; Uri serviceBaseUri = null; string serviceDocument = null; string metadataDocument = null; string entityType = null; string jsonFullMetadataPayload = null; var serviceStatus = ServiceStatus.GetInstance(); if (string.IsNullOrEmpty(format)) { throw new ArgumentException(Resource.ArgumentNotNullOrEmpty, "format"); } try { if (destination.EndsWith(@"/")) { destination = destination.TrimEnd('/'); } inputUri = new Uri(destination); } catch (UriFormatException) { if (!destination.StartsWith(@"http://") && !destination.StartsWith(@"https://")) { inputUri = new Uri(SupportedScheme.SchemeHttp + "://" + destination); } else { inputUri = new Uri(Uri.EscapeUriString(destination)); } } if (!SupportedScheme.Instance.Contains(inputUri.Scheme)) { throw new ArgumentException( string.Format(CultureInfo.CurrentCulture, Resource.formatSchemeNotSupported, inputUri.Scheme), "destination"); } string acceptHeader = ServiceContextFactory.MapFormatToAcceptValue(format); ODataMetadataType odataMetadata = ServiceContextFactory.MapFormatToMetadataType(format); Response response = WebHelper.Get(inputUri, acceptHeader, maximumPayloadSize, reqHeaders); if (response.StatusCode == HttpStatusCode.NotFound) { return(null); } var payloadFormat = response.ResponsePayload.GetFormatFromPayload(); var payloadType = ContextHelper.GetPayloadType(response.ResponsePayload, payloadFormat, response.ResponseHeaders); switch (payloadType) { case PayloadType.ServiceDoc: serviceBaseUri = inputUri; serviceDocument = response.ResponsePayload; break; case PayloadType.Metadata: if (inputUri.AbsoluteUri.EndsWith(Constants.OptionMetadata, StringComparison.Ordinal)) { if (payloadFormat == PayloadFormat.JsonLight) { serviceBaseUri = new Uri(serviceStatus.RootURL); serviceDocument = serviceStatus.ServiceDocument; } else { serviceBaseUri = new Uri(inputUri.AbsoluteUri.Substring(0, inputUri.AbsoluteUri.Length - Constants.OptionMetadata.Length)); var respSvcDoc = WebHelper.Get(serviceBaseUri, acceptHeader, maximumPayloadSize, reqHeaders); serviceDocument = respSvcDoc.ResponsePayload; } } break; default: if (payloadType.IsValidPayload()) { string fullPath = inputUri.GetLeftPart(UriPartial.Path).TrimEnd('/'); var uriPath = new Uri(fullPath); Uri baseUri; Response serviceDoc; if (ServiceContextFactory.TryGetServiceDocument(maximumPayloadSize, uriPath, acceptHeader, uriPath.AbsoluteUri == fullPath, out baseUri, out serviceDoc, reqHeaders)) { serviceBaseUri = baseUri; serviceDocument = serviceDoc.ResponsePayload; } } break; } if (payloadType == PayloadType.Metadata) { metadataDocument = response.ResponsePayload; } else { if (serviceBaseUri != null) { if (payloadFormat == PayloadFormat.JsonLight && payloadType == PayloadType.ServiceDoc) { metadataDocument = serviceStatus.MetadataDocument; } else { try { string metadataURL = serviceBaseUri.AbsoluteUri.EndsWith(@"/") ? Constants.OptionMetadata.TrimStart('/') : Constants.OptionMetadata; var responseMetadata = WebHelper.Get(new Uri(serviceBaseUri.AbsoluteUri + metadataURL), null, maximumPayloadSize, reqHeaders); if (responseMetadata != null) { metadataDocument = responseMetadata.ResponsePayload; } } catch (OversizedPayloadException) { // do nothing } } } } if (payloadFormat == PayloadFormat.JsonLight) { try { // Specify full metadata accept header string acceptHeaderOfFullMetadata = string.Empty; if (acceptHeader.Equals(Constants.V3AcceptHeaderJsonFullMetadata) || acceptHeader.Equals(Constants.V3AcceptHeaderJsonMinimalMetadata) || acceptHeader.Equals(Constants.V3AcceptHeaderJsonNoMetadata)) { acceptHeaderOfFullMetadata = Constants.V3AcceptHeaderJsonFullMetadata; } else { acceptHeaderOfFullMetadata = Constants.V4AcceptHeaderJsonFullMetadata; } // Send full metadata request and get full metadata response. var responseFullMetadata = WebHelper.Get(inputUri, acceptHeaderOfFullMetadata, maximumPayloadSize, reqHeaders); if (responseFullMetadata != null) { jsonFullMetadataPayload = responseFullMetadata.ResponsePayload; entityType = jsonFullMetadataPayload.GetFullEntityType(payloadType, payloadFormat, metadataDocument); } } catch (OversizedPayloadException) { // do nothing } } else { entityType = response.ResponsePayload.GetFullEntityType(payloadType, payloadFormat, metadataDocument); } return(new ServiceContext(inputUri, jobId, response.StatusCode, response.ResponseHeaders, response.ResponsePayload, entityType, serviceBaseUri, serviceDocument, metadataDocument, false, reqHeaders, odataMetadata, jsonFullMetadataPayload, category)); }
/// <summary> /// Creates an offline service context with specified job id from payload context and metadata document. /// </summary> /// <param name="payload">The payload context</param> /// <param name="metadata">The metadata document</param> /// <param name="jobId">The job id</param> /// <param name="respHeaders">The optional Http response headers</param> /// <param name="reqHeaders">The request headers</param> /// <returns>Service context object which represents the offline interop validation session</returns> public static ServiceContext Create(string payload, string metadata, Guid jobId, string respHeaders, IEnumerable <KeyValuePair <string, string> > reqHeaders) { if (string.IsNullOrEmpty(payload) && string.IsNullOrEmpty(metadata)) { throw new ArgumentException("invalid parameters"); } if (string.IsNullOrEmpty(payload)) { payload = metadata; metadata = null; } Uri inputUri = new Uri(Constants.DefaultOfflineTarget); string entityType = null; Uri serviceBaseUri = null; string serviceDocument = null; string metadataDocument = null; var payloadFormat = payload.GetFormatFromPayload(); var payloadType = payload.GetTypeFromPayload(payloadFormat); ODataMetadataType metadataType = ServiceContextFactory.GetMetadataTypeFromOfflineHeader(respHeaders); if (payloadType != PayloadType.Metadata && !string.IsNullOrEmpty(metadata)) { var metaFormat = metadata.GetFormatFromPayload(); if (metaFormat == PayloadFormat.Xml) { var metaType = metadata.GetTypeFromPayload(metaFormat); if (metaType == PayloadType.Metadata) { //do sanity check to ensure a matching metadata, should payload be a feed or an entry if (IsMetadataMacthing(payload, metadata, payloadFormat, payloadType)) { metadataDocument = metadata; } } } } switch (payloadType) { case PayloadType.ServiceDoc: serviceDocument = payload; if (payloadFormat == PayloadFormat.Xml || payloadFormat == PayloadFormat.Atom) { XElement payloadXml = XElement.Parse(payload); XNamespace ns = "http://www.w3.org/XML/1998/namespace"; // xmlns:xml definition according to http://www.w3.org/TR/REC-xml-names/ var xmlBase = payloadXml.Attribute(ns + "base"); // rfc5023: it MAY have an "xml:base" attribute ... serving as the base URI if (xmlBase != null && !string.IsNullOrEmpty(xmlBase.Value)) { inputUri = new Uri(xmlBase.Value); } } break; case PayloadType.Metadata: serviceDocument = null; metadataDocument = payload; break; case PayloadType.Error: break; case PayloadType.Feed: case PayloadType.Entry: { entityType = payload.GetFullEntityType(payloadType, payloadFormat, metadataDocument); string shortEntityTypeName = entityType.GetLastSegment(); string target = payload.GetIdFromFeedOrEntry(payloadFormat); if (!string.IsNullOrEmpty(target)) { var projectedProperties = payload.GetProjectedPropertiesFromFeedOrEntry(payloadFormat, metadataDocument, shortEntityTypeName); if (projectedProperties != null && projectedProperties.Any()) { var opt = string.Join(",", projectedProperties); try { inputUri = new Uri(target + "?$select=" + opt); } catch (UriFormatException) { //do nothing } } else { try { inputUri = new Uri(target); } catch (UriFormatException) { //do nothing } } } } break; } return(new ServiceContext(inputUri, jobId, null, respHeaders, payload, entityType, serviceBaseUri, serviceDocument, metadataDocument, true, reqHeaders, metadataType)); }
/// <summary> /// Creates an instance of ServiceContext. /// </summary> /// <param name="destination">request Uri of the service context</param> /// <param name="jobId">Job identifier</param> /// <param name="statusCode">Http status code of the response</param> /// <param name="responseHttpHeaders">Header text of the response</param> /// <param name="responsePayload">Payload content of the response</param> /// <param name="entityType">Fully-qualified name of entity type the repsonse payload is about</param> /// <param name="serviceBaseUri">Uri of service document</param> /// <param name="serviceDocument">Content of service document</param> /// <param name="metadataDocument">Content of metadata document</param> /// <param name="offline">Flag of conetxt being offline(true) or live(false)</param> /// <param name="reqHeaders">Http headers used as part of header</param> /// <param name="odataMetadata">Odata metadata type</param> public ServiceContext( Uri destination, Guid jobId, HttpStatusCode? statusCode, string responseHttpHeaders, string responsePayload, string entityType, Uri serviceBaseUri, string serviceDocument, string metadataDocument, bool offline, IEnumerable<KeyValuePair<string, string>> reqHeaders, ODataMetadataType odataMetadata = ODataMetadataType.MinOnly, string jsonFullmetadataPayload = null, string category = "core") { if (destination == null) { throw new ArgumentNullException("destination"); } // TODO: uncomment this to enable uri canonicalization // this.Destination = destination.Canonicalize(); this.Destination = destination; this.DestinationBasePath = this.Destination.GetLeftPart(UriPartial.Path).TrimEnd('/'); AnnotationDVsManager.Instance(this.DestinationBasePath); if (!string.IsNullOrEmpty(this.DestinationBasePath)) { string lastLeg = this.DestinationBasePath.Substring(this.DestinationBasePath.LastIndexOf('/')); if (!string.IsNullOrEmpty(lastLeg)) { this.DestinationBaseLastSegment = lastLeg.TrimStart('/'); } } this.Projection = this.Destination.Query.IndexOf("$select=", StringComparison.OrdinalIgnoreCase) >= 0; this.JobId = jobId; this.HttpStatusCode = statusCode; this.ResponseHttpHeaders = responseHttpHeaders; this.OdataMetadataType = odataMetadata; this.JsonFullMetadataPayload = jsonFullmetadataPayload; this.MetadataDocument = metadataDocument; this.ResponsePayload = responsePayload; this.EntityTypeFullName = entityType; this.ServiceBaseUri = serviceBaseUri; this.ServiceDocument = serviceDocument; this.IsOffline = offline; this.RequestHeaders = reqHeaders; this.Category = category; this.ServiceType = ConformanceServiceType.ReadWrite; this.LevelTypes = new ConformanceLevelType[] { ConformanceLevelType.Minimal }; if (category.Contains(";")) { string[] array = category.Split(';'); this.Category = array[0]; this.ServiceType = (ConformanceServiceType)Enum.Parse(typeof(ConformanceServiceType), array[1]); if (array.Length > 2 && array[2].Contains(",")) { string[] levelArray = array[2].Split(','); this.LevelTypes = new ConformanceLevelType[levelArray.Length]; for (int i = 0; i < levelArray.Length; i++) { ConformanceLevelType level; if (Enum.TryParse(levelArray[i], out level)) { this.LevelTypes[i] = level; } } } } }
/// <summary> /// Filters rules based on odata metadata type /// </summary> /// <param name="rules">The collection of input rules</param> /// <param name="ODataMetadataType">OData metadata type</param> /// <returns>The subset of input rules that applies to the context</returns> private static IEnumerable <Rule> SelectRulesByMetadataFlag(this IEnumerable <Rule> rules, ODataMetadataType odataMetadataType) { return(from r in rules where !r.OdataMetadataType.HasValue || r.OdataMetadataType.Value == odataMetadataType select r); }