Auto-detect Content-Type and Accept headers if enabled

Add AutoDetectHeaders option to RecAction config and handler. When enabled, automatically set Content-Type based on body content (JSON or XML) and default Accept to application/json if missing. Log warnings when headers are auto-detected. Improves robustness and makes header detection configurable.
This commit is contained in:
2026-04-17 15:13:33 +02:00
parent 17d40817f2
commit 28a4146069
3 changed files with 23 additions and 2 deletions

View File

@@ -10,8 +10,8 @@
"EnableDetailedErrors": false
},
"RecAction": {
"AddedWho": "ReC.API",
"UseHttp1ForNtlm": false
"UseHttp1ForNtlm": false,
"AutoDetectHeaders": false
},
// Bad request SqlException numbers numbers can be updated at runtime; no restart required.
"SqlException": {

View File

@@ -3,4 +3,5 @@
public class RecActionOptions
{
public bool UseHttp1ForNtlm { get; set; } = false;
public bool AutoDetectHeaders { get; set; } = false;
}

View File

@@ -70,6 +70,20 @@ public class InvokeRecActionViewCommandHandler(
logger?.LogWarning(ex, "Content-Type '{Value}' could not be parsed with strict validation, falling back to TryAddWithoutValidation. ActionId: {ActionId}, ProfileId: {ProfileId}", contentType.Value.Value, action.Id, action.ProfileId);
httpReq.Content.Headers.TryAddWithoutValidation("Content-Type", contentType.Value.Value);
}
else if (_options.AutoDetectHeaders)
{
var body = action.Body.TrimStart();
if (body.StartsWith('{') || body.StartsWith('['))
{
httpReq.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json") { CharSet = "utf-8" };
logger?.LogWarning("Content-Type header was not specified. Auto-detected 'application/json; charset=utf-8' based on body content. ActionId: {ActionId}, ProfileId: {ProfileId}", action.Id, action.ProfileId);
}
else if (body.StartsWith('<'))
{
httpReq.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml") { CharSet = "utf-8" };
logger?.LogWarning("Content-Type header was not specified. Auto-detected 'application/xml; charset=utf-8' based on body content. ActionId: {ActionId}, ProfileId: {ProfileId}", action.Id, action.ProfileId);
}
}
}
if (action.Headers is not null)
@@ -81,6 +95,12 @@ public class InvokeRecActionViewCommandHandler(
httpReq.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
if (_options.AutoDetectHeaders && !httpReq.Headers.Contains("Accept"))
{
httpReq.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
logger?.LogWarning("Accept header was not specified. Defaulting to 'application/json'. ActionId: {ActionId}, ProfileId: {ProfileId}", action.Id, action.ProfileId);
}
switch (action.EndpointAuthType)
{
case EndpointAuthType.NoAuth: