Пример #1
0
    public async ValueTask InvokeAsync(IRequestContext context)
    {
        IQueryRequest request    = context.Request;
        var           addToCache = true;

        if (context.Document is null)
        {
            if (request.QueryId != null &&
                _documentCache.TryGetDocument(request.QueryId, out DocumentNode document))
            {
                context.DocumentId       = request.QueryId;
                context.Document         = document;
                context.ValidationResult = DocumentValidatorResult.Ok;
                context.IsCachedDocument = true;
                addToCache = false;
                _diagnosticEvents.RetrievedDocumentFromCache(context);
            }
            else if (request.QueryHash != null &&
                     _documentCache.TryGetDocument(request.QueryHash, out document))
            {
                context.DocumentId       = request.QueryHash;
                context.Document         = document;
                context.ValidationResult = DocumentValidatorResult.Ok;
                context.IsCachedDocument = true;
                addToCache = false;
                _diagnosticEvents.RetrievedDocumentFromCache(context);
            }
            else if (request.QueryHash is null && request.Query != null)
            {
                context.DocumentHash =
                    _documentHashProvider.ComputeHash(request.Query.AsSpan());

                if (_documentCache.TryGetDocument(context.DocumentHash, out document))
                {
                    context.DocumentId       = context.DocumentHash;
                    context.Document         = document;
                    context.ValidationResult = DocumentValidatorResult.Ok;
                    context.IsCachedDocument = true;
                    addToCache = false;
                    _diagnosticEvents.RetrievedDocumentFromCache(context);
                }
            }
        }

        await _next(context).ConfigureAwait(false);

        if (addToCache &&
            context.DocumentId != null &&
            context.Document != null &&
            context.IsValidDocument)
        {
            _documentCache.TryAddDocument(context.DocumentId, context.Document);
            _diagnosticEvents.AddedDocumentToCache(context);
        }
    }
Пример #2
0
        private async Task <IQueryDescriptor> LoadAsync(
            string name, string fileName, DocumentNode document)
        {
            OperationDefinitionNode operation =
                document.Definitions.OfType <OperationDefinitionNode>()
                .FirstOrDefault(t => t.Name is null);

            if (operation != null)
            {
                throw new GeneratorException(HCErrorBuilder.New()
                                             .SetMessage("All operations have to have a name in order " +
                                                         "to work with Strawberry Shake. Check the specified " +
                                                         "operation and give it a name, then retry generating " +
                                                         "the client.")
                                             .SetCode("OPERATION_NO_NAME")
                                             .AddLocation(operation)
                                             .SetExtension("fileName", fileName)
                                             .Build());
            }

            DocumentNode rewritten = AddTypeNameQueryRewriter.Rewrite(document);

            byte[] rewrittenBuffer;

            var serializer = new QuerySyntaxSerializer(false);

            using (var stream = new MemoryStream())
            {
                using (var sw = new StreamWriter(stream))
                {
                    using (var writer = new DocumentWriter(sw))
                    {
                        serializer.Visit(rewritten, writer);
                    }
                }

                await stream.FlushAsync().ConfigureAwait(false);

                rewrittenBuffer = stream.ToArray();
            }

            string hash = _hashProvider.ComputeHash(rewrittenBuffer);

            var descriptor = new QueryDescriptor(
                name,
                _namespace,
                _hashProvider.Name,
                hash,
                rewrittenBuffer,
                document);

            _descriptors.Add(descriptor);
            return(descriptor);
        }
Пример #3
0
        private IReadOnlyList <GraphQLRequest> ParseQuery(
            byte[] buffer, int bytesBuffered)
        {
            var graphQLData = new ReadOnlySpan <byte>(buffer);

            graphQLData = graphQLData.Slice(0, bytesBuffered);

            var requestParser = new Utf8GraphQLParser(graphQLData, _parserOptions);

            string       queryHash = _documentHashProvider.ComputeHash(graphQLData);
            DocumentNode document  = requestParser.Parse();

            return(new[] { new GraphQLRequest(document, queryHash) });
        }
        private string ResolveQueryKey(IReadOnlyQueryRequest request)
        {
            string queryKey = request.QueryName;

            if (queryKey is null || request.Query != null)
            {
                queryKey = request.QueryHash is null
                    ? _documentHashProvider.ComputeHash(
                    request.Query.ToSpan())
                    : request.QueryHash;
            }

            return(queryKey);
        }
