/// <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); }
/// <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(); } } }
/// <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(); } } }
/// <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); } }
/// <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); } }
/// <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); } }