Esempio n. 1
0
        /// <summary>
        /// Evaluates the Command in the given Context
        /// </summary>
        /// <param name="context">Evaluation Context</param>
        public override void Evaluate(SparqlUpdateEvaluationContext context)
        {
            bool datasetOk  = false;
            bool defGraphOk = false;

            try
            {
                //First evaluate the WHERE pattern to get the affected bindings
                ISparqlAlgebra where = this._wherePattern.ToAlgebra();
                if (context.Commands != null)
                {
                    where = context.Commands.ApplyAlgebraOptimisers(where);
                }

                //Set Active Graph for the WHERE
                //Don't bother if there are USING URIs as these would override any Active Graph we set here
                //so we can save ourselves the effort of doing this
                if (!this.UsingUris.Any())
                {
                    if (this._graphUri != null)
                    {
                        context.Data.SetActiveGraph(this._graphUri);
                        defGraphOk = true;
                    }
                    else
                    {
                        context.Data.SetActiveGraph((Uri)null);
                        defGraphOk = true;
                    }
                }

                //We need to make a dummy SparqlQuery object since if the Command has used any
                //USING NAMEDs along with GRAPH clauses then the algebra needs to have the
                //URIs available to it which it gets from the Query property of the Context
                //object
                SparqlQuery query = new SparqlQuery();
                foreach (Uri u in this.UsingUris)
                {
                    query.AddDefaultGraph(u);
                }
                foreach (Uri u in this.UsingNamedUris)
                {
                    query.AddNamedGraph(u);
                }
                SparqlEvaluationContext queryContext = new SparqlEvaluationContext(query, context.Data, context.QueryProcessor);
                if (this.UsingUris.Any())
                {
                    //If there are USING URIs set the Active Graph to be formed of the Graphs with those URIs
                    context.Data.SetActiveGraph(this._usingUris);
                    datasetOk = true;
                }
                BaseMultiset results = queryContext.Evaluate(where);
                if (results is IdentityMultiset)
                {
                    queryContext.OutputMultiset = new SingletonMultiset(results.Variables);
                }
                if (this.UsingUris.Any())
                {
                    //If there are USING URIs reset the Active Graph afterwards
                    //Also flag the dataset as no longer being OK as this flag is used in the finally
                    //block to determine whether the Active Graph needs resetting which it may do if the
                    //evaluation of the query fails for any reason
                    context.Data.ResetActiveGraph();
                    datasetOk = false;
                }

                //Reset Active Graph for the WHERE
                if (defGraphOk)
                {
                    context.Data.ResetActiveGraph();
                    defGraphOk = false;
                }

                //TODO: Need to detect when we create a Graph for Insertion but then fail to insert anything since in this case the Inserted Graph should be removed

                //Get the Graph to which we are inserting Triples with no explicit Graph clause
                IGraph g = null;
                if (this._insertPattern.TriplePatterns.Count > 0)
                {
                    if (context.Data.HasGraph(this._graphUri))
                    {
                        g = context.Data.GetModifiableGraph(this._graphUri);
                    }
                    else
                    {
                        //insertedGraphs.Add(this._graphUri);
                        g         = new Graph();
                        g.BaseUri = this._graphUri;
                        context.Data.AddGraph(g);
                        g = context.Data.GetModifiableGraph(this._graphUri);
                    }
                }

                //Keep a record of graphs to which we insert
                MultiDictionary <Uri, IGraph> graphs = new MultiDictionary <Uri, IGraph>(u => (u != null ? u.GetEnhancedHashCode() : 0), true, new UriComparer(), MultiDictionaryMode.AVL);

                //Insert the Triples for each Solution
                foreach (ISet s in queryContext.OutputMultiset.Sets)
                {
                    List <Triple> insertedTriples = new List <Triple>();

                    try
                    {
                        //Create a new Construct Context for each Solution
                        ConstructContext constructContext = new ConstructContext(null, s, true);

                        //Triples from raw Triple Patterns
                        if (this._insertPattern.TriplePatterns.Count > 0)
                        {
                            foreach (IConstructTriplePattern p in this._insertPattern.TriplePatterns.OfType <IConstructTriplePattern>())
                            {
                                try
                                {
                                    insertedTriples.Add(p.Construct(constructContext));
                                }
                                catch (RdfQueryException)
                                {
                                    //If we throw an error this means we couldn't construct a specific Triple
                                    //so we continue anyway
                                }
                            }
                            g.Assert(insertedTriples);
                        }

                        //Triples from GRAPH clauses
                        foreach (GraphPattern gp in this._insertPattern.ChildGraphPatterns)
                        {
                            insertedTriples.Clear();
                            try
                            {
                                String graphUri;
                                switch (gp.GraphSpecifier.TokenType)
                                {
                                case Token.URI:
                                    graphUri = gp.GraphSpecifier.Value;
                                    break;

                                case Token.VARIABLE:
                                    String graphVar = gp.GraphSpecifier.Value.Substring(1);
                                    if (s.ContainsVariable(graphVar))
                                    {
                                        INode temp = s[graphVar];
                                        if (temp == null)
                                        {
                                            //If the Variable is not bound then skip
                                            continue;
                                        }
                                        else if (temp.NodeType == NodeType.Uri)
                                        {
                                            graphUri = temp.ToSafeString();
                                        }
                                        else
                                        {
                                            //If the Variable is not bound to a URI then skip
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        //If the Variable is not bound for this solution then skip
                                        continue;
                                    }
                                    break;

                                default:
                                    //Any other Graph Specifier we have to ignore this solution
                                    continue;
                                }

                                //Ensure the Graph we're inserting to exists in the dataset creating it if necessary
                                IGraph h;
                                Uri    destUri = UriFactory.Create(graphUri);
                                if (graphs.ContainsKey(destUri))
                                {
                                    h = graphs[destUri];
                                }
                                else
                                {
                                    if (context.Data.HasGraph(destUri))
                                    {
                                        h = context.Data.GetModifiableGraph(destUri);
                                    }
                                    else
                                    {
                                        //insertedGraphs.Add(destUri);
                                        h         = new Graph();
                                        h.BaseUri = destUri;
                                        context.Data.AddGraph(h);
                                        h = context.Data.GetModifiableGraph(destUri);
                                    }
                                    graphs.Add(destUri, h);
                                }

                                //Do the actual Insertions
                                foreach (IConstructTriplePattern p in gp.TriplePatterns.OfType <IConstructTriplePattern>())
                                {
                                    try
                                    {
                                        insertedTriples.Add(p.Construct(constructContext));
                                    }
                                    catch (RdfQueryException)
                                    {
                                        //If we throw an error this means we couldn't construct a specific Triple
                                        //so we continue anyway
                                    }
                                }
                                h.Assert(insertedTriples);
                            }
                            catch (RdfQueryException)
                            {
                                //If we throw an error this means we couldn't construct for this solution so the
                                //solution is ignored for this Graph
                            }
                        }
                    }
                    catch (RdfQueryException)
                    {
                        //If we throw an error this means we couldn't construct for this solution so the
                        //solution is ignored for this graph
                    }
                }
            }
            finally
            {
                //If the Dataset was set and an error occurred in doing the WHERE clause then
                //we'll need to Reset the Active Graph
                if (datasetOk)
                {
                    context.Data.ResetActiveGraph();
                }
                if (defGraphOk)
                {
                    context.Data.ResetActiveGraph();
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Evaluates the Command in the given Context
        /// </summary>
        /// <param name="context">Evaluation Context</param>
        public override void Evaluate(SparqlUpdateEvaluationContext context)
        {
            bool defGraphOk = false;
            bool datasetOk  = false;

            try
            {
                //First evaluate the WHERE pattern to get the affected bindings
                ISparqlAlgebra where = this._wherePattern.ToAlgebra();
                if (context.Commands != null)
                {
                    where = context.Commands.ApplyAlgebraOptimisers(where);
                }

                //Set Active Graph for the WHERE based upon the WITH clause
                //Don't bother if there are USING URIs as these would override any Active Graph we set here
                //so we can save ourselves the effort of doing this
                if (!this.UsingUris.Any())
                {
                    if (this._graphUri != null)
                    {
                        context.Data.SetActiveGraph(this._graphUri);
                        defGraphOk = true;
                    }
                    else
                    {
                        context.Data.SetActiveGraph((Uri)null);
                        defGraphOk = true;
                    }
                }

                //We need to make a dummy SparqlQuery object since if the Command has used any
                //USING/USING NAMEDs along with GRAPH clauses then the algebra needs to have the
                //URIs available to it which it gets from the Query property of the Context
                //object
                SparqlQuery query = new SparqlQuery();
                foreach (Uri u in this.UsingUris)
                {
                    query.AddDefaultGraph(u);
                }
                foreach (Uri u in this.UsingNamedUris)
                {
                    query.AddNamedGraph(u);
                }
                SparqlEvaluationContext queryContext = new SparqlEvaluationContext(query, context.Data, context.QueryProcessor);
                if (this.UsingUris.Any())
                {
                    //If there are USING URIs set the Active Graph to be formed of the Graphs with those URIs
                    context.Data.SetActiveGraph(this._usingUris);
                    datasetOk = true;
                }
                BaseMultiset results = queryContext.Evaluate(where);
                if (results is IdentityMultiset)
                {
                    results = new SingletonMultiset(results.Variables);
                }
                if (this.UsingUris.Any())
                {
                    //If there are USING URIs reset the Active Graph afterwards
                    //Also flag the dataset as no longer being OK as this flag is used in the finally
                    //block to determine whether the Active Graph needs resetting which it may do if the
                    //evaluation of the
                    context.Data.ResetActiveGraph();
                    datasetOk = false;
                }

                //Reset Active Graph for the WHERE
                if (defGraphOk)
                {
                    context.Data.ResetActiveGraph();
                    defGraphOk = false;
                }

                //Get the Graph from which we are deleting
                IGraph g = context.Data.GetModifiableGraph(this._graphUri);

                //Delete the Triples for each Solution
                foreach (ISet s in results.Sets)
                {
                    List <Triple> deletedTriples = new List <Triple>();

                    //Triples from raw Triple Patterns
                    try
                    {
                        ConstructContext constructContext = new ConstructContext(g, s, true);
                        foreach (IConstructTriplePattern p in this._deletePattern.TriplePatterns.OfType <IConstructTriplePattern>())
                        {
                            try
                            {
                                deletedTriples.Add(p.Construct(constructContext));
                            }
                            catch (RdfQueryException)
                            {
                                //If we get an error here then we couldn't construct a specific Triple
                                //so we continue anyway
                            }
                        }
                        g.Retract(deletedTriples);
                    }
                    catch (RdfQueryException)
                    {
                        //If we throw an error this means we couldn't construct for this solution so the
                        //solution is ignored this graph
                    }

                    //Triples from GRAPH clauses
                    foreach (GraphPattern gp in this._deletePattern.ChildGraphPatterns)
                    {
                        deletedTriples.Clear();
                        try
                        {
                            String graphUri;
                            switch (gp.GraphSpecifier.TokenType)
                            {
                            case Token.URI:
                                graphUri = gp.GraphSpecifier.Value;
                                break;

                            case Token.VARIABLE:
                                String graphVar = gp.GraphSpecifier.Value.Substring(1);
                                if (s.ContainsVariable(graphVar))
                                {
                                    INode temp = s[graphVar];
                                    if (temp == null)
                                    {
                                        //If the Variable is not bound then skip
                                        continue;
                                    }
                                    else if (temp.NodeType == NodeType.Uri)
                                    {
                                        graphUri = temp.ToSafeString();
                                    }
                                    else
                                    {
                                        //If the Variable is not bound to a URI then skip
                                        continue;
                                    }
                                }
                                else
                                {
                                    //If the Variable is not bound for this solution then skip
                                    continue;
                                }
                                break;

                            default:
                                //Any other Graph Specifier we have to ignore this solution
                                continue;
                            }

                            //If the Dataset doesn't contain the Graph then no need to do the Deletions
                            if (!context.Data.HasGraph(UriFactory.Create(graphUri)))
                            {
                                continue;
                            }

                            //Do the actual Deletions
                            IGraph           h = context.Data.GetModifiableGraph(UriFactory.Create(graphUri));
                            ConstructContext constructContext = new ConstructContext(h, s, true);
                            foreach (IConstructTriplePattern p in gp.TriplePatterns.OfType <IConstructTriplePattern>())
                            {
                                try
                                {
                                    deletedTriples.Add(p.Construct(constructContext));
                                }
                                catch (RdfQueryException)
                                {
                                    //If we get an error here then we couldn't construct a specific
                                    //triple so we continue anyway
                                }
                            }
                            h.Retract(deletedTriples);
                        }
                        catch (RdfQueryException)
                        {
                            //If we get an error here this means we couldn't construct for this solution so the
                            //solution is ignored for this graph
                        }
                    }
                }
            }
            finally
            {
                //If the Dataset was set and an error occurred in doing the WHERE clause then
                //we'll need to Reset the Active Graph
                if (datasetOk)
                {
                    context.Data.ResetActiveGraph();
                }
                if (defGraphOk)
                {
                    context.Data.ResetActiveGraph();
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Processes a SPARQL Query Request
        /// </summary>
        /// <param name="context">HTTP Context</param>
        public void ProcessRequest(HttpContext context)
        {
            this._config = this.LoadConfig(context);

            //Add our Standard Headers
            HandlerHelper.AddStandardHeaders(context, this._config);

            if (context.Request.HttpMethod.Equals("OPTIONS"))
            {
                //OPTIONS requests always result in the Service Description document
                IGraph svcDescrip = SparqlServiceDescriber.GetServiceDescription(context, this._config, new Uri(context.Request.Url.AbsoluteUri));
                HandlerHelper.SendToClient(context, svcDescrip, this._config);
                return;
            }

            //See if there has been an query submitted
            String queryText = context.Request.QueryString["query"];

            if (queryText == null || queryText.Equals(String.Empty))
            {
                queryText = context.Request.Form["query"];
            }

            //If no Query sent either show Query Form or give a HTTP 400 response
            if (queryText == null || queryText.Equals(String.Empty))
            {
                //If there is no Query we may return the SPARQL Service Description where appropriate
                try
                {
                    //If we might show the Query Form only show the Description if the selected writer is
                    //not a HTML writer
                    MimeTypeDefinition definition = MimeTypesHelper.GetDefinitions(HandlerHelper.GetAcceptTypes(context)).FirstOrDefault(d => d.CanWriteRdf);
                    if (definition != null)
                    {
                        IRdfWriter writer = definition.GetRdfWriter();
                        if (!this._config.ShowQueryForm || !(writer is IHtmlWriter))
                        {
                            //If not a HTML Writer selected OR not showing Query Form then show the Service Description Graph
                            //unless an error occurs creating it
                            IGraph serviceDescrip = SparqlServiceDescriber.GetServiceDescription(context, this._config, new Uri(context.Request.Url.AbsoluteUri));
                            context.Response.ContentType     = definition.CanonicalMimeType;
                            context.Response.ContentEncoding = definition.Encoding;
                            writer.Save(serviceDescrip, new StreamWriter(context.Response.OutputStream, definition.Encoding));
                            return;
                        }
                    }
                }
                catch
                {
                    //Ignore Exceptions - we'll just show the Query Form or return a 400 Bad Request instead
                }

                //If a Writer can't be selected then we'll either show the Query Form or return a 400 Bad Request
                if (this._config.ShowQueryForm)
                {
                    this.ShowQueryForm(context);
                }
                else
                {
                    context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                }
                return;
            }

            //Get Other options associated with this query
            List <String> userDefaultGraphs = new List <String>();
            List <String> userNamedGraphs   = new List <String>();
            long          timeout           = 0;
            bool          partialResults    = this._config.DefaultPartialResults;

            //Get the Default Graph URIs (if any)
            if (context.Request.QueryString["default-graph-uri"] != null)
            {
                userDefaultGraphs.AddRange(context.Request.QueryString.GetValues("default-graph-uri"));
            }
            else if (context.Request.Form["default-graph-uri"] != null)
            {
                userDefaultGraphs.AddRange(context.Request.Form.GetValues("default-graph-uri"));
            }
            //Get the Named Graph URIs (if any)
            if (context.Request.QueryString["named-graph-uri"] != null)
            {
                userNamedGraphs.AddRange(context.Request.QueryString.GetValues("named-graph-uri"));
            }
            else if (context.Request.Form["named-graph-uri"] != null)
            {
                userNamedGraphs.AddRange(context.Request.Form.GetValues("named-graph-uri"));
            }

            //Get Timeout setting (if any)
            if (context.Request.QueryString["timeout"] != null)
            {
                if (!Int64.TryParse(context.Request.QueryString["timeout"], out timeout))
                {
                    timeout = this._config.DefaultTimeout;
                }
            }
            else if (context.Request.Form["timeout"] != null)
            {
                if (!Int64.TryParse(context.Request.Form["timeout"], out timeout))
                {
                    timeout = this._config.DefaultTimeout;
                }
            }
            //Get Partial Results Setting (if any);
            if (context.Request.QueryString["partialResults"] != null)
            {
                if (!Boolean.TryParse(context.Request.QueryString["partialResults"], out partialResults))
                {
                    partialResults = this._config.DefaultPartialResults;
                }
            }
            else if (context.Request.Form["partialResults"] != null)
            {
                if (!Boolean.TryParse(context.Request.Form["partialResults"], out partialResults))
                {
                    partialResults = this._config.DefaultPartialResults;
                }
            }

            try
            {
                //Now we're going to parse the Query
                SparqlQueryParser parser = new SparqlQueryParser(this._config.Syntax);
                parser.ExpressionFactories = this._config.ExpressionFactories;
                parser.QueryOptimiser      = this._config.QueryOptimiser;
                SparqlQuery query = parser.ParseFromString(queryText);
                query.AlgebraOptimisers = this._config.AlgebraOptimisers;

                //Check whether we need to use authentication
                //If there are no user groups then no authentication is in use so we default to authenticated with no per-action authentication needed
                bool isAuth = true, requireActionAuth = false;
                if (this._config.UserGroups.Any())
                {
                    //If we have user
                    isAuth            = HandlerHelper.IsAuthenticated(context, this._config.UserGroups);
                    requireActionAuth = true;
                }
                if (!isAuth)
                {
                    return;
                }

                //Is this user allowed to make this kind of query?
                if (requireActionAuth)
                {
                    HandlerHelper.IsAuthenticated(context, this._config.UserGroups, this.GetPermissionAction(query));
                }

                //Set the Default Graph URIs (if any)
                if (userDefaultGraphs.Count > 0)
                {
                    //Default Graph Uri specified by default-graph-uri parameter or Web.config settings
                    foreach (String userDefaultGraph in userDefaultGraphs)
                    {
                        if (!userDefaultGraph.Equals(String.Empty))
                        {
                            query.AddDefaultGraph(new Uri(userDefaultGraph));
                        }
                    }
                }
                else if (!this._config.DefaultGraphURI.Equals(String.Empty))
                {
                    //Only applies if the Query doesn't specify any Default Graph
                    if (!query.DefaultGraphs.Any())
                    {
                        query.AddDefaultGraph(new Uri(this._config.DefaultGraphURI));
                    }
                }

                //Set the Named Graph URIs (if any)
                if (userNamedGraphs.Count > 0)
                {
                    foreach (String userNamedGraph in userNamedGraphs)
                    {
                        if (!userNamedGraph.Equals(String.Empty))
                        {
                            query.AddNamedGraph(new Uri(userNamedGraph));
                        }
                    }
                }

                //Set Timeout setting
                if (timeout > 0)
                {
                    query.Timeout = timeout;
                }
                else
                {
                    query.Timeout = this._config.DefaultTimeout;
                }

                //Set Partial Results Setting
                query.PartialResultsOnTimeout = partialResults;

                //Set Describe Algorithm
                query.Describer = this._config.DescribeAlgorithm;

                //Now we can finally make the query and return the results
                Object result = this.ProcessQuery(query);
                this.ProcessResults(context, result);

                //Update the Cache as the request may have changed the endpoint
                this.UpdateConfig(context);
            }
            catch (RdfParseException parseEx)
            {
                HandleErrors(context, "Parsing Error", queryText, parseEx, (int)HttpStatusCode.BadRequest);
            }
            catch (RdfQueryTimeoutException timeoutEx)
            {
                HandleErrors(context, "Query Timeout Error", queryText, timeoutEx);
            }
            catch (RdfQueryException queryEx)
            {
                HandleErrors(context, "Update Error", queryText, queryEx);
            }
            catch (RdfWriterSelectionException writerSelEx)
            {
                HandleErrors(context, "Output Selection Error", queryText, writerSelEx, (int)HttpStatusCode.NotAcceptable);
            }
            catch (RdfException rdfEx)
            {
                HandleErrors(context, "RDF Error", queryText, rdfEx);
            }
            catch (Exception ex)
            {
                HandleErrors(context, "Error", queryText, ex);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Processes Query requests
        /// </summary>
        /// <param name="context">HTTP Context</param>
        public void ProcessQueryRequest(HttpContext context)
        {
            if (this._config.QueryProcessor == null)
            {
                context.Response.StatusCode = (int)HttpStatusCode.NotImplemented;
                return;
            }

            if (context.Request.HttpMethod.Equals("OPTIONS"))
            {
                //OPTIONS requests always result in the Service Description document
                IGraph svcDescrip = SparqlServiceDescriber.GetServiceDescription(context, this._config, new Uri(context.Request.Url.AbsoluteUri), ServiceDescriptionType.Query);
                HandlerHelper.SendToClient(context, svcDescrip, this._config);
                return;
            }

            //See if there has been an query submitted
            String queryText = context.Request.QueryString["query"];

            if (queryText == null || queryText.Equals(String.Empty))
            {
                queryText = context.Request.Form["query"];
            }

            //If no Query sent either show Query Form or give a HTTP 400 response
            if (queryText == null || queryText.Equals(String.Empty))
            {
                if (this._config.ShowQueryForm)
                {
                    this.ShowQueryForm(context);
                    return;
                }
                else
                {
                    context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                    return;
                }
            }

            //Get Other options associated with this query
            List <String> userDefaultGraphs = new List <String>();
            List <String> userNamedGraphs   = new List <String>();
            long          timeout           = 0;
            bool          partialResults    = this._config.DefaultPartialResults;

            //Get the Default Graph URIs (if any)
            if (context.Request.QueryString["default-graph-uri"] != null)
            {
                userDefaultGraphs.AddRange(context.Request.QueryString.GetValues("default-graph-uri"));
            }
            else if (context.Request.Form["default-graph-uri"] != null)
            {
                userDefaultGraphs.AddRange(context.Request.Form.GetValues("default-graph-uri"));
            }
            //Get the Named Graph URIs (if any)
            if (context.Request.QueryString["named-graph-uri"] != null)
            {
                userNamedGraphs.AddRange(context.Request.QueryString.GetValues("named-graph-uri"));
            }
            else if (context.Request.Form["named-graph-uri"] != null)
            {
                userNamedGraphs.AddRange(context.Request.Form.GetValues("named-graph-uri"));
            }

            //Get Timeout setting (if any)
            if (context.Request.QueryString["timeout"] != null)
            {
                if (!Int64.TryParse(context.Request.QueryString["timeout"], out timeout))
                {
                    timeout = this._config.DefaultTimeout;
                }
            }
            else if (context.Request.Form["timeout"] != null)
            {
                if (!Int64.TryParse(context.Request.Form["timeout"], out timeout))
                {
                    timeout = this._config.DefaultTimeout;
                }
            }
            //Get Partial Results Setting (if any);
            if (context.Request.QueryString["partialResults"] != null)
            {
                if (!Boolean.TryParse(context.Request.QueryString["partialResults"], out partialResults))
                {
                    partialResults = this._config.DefaultPartialResults;
                }
            }
            else if (context.Request.Form["partialResults"] != null)
            {
                if (!Boolean.TryParse(context.Request.Form["partialResults"], out partialResults))
                {
                    partialResults = this._config.DefaultPartialResults;
                }
            }

            try
            {
                //Now we're going to parse the Query
                SparqlQueryParser parser = new SparqlQueryParser(this._config.QuerySyntax);
                parser.ExpressionFactories = this._config.ExpressionFactories;
                parser.QueryOptimiser      = this._config.QueryOptimiser;
                SparqlQuery query = parser.ParseFromString(queryText);
                query.AlgebraOptimisers = this._config.AlgebraOptimisers;

                //Check whether we need to use authentication
                //If there are no user groups then no authentication is in use so we default to authenticated with no per-action authentication needed
                bool isAuth = true, requireActionAuth = false;
                if (this._config.UserGroups.Any())
                {
                    //If we have user
                    isAuth            = HandlerHelper.IsAuthenticated(context, this._config.UserGroups);
                    requireActionAuth = true;
                }
                if (!isAuth)
                {
                    return;
                }

                //Is this user allowed to make this kind of query?
                if (requireActionAuth)
                {
                    HandlerHelper.IsAuthenticated(context, this._config.UserGroups, this.GetQueryPermissionAction(query));
                }

                //Set the Default Graph URIs (if any)
                if (userDefaultGraphs.Count > 0)
                {
                    //Default Graph Uri specified by default-graph-uri parameter or Web.config settings
                    foreach (String userDefaultGraph in userDefaultGraphs)
                    {
                        if (!userDefaultGraph.Equals(String.Empty))
                        {
                            query.AddDefaultGraph(new Uri(userDefaultGraph));
                        }
                    }
                }
                else if (!this._config.DefaultGraphURI.Equals(String.Empty))
                {
                    //Only applies if the Query doesn't specify any Default Graph
                    if (!query.DefaultGraphs.Any())
                    {
                        query.AddDefaultGraph(new Uri(this._config.DefaultGraphURI));
                    }
                }

                //Set the Named Graph URIs (if any)
                if (userNamedGraphs.Count > 0)
                {
                    foreach (String userNamedGraph in userNamedGraphs)
                    {
                        if (!userNamedGraph.Equals(String.Empty))
                        {
                            query.AddNamedGraph(new Uri(userNamedGraph));
                        }
                    }
                }

                //Set Timeout setting
                if (timeout > 0)
                {
                    query.Timeout = timeout;
                }
                else
                {
                    query.Timeout = this._config.DefaultTimeout;
                }

                //Set Partial Results Setting
                query.PartialResultsOnTimeout = partialResults;

                //Set Describe Algorithm
                query.Describer = this._config.DescribeAlgorithm;

                //Now we can finally make the query and return the results
                Object result = this.ProcessQuery(query);
                this.ProcessQueryResults(context, result);

                //Update the Cache as the request may have changed the endpoint
                this.UpdateConfig(context);
            }
            catch (RdfParseException parseEx)
            {
                HandleQueryErrors(context, "Parsing Error", queryText, parseEx, (int)HttpStatusCode.BadRequest);
            }
            catch (RdfQueryTimeoutException timeoutEx)
            {
                HandleQueryErrors(context, "Query Timeout Error", queryText, timeoutEx);
            }
            catch (RdfQueryException queryEx)
            {
                HandleQueryErrors(context, "Query Error", queryText, queryEx);
            }
            catch (RdfWriterSelectionException writerSelEx)
            {
                HandleQueryErrors(context, "Output Selection Error", queryText, writerSelEx, (int)HttpStatusCode.NotAcceptable);
            }
            catch (RdfException rdfEx)
            {
                HandleQueryErrors(context, "RDF Error", queryText, rdfEx);
            }
            catch (Exception ex)
            {
                HandleQueryErrors(context, "Error", queryText, ex);
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Processes a SPARQL Query Request
        /// </summary>
        /// <param name="context">HTTP Context</param>
        public void ProcessRequest(HttpContext context)
        {
            this._config = this.LoadConfig(context);
            WebContext webContext = new WebContext(context);

            //Add our Standard Headers
            HandlerHelper.AddStandardHeaders(webContext, this._config);

            //Options we need to determine based on the HTTP Method used
            String[]      queries;
            String        queryText         = null;
            List <String> userDefaultGraphs = new List <String>();
            List <String> userNamedGraphs   = new List <String>();

            try
            {
                //Decide what to do based on the HTTP Method
                switch (context.Request.HttpMethod.ToUpper())
                {
                case "OPTIONS":
                    //OPTIONS requests always result in the Service Description document
                    IGraph svcDescrip = SparqlServiceDescriber.GetServiceDescription(this._config, UriFactory.Create(context.Request.Url.AbsoluteUri));
                    HandlerHelper.SendToClient(webContext, svcDescrip, this._config);
                    return;

                case "HEAD":
                    //Just return from a HEAD request
                    return;

                case "GET":
                    //GET expects a query parameter in the querystring
                    queries = context.Request.QueryString.GetValues("query");
                    if (queries != null)
                    {
                        if (queries.Length > 1)
                        {
                            throw new ArgumentException("The query parameter was specified multiple times in the querystring");
                        }
                        queryText = queries.Length == 1 ? queries[0] : null;
                    }

                    //If no Query sent either show Query Form or give a HTTP 400 response
                    if (String.IsNullOrEmpty(queryText))
                    {
                        //If there is no Query we may return the SPARQL Service Description where appropriate
                        try
                        {
                            //If we might show the Query Form only show the Description if the selected writer is
                            //not a HTML writer
                            MimeTypeDefinition definition = MimeTypesHelper.GetDefinitions(HandlerHelper.GetAcceptTypes(webContext)).FirstOrDefault(d => d.CanWriteRdf);
                            if (definition != null)
                            {
                                IRdfWriter writer = definition.GetRdfWriter();
                                if (!this._config.ShowQueryForm || !(writer is IHtmlWriter))
                                {
                                    //If not a HTML Writer selected OR not showing Query Form then show the Service Description Graph
                                    //unless an error occurs creating it
                                    IGraph serviceDescrip = SparqlServiceDescriber.GetServiceDescription(this._config, UriFactory.Create(context.Request.Url.AbsoluteUri));
                                    context.Response.ContentType     = definition.CanonicalMimeType;
                                    context.Response.ContentEncoding = definition.Encoding;
                                    writer.Save(serviceDescrip, new StreamWriter(context.Response.OutputStream, definition.Encoding));
                                    return;
                                }
                            }
                        }
                        catch
                        {
                            //Ignore Exceptions - we'll just show the Query Form or return a 400 Bad Request instead
                        }

                        //Otherwise we'll either show the Query Form or return a 400 Bad Request
                        if (this._config.ShowQueryForm)
                        {
                            this.ShowQueryForm(context);
                        }
                        else
                        {
                            throw new ArgumentException("Missing required query parameter");
                        }
                        return;
                    }

                    //Get the Default Graph URIs (if any)
                    if (context.Request.QueryString["default-graph-uri"] != null)
                    {
                        userDefaultGraphs.AddRange(context.Request.QueryString.GetValues("default-graph-uri"));
                    }
                    //Get the Named Graph URIs (if any)
                    if (context.Request.QueryString["named-graph-uri"] != null)
                    {
                        userNamedGraphs.AddRange(context.Request.QueryString.GetValues("named-graph-uri"));
                    }
                    break;

                case "POST":
                    //POST requires a valid content type
                    if (context.Request.ContentType != null)
                    {
                        MimeTypeSelector contentType = MimeTypeSelector.Create(context.Request.ContentType, 0);
                        if (contentType.Type.Equals(MimeTypesHelper.WWWFormURLEncoded))
                        {
                            //Form URL Encoded was declared type so expect a query parameter in the Form parameters
                            queries = context.Request.Form.GetValues("query");
                            if (queries == null)
                            {
                                throw new ArgumentException("Required query parameter in POST body was missing");
                            }
                            if (queries.Length == 0)
                            {
                                throw new ArgumentException("Required query parameter in POST body was missing");
                            }
                            if (queries.Length > 1)
                            {
                                throw new ArgumentException("The query parameter was specified multiple times in the POST body");
                            }
                            queryText = queries[0];

                            //For Form URL Encoded the Default/Named Graphs may be specified by Form parameters
                            //Get the Default Graph URIs (if any)
                            if (context.Request.Form["default-graph-uri"] != null)
                            {
                                userDefaultGraphs.AddRange(context.Request.Form.GetValues("default-graph-uri"));
                            }
                            //Get the Named Graph URIs (if any)
                            if (context.Request.Form["named-graph-uri"] != null)
                            {
                                userNamedGraphs.AddRange(context.Request.Form.GetValues("named-graph-uri"));
                            }

                            break;
                        }
                        else if (contentType.Type.Equals(MimeTypesHelper.SparqlQuery))
                        {
                            //application/sparql-query was declared type so expect utf-8 charset (if present)
                            if (contentType.Charset != null && !contentType.Charset.ToLower().Equals(MimeTypesHelper.CharsetUtf8))
                            {
                                throw new ArgumentException("HTTP POST request was received with a " + MimeTypesHelper.SparqlQuery + " Content-Type but a non UTF-8 charset parameter");
                            }

                            //Read the query from the request body
                            using (StreamReader reader = new StreamReader(context.Request.InputStream))
                            {
                                queryText = reader.ReadToEnd();
                                reader.Close();
                            }

                            //For application/sparql-query the Default/Named Graphs may be specified by querystring parameters
                            //Get the Default Graph URIs (if any)
                            if (context.Request.QueryString["default-graph-uri"] != null)
                            {
                                userDefaultGraphs.AddRange(context.Request.QueryString.GetValues("default-graph-uri"));
                            }
                            //Get the Named Graph URIs (if any)
                            if (context.Request.QueryString["named-graph-uri"] != null)
                            {
                                userNamedGraphs.AddRange(context.Request.QueryString.GetValues("named-graph-uri"));
                            }

                            break;
                        }
                        else
                        {
                            throw new ArgumentException("HTTP POST made to SPARQL query endpoint had an invalid Content-Type header, only " + MimeTypesHelper.WWWFormURLEncoded + " and " + MimeTypesHelper.SparqlQuery + " are acceptable");
                        }
                    }
                    throw new ArgumentException("HTTP POST made to SPARQL Query endpoint was missing the required Content-Type header");

                default:
                    throw new NotSupportedException("HTTP " + context.Request.HttpMethod.ToUpper() + " is not supported by a SPARQL Query endpoint");
                }

                //Get non-standard options associated with the query
                long timeout        = 0;
                bool partialResults = this._config.DefaultPartialResults;

                //Get Timeout setting (if any)
                if (context.Request.QueryString["timeout"] != null)
                {
                    if (!Int64.TryParse(context.Request.QueryString["timeout"], out timeout))
                    {
                        timeout = this._config.DefaultTimeout;
                    }
                }
                else if (context.Request.Form["timeout"] != null)
                {
                    if (!Int64.TryParse(context.Request.Form["timeout"], out timeout))
                    {
                        timeout = this._config.DefaultTimeout;
                    }
                }
                //Get Partial Results Setting (if any);
                if (context.Request.QueryString["partialResults"] != null)
                {
                    if (!Boolean.TryParse(context.Request.QueryString["partialResults"], out partialResults))
                    {
                        partialResults = this._config.DefaultPartialResults;
                    }
                }
                else if (context.Request.Form["partialResults"] != null)
                {
                    if (!Boolean.TryParse(context.Request.Form["partialResults"], out partialResults))
                    {
                        partialResults = this._config.DefaultPartialResults;
                    }
                }

                //Now we're going to parse the Query
                SparqlQueryParser parser = new SparqlQueryParser(this._config.Syntax);
                parser.DefaultBaseUri      = context.Request.Url;
                parser.ExpressionFactories = this._config.ExpressionFactories;
                parser.QueryOptimiser      = this._config.QueryOptimiser;
                SparqlQuery query = parser.ParseFromString(queryText);
                query.AlgebraOptimisers         = this._config.AlgebraOptimisers;
                query.PropertyFunctionFactories = this._config.PropertyFunctionFactories;

                //Check whether we need to use authentication
                //If there are no user groups then no authentication is in use so we default to authenticated with no per-action authentication needed
                bool isAuth = true, requireActionAuth = false;
                if (this._config.UserGroups.Any())
                {
                    //If we have user
                    isAuth            = HandlerHelper.IsAuthenticated(webContext, this._config.UserGroups);
                    requireActionAuth = true;
                }
                if (!isAuth)
                {
                    return;
                }

                //Is this user allowed to make this kind of query?
                if (requireActionAuth)
                {
                    HandlerHelper.IsAuthenticated(webContext, this._config.UserGroups, this.GetPermissionAction(query));
                }

                //Clear query dataset if there is a protocol defined one
                userDefaultGraphs.RemoveAll(g => String.IsNullOrEmpty(g));
                userNamedGraphs.RemoveAll(g => String.IsNullOrEmpty(g));
                bool isProtocolDataset = false;
                if (userDefaultGraphs.Count > 0 || userNamedGraphs.Count > 0)
                {
                    query.ClearDefaultGraphs();
                    query.ClearNamedGraphs();
                    isProtocolDataset = true;
                }

                //Set the Default Graph URIs (if any)
                if (isProtocolDataset)
                {
                    foreach (String userDefaultGraph in userDefaultGraphs)
                    {
                        query.AddDefaultGraph(UriFactory.Create(userDefaultGraph));
                    }
                }
                else if (!this._config.DefaultGraphURI.Equals(String.Empty))
                {
                    //Only applies if the Query doesn't specify any Default Graph and there wasn't a protocol defined
                    //dataset present
                    if (!query.DefaultGraphs.Any())
                    {
                        query.AddDefaultGraph(UriFactory.Create(this._config.DefaultGraphURI));
                    }
                }

                //Set the Named Graph URIs (if any)
                if (isProtocolDataset)
                {
                    query.ClearNamedGraphs();
                    foreach (String userNamedGraph in userNamedGraphs)
                    {
                        query.AddNamedGraph(UriFactory.Create(userNamedGraph));
                    }
                }

                //Set Timeout setting
                if (timeout > 0)
                {
                    query.Timeout = timeout;
                }
                else
                {
                    query.Timeout = this._config.DefaultTimeout;
                }

                //Set Partial Results Setting
                query.PartialResultsOnTimeout = partialResults;

                //Set Describe Algorithm
                query.Describer = this._config.DescribeAlgorithm;

                //Now we can finally make the query and return the results
                Object result = this.ProcessQuery(query);
                this.ProcessResults(context, result);

                //Update the Cache as the request may have changed the endpoint
                this.UpdateConfig(context);
            }
            catch (RdfParseException parseEx)
            {
                HandleErrors(context, "Parsing Error", queryText, parseEx, (int)HttpStatusCode.BadRequest);
            }
            catch (RdfQueryTimeoutException timeoutEx)
            {
                HandleErrors(context, "Query Timeout Error", queryText, timeoutEx);
            }
            catch (RdfQueryException queryEx)
            {
                HandleErrors(context, "Update Error", queryText, queryEx);
            }
            catch (RdfWriterSelectionException writerSelEx)
            {
                HandleErrors(context, "Output Selection Error", queryText, writerSelEx, (int)HttpStatusCode.NotAcceptable);
            }
            catch (RdfException rdfEx)
            {
                HandleErrors(context, "RDF Error", queryText, rdfEx);
            }
            catch (NotSupportedException notSupEx)
            {
                HandleErrors(context, "HTTP Request Error", null, notSupEx, (int)HttpStatusCode.MethodNotAllowed);
            }
            catch (ArgumentException argEx)
            {
                HandleErrors(context, "HTTP Request Error", null, argEx, (int)HttpStatusCode.BadRequest);
            }
            catch (Exception ex)
            {
                HandleErrors(context, "Error", queryText, ex);
            }
        }