Пример #5
0
        private GraphQLRequest ParseRequest()
        {
            var request = new Request();

            _reader.Expect(TokenKind.LeftBrace);

            while (_reader.Kind != TokenKind.RightBrace)
            {
                ParseRequestProperty(ref request);
            }

            if (request.IsQueryNull &&
                request.NamedQuery == null)
            {
                // TODO : resources
                throw new SyntaxException(
                          _reader,
                          "Either the query `property` or the `namedQuery` " +
                          "property have to have a value.");
            }

            DocumentNode document;

            if (_useCache)
            {
                if (request.NamedQuery is null)
                {
                    request.NamedQuery =
                        _hashProvider.ComputeHash(request.Query);
                }

                if (!_cache.TryGetDocument(request.NamedQuery, out document))
                {
                    document = ParseQuery(in request);
                }
            }
            else
            {
                document = ParseQuery(in request);
            }

            return(new GraphQLRequest
                   (
                       document,
                       request.NamedQuery,
                       request.OperationName,
                       request.Variables,
                       request.Extensions
                   ));
        }
        public async Task ActivePersistedQueries_Invalid_Hash()
        {
            // arrange
            var serviceCollection = new ServiceCollection();

            // configure presistence
            serviceCollection.AddGraphQLSchema(b => b
                                               .AddDocumentFromString("type Query { foo: String }")
                                               .AddResolver("Query", "foo", "bar"));
            serviceCollection.AddQueryExecutor(b => b
                                               .AddSha256DocumentHashProvider(HashFormat.Hex)
                                               .UseActivePersistedQueryPipeline());

            // add in-memory query storage
            serviceCollection.AddSingleton <InMemoryQueryStorage>();
            serviceCollection.AddSingleton <IReadStoredQueries>(sp =>
                                                                sp.GetRequiredService <InMemoryQueryStorage>());
            serviceCollection.AddSingleton <IWriteStoredQueries>(sp =>
                                                                 sp.GetRequiredService <InMemoryQueryStorage>());

            IServiceProvider services =
                serviceCollection.BuildServiceProvider();

            IQueryExecutor executor =
                services.GetRequiredService <IQueryExecutor>();

            IDocumentHashProvider hashProvider =
                services.GetRequiredService <IDocumentHashProvider>();
            InMemoryQueryStorage storage = services.GetRequiredService <InMemoryQueryStorage>();

            var query = new QuerySourceText("{ foo }");
            var hash  = hashProvider.ComputeHash(query.AsSpan());

            // act
            IExecutionResult result = await executor.ExecuteAsync(
                QueryRequestBuilder.New()
                .SetQuery(query.Text)
                .SetQueryName(hash)
                .AddExtension("persistedQuery",
                              new Dictionary <string, object>
            {
                { "sha256Hash", "123" }
            })
                .Create());

            // assert
            Assert.False(storage.WrittenQuery.HasValue);
            result.ToJson().MatchSnapshot();
        }
Пример #7
0
        public async Task InvokeAsync(IQueryContext context)
        {
            if (IsContextIncomplete(context))
            {
                context.Result = QueryResult.CreateError(
                    ErrorBuilder.New()
                    .SetMessage(CoreResources
                                .ParseQueryMiddleware_InComplete)
                    .Build());
            }
            else
            {
                Activity activity = _diagnosticEvents.BeginParsing(context);

                try
                {
                    bool documentRetrievedFromCache = true;

                    string queryKey = context.Request.QueryHash
                                      ?? context.Request.QueryName;

                    if (queryKey is null)
                    {
                        queryKey = _documentHashProvider.ComputeHash(
                            context.Request.Query.ToSource());
                    }

                    context.QueryKey    = queryKey;
                    context.CachedQuery = _queryCache.GetOrCreate(
                        queryKey,
                        () =>
                    {
                        documentRetrievedFromCache = false;
                        DocumentNode document      =
                            ParseDocument(context.Request.Query);
                        return(new CachedQuery(queryKey, document));
                    });
                    context.Document = context.CachedQuery.Document;
                    context.ContextData[ContextDataKeys.DocumentCached] =
                        documentRetrievedFromCache;
                }
                finally
                {
                    _diagnosticEvents.EndParsing(activity, context);
                }
            }

            await _next(context).ConfigureAwait(false);
        }
Пример #8
0
        private static DocumentModel CreateDocumentModel(
            IDocumentAnalyzerContext context,
            string name,
            DocumentNode original,
            IDocumentHashProvider hashProvider)
        {
            DocumentNode optimized = TypeNameQueryRewriter.Rewrite(original);

            string serialized = QuerySyntaxSerializer.Serialize(optimized, false);

            byte[] buffer = Encoding.UTF8.GetBytes(serialized);
            string hash   = hashProvider.ComputeHash(buffer);

            return(new DocumentModel(
                       name,
                       context.Operations.Where(t => t.Document == original).ToArray(),
                       original,
                       optimized,
                       buffer,
                       hashProvider.Name,
                       hash));
        }
