/// <summary> /// Saves a Graph to the Protocol Server /// </summary> /// <param name="g">Graph to save</param> public virtual void SaveGraph(IGraph g) { String saveUri = _serviceUri; if (g.BaseUri != null) { saveUri += "?graph=" + Uri.EscapeDataString(g.BaseUri.AbsoluteUri); } else { saveUri += "?default"; } try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(UriFactory.Create(saveUri)); request.Method = "PUT"; //request.ContentType = MimeTypesHelper.RdfXml[0]; request.ContentType = _writerMimeTypeDefinition.CanonicalMimeType; request = ApplyRequestOptions(request); //RdfXmlWriter writer = new RdfXmlWriter(); IRdfWriter writer = _writerMimeTypeDefinition.GetRdfWriter(); writer.Save(g, new StreamWriter(request.GetRequestStream())); Tools.HttpDebugRequest(request); using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { Tools.HttpDebugResponse(response); // If we get here then it was OK response.Close(); } } catch (WebException webEx) { throw StorageHelper.HandleHttpError(webEx, "saving a Graph to"); } }
/// <summary> /// Sends the given Graph to the Client via the HTTP Response. /// </summary> /// <param name="context">HTTP Context.</param> /// <param name="g">Graph to send.</param> protected void SendResultsToClient(IHttpContext context, IGraph g) { IRdfWriter writer; String ctype; // Look up the MIME Type Definition - if none use GetWriter instead MimeTypeDefinition definition = MimeTypesHelper.GetDefinitions(context.GetAcceptTypes()).FirstOrDefault(d => d.CanWriteRdf); if (definition != null) { writer = definition.GetRdfWriter(); ctype = definition.CanonicalMimeType; } else { writer = MimeTypesHelper.GetWriter(context.GetAcceptTypes(), out ctype); } // Set up the Writer if (writer is ICompressingWriter) { ((ICompressingWriter)writer).CompressionLevel = Options.DefaultCompressionLevel; } // Send Content to Client context.Response.ContentType = ctype; if (definition != null) { context.Response.ContentEncoding = definition.Encoding; writer.Save(g, new StreamWriter(context.Response.OutputStream, definition.Encoding)); } else { writer.Save(g, new StreamWriter(context.Response.OutputStream)); } }
public void RunConvert(String[] args) { //Set the Options if (!this.SetOptions(args)) { //If SetOptions returns false then some options were invalid and errors have been output to the error stream return; } //First grab the MIME Type Definitions for the conversion List <MimeTypeDefinition> defs = MimeTypesHelper.GetDefinitions(this._outFormats).ToList(); //Process each input to determine the Conversion Handler to use foreach (IConversionInput input in this._inputs) { String outFile; String ext = this._outExt; //First determine the writer we'll use MimeTypeDefinition graphDef = defs.FirstOrDefault(d => d.CanWriteRdf); if (graphDef != null) { //Then generate the output filename if (ext.Equals(String.Empty)) { ext = "." + graphDef.CanonicalFileExtension; } if (this._inputs.Count == 1 && !this._outputFilename.Equals(String.Empty)) { outFile = this._outputFilename; } else { outFile = input.GetFilename(this._outputFilename, ext); } //Check it doesn't already exist or overwrite is enabled if (File.Exists(outFile) && !this._overwrite) { Console.Error.WriteLine("rdfConvert: Warning: Skipping Conversion of Input " + input.ToString() + " as this would generate the Output File '" + outFile + "' which already exists and the -overwrite option was not specified"); continue; } //Get the Writer and apply Conversion Options IRdfWriter writer = graphDef.GetRdfWriter(); foreach (IConversionOption option in this._options) { option.Apply(writer); } //If -best always use SaveOnCompletionHandler if (this._best) { if (this._verbose) { Console.WriteLine("rdfConvert: Using Best Quality data conversion subject to user specified compression options"); } input.ConversionHandler = new SaveOnCompletionHandler(writer, new StreamWriter(outFile, false, graphDef.Encoding)); } else { //Use the fast WriteThroughHandler where possible if (writer is IFormatterBasedWriter) { if (this._verbose) { Console.WriteLine("rdfConvert: Using Streaming Conversion with formatter " + ((IFormatterBasedWriter)writer).TripleFormatterType.Name); } input.ConversionHandler = new WriteToFileHandler(outFile, graphDef.Encoding, ((IFormatterBasedWriter)writer).TripleFormatterType); } else { //Can't use it in this case if (this._verbose) { Console.WriteLine("rdfConvert: Warning: Target Format not suitable for streaming conversion, input data will be loaded into memory prior to conversion"); } input.ConversionHandler = new SaveOnCompletionHandler(writer, new StreamWriter(outFile, false, graphDef.Encoding)); } } } else { MimeTypeDefinition storeDef = defs.FirstOrDefault(d => d.CanWriteRdfDatasets); if (storeDef != null) { //Then generate the output filename if (ext.Equals(String.Empty)) { ext = "." + storeDef.CanonicalFileExtension; } outFile = input.GetFilename(this._outputFilename, ext); //Get the Writer and apply conversion options IStoreWriter writer = storeDef.GetRdfDatasetWriter(); foreach (IConversionOption option in this._options) { option.Apply(writer); } //If -best always use SaveOnCompletionHandler if (this._best) { if (this._verbose) { Console.WriteLine("rdfConvert: Using Best Quality data conversion subject to user specified compression options"); } input.ConversionHandler = new SaveStoreOnCompletionHandler(writer, new StreamWriter(outFile, false, storeDef.Encoding)); } else { //Use the fast WriteThroughHandler where possible if (writer is IFormatterBasedWriter) { if (this._verbose) { Console.WriteLine("rdfConvert: Using Streaming Conversion with formatter " + ((IFormatterBasedWriter)writer).TripleFormatterType.Name); } input.ConversionHandler = new WriteToFileHandler(outFile, graphDef.Encoding, ((IFormatterBasedWriter)writer).TripleFormatterType); } else { if (this._verbose) { Console.WriteLine("rdfConvert: Warning: Target Format not suitable for streaming conversion, input data will be loaded into memory prior to conversion"); } input.ConversionHandler = new SaveStoreOnCompletionHandler(writer, new StreamWriter(outFile, false, storeDef.Encoding)); } } } else { Console.Error.WriteLine("rdfConvert: Warning: Skipping Conversion of Input " + input.ToString() + " as unable to determine how to convert it"); continue; } } //Then do the Conversion Console.WriteLine("rdfConvert: Converting Input " + input.ToString() + " to '" + outFile + "'..."); try { if (this._verbose) { input.ConversionHandler = new ConversionProgressHandler(input.ConversionHandler); Console.WriteLine("rdfConvert: Debug: Conversion Handler is " + input.ConversionHandler.GetType().FullName); } input.Convert(); Console.WriteLine("rdfConvert: Converted Input " + input.ToString() + " to '" + outFile + "' OK"); } catch (RdfParseException parseEx) { Console.Error.WriteLine("rdfConvert: Error: Error Converting Input " + input.ToString() + " due to a RDF Parse Exception"); Console.Error.WriteLine(parseEx.Message); if (this._debug) { this.DebugErrors(parseEx); } } catch (RdfException rdfEx) { Console.Error.WriteLine("rdfConvert: Error: Error Converting Input " + input.ToString() + " due to a RDF Exception"); Console.Error.WriteLine(rdfEx.Message); if (this._debug) { this.DebugErrors(rdfEx); } } catch (Exception ex) { Console.Error.WriteLine("rdfConvert: Error: Error Converting Input " + input.ToString() + " due to a Unexpected Exception"); Console.Error.WriteLine(ex.Message); if (this._debug) { this.DebugErrors(ex); } } } }
/// <summary> /// Selects the Writer to use for sending the Graph to the Client /// </summary> /// <param name="definition">Selected MIME Type Definition</param> /// <returns></returns> /// <remarks> /// <para> /// Implementations may override this if they wish to substitute in an alternative writer for certain MIME types (e.g. as done by the <see cref="SchemaGraphHandler">SchemaGraphHandler</see>) /// </para> /// </remarks> protected virtual IRdfWriter SelectWriter(MimeTypeDefinition definition) { return definition.GetRdfWriter(); }
/// <summary> /// Processes SPARQL Update requests /// </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[] updates; String updateText = 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": // A GET with an update parameter is a Bad Request updates = context.Request.QueryString.GetValues("update"); if (updates != null && updates.Length > 0) { throw new ArgumentException("Updates cannot be submitted as GET requests"); } // Otherwise GET either results in the Service Description if appropriately conneg'd or // the update form if enabled try { // If we might show the Update Form only show the Description if the selected writer is // not a HTML writer MimeTypeDefinition definition = MimeTypesHelper.GetDefinitions(webContext.GetAcceptTypes()).FirstOrDefault(d => d.CanWriteRdf); if (definition != null) { IRdfWriter writer = definition.GetRdfWriter(); if (!(writer is IHtmlWriter)) { // If not a HTML Writer selected 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 } // If a Writer can't be selected then we'll either show the Update Form or return a 400 Bad Request if (this._config.ShowUpdateForm) { this.ShowUpdateForm(context); } else { throw new ArgumentException("Updates cannot be submitted as GET requests"); } return; case "POST": 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 an update parameter in the Form parameters updates = context.Request.Form.GetValues("update"); if (updates == null) { throw new ArgumentException("Required update parameter in POST body was missing"); } if (updates.Length == 0) { throw new ArgumentException("Required update parameter in POST body was missing"); } if (updates.Length > 1) { throw new ArgumentException("The update parameter was specified multiple times in the POST body"); } updateText = updates[0]; // For Form URL Encoded the Using/Using Named Graphs may be specified by Form parameters // Get the USING URIs (if any) if (context.Request.Form["using-graph-uri"] != null) { userDefaultGraphs.AddRange(context.Request.Form.GetValues("using-graph-uri")); } // Get the USING NAMED URIs (if any) if (context.Request.Form["using-named-graph-uri"] != null) { userNamedGraphs.AddRange(context.Request.Form.GetValues("using-named-graph-uri")); } break; } else if (contentType.Type.Equals(MimeTypesHelper.SparqlUpdate)) { // application/sparql-update 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.SparqlUpdate + " Content-Type but a non UTF-8 charset parameter"); } using (StreamReader reader = new StreamReader(context.Request.InputStream)) { updateText = reader.ReadToEnd(); reader.Close(); } // For application/sparql-update the Using/Using Named Graphs may be specified by querystring parameters // Get the USING URIs (if any) if (context.Request.QueryString["using-graph-uri"] != null) { userDefaultGraphs.AddRange(context.Request.QueryString.GetValues("using-graph-uri")); } // Get the USING NAMED URIs (if any) if (context.Request.QueryString["using-named-graph-uri"] != null) { userNamedGraphs.AddRange(context.Request.QueryString.GetValues("using-named-graph-uri")); } break; } else { throw new ArgumentException("HTTP POST made to SPARQL update endpoint had an invalid Content-Type header, only " + MimeTypesHelper.WWWFormURLEncoded + " and " + MimeTypesHelper.SparqlUpdate + " 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 Update endpoint"); } // Clean up protocol provided dataset userDefaultGraphs.RemoveAll(g => String.IsNullOrEmpty(g)); userNamedGraphs.RemoveAll(g => String.IsNullOrEmpty(g)); // Now we're going to parse the Updates SparqlUpdateParser parser = new SparqlUpdateParser(); parser.DefaultBaseUri = context.Request.Url; parser.ExpressionFactories = this._config.ExpressionFactories; SparqlUpdateCommandSet commands = parser.ParseFromString(updateText); // 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; } // First check actions to see whether they are all permissible and apply USING/USING NAMED parameters foreach (SparqlUpdateCommand cmd in commands.Commands) { // Authenticate each action bool actionAuth = true; if (requireActionAuth) { actionAuth = HandlerHelper.IsAuthenticated(webContext, this._config.UserGroups, this.GetPermissionAction(cmd)); } if (!actionAuth) { throw new SparqlUpdatePermissionException("You are not authorised to perform the " + this.GetPermissionAction(cmd) + " action"); } // Check whether we need to (and are permitted to) apply USING/USING NAMED parameters if (userDefaultGraphs.Count > 0 || userNamedGraphs.Count > 0) { BaseModificationCommand modify = cmd as BaseModificationCommand; if (modify != null) { if (modify.GraphUri != null || modify.UsingUris.Any() || modify.UsingNamedUris.Any()) { // Invalid if a command already has a WITH/USING/USING NAMED throw new SparqlUpdateMalformedException("A command in your update request contains a WITH/USING/USING NAMED clause but you have also specified one/both of the using-graph-uri or using-named-graph-uri parameters which is not permitted by the SPARQL Protocol"); } else { // Otherwise go ahead and apply userDefaultGraphs.ForEach(u => modify.AddUsingUri(UriFactory.Create(u))); userNamedGraphs.ForEach(u => modify.AddUsingNamedUri(UriFactory.Create(u))); } } } } // Then assuming we got here this means all our actions are permitted so now we can process the updates this.ProcessUpdates(commands); // Flush outstanding changes this._config.Processor.Flush(); // Update the Cache as the request may have changed the endpoint this.UpdateConfig(context); } catch (RdfParseException parseEx) { HandleErrors(context, "Parsing Error", updateText, parseEx, (int)HttpStatusCode.BadRequest); } catch (SparqlUpdatePermissionException permEx) { HandleErrors(context, "Permissions Error", updateText, permEx, (int)HttpStatusCode.Forbidden); } catch (SparqlUpdateMalformedException malEx) { HandleErrors(context, "Malformed Update Error", updateText, malEx, (int)HttpStatusCode.BadRequest); } catch (SparqlUpdateException updateEx) { HandleErrors(context, "Update Error", updateText, updateEx); } catch (RdfException rdfEx) { HandleErrors(context, "RDF Error", updateText, 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", updateText, ex); } }
/// <summary> /// Selects the Writer to use for sending the Graph to the Client /// </summary> /// <param name="definition">Selected MIME Type Definition</param> /// <returns></returns> /// <remarks> /// <para> /// Implementations may override this if they wish to substitute in an alternative writer for certain MIME types (e.g. as done by the <see cref="SchemaGraphHandler">SchemaGraphHandler</see>) /// </para> /// </remarks> protected virtual IRdfWriter SelectWriter(MimeTypeDefinition definition) { return(definition.GetRdfWriter()); }
/// <summary> /// Processes SPARQL Update requests /// </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 update submitted String updateText = context.Request.QueryString["update"]; if (updateText == null || updateText.Equals(String.Empty)) { updateText = context.Request.Form["update"]; } //If no Update sent either show Update Form or give a HTTP 400 response if (updateText == null || updateText.Equals(String.Empty)) { //If there is no Update we may return the SPARQL Service Description where appropriate try { //If we might show the Update 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.ShowUpdateForm || !(writer is IHtmlWriter)) { //If not a HTML Writer selected OR not showing Update 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 Update Form or return a 400 Bad Request if (this._config.ShowUpdateForm) { this.ShowUpdateForm(context); } else { context.Response.StatusCode = (int)HttpStatusCode.BadRequest; } return; } try { //Now we're going to parse the Updates SparqlUpdateParser parser = new SparqlUpdateParser(); parser.ExpressionFactories = this._config.ExpressionFactories; SparqlUpdateCommandSet commands = parser.ParseFromString(updateText); //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; } //First check actions to see whether they are all permissible foreach (SparqlUpdateCommand cmd in commands.Commands) { //Authenticate each action bool actionAuth = true; if (requireActionAuth) { actionAuth = HandlerHelper.IsAuthenticated(context, this._config.UserGroups, this.GetPermissionAction(cmd)); } if (!actionAuth) { throw new SparqlUpdateException("You are not authorised to perform the " + this.GetPermissionAction(cmd) + " action"); } } //Then assuming we got here this means all our actions are permitted so now we can process the updates this.ProcessUpdates(commands); //Flush outstanding changes this._config.Processor.Flush(); //Update the Cache as the request may have changed the endpoint this.UpdateConfig(context); } catch (RdfParseException parseEx) { HandleErrors(context, "Parsing Error", updateText, parseEx); } catch (SparqlUpdateException updateEx) { HandleErrors(context, "Update Error", updateText, updateEx); } catch (RdfException rdfEx) { HandleErrors(context, "RDF Error", updateText, rdfEx); } catch (Exception ex) { HandleErrors(context, "Error", updateText, ex); } }
/// <summary> /// Processes SPARQL Update requests /// </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, UriFactory.Create(context.Request.Url.AbsoluteUri)); HandlerHelper.SendToClient(context, svcDescrip, this._config); return; } //See if there has been an update submitted String updateText = null; if (context.Request.ContentType != null) { if (context.Request.ContentType.Equals(MimeTypesHelper.WWWFormURLEncoded)) { updateText = context.Request.Form["update"]; } else if (context.Request.ContentType.Equals(MimeTypesHelper.SparqlUpdate)) { updateText = new StreamReader(context.Request.InputStream).ReadToEnd(); } } else { updateText = context.Request.Form["update"]; } //If no Update sent either show Update Form or give a HTTP 400 response if (updateText == null || updateText.Equals(String.Empty)) { //If there is no Update we may return the SPARQL Service Description where appropriate try { //If we might show the Update 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.ShowUpdateForm || !(writer is IHtmlWriter)) { //If not a HTML Writer selected OR not showing Update Form then show the Service Description Graph //unless an error occurs creating it IGraph serviceDescrip = SparqlServiceDescriber.GetServiceDescription(context, 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 } //If a Writer can't be selected then we'll either show the Update Form or return a 400 Bad Request if (this._config.ShowUpdateForm) { this.ShowUpdateForm(context); } else { context.Response.StatusCode = (int)HttpStatusCode.BadRequest; } return; } //Get Other options associated with this update List <String> userDefaultGraphs = new List <String>(); List <String> userNamedGraphs = new List <String>(); //Get the USING URIs (if any) if (context.Request.QueryString["using-graph-uri"] != null) { userDefaultGraphs.AddRange(context.Request.QueryString.GetValues("using-graph-uri")); } else if (context.Request.Form["using-graph-uri"] != null) { userDefaultGraphs.AddRange(context.Request.Form.GetValues("using-graph-uri")); } //Get the USING NAMED URIs (if any) if (context.Request.QueryString["using-named-graph-uri"] != null) { userNamedGraphs.AddRange(context.Request.QueryString.GetValues("using-named-graph-uri")); } else if (context.Request.Form["using-named-graph-uri"] != null) { userNamedGraphs.AddRange(context.Request.Form.GetValues("using-named-graph-uri")); } try { //Now we're going to parse the Updates SparqlUpdateParser parser = new SparqlUpdateParser(); parser.ExpressionFactories = this._config.ExpressionFactories; SparqlUpdateCommandSet commands = parser.ParseFromString(updateText); //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; } //First check actions to see whether they are all permissible and apply USING/USING NAMED parameters foreach (SparqlUpdateCommand cmd in commands.Commands) { //Authenticate each action bool actionAuth = true; if (requireActionAuth) { actionAuth = HandlerHelper.IsAuthenticated(context, this._config.UserGroups, this.GetPermissionAction(cmd)); } if (!actionAuth) { throw new SparqlUpdatePermissionException("You are not authorised to perform the " + this.GetPermissionAction(cmd) + " action"); } //Check whether we need to (and are permitted to) apply USING/USING NAMED parameters if (userDefaultGraphs.Count > 0 || userNamedGraphs.Count > 0) { BaseModificationCommand modify = cmd as BaseModificationCommand; if (modify != null) { if (modify.GraphUri != null || modify.UsingUris.Any() || modify.UsingNamedUris.Any()) { //Invalid if a command already has a WITH/USING/USING NAMED throw new SparqlUpdateMalformedException("A command in your update request contains a WITH/USING/USING NAMED clause but you have also specified one/both of the using-graph-uri or using-named-graph-uri parameters which is not permitted by the SPARQL Protocol"); } else { //Otherwise go ahead and apply userDefaultGraphs.ForEach(u => modify.AddUsingUri(UriFactory.Create(u))); userNamedGraphs.ForEach(u => modify.AddUsingNamedUri(UriFactory.Create(u))); } } } } //Then assuming we got here this means all our actions are permitted so now we can process the updates this.ProcessUpdates(commands); //Flush outstanding changes this._config.Processor.Flush(); //Update the Cache as the request may have changed the endpoint this.UpdateConfig(context); } catch (RdfParseException parseEx) { HandleErrors(context, "Parsing Error", updateText, parseEx, (int)HttpStatusCode.BadRequest); } catch (SparqlUpdatePermissionException permEx) { HandleErrors(context, "Permissions Error", updateText, permEx, (int)HttpStatusCode.Forbidden); } catch (SparqlUpdateMalformedException malEx) { HandleErrors(context, "Malformed Update Error", updateText, malEx, (int)HttpStatusCode.BadRequest); } catch (SparqlUpdateException updateEx) { HandleErrors(context, "Update Error", updateText, updateEx); } catch (RdfException rdfEx) { HandleErrors(context, "RDF Error", updateText, rdfEx); } catch (Exception ex) { HandleErrors(context, "Error", updateText, 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); } }
static void DoProtocol(Dictionary <String, String> arguments) { String method; SparqlHttpProtocolConnector endpoint; bool verbose = arguments.ContainsKey("verbose") || arguments.ContainsKey("v"); if (verbose) { Options.HttpDebugging = true; } Options.UriLoaderCaching = !arguments.ContainsKey("nocache"); String dataFile; //First Argument must be HTTP Method if (arguments.ContainsKey("$1") && !arguments["$1"].Equals(String.Empty)) { method = arguments["$1"].ToUpper(); } else { Console.Error.WriteLine("soh: Error: First argument must be one of head, get, put or post - type soh --help for details"); Environment.Exit(-1); return; } try { if (arguments.ContainsKey("$2") && !arguments["$2"].Equals(String.Empty)) { endpoint = new SparqlHttpProtocolConnector(new Uri(arguments["$2"])); } else { Console.Error.WriteLine("soh: Error: Second argument is required and must be the Dataset URI"); Environment.Exit(-1); return; } } catch (UriFormatException uriEx) { Console.Error.WriteLine("soh: Error: Malformed SPARQL Endpoint URI"); Console.Error.WriteLine(uriEx.Message); Environment.Exit(-1); return; } if (verbose) { Console.Error.WriteLine("soh: Connection to SPARQL Uniform HTTP Protocol endpoint created OK"); } Uri graphUri; try { if (arguments.ContainsKey("$3") && !arguments["$3"].Equals(String.Empty)) { if (arguments["$3"].Equals("default")) { graphUri = null; if (verbose) { Console.Error.WriteLine("soh: Graph URI for Protocol request is 'default' (indicates the default unnamed graph)"); } } else { graphUri = new Uri(arguments["$3"]); if (verbose) { Console.Error.WriteLine("soh: Graph URI for Protocol request is '" + graphUri.ToString() + "'"); } } } else { Console.Error.WriteLine("soh: Error: Third argument is required and must be the Graph URI or default to indicate the default unnamed Graph"); Environment.Exit(-1); return; } } catch (UriFormatException uriEx) { Console.Error.WriteLine("soh: Error: Malformed Graph URI"); Console.Error.WriteLine(uriEx.Message); Environment.Exit(-1); return; } try { switch (method) { case "GET": if (arguments.ContainsKey("$4")) { Console.Error.WriteLine("soh: Error: Optional file argument for protocol mode is not permitted with the get method"); Environment.Exit(-1); return; } if (verbose) { Console.Error.WriteLine("soh: Making a GET request to the Protocol endpoint"); } Graph g = new Graph(); endpoint.LoadGraph(g, graphUri); if (verbose) { Console.Error.WriteLine("soh: Received a Graph with " + g.Triples.Count + " Triples"); } //Use users choice of output format otherwise RDF/XML MimeTypeDefinition definition = null; if (arguments.ContainsKey("accept")) { definition = MimeTypesHelper.GetDefinitions(arguments["accept"]).FirstOrDefault(d => d.CanWriteRdf); } if (definition != null) { Console.OutputEncoding = definition.Encoding; IRdfWriter writer = definition.GetRdfWriter(); writer.Save(g, new StreamWriter(Console.OpenStandardOutput(), definition.Encoding)); } else { if (arguments.ContainsKey("accept") && verbose) { Console.Error.WriteLine("soh: Warning: You wanted output in format '" + arguments["accept"] + "' but dotNetRDF does not support this format so RDF/XML will be returned instead"); } RdfXmlWriter rdfXmlWriter = new RdfXmlWriter(); rdfXmlWriter.Save(g, new StreamWriter(Console.OpenStandardOutput(), Encoding.UTF8)); } break; case "HEAD": if (arguments.ContainsKey("$4")) { Console.Error.WriteLine("soh: Error: Optional file argument for protocol mode is not permitted with the head method"); Environment.Exit(-1); return; } if (verbose) { Console.Error.WriteLine("soh: Making a HEAD request to the Protocol endpoint"); } bool exists = endpoint.HasGraph(graphUri); Console.WriteLine(exists.ToString().ToLower()); break; case "PUT": //Parse in the Graph to be PUT first if (arguments.ContainsKey("$4") && !arguments["$4"].Equals(String.Empty)) { dataFile = arguments["$4"]; } else { Console.Error.WriteLine("soh: Error: The file argument for protocol mode is required when using the put method"); Environment.Exit(-1); return; } Graph toPut = new Graph(); FileLoader.Load(toPut, dataFile); toPut.BaseUri = graphUri; if (verbose) { Console.Error.WriteLine("soh: Graph to be uploaded has " + toPut.Triples.Count + " Triples"); Console.Error.WriteLine("soh: Making a PUT request to the Protocol endpoint"); } endpoint.SaveGraph(toPut); Console.WriteLine("soh: Graph saved to Protocol endpoint OK"); break; case "POST": //Parse in the Graph to be PUT first if (arguments.ContainsKey("$4") && !arguments["$4"].Equals(String.Empty)) { dataFile = arguments["$4"]; } else { Console.Error.WriteLine("soh: Error: The file argument for protocol mode is required when using the post method"); Environment.Exit(-1); return; } Graph toPost = new Graph(); FileLoader.Load(toPost, dataFile); if (verbose) { Console.Error.WriteLine("soh: Graph to be uploaded has " + toPost.Triples.Count + " Triples"); Console.Error.WriteLine("soh: Making a POST request to the Protocol endpoint"); } endpoint.UpdateGraph(graphUri, toPost.Triples, null); Console.WriteLine("soh: Graph updated to Protocol endpoint OK"); break; case "DELETE": if (arguments.ContainsKey("$4")) { Console.Error.WriteLine("soh: Error: Optional file argument for protocol mode is not permitted with the head method"); Environment.Exit(-1); return; } endpoint.DeleteGraph(graphUri); Console.WriteLine("soh: Graph deleted from Protocol endpoint OK"); break; default: Console.Error.WriteLine("soh: Error: " + method + " is not a HTTP Method supported by this tool"); Environment.Exit(-1); return; } } catch (Exception ex) { Console.Error.WriteLine("soh: Error: Error processing HTTP Protocol request"); Console.Error.WriteLine(ex.Message); while (ex.InnerException != null) { Console.Error.WriteLine(); Console.Error.WriteLine(ex.InnerException.Message); Console.Error.WriteLine(ex.InnerException.StackTrace); ex = ex.InnerException; } Environment.Exit(-1); return; } }