Manually sending RayGunMessage does not properly ignore header names
steve
Posted on
Nov 23 2016
version: Raygun4Net.AspNetCore, Version=5.3.2.0
I have a custom provider that strips out certain headers, i.e.:
public override RaygunClient GetClient(RaygunSettings settings, HttpContext context)
...
client.IgnoreHeaderNames("Connection", "Host");
When GetClient() is invoked via the middleware, the resulting error report properly has the headers stripped out. However when I try to build up and send the message manually, the "connection" and "host" headers incorrectly remain in the report.
In both cases the same Provider.GetClient() method is called. Am I doing something wrong in the manual case or is there a bug?
A fully reproducible case can be found here: https://github.com/steve-torchia/ExceptionTesting
See HomeController.Index() for the code that causes a report to be sent incorrectly as it still contains "Host" and "Connection" headers.
Deleted User
Raygun
Posted on
Nov 24 2016
Hi Steve,
The provider strips out headers when the message is being built, which is fine when the provider builds the message from the sending of an exception as we build the message internally and set the options. If you are building the message manually then you need to provide the options to the RaygunAspNetCoreRequestMessageBuilder class in the Build method via the second parameter that takes an instance of the RaygunRequestMessageOptions class.
Here is an example of this, note I'm using the constructor of RaygunRequestMessageOptions that takes the ignore setting values which are coming from my appsettings.json configuration.
public class HomeController : Controller
{
private readonly IRaygunAspNetCoreClientProvider _clientProvider;
private readonly IOptions<RaygunSettings> _settings;
public HomeController(IRaygunAspNetCoreClientProvider clientProvider, IOptions<RaygunSettings> settings)
{
_clientProvider = clientProvider;
_settings = settings;
}
public async Task<IActionResult> Test()
{
try
{
throw new Exception("Test .NET core MVC app");
}
catch (Exception ex)
{
var msg = new RaygunMessage();
var options = new RaygunRequestMessageOptions(_settings.Value.IgnoreFormFieldNames ?? new string[0], _settings.Value.IgnoreHeaderNames ?? new string[0], _settings.Value.IgnoreCookieNames ?? new string[0], _settings.Value.IgnoreServerVariableNames ?? new string[0]);
msg.Details = new RaygunMessageDetails
{
Error = RaygunErrorMessageBuilder.Build(ex),
Request = await RaygunAspNetCoreRequestMessageBuilder.Build(HttpContext, options)
};
var raygunClient = _clientProvider.GetClient(_settings.Value);
await raygunClient.SendInBackground(msg);
}
return View();
}
}
steve
Posted on
Nov 29 2016
Thanks for the info. Although I now see how to manually set the fields I want ignored, I still think there is a problem. If the message building phase is when headers should be getting stripped out, it is very confusing to then have methods on the RaygunClient object which seem to also give you that same option.
For example, the Ignore* methods below are essentially NOOPs when the GetClient() method is used in any scenario where the message needs to be manually built.
Unless I'm missing something I would suggest either removing those methods altogether or have them work as expected in all scenarios. I would vote for the latter.
public override RaygunClient GetClient(RaygunSettings settings, HttpContext context)
{
settings.ApiKey = _apiKey;
var client = base.GetClient(settings, context);
// strip out all cookie info:
client.IgnoreCookieNames("*");
// strip addl fields that may have sensitive data in it
client.IgnoreServerVariableNames("ALL_HTTP", "ALL_RAW", "HTTP_COOKIE");
// strip out certain headers
client.IgnoreHeaderNames(new[] { "Authorization", "Cookie" });
// ignore password field on the form
client.IgnoreFormFieldNames("*password*");
return client;
}
Deleted User
Raygun
Posted on
Nov 29 2016
Hi Steve,
The RaygunClient was not originally developed with this usage scenario in mind and the methods were added to support non-standard use cases.
Our recommended approach would be to have your configuration for the Ignore* in the appsettings.json file and to use the RaygunClient to send the Exception object, which will build the message internally according to the defined settings. Building up a RaygunMessage object and sending that is for when you need full control of the message and what is sent, which is why there is no filtering on that method. I understand this may not be clear or well documented as it is something that has evolved over time for different usage scenarios.
It would be good to understand why you are using this method as we may be able to provide some advice on how to use the standard send method with your usage scenario.
Thanks.
steve
Posted on
Nov 29 2016
Hi Jeremy,
We have two exception handling scenarios: Unhandled & Handled. The unhandled case is easy. We set up our CustomRayGunClientProvider and let the middleware pipeline take care of the rest. The GetClient() method on our provider does things like: extract identity out of the HttpContext to determine the RaygunClient.User, set appropriate header, cookie, form field names, etc.. to ignore.
Our Handled case is for when we need to do some additional work prior to sending the exception to RayGun. We use the .net core ExceptionFilterAttribute to do the heavy lifting. It's nice in that we can decorate entire controllers with that attribute, thereby avoiding try/catch blocks altogether.
In the OnException() method in of our attribute I (incorrectly) assumed I could just use our existing CustomRayGunClientProvider.GetClient() method to get the client. After all, it already had all the code I need to get user information and what values I need to filter/ignore. I guess from this discussion I need to stop using the provider to get the client and just create a new one instead.
Are you saying that even in the Unhandled scenario, where we rely on our custom provider, that using the client.Ignore* methods is not supported? The reason I am trying to avoid putting the settings in appsettings.json is because our provider is in a shared assembly, used by at least four different executables. I don't want to have to put the same exact RayGunSettings in four appsettings.json files. The client.ignore* methods do seem to work in the Unhandled scenario. I just need to know if I should trust them ????
-steve
Deleted User
Raygun
Posted on
Dec 01 2016
However you get an instance of the RaygunClient, if you use the Send or SendInBackground methods that take a RaygunMessage object then none of the ignore* settings will be applied. These are only taken into account when using the Send or SendInBackground methods that take an Exception object. However the ignore* settings are configured, they will always apply when using the methods that take an Exception object.
If you can, I would suggest changing your code to use one of the Send/InBackground methods that take an Exception. If you need to customise the message before it sent to Raygun then it would be best to attach to the SendingMessage event on the RaygunClient and modify the message there. This then ensures that all ignore* settings are applied at the same time as giving complete control over the message sent.
I've set up a public GitHub repository with some examples that may help. In here I've tried to replicate the usage of an ExceptionFilterAttribute, that uses the same ClientProvider that has my logic for getting a user, setting version and attaching to the SendingMessage event. Hopefully this helps a bit.
Exception Filter Attribute https://github.com/j5alive/Raygun4NetCoreExample/blob/master/src/Raygun4NetCoreExample/RaygunErrorAttribute.cs
Custom Client Provider https://github.com/j5alive/Raygun4NetCoreExample/blob/master/src/Raygun4NetCoreExample/ExampleRaygunAspNetCoreClientProvider.cs
My buggy Controller https://github.com/j5alive/Raygun4NetCoreExample/blob/master/src/Raygun4NetCoreExample/Controllers/HomeController.cs
Jeremy
steve
Posted on
Dec 03 2016
Thanks very much Jeremy.