/// <summary>
        /// Selects the <see cref="IOutputFormatter"/> to write the response based on the content type values
        /// present in <paramref name="sortedAcceptableContentTypes"/> and <paramref name="possibleOutputContentTypes"/>.
        /// </summary>
        /// <param name="formatterContext">The <see cref="OutputFormatterWriteContext"/>.</param>
        /// <param name="formatters">
        /// The list of <see cref="IOutputFormatter"/> instances to consider.
        /// </param>
        /// <param name="sortedAcceptableContentTypes">
        /// The ordered content types from the <c>Accept</c> header, sorted by descending q-value.
        /// </param>
        /// <param name="possibleOutputContentTypes">
        /// The ordered content types from <see cref="ObjectResult.ContentTypes"/> in descending priority order.
        /// </param>
        /// <returns>
        /// The selected <see cref="IOutputFormatter"/> or <c>null</c> if no formatter can write the response.
        /// </returns>
        protected virtual IOutputFormatter SelectFormatterUsingSortedAcceptHeadersAndContentTypes(
            OutputFormatterWriteContext formatterContext,
            IList <IOutputFormatter> formatters,
            IList <MediaTypeSegmentWithQuality> sortedAcceptableContentTypes,
            MediaTypeCollection possibleOutputContentTypes)
        {
            for (var i = 0; i < sortedAcceptableContentTypes.Count; i++)
            {
                var acceptableContentType = new MediaType(sortedAcceptableContentTypes[i].MediaType);
                for (var j = 0; j < possibleOutputContentTypes.Count; j++)
                {
                    var candidateContentType = new MediaType(possibleOutputContentTypes[j]);
                    if (candidateContentType.IsSubsetOf(acceptableContentType))
                    {
                        for (var k = 0; k < formatters.Count; k++)
                        {
                            var formatter = formatters[k];
                            formatterContext.ContentType = new StringSegment(possibleOutputContentTypes[j]);
                            if (formatter.CanWriteResult(formatterContext))
                            {
                                return(formatter);
                            }
                        }
                    }
                }
            }

            return(null);
        }
Ejemplo n.º 2
0
        public IActionResult GetBookForAuthor(Guid authorId, Guid id,
                                              [FromHeader(Name = Headers.Accept)] string mediaType)
        {
            if (!_libraryRepository.AuthorExists(authorId))
            {
                return(NotFound());
            }
            var loadedBook = _libraryRepository.GetBookForAuthor(authorId, id);

            if (loadedBook == null)
            {
                return(NotFound());
            }
            var currentMediaType = new MediaType(mediaType);
            var includeLinks     = currentMediaType.IsSubsetOf(VendorMediaType.HateoasLinksMediaType);

            var book = Mapper.Map <Book>(loadedBook);

            if (includeLinks)
            {
                return(Ok(CreateLinks(book)));
            }
            else
            {
                return(Ok(book));
            }
        }
Ejemplo n.º 3
0
        private bool isFileAllowedType(IFormFile file)
        {
            if (FileTypes.Length == 0)
            {
                return(true);
            }

            string fileType = file.ContentType.ToLower();

            var parsedContentType = new MediaType(fileType);

            for (var i = 0; i < FileTypes.Length; i++)
            {
                // For supported media types that are not wildcard patterns, confirm that this formatter
                // supports a more specific media type than requested e.g. OK if "text/*" requested and
                // formatter supports "text/plain".
                // contentType is typically what we got in an Accept header.
                var supportedMediaType = new MediaType(FileTypes[i]);
                if (parsedContentType.IsSubsetOf(supportedMediaType))
                {
                    return(true);
                }
            }

            return(false);
        }
        /// <summary>
        /// Tests if the media type qualifies for XML deserialization
        /// </summary>
        /// <param name="mediaType">The media type to test</param>
        /// <returns><see langword="true"/> when the media type might be an XML type</returns>
        public static bool IsXml(string mediaType)
        {
            var contentType = new MediaType(mediaType);
            var isXml       = XmlMediaTypes.Any(x => contentType.IsSubsetOf(x));

            return(isXml);
        }
        public IActionResult CreateAuthor([FromBody] CreateAuthor author, [FromHeader(Name = Headers.Accept)] string mediaType)
        {
            if (author == null)
            {
                return(BadRequest());
            }

            var newAuthor = Mapper.Map <Entities.Author>(author);

            _repo.AddAuthor(newAuthor);
            if (!_repo.Save())
            {
                throw new Exception("Failed to Create new author");
            }
            var createdAuthor = Mapper.Map <Author>(newAuthor);

            var currentMediaType = new MediaType(mediaType);

            var includeLinks = currentMediaType.IsSubsetOf(VendorMediaType.HateoasLinksMediaType);

            if (includeLinks)
            {
                var links = CreateLinks(createdAuthor.Id, null);

                var linkedResourceToReturn = createdAuthor.ShapeData(null) as IDictionary <string, object>;
                linkedResourceToReturn.Add("links", links);


                return(CreatedAtRoute(nameof(GetAuthor), new { id = linkedResourceToReturn[nameof(Author.Id)] }, linkedResourceToReturn));
            }
            return(CreatedAtRoute(nameof(GetAuthor), new { id = createdAuthor.Id }, createdAuthor));
        }
        public IActionResult GetAuthor(Guid id, [FromQuery] string fields, [FromHeader(Name = Headers.Accept)] string mediaType)
        {
            if (!_typeHelperService.TypeHasProperties <Author>(fields))
            {
                return(BadRequest());
            }
            var currentMediaType = new MediaType(mediaType);

            var includeLinks = currentMediaType.IsSubsetOf(VendorMediaType.HateoasLinksMediaType);

            var author = _repo.GetAuthor(id);

            if (author == null)
            {
                return(NotFound());
            }

            var result = Mapper.Map <Author>(author);

            if (includeLinks)
            {
                var links = CreateLinks(id, fields);
                var linkedResourceToReturn = result.ShapeData(fields) as IDictionary <string, object>;
                linkedResourceToReturn.Add("links", links);
                return(Ok(linkedResourceToReturn));
            }
            else
            {
                return(Ok(result));
            }
        }
