예제 #1
0
        /// <summary>
        /// Evaluates the subquery in the given context.
        /// </summary>
        /// <param name="context">Evaluation Context.</param>
        /// <returns></returns>
        public BaseMultiset Evaluate(SparqlEvaluationContext context)
        {
            // Use the same algebra optimisers as the parent query (if any)
            if (context.Query != null)
            {
                _subquery.AlgebraOptimisers = context.Query.AlgebraOptimisers;
            }

            if (context.InputMultiset is NullMultiset)
            {
                context.OutputMultiset = context.InputMultiset;
            }
            else if (context.InputMultiset.IsEmpty)
            {
                context.OutputMultiset = new NullMultiset();
            }
            else
            {
                SparqlEvaluationContext subcontext = new SparqlEvaluationContext(_subquery, context.Data, context.Processor);

                // Add any Named Graphs to the subquery
                if (context.Query != null)
                {
                    foreach (Uri u in context.Query.NamedGraphs)
                    {
                        _subquery.AddNamedGraph(u);
                    }
                }

                ISparqlAlgebra query = _subquery.ToAlgebra();
                try
                {
                    // Evaluate the Subquery
                    context.OutputMultiset = subcontext.Evaluate(query);

                    // If the Subquery contains a GROUP BY it may return a Group Multiset in which case we must flatten this to a Multiset
                    if (context.OutputMultiset is GroupMultiset)
                    {
                        context.OutputMultiset = new Multiset((GroupMultiset)context.OutputMultiset);
                    }

                    // Strip out any Named Graphs from the subquery
                    if (_subquery.NamedGraphs.Any())
                    {
                        _subquery.ClearNamedGraphs();
                    }
                }
                catch (RdfQueryException queryEx)
                {
                    throw new RdfQueryException("Query failed due to a failure in Subquery Execution:\n" + queryEx.Message, queryEx);
                }
            }

            return(context.OutputMultiset);
        }
예제 #2
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);
            }
        }