Skip to content

Saves a bit memory allocations on common path #931

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions src/Transports.AspNetCore/GraphQLHttpMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace GraphQL.Server.Transports.AspNetCore;
/// Type of GraphQL schema that is used to validate and process requests.
/// This may be a typed schema as well as <see cref="ISchema"/>. In both cases registered schemas will be pulled from
/// the dependency injection framework. Note that when specifying <see cref="ISchema"/> the first schema registered via
/// <see cref="global::GraphQL.GraphQLBuilderExtensions.AddSchema{TSchema}(DI.IGraphQLBuilder, DI.ServiceLifetime)">AddSchema</see>
/// <see cref="GraphQLBuilderExtensions.AddSchema{TSchema}(DI.IGraphQLBuilder, DI.ServiceLifetime)">AddSchema</see>
/// will be pulled (the "default" schema).
/// </typeparam>
public class GraphQLHttpMiddleware<TSchema> : GraphQLHttpMiddleware
Expand Down Expand Up @@ -428,7 +428,7 @@ protected virtual async Task<ExecutionResult> ExecuteRequestAsync(HttpContext co
/// <see cref="HttpContext"/>.
/// <br/><br/>
/// To tailor the user context individually for each request, call
/// <see cref="global::GraphQL.GraphQLBuilderExtensions.ConfigureExecutionOptions(DI.IGraphQLBuilder, Action{ExecutionOptions})"/>
/// <see cref="GraphQLBuilderExtensions.ConfigureExecutionOptions(DI.IGraphQLBuilder, Action{ExecutionOptions})"/>
/// to set or modify the user context, pulling the HTTP context from
/// <see cref="IHttpContextAccessor"/> via <see cref="ExecutionOptions.RequestServices"/>
/// if needed.
Expand Down Expand Up @@ -473,9 +473,11 @@ protected virtual async Task<ExecutionResult> ExecuteRequestAsync(HttpContext co
protected virtual string SelectResponseContentType(HttpContext context)
{
// pull the Accept header, which may contain multiple content types
var acceptHeaders = context.Request.GetTypedHeaders().Accept;
var acceptHeaders = context.Request.Headers.ContainsKey(Microsoft.Net.Http.Headers.HeaderNames.Accept)
? context.Request.GetTypedHeaders().Accept
: Array.Empty<MediaTypeHeaderValueMs>();

if (acceptHeaders != null)
if (acceptHeaders.Count > 0)
{
// enumerate through each content type and see if it matches a supported content type
// give priority to specific types, then to types with wildcards
Expand All @@ -488,7 +490,7 @@ protected virtual string SelectResponseContentType(HttpContext context)
}

// return the default content type if no match is found, or if there is no 'Accept' header
return _options.DefaultResponseContentType.ToString();
return _options.DefaultResponseContentTypeString;

string? CheckForMatch(MediaTypeHeaderValueMs acceptHeader)
{
Expand All @@ -500,7 +502,7 @@ protected virtual string SelectResponseContentType(HttpContext context)

// check if this matches the default content type header
if (IsSubsetOf(_options.DefaultResponseContentType, acceptHeader))
return _options.DefaultResponseContentType.ToString();
return _options.DefaultResponseContentTypeString;

// if the default content type header does not contain a charset, test with utf-8 as the charset
if (_options.DefaultResponseContentType.Charset.Length == 0)
Expand Down Expand Up @@ -533,18 +535,18 @@ protected virtual string SelectResponseContentType(HttpContext context)

/*
* Copyright (c) .NET Foundation. All rights reserved.
*
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* these files except in compliance with the License. You may obtain a copy of the
* License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*
*/

static bool IsSubsetOf(MediaTypeHeaderValueMs mediaType, MediaTypeHeaderValueMs otherMediaType)
Expand Down Expand Up @@ -647,7 +649,8 @@ protected virtual Task WriteJsonResponseAsync<TResult>(HttpContext context, Http
return _serializer.WriteAsync(context.Response.Body, result, context.RequestAborted);
}

private static readonly IEnumerable<string> _supportedSubProtocols = new List<string>(new[] {
private static readonly IEnumerable<string> _supportedSubProtocols = new List<string>(new[]
{
WebSockets.GraphQLWs.SubscriptionServer.SubProtocol,
WebSockets.SubscriptionsTransportWs.SubscriptionServer.SubProtocol,
}).AsReadOnly();
Expand Down
14 changes: 13 additions & 1 deletion src/Transports.AspNetCore/GraphQLHttpMiddlewareOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,21 @@ public class GraphQLHttpMiddlewareOptions : IAuthorizationOptions
/// </summary>
public GraphQLWebSocketOptions WebSockets { get; set; } = new();

private MediaTypeHeaderValueMs _defaultResponseContentType = MediaTypeHeaderValueMs.Parse(GraphQLHttpMiddleware.CONTENTTYPE_GRAPHQLRESPONSEJSON);

/// <summary>
/// The Content-Type to use for GraphQL responses, if it matches the 'Accept'
/// HTTP request header. Defaults to "application/graphql-response+json; charset=utf-8".
/// </summary>
public MediaTypeHeaderValueMs DefaultResponseContentType { get; set; } = MediaTypeHeaderValueMs.Parse(GraphQLHttpMiddleware.CONTENTTYPE_GRAPHQLRESPONSEJSON);
public MediaTypeHeaderValueMs DefaultResponseContentType
{
get => _defaultResponseContentType;
set
{
_defaultResponseContentType = value;
DefaultResponseContentTypeString = value.ToString();
}
}

internal string DefaultResponseContentTypeString { get; set; } = GraphQLHttpMiddleware.CONTENTTYPE_GRAPHQLRESPONSEJSON;
}