Ejemplo n.º 7
0
    /// <inheritdoc />
    public virtual IReadOnlyList <string>?GetSupportedContentTypes(
        string contentType,
        Type objectType)
    {
        if (SupportedMediaTypes.Count == 0)
        {
            var message = Resources.FormatFormatter_NoMediaTypes(
                GetType().FullName,
                nameof(SupportedMediaTypes));

            throw new InvalidOperationException(message);
        }

        if (!CanWriteType(objectType))
        {
            return(null);
        }

        List <string>?mediaTypes = null;

        var parsedContentType = contentType != null ? new MediaType(contentType) : default(MediaType);

        foreach (var mediaType in SupportedMediaTypes)
        {
            var parsedMediaType = new MediaType(mediaType);
            if (parsedMediaType.HasWildcard)
            {
                // For supported media types that are wildcard patterns, confirm that the requested
                // media type satisfies the wildcard pattern (e.g., if "text/entity+json;v=2" requested
                // and formatter supports "text/*+json").
                // Treat contentType like it came from a [Produces] attribute.
                if (contentType != null && parsedContentType.IsSubsetOf(parsedMediaType))
                {
                    if (mediaTypes == null)
                    {
                        mediaTypes = new List <string>(SupportedMediaTypes.Count);
                    }

                    mediaTypes.Add(contentType);
                }
            }
            else
            {
                // Confirm this formatter supports a more specific media type than requested e.g. OK if "text/*"
                // requested and formatter supports "text/plain". Treat contentType like it came from an Accept header.
                if (contentType == null || parsedMediaType.IsSubsetOf(parsedContentType))
                {
                    if (mediaTypes == null)
                    {
                        mediaTypes = new List <string>(SupportedMediaTypes.Count);
                    }

                    mediaTypes.Add(mediaType);
                }
            }
        }

        return(mediaTypes);
    }
        public IActionResult GetAuthors([FromQuery] AuthorsResourceParameters parameters,
                                        [FromHeader(Name = Headers.Accept)] string mediaType)
        {
            if (!_propertyMappingService.ValidMappingExistsFor <Author, Entities.Author>(parameters.OrderBy))
            {
                return(BadRequest());
            }

            if (!_typeHelperService.TypeHasProperties <Author>(parameters.Fields))
            {
                return(BadRequest());
            }


            var authors = _repo.GetAuthors(parameters);

            var currentMediaType = new MediaType(mediaType);
            var includeLinks     = currentMediaType.IsSubsetOf(VendorMediaType.HateoasLinksMediaType);
            var prev             = authors.HasPrevious ? CreateAuthorsResourceUri(parameters, ResourceUriType.Previous) : null;
            var next             = authors.HasNext ? CreateAuthorsResourceUri(parameters, ResourceUriType.Next) : null;

            var result = Mapper.Map <IEnumerable <Author> >(authors);

            var pagination = new Pagination()
            {
                IncludeLinks     = !includeLinks,
                TotalCount       = authors.TotalCount,
                PageSize         = authors.PageSize,
                CurrentPage      = authors.CurrentPage,
                TotalPages       = authors.TotalPages,
                NextPageLink     = next,
                PreviousPageLink = prev,
            };

            Pagination.AddHeader(Response, pagination);

            if (includeLinks)
            {
                var links = CreateLinks(parameters, authors.HasNext, authors.HasPrevious);

                var shapedAuthors = result.ShapeData(parameters.Fields);

                var shapedAuthorsWithLinks = shapedAuthors.Select(a =>
                {
                    var authorDictionary = a as IDictionary <string, object>;
                    var authorLinks      = CreateLinks((Guid)authorDictionary[nameof(Author.Id)], parameters.Fields);
                    authorDictionary.Add("links", authorLinks);
                    return(authorDictionary);
                }
                                                                  );

                var linkCollection = new { value = shapedAuthorsWithLinks, links };
                return(Ok(linkCollection));
            }

            return(Ok(result));
        }
Ejemplo n.º 9
0
        public void IsSubsetOf_ReturnsFalseWhenExpected(string set, string subset)
        {
            // Arrange
            var setMediaType    = new MediaType(set);
            var subSetMediaType = new MediaType(subset);

            // Act
            var result = subSetMediaType.IsSubsetOf(setMediaType);

            // Assert
            Assert.False(result);
        }
Ejemplo n.º 10
0
        private static bool IsSubsetOfAny(
            this StringValues requestedMediaType,
            MediaTypeCollection mediaTypes)
        {
            if (requestedMediaType == default(StringValues))
            {
                return(false);
            }

            var requested = new MediaType(requestedMediaType);

            return(mediaTypes.Any(mediaType => requested.IsSubsetOf(new MediaType(mediaType))));
        }
        private bool IsSubsetOfAnySupportedContentType(string contentType)
        {
            var parsedContentType = new MediaType(contentType);

            for (var i = 0; i < SupportedMediaTypes.Count; i++)
            {
                var supportedMediaType = new MediaType(SupportedMediaTypes[i]);
                if (parsedContentType.IsSubsetOf(supportedMediaType))
                {
                    return(true);
                }
            }
            return(false);
        }