Пример #9
0
    public GraphQLRequest ReadParamsRequest(IQueryCollection parameters)
    {
        // next we deserialize the GET request with the query request builder ...
        string query         = parameters[_queryIdentifier];
        string queryId       = parameters[_queryIdIdentifier];
        string operationName = parameters[_operationNameIdentifier];
        IReadOnlyDictionary <string, object?>?extensions = null;

        // if we have no query or query id we cannot execute anything.
        if (string.IsNullOrEmpty(query) && string.IsNullOrEmpty(queryId))
        {
            // so, if we do not find a top-level query or top-level id we will try to parse
            // the extensions and look in the extensions for Apollo`s active persisted
            // query extensions.
            if ((string)parameters[_extensionsIdentifier] is { Length : > 0 } se)
            {
                extensions = ParseJsonObject(se);
            }

            // we will use the request parser utils to extract the has from the extensions.
            if (!TryExtractHash(extensions, _documentHashProvider, out var hash))
            {
                // if we cannot find any query hash in the extensions or if the extensions are
                // null we are unable to execute and will throw a request error.
                throw DefaultHttpRequestParser_QueryAndIdMissing();
            }

            // if we however found a query hash we will use it as a query id and move on
            // to execute the query.
            queryId = hash;
        }

        try
        {
            string?      queryHash = null;
            DocumentNode?document  = null;


            if (query is { Length : > 0 })
            {
                byte[] buffer = Encoding.UTF8.GetBytes(query);
                document  = Utf8GraphQLParser.Parse(buffer);
                queryHash = _documentHashProvider.ComputeHash(buffer);
            }

            IReadOnlyDictionary <string, object?>?variables = null;

            // if we find variables we do need to parse them
            if ((string)parameters[_variablesIdentifier] is { Length : > 0 } sv)
            {
                variables = ParseVariables(sv);
            }

            if (extensions is null &&
                (string)parameters[_extensionsIdentifier] is { Length : > 0 } se)
            {
                extensions = ParseJsonObject(se);
            }

            return(new GraphQLRequest(
                       document,
                       queryId,
                       queryHash,
                       operationName,
                       variables,
                       extensions));
        }
        public async Task InvokeAsync(IQueryContext context)
        {
            if (IsContextIncomplete(context))
            {
                context.Result = QueryResult.CreateError(
                    ErrorBuilder.New()
                    .SetMessage(CoreResources
                                .ParseQueryMiddleware_InComplete)
                    .Build());
            }
            else
            {
                Activity activity = _diagnosticEvents.BeginParsing(context);

                try
                {
                    bool         documentRetrievedFromCache = true;
                    string       queryKey    = context.Request.QueryName;
                    ICachedQuery cachedQuery = null;

                    if (queryKey is null || context.Request.Query != null)
                    {
                        queryKey = context.Request.QueryHash is null
                            ? _documentHashProvider.ComputeHash(
                            context.Request.Query.ToSource())
                            : context.Request.QueryHash;
                    }

                    if (context.Request.Query is null &&
                        !_queryCache.TryGet(queryKey, out cachedQuery))
                    {
                        // TODO : check for query storage here?
                        // TODO : RESOURCES
                        context.Result = QueryResult.CreateError(
                            ErrorBuilder.New()
                            .SetMessage("persistedQueryNotFound")
                            .SetCode("CACHED_QUERY_NOT_FOUND")
                            .Build());
                        return;
                    }

                    if (cachedQuery is null)
                    {
                        cachedQuery = _queryCache.GetOrCreate(
                            queryKey,
                            () =>
                        {
                            documentRetrievedFromCache = false;
                            DocumentNode document      =
                                ParseDocument(context.Request.Query);
                            return(new CachedQuery(queryKey, document));
                        });
                    }

                    // update context
                    context.QueryKey    = queryKey;
                    context.CachedQuery = cachedQuery;
                    context.Document    = context.CachedQuery.Document;
                    context.ContextData[ContextDataKeys.DocumentCached] =
                        documentRetrievedFromCache;
                }
                finally
                {
                    _diagnosticEvents.EndParsing(activity, context);
                }

                await _next(context).ConfigureAwait(false);
            }
        }