/// <summary> /// Parses the entity identifier. /// </summary> /// <returns>EntityIdSegment contained absolute Uri representing $id</returns> public EntityIdSegment ParseEntityId() { if (this.entityIdSegment != null) { return(this.entityIdSegment); } InitQueryOptionDic(); string idQuery = null; if (!this.Resolver.EnableCaseInsensitive) { if (!this.queryOptionDic.TryGetValue(UriQueryConstants.IdQueryOption, out idQuery)) { return(null); } } else { var list = this.queryOptionDic .Where(pair => string.Equals(UriQueryConstants.IdQueryOption, pair.Key, StringComparison.OrdinalIgnoreCase)) .ToList(); if (list.Count == 0) { return(null); } else if (list.Count == 1) { idQuery = list.First().Value; } else { throw new ODataException(Strings.QueryOptionUtils_QueryParameterMustBeSpecifiedOnce(UriQueryConstants.IdQueryOption)); } } Uri idUri = new Uri(idQuery, UriKind.RelativeOrAbsolute); if (!idUri.IsAbsoluteUri) { if (!this.uri.IsAbsoluteUri) { Uri baseUri = UriUtils.CreateMockAbsoluteUri(); Uri c = new Uri(UriUtils.CreateMockAbsoluteUri(this.uri), idUri); idUri = baseUri.MakeRelativeUri(c); } else { idUri = new Uri(this.uri, idUri); } } this.entityIdSegment = new EntityIdSegment(idUri); return(this.entityIdSegment); }
/// <summary> /// Build an ODataUriParser /// </summary> /// <param name="model">Model to use for metadata binding.</param> /// <param name="relativeUri">Relative URI to be parsed.</param> /// <param name="container">The optional dependency injection container to get related services for URI parsing.</param> public ODataUriParser(IEdmModel model, Uri relativeUri, IServiceProvider container) { ExceptionUtils.CheckArgumentNotNull(relativeUri, "relativeUri"); if (relativeUri.IsAbsoluteUri) { throw new ODataException(Strings.UriParser_RelativeUriMustBeRelative); } this.configuration = new ODataUriParserConfiguration(model, container); this.uri = relativeUri; this.queryOptions = QueryOptionUtils.ParseQueryOptions(UriUtils.CreateMockAbsoluteUri(this.uri)); }
/// <summary> /// Returns list of segments in the specified path (eg: /abc/pqr -> abc, pqr). /// </summary> /// <param name="fullUri">The full URI of the request.</param> /// <param name="serviceBaseUri">The service base URI for the request.</param> /// <returns>List of unescaped segments.</returns> public virtual ICollection <string> ParsePathIntoSegments(Uri fullUri, Uri serviceBaseUri) { if (serviceBaseUri == null) { Debug.Assert(!fullUri.IsAbsoluteUri, "fullUri must be relative Uri"); serviceBaseUri = UriUtils.CreateMockAbsoluteUri(); fullUri = UriUtils.CreateMockAbsoluteUri(fullUri); } if (!UriUtils.UriInvariantInsensitiveIsBaseOf(serviceBaseUri, fullUri)) { throw new ODataException(Strings.UriQueryPathParser_RequestUriDoesNotHaveTheCorrectBaseUri(fullUri, serviceBaseUri)); } // COMPAT 29: Slash in key lookup breaks URI parser // TODO: The code below has a bug that / in the named values will be considered a segment separator // so for example /Customers('abc/pqr') is treated as two segments, which is wrong. try { Uri uri = fullUri; int numberOfSegmentsToSkip = 0; // Skip over the base URI segments #if !ORCAS // need to calculate the number of segments to skip in the full // uri (so that we can skip over http://blah.com/basePath for example, // get only the odata specific parts of the path). // // because of differences in system.uri between portable lib and // the desktop library, we need to handle this differently. // in this case we get the number of segments to skip as simply // then number of tokens in the serviceBaseUri split on slash, with // length - 1 since its a zero based array. numberOfSegmentsToSkip = serviceBaseUri.AbsolutePath.Split('/').Length - 1; string[] uriSegments = uri.AbsolutePath.Split('/'); #else numberOfSegmentsToSkip = serviceBaseUri.Segments.Length; string[] uriSegments = uri.Segments; #endif int escapedStart = -1; List <string> segments = new List <string>(); for (int i = numberOfSegmentsToSkip; i < uriSegments.Length; i++) { string segment = uriSegments[i]; // Skip the empty segment or the "/" segment if (segment.Length == 0 || segment == "/") { continue; } // When we use "uri.Segments" to get the segments, // The segment element includes the "/", we should remove that. if (segment[segment.Length - 1] == '/') { segment = segment.Substring(0, segment.Length - 1); } if (segments.Count == this.maxSegments) { throw new ODataException(Strings.UriQueryPathParser_TooManySegments); } // Handle the "root...::/{xyz}" if (segment.Length >= 2 && segment.EndsWith("::", StringComparison.Ordinal)) { // It should be the terminal of the provious escape segment and the start of next escape semgent. // Otherwise, it's an invalid Uri. if (escapedStart == -1) { throw new ODataException(Strings.UriQueryPathParser_InvalidEscapeUri(segment)); } else { string value = String.Join("/", uriSegments, escapedStart, i - escapedStart + 1); segments.Add(":" + value.Substring(0, value.Length - 1));// because the last one has "::", remove one. escapedStart = i + 1; } } else if (segment.Length >= 1 && segment[segment.Length - 1] == ':') { // root:/{abc}.... if (escapedStart == -1) { if (segment != ":") { segments.Add(segment.Substring(0, segment.Length - 1));// remove the last ':' } escapedStart = i + 1; } else { // root:/{abc}:.... string escapedSegment = ":" + String.Join("/", uriSegments, escapedStart, i - escapedStart + 1); // the last has one ":"; segments.Add(escapedSegment); escapedStart = -1; } } else { // if we didn't find a starting escape, the current segment is normal segment, accept it. // otherwise, it's part of the escape, skip it and process it when we find the ending delimiter. if (escapedStart == -1) { segments.Add(Uri.UnescapeDataString(segment)); } } } if (escapedStart != -1 && escapedStart < uriSegments.Length) { string escapedSegment = ":" + String.Join("/", uriSegments, escapedStart, uriSegments.Length - escapedStart); segments.Add(escapedSegment); // We should not use "segments.Add(Uri.UnescapeDataString(escapedSegment));" to keep the orignal string. } return(segments.ToArray()); } #if !ORCAS catch (FormatException uriFormatException) #else catch (UriFormatException uriFormatException) #endif { throw new ODataException(Strings.UriQueryPathParser_SyntaxError, uriFormatException); } }
/// <summary> /// Returns list of segments in the specified path (eg: /abc/pqr -> abc, pqr). /// </summary> /// <param name="fullUri">The full URI of the request.</param> /// <param name="serviceBaseUri">The service base URI for the request.</param> /// <returns>List of unescaped segments.</returns> internal ICollection <string> ParsePathIntoSegments(Uri fullUri, Uri serviceBaseUri) { if (serviceBaseUri == null) { Debug.Assert(!fullUri.IsAbsoluteUri, "fullUri must be relative Uri"); serviceBaseUri = UriUtils.CreateMockAbsoluteUri(); fullUri = UriUtils.CreateMockAbsoluteUri(fullUri); } if (!UriUtils.UriInvariantInsensitiveIsBaseOf(serviceBaseUri, fullUri)) { throw new ODataException(Strings.UriQueryPathParser_RequestUriDoesNotHaveTheCorrectBaseUri(fullUri, serviceBaseUri)); } try { Uri uri = fullUri; int numberOfSegmentsToSkip = 0; // Skip over the base URI segments #if !ORCAS // need to calculate the number of segments to skip in the full // uri (so that we can skip over http://blah.com/basePath for example, // get only the odata specific parts of the path). // // because of differences in system.uri between portable lib and // the desktop library, we need to handle this differently. // in this case we get the number of segments to skip as simply // then number of tokens in the serviceBaseUri split on slash, with // length - 1 since its a zero based array. numberOfSegmentsToSkip = serviceBaseUri.AbsolutePath.Split('/').Length - 1; string[] uriSegments = uri.AbsolutePath.Split('/'); #else numberOfSegmentsToSkip = serviceBaseUri.Segments.Length; string[] uriSegments = uri.Segments; #endif List <string> segments = new List <string>(); for (int i = numberOfSegmentsToSkip; i < uriSegments.Length; i++) { string segment = uriSegments[i]; if (segment.Length != 0 && segment != "/") { if (segment[segment.Length - 1] == '/') { segment = segment.Substring(0, segment.Length - 1); } if (segments.Count == this.maxSegments) { throw new ODataException(Strings.UriQueryPathParser_TooManySegments); } segments.Add(Uri.UnescapeDataString(segment)); } } return(segments.ToArray()); } #if !ORCAS catch (FormatException uriFormatException) #else catch (UriFormatException uriFormatException) #endif { throw new ODataException(Strings.UriQueryPathParser_SyntaxError, uriFormatException); } }
/// <summary> /// Returns list of segments in the specified path (eg: /abc/pqr -> abc, pqr). /// </summary> /// <param name="fullUri">The full URI of the request.</param> /// <param name="serviceBaseUri">The service base URI for the request.</param> /// <returns>List of unescaped segments.</returns> public virtual ICollection <string> ParsePathIntoSegments(Uri fullUri, Uri serviceBaseUri) { if (serviceBaseUri == null) { Debug.Assert(!fullUri.IsAbsoluteUri, "fullUri must be relative Uri"); serviceBaseUri = UriUtils.CreateMockAbsoluteUri(); fullUri = UriUtils.CreateMockAbsoluteUri(fullUri); } if (!UriUtils.UriInvariantInsensitiveIsBaseOf(serviceBaseUri, fullUri)) { throw new ODataException(Strings.UriQueryPathParser_RequestUriDoesNotHaveTheCorrectBaseUri(fullUri, serviceBaseUri)); } // COMPAT 29: Slash in key lookup breaks URI parser // TODO: The code below has a bug that / in the named values will be considered a segment separator // so for example /Customers('abc/pqr') is treated as two segments, which is wrong. try { Uri uri = fullUri; int numberOfSegmentsToSkip = 0; // Skip over the base URI segments // need to calculate the number of segments to skip in the full // uri (so that we can skip over http://blah.com/basePath for example, // get only the odata specific parts of the path). // // because of differences in system.uri between portable lib and // the desktop library, we need to handle this differently. // in this case we get the number of segments to skip as simply // then number of tokens in the serviceBaseUri split on slash, with // length - 1 since its a zero based array. numberOfSegmentsToSkip = serviceBaseUri.AbsolutePath.Split('/').Length - 1; string[] uriSegments = uri.AbsolutePath.Split('/'); List <string> segments = new List <string>(); for (int i = numberOfSegmentsToSkip; i < uriSegments.Length; i++) { string segment = uriSegments[i]; // Skip the empty segment or the "/" segment if (segment.Length == 0 || segment == "/") { continue; } // When we use "uri.Segments" to get the segments, // The segment element includes the "/", we should remove that. if (segment[segment.Length - 1] == '/') { segment = segment.Substring(0, segment.Length - 1); } if (segments.Count == this.maxSegments) { throw new ODataException(Strings.UriQueryPathParser_TooManySegments); } segments.Add(Uri.UnescapeDataString(segment)); } return(segments.ToArray()); } catch (FormatException uriFormatException) { throw new ODataException(Strings.UriQueryPathParser_SyntaxError, uriFormatException); } }