Ejemplo n.º 12
0
        private bool IsSubsetOfAnyContentType(string requestMediaType)
        {
            var parsedRequestMediaType = new MediaType(requestMediaType);

            for (var i = 0; i < ContentTypes.Count; i++)
            {
                var contentTypeMediaType = new MediaType(ContentTypes[i]);
                if (parsedRequestMediaType.IsSubsetOf(contentTypeMediaType))
                {
                    return(true);
                }
            }
            return(false);
        }
Ejemplo n.º 13
0
        private async Task <Job> GetJobAsync(string targetTypeName, string targetMethodName)
        {
            var context = _httpContextAccessor.HttpContext;

            if (context == null)
            {
                return(null);
            }
            var jobEntry = _jobEntryResolver.GetJobEntry(targetTypeName, targetMethodName);

            if (jobEntry == null)
            {
                return(null);
            }
            FormCollection form = FormCollection.Empty;
            MediaType      parsedContentType = new MediaType(context.Request.ContentType);

            if (parsedContentType.IsSubsetOf(_jobEntryResolver.SupportedMediaType))
            {
                context.Request.Body.Position = 0;
                var body = await context.Request.BodyReader.ReadAsync();

                var jsonString = Encoding.UTF8.GetString(body.Buffer.ToArray());
                var dict       = new Dictionary <string, StringValues>();
                using (JsonDocument document = JsonDocument.Parse(jsonString))
                {
                    JsonElement root = document.RootElement;
                    if (root.ValueKind.Equals(JsonValueKind.Object))
                    {
                        foreach (JsonProperty jsonProperty in root.EnumerateObject())
                        {
                            dict.Add(jsonProperty.Name, new StringValues(jsonProperty.Value.ToString()));
                        }
                    }
                }
                form = new FormCollection(dict);
            }
            Expression instance = null;

            if (!jobEntry.IsStaticMethod)
            {
                // 获取对象实例
                var TargetInstance = ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider, jobEntry.TargetType);
                instance = Expression.Constant(TargetInstance, jobEntry.TargetType);
            }
            var job = jobEntry.GetJob(instance, form);

            return(job);
        }
Ejemplo n.º 14
0
    private static bool IsSuperSetOfAnySupportedMediaType(string contentType, MediaTypeCollection supportedMediaTypes)
    {
        var parsedContentType = new MediaType(contentType);

        for (var i = 0; i < supportedMediaTypes.Count; i++)
        {
            var supportedMediaType = new MediaType(supportedMediaTypes[i]);
            if (supportedMediaType.IsSubsetOf(parsedContentType))
            {
                return(true);
            }
        }

        return(false);
    }
Ejemplo n.º 15
0
        /// <inheritdoc />
        public virtual bool CanWriteResult(OutputFormatterCanWriteContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (SupportedMediaTypes.Count == 0)
            {
                var message = Resources.FormatFormatter_NoMediaTypes(
                    GetType().FullName,
                    nameof(SupportedMediaTypes));

                throw new InvalidOperationException(message);
            }

            if (!CanWriteType(context.ObjectType))
            {
                return false;
            }

            if (!context.ContentType.HasValue)
            {
                // If the desired content type is set to null, then the current formatter can write anything
                // it wants.
                context.ContentType = new StringSegment(SupportedMediaTypes[0]);
                return true;
            }
            else
            {
                // Confirm this formatter supports a more specific media type than requested e.g. OK if "text/*"
                // requested and formatter supports "text/plain". contentType is typically what we got in an Accept
                // header.
                var parsedContentType = new MediaType(context.ContentType);
                for (var i = 0; i < SupportedMediaTypes.Count; i++)
                {
                    var supportedMediaType = new MediaType(SupportedMediaTypes[i]);
                    if (supportedMediaType.IsSubsetOf(parsedContentType))
                    {
                        context.ContentType = new StringSegment(SupportedMediaTypes[i]);
                        return true;
                    }
                }
            }

            return false;
        }
Ejemplo n.º 16
0
        public IActionResult GetRoot([FromHeader(Name = Headers.Accept)] string mediaType)
        {
            var currentMediaType = new MediaType(mediaType);
            var includeLinks     = currentMediaType.IsSubsetOf(VendorMediaType.HateoasLinksMediaType);

            if (includeLinks)
            {
                var links = new List <Link>
                {
                    new Link(_urlHelper.Link(nameof(GetRoot), new { }), "self", "GET"),
                    new Link(_urlHelper.Link(nameof(AuthorsController.GetAuthors), new { }), "authors", "GET"),
                    new Link(_urlHelper.Link(nameof(AuthorsController.CreateAuthor), new { }), "create_author", "POST")
                };
                return(Ok(links));
            }
            return(NoContent());
        }
