// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.Contracts; using System.Linq; using System.Net.Http.Headers; namespace System.Net.Http { /// /// Extension methods to provide convenience methods for finding items /// within a collection. /// [EditorBrowsable(EditorBrowsableState.Never)] public static class HttpContentCollectionExtensions { private const string ContentID = @"Content-ID"; /// /// Returns the first in a sequence that has a header field /// with a property equal to . /// /// The contents to evaluate /// The disposition type to look for. /// The first in the sequence with a matching disposition type. public static HttpContent FirstDispositionType(this IEnumerable contents, string dispositionType) { if (contents == null) { throw new ArgumentNullException("contents"); } if (String.IsNullOrWhiteSpace(dispositionType)) { throw new ArgumentNullException("dispositionType"); } return contents.First((item) => { return HttpContentCollectionExtensions.FirstDispositionType(item, dispositionType); }); } /// /// Returns the first in a sequence that has a header field /// with a property equal to . /// /// The contents to evaluate /// The disposition type to look for. /// null if source is empty or if no element matches; otherwise the first in /// the sequence with a matching disposition type. public static HttpContent FirstDispositionTypeOrDefault(this IEnumerable contents, string dispositionType) { if (contents == null) { throw new ArgumentNullException("contents"); } if (String.IsNullOrWhiteSpace(dispositionType)) { throw new ArgumentNullException("dispositionType"); } return contents.FirstOrDefault((item) => { return HttpContentCollectionExtensions.FirstDispositionType(item, dispositionType); }); } /// /// Returns the first in a sequence that has a header field /// with a property equal to . /// /// The contents to evaluate /// The disposition name to look for. /// The first in the sequence with a matching disposition name. public static HttpContent FirstDispositionName(this IEnumerable contents, string dispositionName) { if (contents == null) { throw new ArgumentNullException("contents"); } if (String.IsNullOrWhiteSpace(dispositionName)) { throw new ArgumentNullException("dispositionName"); } return contents.First((item) => { return HttpContentCollectionExtensions.FirstDispositionName(item, dispositionName); }); } /// /// Returns the first in a sequence that has a header field /// with a property equal to . /// /// The contents to evaluate /// The disposition name to look for. /// null if source is empty or if no element matches; otherwise the first in /// the sequence with a matching disposition name. public static HttpContent FirstDispositionNameOrDefault(this IEnumerable contents, string dispositionName) { if (contents == null) { throw new ArgumentNullException("contents"); } if (String.IsNullOrWhiteSpace(dispositionName)) { throw new ArgumentNullException("dispositionName"); } return contents.FirstOrDefault((item) => { return HttpContentCollectionExtensions.FirstDispositionName(item, dispositionName); }); } /// /// Returns the start multipart body part. The start is used to identify the main body /// in multipart/related content (see RFC 2387). /// /// The contents to evaluate. /// The start value to look for. /// A match is found if a has a Content-ID /// header field with the given value. /// The first in the sequence with a matching value. public static HttpContent FirstStart(this IEnumerable contents, string start) { if (contents == null) { throw new ArgumentNullException("contents"); } if (String.IsNullOrWhiteSpace(start)) { throw new ArgumentNullException("start"); } return contents.First((item) => { return HttpContentCollectionExtensions.FirstStart(item, start); }); } /// /// Returns the first in a sequence that has a header field /// parameter equal to . This parameter is typically used in connection with multipart/related /// content (see RFC 2387). /// /// The contents to evaluate. /// The start value to look for. A match is found if a has a Content-ID /// header field with the given value. /// null if source is empty or if no element matches; otherwise the first in /// the sequence with a matching value. public static HttpContent FirstStartOrDefault(this IEnumerable contents, string start) { if (contents == null) { throw new ArgumentNullException("contents"); } if (String.IsNullOrWhiteSpace(start)) { throw new ArgumentNullException("start"); } return contents.FirstOrDefault((item) => { return HttpContentCollectionExtensions.FirstStart(item, start); }); } /// /// Returns all instances of in a sequence that has a header field /// with a property equal to the provided . /// /// The content to evaluate /// The media type to look for. /// null if source is empty or if no element matches; otherwise the first in /// the sequence with a matching media type. public static IEnumerable FindAllContentType(this IEnumerable contents, string contentType) { if (String.IsNullOrWhiteSpace(contentType)) { throw new ArgumentNullException("contentType"); } return HttpContentCollectionExtensions.FindAllContentType(contents, new MediaTypeHeaderValue(contentType)); } /// /// Returns all instances of in a sequence that has a header field /// with a property equal to the provided . /// /// The content to evaluate /// The media type to look for. /// null if source is empty or if no element matches; otherwise the first in /// the sequence with a matching media type. public static IEnumerable FindAllContentType(this IEnumerable contents, MediaTypeHeaderValue contentType) { if (contents == null) { throw new ArgumentNullException("contents"); } if (contentType == null) { throw new ArgumentNullException("contentType"); } return contents.Where((item) => { return HttpContentCollectionExtensions.FindAllContentType(item, contentType); }); } private static bool FirstStart(HttpContent content, string start) { Contract.Assert(content != null, "content cannot be null"); Contract.Assert(start != null, "start cannot be null"); if (content.Headers != null) { IEnumerable values; if (content.Headers.TryGetValues(ContentID, out values)) { return String.Equals( FormattingUtilities.UnquoteToken(values.ElementAt(0)), FormattingUtilities.UnquoteToken(start), StringComparison.OrdinalIgnoreCase); } } return false; } private static bool FirstDispositionType(HttpContent content, string dispositionType) { Contract.Assert(content != null, "content cannot be null"); Contract.Assert(dispositionType != null, "dispositionType cannot be null"); return content.Headers != null && content.Headers.ContentDisposition != null && String.Equals( FormattingUtilities.UnquoteToken(content.Headers.ContentDisposition.DispositionType), FormattingUtilities.UnquoteToken(dispositionType), StringComparison.OrdinalIgnoreCase); } private static bool FirstDispositionName(HttpContent content, string dispositionName) { Contract.Assert(content != null, "content cannot be null"); Contract.Assert(dispositionName != null, "dispositionName cannot be null"); return content.Headers != null && content.Headers.ContentDisposition != null && String.Equals( FormattingUtilities.UnquoteToken(content.Headers.ContentDisposition.Name), FormattingUtilities.UnquoteToken(dispositionName), StringComparison.OrdinalIgnoreCase); } private static bool FindAllContentType(HttpContent content, MediaTypeHeaderValue contentType) { Contract.Assert(content != null, "content cannot be null"); Contract.Assert(contentType != null, "contentType cannot be null"); return content.Headers != null && content.Headers.ContentType != null && String.Equals( content.Headers.ContentType.MediaType, contentType.MediaType, StringComparison.OrdinalIgnoreCase); } } }