Ejemplo n.º 17
0
        public IActionResult CreateBookForAuthor(Guid authorId, [FromBody] CreateBook book,
                                                 [FromHeader(Name = Headers.Accept)] string mediaType)
        {
            if (book == null)
            {
                return(BadRequest());
            }

            if (book.Description == book.Title)
            {
                ModelState.AddModelError(nameof(CreateBook), "The description should differ from the title.");
            }
            if (!ModelState.IsValid)
            {
                return(UnprocessableEntity(ModelState));
            }

            if (!_libraryRepository.AuthorExists(authorId))
            {
                return(NotFound());
            }

            var newBook = Mapper.Map <Entities.Book>(book);

            _libraryRepository.AddBookForAuthor(authorId, newBook);

            if (!_libraryRepository.Save())
            {
                throw new Exception($"Couldn't save new book for Author {authorId}");
            }

            var currentMediaType = new MediaType(mediaType);
            var includeLinks     = currentMediaType.IsSubsetOf(VendorMediaType.HateoasLinksMediaType);

            var bookToReturn = Mapper.Map <Book>(newBook);

            if (includeLinks)
            {
                return(CreatedAtRoute(nameof(GetBookForAuthor), new { authorId, id = newBook.Id }, CreateLinks(bookToReturn)));
            }
            else
            {
                return(CreatedAtRoute(nameof(GetBookForAuthor), new { authorId, id = newBook.Id }, bookToReturn));
            }
        }
Ejemplo n.º 18
0
    /// <inheritdoc />
    public virtual IReadOnlyList <string>?GetSupportedContentTypes(string contentType, Type objectType)
    {
        if (SupportedMediaTypes.Count == 0)
        {
            var message = Resources.FormatFormatter_NoMediaTypes(
                GetType().FullName,
                nameof(SupportedMediaTypes));

            throw new InvalidOperationException(message);
        }

        if (!CanReadType(objectType))
        {
            return(null);
        }

        if (contentType == null)
        {
            // If contentType is null, then any type we support is valid.
            return(SupportedMediaTypes);
        }
        else
        {
            var           parsedContentType = new MediaType(contentType);
            List <string>?mediaTypes        = null;

            // Confirm this formatter supports a more specific media type than requested e.g. OK if "text/*"
            // requested and formatter supports "text/plain". Treat contentType like it came from an Content-Type header.
            foreach (var mediaType in SupportedMediaTypes)
            {
                var parsedMediaType = new MediaType(mediaType);
                if (parsedMediaType.IsSubsetOf(parsedContentType))
                {
                    if (mediaTypes == null)
                    {
                        mediaTypes = new List <string>(SupportedMediaTypes.Count);
                    }

                    mediaTypes.Add(mediaType);
                }
            }

            return(mediaTypes);
        }
    }
        private static bool IsMediaTypeSupported(MediaTypeCollection mediaTypeCollection,
                                                 MediaTypeCollection supportedMediaTypes)
        {
            foreach (var supportedMediaTypeString in supportedMediaTypes)
            {
                var supportedMediaType = new MediaType(supportedMediaTypeString);
                foreach (var mediaType in mediaTypeCollection)
                {
                    var inputMediaType = new MediaType(mediaType);
                    if (inputMediaType.IsSubsetOf(supportedMediaType))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 20
0
        public static bool HasAcceptHeader(this HttpRequest request, string mediaType)
        {
            var acceptHeader = request.Headers[HeaderNames.Accept];

            if (string.IsNullOrWhiteSpace(acceptHeader))
            {
                return(false);
            }

            var parsedRequestMediaType = new MediaType(acceptHeader);

            if (parsedRequestMediaType.IsSubsetOf(new MediaType(mediaType)))
            {
                return(true);
            }

            return(false);
        }
        public virtual bool CanWriteResult(WebSocketOutputFormatterCanWriteContext context)
        {
            if (context.ObjectType == null)
            {
                throw new ArgumentNullException(nameof(context.ObjectType));
            }

            if (SupportedMediaTypes.Count == 0)
            {
                throw new InvalidOperationException("No media types supported");
            }

            if (!CanWriteType(context.ObjectType))
            {
                return(false);
            }

            if (!context.ContentType.HasValue)
            {
                // If the desired content type is set to null, then the current formatter can write anything
                // it wants.
                context.ContentType = new StringSegment(SupportedMediaTypes[0]);
                return(true);
            }

            // Confirm this formatter supports a more specific media type than requested e.g. OK if "text/*"
            // requested and formatter supports "text/plain". contentType is typically what we got in an Accept
            // header.
            var parsedContentType = new MediaType(context.ContentType.Value);

            for (var i = 0; i < SupportedMediaTypes.Count; i++)
            {
                var supportedMediaType = new MediaType(SupportedMediaTypes[i]);
                if (supportedMediaType.IsSubsetOf(parsedContentType))
                {
                    context.ContentType = new StringSegment(SupportedMediaTypes[i]);
                    return(true);
                }
            }

            return(false);
        }
Ejemplo n.º 22
0
        private static bool InAcceptableMediaTypes(StringSegment mediaType, MediaTypeCollection acceptableMediaTypes)
        {
            if (acceptableMediaTypes.Count == 0)
            {
                return(true);
            }

            var parsedMediaType = new MediaType(mediaType);

            for (int i = 0; i < acceptableMediaTypes.Count; i++)
            {
                var acceptableMediaType = new MediaType(acceptableMediaTypes[i]);
                if (acceptableMediaType.IsSubsetOf(parsedMediaType))
                {
                    return(true);
                }
            }

            return(false);
        }
        public IDeserializer GetDeserializer(string mediaType)
        {
            if (mediaType == null)
            {
                throw new ArgumentNullException(nameof(mediaType));
            }

            var inputMediaType = new MediaType(mediaType);

            foreach (var deserializer in Deserializers)
            {
                foreach (var supportedMediaTypeString in deserializer.SupportedMediaTypes)
                {
                    var supportedMediaType = new MediaType(supportedMediaTypeString);
                    if (inputMediaType.IsSubsetOf(supportedMediaType))
                    {
                        return(deserializer);
                    }
                }
            }

            return(null);
        }
Ejemplo n.º 24
0
        /// <inheritdoc />
        public override async Task ExecuteResultAsync(ActionContext context)
        {
            var response = context.HttpContext.Response;

            // Sets the HTTP status code
            await base.ExecuteResultAsync(context).ConfigureAwait(false);

            // Sets the reason phrase
            var responseFeature = context.HttpContext.Features.Get <IHttpResponseFeature>();

            if (responseFeature != null)
            {
                responseFeature.ReasonPhrase = _result.StatusCode.GetReasonPhrase();
            }

            if (_logger?.IsEnabled(LogLevel.Debug) ?? false)
            {
                var loggingResponse = new LoggingWebDavResponse(_dispatcher);
                await _result.ExecuteResultAsync(loggingResponse, context.HttpContext.RequestAborted).ConfigureAwait(false);

                if (!string.IsNullOrEmpty(loggingResponse.ContentType))
                {
                    var mediaType = new MediaType(loggingResponse.ContentType);
                    if (_supportedMediaTypes.Any(x => mediaType.IsSubsetOf(x)))
                    {
                        var doc = loggingResponse.Load();
                        if (doc != null)
                        {
                            _logger.LogDebug(doc.ToString(SaveOptions.OmitDuplicateNamespaces));
                        }
                    }
                }
            }

            // Writes the XML response
            await _result.ExecuteResultAsync(new WebDavResponse(_dispatcher, response), context.HttpContext.RequestAborted).ConfigureAwait(false);
        }
Ejemplo n.º 25
0
            private bool OutputFormatterSupportsMediaType(OutputFormatter outputForamtter, OutputFormatterCanWriteContext context)
            {
                var parsedContentType = new MediaType(context.ContentType);

                for (var i = 0; i < outputForamtter.SupportedMediaTypes.Count; i++)
                {
                    var supportedMediaType = new MediaType(outputForamtter.SupportedMediaTypes[i]);
                    if (supportedMediaType.HasWildcard)
                    {
                        // For supported media types that are wildcard patterns, confirm that the requested
                        // media type satisfies the wildcard pattern (e.g., if "text/entity+json;v=2" requested
                        // and formatter supports "text/*+json").
                        // We only do this when comparing against server-defined content types (e.g., those
                        // from [Produces] or Response.ContentType), otherwise we'd potentially be reflecting
                        // back arbitrary Accept header values.
                        if (context.ContentTypeIsServerDefined &&
                            parsedContentType.IsSubsetOf(supportedMediaType))
                        {
                            return(true);
                        }
                    }
                    else
                    {
                        // For supported media types that are not wildcard patterns, confirm that this formatter
                        // supports a more specific media type than requested e.g. OK if "text/*" requested and
                        // formatter supports "text/plain".
                        // contentType is typically what we got in an Accept header.
                        if (supportedMediaType.IsSubsetOf(parsedContentType))
                        {
                            context.ContentType = new StringSegment(outputForamtter.SupportedMediaTypes[i]);
                            return(true);
                        }
                    }
                }

                return(false);
            }
Ejemplo n.º 26
0
        /// <summary>
        /// 能否使用当前格式输出
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override bool CanWriteResult(OutputFormatterCanWriteContext context)
        {
            Assert.NotNull(context, nameof(context));
            if (!context.ContentType.HasValue)
            {
                return(false);
            }
            var parsedContentType = new MediaType(context.ContentType);

            for (var i = 0; i < SupportedMediaTypes.Count; i++)
            {
                var supportedMediaType = new MediaType(SupportedMediaTypes[i]);
                if (supportedMediaType.IsSubsetOf(parsedContentType)
                    &&
                    context.ObjectType.GetCustomAttribute(typeof(ProtoContractAttribute)
                                                          ) != null
                    )
                {
                    context.ContentType = new StringSegment(SupportedMediaTypes[i]);
                    return(true);
                }
            }
            return(false);
        }
Ejemplo n.º 27
0
        public IReadOnlyList <PolicyNodeEdge> GetEdges(IReadOnlyList <Endpoint> endpoints)
        {
            if (endpoints == null)
            {
                throw new ArgumentNullException(nameof(endpoints));
            }

            // The algorithm here is designed to be preserve the order of the endpoints
            // while also being relatively simple. Preserving order is important.

            // First, build a dictionary of all of the content-type patterns that are included
            // at this node.
            //
            // For now we're just building up the set of keys. We don't add any endpoints
            // to lists now because we don't want ordering problems.
            var edges = new Dictionary <string, List <Endpoint> >(StringComparer.OrdinalIgnoreCase);

            for (var i = 0; i < endpoints.Count; i++)
            {
                var endpoint     = endpoints[i];
                var contentTypes = endpoint.Metadata.GetMetadata <IConsumesMetadata>()?.ContentTypes;
                if (contentTypes == null || contentTypes.Count == 0)
                {
                    contentTypes = new string[] { AnyContentType, };
                }

                for (var j = 0; j < contentTypes.Count; j++)
                {
                    var contentType = contentTypes[j];

                    if (!edges.ContainsKey(contentType))
                    {
                        edges.Add(contentType, new List <Endpoint>());
                    }
                }
            }

            // Now in a second loop, add endpoints to these lists. We've enumerated all of
            // the states, so we want to see which states this endpoint matches.
            for (var i = 0; i < endpoints.Count; i++)
            {
                var endpoint     = endpoints[i];
                var contentTypes = endpoint.Metadata.GetMetadata <IConsumesMetadata>()?.ContentTypes ?? Array.Empty <string>();
                if (contentTypes.Count == 0)
                {
                    // OK this means that this endpoint matches *all* content methods.
                    // So, loop and add it to all states.
                    foreach (var kvp in edges)
                    {
                        kvp.Value.Add(endpoint);
                    }
                }
                else
                {
                    // OK this endpoint matches specific content types -- we have to loop through edges here
                    // because content types could either be exact (like 'application/json') or they
                    // could have wildcards (like 'text/*'). We don't expect wildcards to be especially common
                    // with consumes, but we need to support it.
                    foreach (var kvp in edges)
                    {
                        // The edgeKey maps to a possible request header value
                        var edgeKey = new MediaType(kvp.Key);

                        for (var j = 0; j < contentTypes.Count; j++)
                        {
                            var contentType = contentTypes[j];

                            var mediaType = new MediaType(contentType);

                            // Example: 'application/json' is subset of 'application/*'
                            //
                            // This means that when the request has content-type 'application/json' an endpoint
                            // what consumes 'application/*' should match.
                            if (edgeKey.IsSubsetOf(mediaType))
                            {
                                kvp.Value.Add(endpoint);

                                // It's possible that a ConsumesMetadata defines overlapping wildcards. Don't add an endpoint
                                // to any edge twice
                                break;
                            }
                        }
                    }
                }
            }

            // If after we're done there isn't any endpoint that accepts */*, then we'll synthesize an
            // endpoint that always returns a 415.
            if (!edges.TryGetValue(AnyContentType, out var anyEndpoints))
            {
                edges.Add(AnyContentType, new List <Endpoint>()
                {
                    CreateRejectionEndpoint(),
                });

                // Add a node to use when there is no request content type.
                // When there is no content type we want the policy to no-op
                edges.Add(string.Empty, endpoints.ToList());
            }
            else
            {
                // If there is an endpoint that accepts */* then it is also used when there is no content type
                edges.Add(string.Empty, anyEndpoints.ToList());
            }


            return(edges
                   .Select(kvp => new PolicyNodeEdge(kvp.Key, kvp.Value))
                   .ToArray());
        }
Ejemplo n.º 28
0
        private static bool InAcceptableMediaTypes(StringSegment mediaType, MediaTypeCollection acceptableMediaTypes)
        {
            if (acceptableMediaTypes.Count == 0)
            {
                return true;
            }

            var parsedMediaType = new MediaType(mediaType);
            for (int i = 0; i < acceptableMediaTypes.Count; i++)
            {
                var acceptableMediaType = new MediaType(acceptableMediaTypes[i]);
                if (acceptableMediaType.IsSubsetOf(parsedMediaType))
                {
                    return true;
                }
            }

            return false;
        }
Ejemplo n.º 29
0
 /// <summary>
 /// Selects the <see cref="IOutputFormatter"/> to write the response based on the content type values
 /// present in <paramref name="sortedAcceptableContentTypes"/> and <paramref name="possibleOutputContentTypes"/>.
 /// </summary>
 /// <param name="formatterContext">The <see cref="OutputFormatterWriteContext"/>.</param>
 /// <param name="formatters">
 /// The list of <see cref="IOutputFormatter"/> instances to consider.
 /// </param>
 /// <param name="sortedAcceptableContentTypes">
 /// The ordered content types from the <c>Accept</c> header, sorted by descending q-value.
 /// </param>
 /// <param name="possibleOutputContentTypes">
 /// The ordered content types from <see cref="ObjectResult.ContentTypes"/> in descending priority order.
 /// </param>
 /// <returns>
 /// The selected <see cref="IOutputFormatter"/> or <c>null</c> if no formatter can write the response.
 /// </returns>
 protected virtual IOutputFormatter SelectFormatterUsingSortedAcceptHeadersAndContentTypes(
     OutputFormatterWriteContext formatterContext,
     IList<IOutputFormatter> formatters,
     IList<MediaTypeSegmentWithQuality> sortedAcceptableContentTypes,
     MediaTypeCollection possibleOutputContentTypes)
 {
     for (var i = 0; i < sortedAcceptableContentTypes.Count; i++) 
     {
         var acceptableContentType = new MediaType(sortedAcceptableContentTypes[i].MediaType);
         for (var j = 0; j < possibleOutputContentTypes.Count; j++) 
         {
             var candidateContentType = new MediaType(possibleOutputContentTypes[j]);
             if (candidateContentType.IsSubsetOf(acceptableContentType)) 
             {
                 for (var k = 0; k < formatters.Count; k++) 
                 {
                     var formatter = formatters[k];
                     formatterContext.ContentType = new StringSegment(possibleOutputContentTypes[j]);
                     if (formatter.CanWriteResult(formatterContext)) 
                     {
                         return formatter;
                     }
                 }
             }
         }
     }
     
     return null;
 }
Ejemplo n.º 30
0
 private bool IsSubsetOfAnyContentType(string requestMediaType)
 {
     var parsedRequestMediaType = new MediaType(requestMediaType);
     for (var i = 0; i < ContentTypes.Count; i++)
     {
         var contentTypeMediaType = new MediaType(ContentTypes[i]);
         if (parsedRequestMediaType.IsSubsetOf(contentTypeMediaType))
         {
             return true;
         }
     }
     return false;
 }
Ejemplo n.º 31
0
        private bool IsSuperSetOfAnySupportedMediaType(string contentType, MediaTypeCollection supportedMediaTypes)
        {
            var parsedContentType = new MediaType(contentType);
            for (var i = 0; i < supportedMediaTypes.Count; i++)
            {
                var supportedMediaType = new MediaType(supportedMediaTypes[i]);
                if (supportedMediaType.IsSubsetOf(parsedContentType))
                {
                    return true;
                }
            }

            return false;
        }
Ejemplo n.º 32
0
        public void IsSubsetOf(string set, string subset, bool expectedResult)
        {
            // Arrange
            var setMediaType = new MediaType(set);
            var subSetMediaType = new MediaType(subset);

            // Act
            var result = subSetMediaType.IsSubsetOf(setMediaType);

            // Assert
            Assert.Equal(expectedResult, result);
        }
        private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaService)
        {
            var schema = await schemaService.GetSchema();

            AbpGraphQLRequest request = null;

            if (HttpMethods.IsPost(context.Request.Method))
            {
                var mediaType = new MediaType(context.Request.ContentType);

                try
                {
                    if (mediaType.IsSubsetOf(JsonMediaType))
                    {
                        using (var sr = new StreamReader(context.Request.Body))
                        {
                            using (var jsonTextReader = new JsonTextReader(sr))
                            {
                                request = Serializer.Deserialize <AbpGraphQLRequest>(jsonTextReader);
                            }
                        }
                    }
                    else if (mediaType.IsSubsetOf(GraphQLMediaType))
                    {
                        request = new AbpGraphQLRequest();

                        using (var sr = new StreamReader(context.Request.Body))
                        {
                            request.Query = await sr.ReadToEndAsync();
                        }
                    }
                    else if (context.Request.Query.ContainsKey("query"))
                    {
                        request = new AbpGraphQLRequest
                        {
                            Query = context.Request.Query["query"]
                        };


                        if (context.Request.Query.ContainsKey("variables"))
                        {
                            request.Variables = JObject.Parse(context.Request.Query["variables"]);
                        }

                        if (context.Request.Query.ContainsKey("operationName"))
                        {
                            request.OperationName = context.Request.Query["operationName"];
                        }
                    }
                }
                catch (Exception e)
                {
                    await WriteErrorAsync(context, "An error occured while processing the GraphQL query", e);

                    return;
                }
            }
            else if (HttpMethods.IsGet(context.Request.Method))
            {
                if (!context.Request.Query.ContainsKey("query"))
                {
                    await WriteErrorAsync(context, "The 'query' query string parameter is missing");

                    return;
                }

                request = new AbpGraphQLRequest
                {
                    Query = context.Request.Query["query"]
                };
            }

            var queryToExecute = request.Query;

            if (!string.IsNullOrEmpty(request.NamedQuery))
            {
                var namedQueries = context.RequestServices.GetServices <INamedQueryProvider>();

                var queries = namedQueries
                              .SelectMany(dict => dict.Resolve())
                              .ToDictionary(pair => pair.Key, pair => pair.Value);

                queryToExecute = queries[request.NamedQuery];
            }

            var result = await _executor.ExecuteAsync(_ =>
            {
                _.Schema        = schema;
                _.Query         = queryToExecute;
                _.OperationName = request.OperationName;
                _.Inputs        = request.Variables.ToInputs();
                _.UserContext   = _options.BuildUserContext?.Invoke(context);

#if DEBUG
                _.ExposeExceptions = true;
#endif
            });

            var httpResult = result.Errors?.Count > 0
                ? HttpStatusCode.BadRequest
                : HttpStatusCode.OK;

            context.Response.StatusCode  = (int)httpResult;
            context.Response.ContentType = "application/json";

            await _writer.WriteAsync(context.Response.Body, result);
        }
Ejemplo n.º 34
0
        /// <inheritdoc />
        public virtual IReadOnlyList<string> GetSupportedContentTypes(
            string contentType,
            Type objectType)
        {
            if (SupportedMediaTypes.Count == 0)
            {
                var message = Resources.FormatFormatter_NoMediaTypes(
                    GetType().FullName,
                    nameof(SupportedMediaTypes));

                throw new InvalidOperationException(message);
            }

            if (!CanWriteType(objectType))
            {
                return null;
            }

            if (contentType == null)
            {
                // If contentType is null, then any type we support is valid.
                return SupportedMediaTypes;
            }
            else
            {
                List<string> mediaTypes = null;

                var parsedContentType = new MediaType(contentType);

                // Confirm this formatter supports a more specific media type than requested e.g. OK if "text/*"
                // requested and formatter supports "text/plain". Treat contentType like it came from an Accept header.
                foreach (var mediaType in SupportedMediaTypes)
                {
                    var parsedMediaType = new MediaType(mediaType);
                    if (parsedMediaType.IsSubsetOf(parsedContentType))
                    {
                        if (mediaTypes == null)
                        {
                            mediaTypes = new List<string>();
                        }

                        mediaTypes.Add(mediaType);
                    }
                }

                return mediaTypes;
            }
        }
Ejemplo n.º 35
0
    /// <inheritdoc />
    public virtual bool CanWriteResult(OutputFormatterCanWriteContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (SupportedMediaTypes.Count == 0)
        {
            var message = Resources.FormatFormatter_NoMediaTypes(
                GetType().FullName,
                nameof(SupportedMediaTypes));

            throw new InvalidOperationException(message);
        }

        if (!CanWriteType(context.ObjectType))
        {
            return(false);
        }

        if (!context.ContentType.HasValue)
        {
            // If the desired content type is set to null, then the current formatter can write anything
            // it wants.
            context.ContentType = new StringSegment(SupportedMediaTypes[0]);
            return(true);
        }
        else
        {
            var parsedContentType = new MediaType(context.ContentType);
            for (var i = 0; i < SupportedMediaTypes.Count; i++)
            {
                var supportedMediaType = new MediaType(SupportedMediaTypes[i]);
                if (supportedMediaType.HasWildcard)
                {
                    // For supported media types that are wildcard patterns, confirm that the requested
                    // media type satisfies the wildcard pattern (e.g., if "text/entity+json;v=2" requested
                    // and formatter supports "text/*+json").
                    // We only do this when comparing against server-defined content types (e.g., those
                    // from [Produces] or Response.ContentType), otherwise we'd potentially be reflecting
                    // back arbitrary Accept header values.
                    if (context.ContentTypeIsServerDefined &&
                        parsedContentType.IsSubsetOf(supportedMediaType))
                    {
                        return(true);
                    }
                }
                else
                {
                    // For supported media types that are not wildcard patterns, confirm that this formatter
                    // supports a more specific media type than requested e.g. OK if "text/*" requested and
                    // formatter supports "text/plain".
                    // contentType is typically what we got in an Accept header.
                    if (supportedMediaType.IsSubsetOf(parsedContentType))
                    {
                        context.ContentType = new StringSegment(SupportedMediaTypes[i]);
                        return(true);
                    }
                }
            }
        }

        return(false);
    }
Ejemplo n.º 36
0
        private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaService)
        {
            var schema = await schemaService.GetSchemaAsync();

            GraphQLRequest request = null;

            // c.f. https://graphql.org/learn/serving-over-http/#post-request

            if (HttpMethods.IsPost(context.Request.Method))
            {
                var mediaType = new MediaType(context.Request.ContentType);

                try
                {
                    if (mediaType.IsSubsetOf(_jsonMediaType))
                    {
                        using (var sr = new StreamReader(context.Request.Body))
                        {
                            // Asynchronous read is mandatory.
                            var json = await sr.ReadToEndAsync();

                            request = JObject.Parse(json).ToObject <GraphQLRequest>();
                        }
                    }
                    else if (mediaType.IsSubsetOf(_graphQlMediaType))
                    {
                        request = new GraphQLRequest();

                        using (var sr = new StreamReader(context.Request.Body))
                        {
                            request.Query = await sr.ReadToEndAsync();
                        }
                    }
                    else if (context.Request.Query.ContainsKey("query"))
                    {
                        request = new GraphQLRequest
                        {
                            Query = context.Request.Query["query"]
                        };

                        if (context.Request.Query.ContainsKey("variables"))
                        {
                            request.Variables = JObject.Parse(context.Request.Query["variables"]);
                        }

                        if (context.Request.Query.ContainsKey("operationName"))
                        {
                            request.OperationName = context.Request.Query["operationName"];
                        }
                    }
                }
                catch (Exception e)
                {
                    await WriteErrorAsync(context, "An error occurred while processing the GraphQL query", e);

                    return;
                }
            }
            else if (HttpMethods.IsGet(context.Request.Method))
            {
                if (!context.Request.Query.ContainsKey("query"))
                {
                    await WriteErrorAsync(context, "The 'query' query string parameter is missing");

                    return;
                }

                request = new GraphQLRequest
                {
                    Query = context.Request.Query["query"]
                };
            }

            var queryToExecute = request.Query;

            if (!String.IsNullOrEmpty(request.NamedQuery))
            {
                var namedQueries = context.RequestServices.GetServices <INamedQueryProvider>();

                var queries = namedQueries
                              .SelectMany(dict => dict.Resolve())
                              .ToDictionary(pair => pair.Key, pair => pair.Value);

                queryToExecute = queries[request.NamedQuery];
            }

            var dataLoaderDocumentListener = context.RequestServices.GetRequiredService <IDocumentExecutionListener>();

            var result = await _executer.ExecuteAsync(_ =>
            {
                _.Schema           = schema;
                _.Query            = queryToExecute;
                _.OperationName    = request.OperationName;
                _.Inputs           = request.Variables.ToInputs();
                _.UserContext      = _settings.BuildUserContext?.Invoke(context);
                _.ExposeExceptions = _settings.ExposeExceptions;
                _.ValidationRules  = DocumentValidator.CoreRules()
                                     .Concat(context.RequestServices.GetServices <IValidationRule>());
                _.ComplexityConfiguration = new ComplexityConfiguration
                {
                    MaxDepth      = _settings.MaxDepth,
                    MaxComplexity = _settings.MaxComplexity,
                    FieldImpact   = _settings.FieldImpact
                };
                _.Listeners.Add(dataLoaderDocumentListener);
            });

            context.Response.StatusCode = (int)(result.Errors == null || result.Errors.Count == 0
                ? HttpStatusCode.OK
                : result.Errors.Any(x => x.Code == RequiresPermissionValidationRule.ErrorCode)
                    ? HttpStatusCode.Unauthorized
                    : HttpStatusCode.BadRequest);

            context.Response.ContentType = "application/json";

            // Asynchronous write to the response body is mandatory.
            var encodedBytes = _utf8Encoding.GetBytes(JObject.FromObject(result).ToString());
            await context.Response.Body.WriteAsync(encodedBytes, 0, encodedBytes.Length);
        }