diff --git a/src/Exceptionless/Configuration/ExceptionlessConfiguration.cs b/src/Exceptionless/Configuration/ExceptionlessConfiguration.cs
index 0853d55e..74deaf4c 100644
--- a/src/Exceptionless/Configuration/ExceptionlessConfiguration.cs
+++ b/src/Exceptionless/Configuration/ExceptionlessConfiguration.cs
@@ -228,6 +228,7 @@ public bool IncludePrivateInformation {
IncludeUserName = value;
IncludeMachineName = value;
IncludeIpAddress = value;
+ IncludeHeaders = value;
IncludeCookies = value;
IncludePostData = value;
IncludeQueryString = value;
@@ -247,6 +248,11 @@ public bool IncludePrivateInformation {
///
public bool IncludeIpAddress { get; set; }
///
+ /// Gets or sets a value indicating whether to include Headers.
+ /// NOTE: DataExclusions are applied to all Headers keys when enabled.
+ ///
+ public bool IncludeHeaders { get; set; }
+ ///
/// Gets or sets a value indicating whether to include Cookies.
/// NOTE: DataExclusions are applied to all Cookie keys when enabled.
///
diff --git a/src/Exceptionless/Models/Client/Data/RequestInfo.cs b/src/Exceptionless/Models/Client/Data/RequestInfo.cs
index 816d8539..41cd9929 100644
--- a/src/Exceptionless/Models/Client/Data/RequestInfo.cs
+++ b/src/Exceptionless/Models/Client/Data/RequestInfo.cs
@@ -5,6 +5,7 @@ namespace Exceptionless.Models.Data {
public class RequestInfo : IData {
public RequestInfo() {
Data = new DataDictionary();
+ Headers = new Dictionary();
Cookies = new Dictionary();
QueryString = new Dictionary();
}
@@ -49,6 +50,11 @@ public RequestInfo() {
///
public string ClientIpAddress { get; set; }
+ ///
+ /// The header values from the request.
+ ///
+ public Dictionary Headers { get; set; }
+
///
/// The request cookies.
///
@@ -70,7 +76,7 @@ public RequestInfo() {
public DataDictionary Data { get; set; }
protected bool Equals(RequestInfo other) {
- return string.Equals(UserAgent, other.UserAgent) && string.Equals(HttpMethod, other.HttpMethod) && IsSecure == other.IsSecure && string.Equals(Host, other.Host) && Port == other.Port && string.Equals(Path, other.Path) && string.Equals(Referrer, other.Referrer) && string.Equals(ClientIpAddress, other.ClientIpAddress) && Cookies.CollectionEquals(other.Cookies) && QueryString.CollectionEquals(other.QueryString) && Equals(Data, other.Data);
+ return string.Equals(UserAgent, other.UserAgent) && string.Equals(HttpMethod, other.HttpMethod) && IsSecure == other.IsSecure && string.Equals(Host, other.Host) && Port == other.Port && string.Equals(Path, other.Path) && string.Equals(Referrer, other.Referrer) && string.Equals(ClientIpAddress, other.ClientIpAddress) && Headers.CollectionEquals(other.Headers) && Cookies.CollectionEquals(other.Cookies) && QueryString.CollectionEquals(other.QueryString) && Equals(Data, other.Data);
}
public override bool Equals(object obj) {
@@ -95,6 +101,7 @@ public override int GetHashCode() {
hashCode = (hashCode * 397) ^ (Path == null ? 0 : Path.GetHashCode());
hashCode = (hashCode * 397) ^ (Referrer == null ? 0 : Referrer.GetHashCode());
hashCode = (hashCode * 397) ^ (ClientIpAddress == null ? 0 : ClientIpAddress.GetHashCode());
+ hashCode = (hashCode * 397) ^ (Headers == null ? 0 : Headers.GetCollectionHashCode());
hashCode = (hashCode * 397) ^ (Cookies == null ? 0 : Cookies.GetCollectionHashCode(_cookieHashCodeExclusions));
hashCode = (hashCode * 397) ^ (QueryString == null ? 0 : QueryString.GetCollectionHashCode());
hashCode = (hashCode * 397) ^ (Data == null ? 0 : Data.GetCollectionHashCode());
diff --git a/src/Platforms/Exceptionless.AspNetCore/RequestInfoCollector.cs b/src/Platforms/Exceptionless.AspNetCore/RequestInfoCollector.cs
index 7b7c624b..31bebdd2 100644
--- a/src/Platforms/Exceptionless.AspNetCore/RequestInfoCollector.cs
+++ b/src/Platforms/Exceptionless.AspNetCore/RequestInfoCollector.cs
@@ -14,6 +14,8 @@
namespace Exceptionless.AspNetCore {
public static class RequestInfoCollector {
private const int MAX_BODY_SIZE = 50 * 1024;
+ private const int MAX_DATA_ITEM_LENGTH = 1000;
+
public static RequestInfo Collect(HttpContext context, ExceptionlessConfiguration config) {
if (context == null)
return null;
@@ -21,7 +23,7 @@ public static RequestInfo Collect(HttpContext context, ExceptionlessConfiguratio
var info = new RequestInfo {
HttpMethod = context.Request.Method,
IsSecure = context.Request.IsHttps,
- Path = context.Request.Path.HasValue ? context.Request.Path.Value : "/",
+ Path = context.Request.Path.HasValue ? context.Request.Path.Value : "/"
};
if (config.IncludeIpAddress)
@@ -32,13 +34,16 @@ public static RequestInfo Collect(HttpContext context, ExceptionlessConfiguratio
info.Port = context.Request.Host.Port.GetValueOrDefault(info.IsSecure ? 443 : 80);
- if (context.Request.Headers.ContainsKey(HeaderNames.UserAgent))
- info.UserAgent = context.Request.Headers[HeaderNames.UserAgent].ToString();
+ if (context.Request.Headers.TryGetValue(HeaderNames.UserAgent, out var userAgentHeader))
+ info.UserAgent = userAgentHeader.ToString();
- if (context.Request.Headers.ContainsKey(HeaderNames.Referer))
- info.Referrer = context.Request.Headers[HeaderNames.Referer].ToString();
+ if (context.Request.Headers.TryGetValue(HeaderNames.Referer, out var refererHeader))
+ info.Referrer = refererHeader.ToString();
var exclusionList = config.DataExclusions as string[] ?? config.DataExclusions.ToArray();
+ if (config.IncludeHeaders)
+ info.Headers = context.Request.Headers.ToHeaderDictionary(exclusionList);
+
if (config.IncludeCookies)
info.Cookies = context.Request.Cookies.ToDictionary(exclusionList);
@@ -93,17 +98,15 @@ private static object GetPostData(HttpContext context, ExceptionlessConfiguratio
return message;
}
- var maxDataToRead = contentLength == 0 ? MAX_BODY_SIZE : contentLength;
-
// pass default values, except for leaveOpen: true. This prevents us from disposing the underlying stream
using (var inputStream = new StreamReader(context.Request.Body, Encoding.UTF8, true, 1024, true)) {
var sb = new StringBuilder();
int numRead;
- int bufferSize = (int)Math.Min(1024, maxDataToRead);
+ int bufferSize = (int)Math.Min(1024, contentLength);
char[] buffer = new char[bufferSize];
- while ((numRead = inputStream.ReadBlock(buffer, 0, bufferSize)) > 0 && (sb.Length + numRead) <= maxDataToRead) {
+ while ((numRead = inputStream.ReadBlock(buffer, 0, bufferSize)) > 0 && (sb.Length + numRead) <= contentLength) {
sb.Append(buffer, 0, numRead);
}
string postData = sb.ToString();
@@ -121,8 +124,15 @@ private static object GetPostData(HttpContext context, ExceptionlessConfiguratio
}
}
- private static readonly List _ignoredFormFields = new List {
- "__*"
+ private static readonly List _ignoredHeaders = new List {
+ HeaderNames.Authorization,
+ HeaderNames.Cookie,
+ HeaderNames.Host,
+ HeaderNames.Method,
+ HeaderNames.Path,
+ HeaderNames.ProxyAuthorization,
+ HeaderNames.Referer,
+ HeaderNames.UserAgent
};
private static readonly List _ignoredCookies = new List {
@@ -131,20 +141,44 @@ private static object GetPostData(HttpContext context, ExceptionlessConfiguratio
"*SessionId*"
};
- private static Dictionary ToDictionary(this IRequestCookieCollection cookies, IList exclusions) {
+ private static readonly List _ignoredFormFields = new List {
+ "__*"
+ };
+
+ private static Dictionary ToHeaderDictionary(this IEnumerable> headers, string[] exclusions) {
+ var d = new Dictionary();
+
+ foreach (var header in headers) {
+ if (String.IsNullOrEmpty(header.Key) || _ignoredHeaders.Contains(header.Key) || header.Key.AnyWildcardMatches(exclusions))
+ continue;
+
+ string[] values = header.Value.Where(hv => hv != null && hv.Length < MAX_DATA_ITEM_LENGTH).ToArray();
+ if (values.Length == 0)
+ continue;
+
+ d[header.Key] = values;
+ }
+
+ return d;
+ }
+
+ private static Dictionary ToDictionary(this IRequestCookieCollection cookies, string[] exclusions) {
var d = new Dictionary();
foreach (var kvp in cookies) {
if (String.IsNullOrEmpty(kvp.Key) || kvp.Key.AnyWildcardMatches(_ignoredCookies) || kvp.Key.AnyWildcardMatches(exclusions))
continue;
- d.Add(kvp.Key, kvp.Value);
+ if (kvp.Value == null || kvp.Value.Length >= MAX_DATA_ITEM_LENGTH)
+ continue;
+
+ d[kvp.Key] = kvp.Value;
}
return d;
}
- private static Dictionary ToDictionary(this IEnumerable> values, IEnumerable exclusions) {
+ private static Dictionary ToDictionary(this IEnumerable> values, string[] exclusions) {
var d = new Dictionary();
foreach (var kvp in values) {
@@ -153,10 +187,12 @@ private static Dictionary ToDictionary(this IEnumerable= MAX_DATA_ITEM_LENGTH)
+ continue;
+
+ d[kvp.Key] = value;
} catch (Exception ex) {
- if (!d.ContainsKey(kvp.Key))
- d.Add(kvp.Key, ex.Message);
+ d[kvp.Key] = $"EXCEPTION: {ex.Message}";
}
}
diff --git a/src/Platforms/Exceptionless.Web/RequestInfoCollector.cs b/src/Platforms/Exceptionless.Web/RequestInfoCollector.cs
index 74de5ee6..ebebdb64 100644
--- a/src/Platforms/Exceptionless.Web/RequestInfoCollector.cs
+++ b/src/Platforms/Exceptionless.Web/RequestInfoCollector.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
-using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
@@ -13,8 +12,8 @@
namespace Exceptionless.ExtendedData {
internal static class RequestInfoCollector {
+ private const int MAX_BODY_SIZE = 50 * 1024;
private const int MAX_DATA_ITEM_LENGTH = 1000;
- private const int MAX_BODY_SIZE = 50*1024;
public static RequestInfo Collect(HttpContextBase context, ExceptionlessConfiguration config) {
if (context == null)
@@ -50,13 +49,12 @@ public static RequestInfo Collect(HttpContextBase context, ExceptionlessConfigur
info.Port = context.Request.Url.Port;
var exclusionList = config.DataExclusions as string[] ?? config.DataExclusions.ToArray();
+ if (config.IncludeHeaders)
+ info.Headers = context.Request.Headers.ToHeaderDictionary(exclusionList);
if (config.IncludeCookies)
info.Cookies = context.Request.Cookies.ToDictionary(exclusionList);
-
- if (config.IncludePostData && !String.Equals(context.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
- info.PostData = GetPostData(context, config, exclusionList);
-
+
if (config.IncludeQueryString) {
try {
info.QueryString = context.Request.QueryString.ToDictionary(exclusionList);
@@ -65,6 +63,9 @@ public static RequestInfo Collect(HttpContextBase context, ExceptionlessConfigur
}
}
+ if (config.IncludePostData && !String.Equals(context.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
+ info.PostData = GetPostData(context, config, exclusionList);
+
return info;
}
@@ -139,8 +140,15 @@ private static object GetPostData(HttpContextBase context, ExceptionlessConfigur
}
}
- private static readonly List _ignoredFormFields = new List {
- "__*"
+ private static readonly List _ignoredHeaders = new List {
+ "Authorization",
+ "Cookie",
+ "Host",
+ "Method",
+ "Path",
+ "Proxy-Authorization",
+ "Referer",
+ "User-Agent"
};
private static readonly List _ignoredCookies = new List {
@@ -149,38 +157,68 @@ private static object GetPostData(HttpContextBase context, ExceptionlessConfigur
"*SessionId*"
};
- private static Dictionary ToDictionary(this HttpCookieCollection cookies, IEnumerable exclusions) {
+ private static readonly List _ignoredFormFields = new List {
+ "__*"
+ };
+
+ private static Dictionary ToHeaderDictionary(this NameValueCollection headers, string[] exclusions) {
+ var result = new Dictionary();
+
+ foreach (string key in headers.AllKeys) {
+ if (String.IsNullOrEmpty(key) || _ignoredHeaders.Contains(key) || key.AnyWildcardMatches(exclusions))
+ continue;
+
+ try {
+ string value = headers.Get(key);
+ if (value == null || value.Length >= MAX_DATA_ITEM_LENGTH)
+ continue;
+
+ result[key] = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+ }
+ catch (Exception ex) {
+ result[key] = new[] { $"EXCEPTION: {ex.Message}" };
+ }
+ }
+
+ return result;
+ }
+
+ private static Dictionary ToDictionary(this HttpCookieCollection cookies, string[] exclusions) {
var d = new Dictionary();
- foreach (string key in cookies.AllKeys.Distinct().Where(k => !String.IsNullOrEmpty(k) && !k.AnyWildcardMatches(_ignoredCookies) && !k.AnyWildcardMatches(exclusions))) {
+ foreach (string key in cookies.AllKeys.Distinct()) {
+ if (String.IsNullOrEmpty(key) || key.AnyWildcardMatches(_ignoredCookies) || key.AnyWildcardMatches(exclusions))
+ continue;
+
try {
- HttpCookie cookie = cookies.Get(key);
- if (cookie != null && cookie.Value != null && cookie.Value.Length < MAX_DATA_ITEM_LENGTH && !d.ContainsKey(key))
- d.Add(key, cookie.Value);
+ var cookie = cookies.Get(key);
+ if (cookie == null || cookie.Value == null || cookie.Value.Length >= MAX_DATA_ITEM_LENGTH)
+ continue;
+
+ d[key] = cookie.Value;
} catch (Exception ex) {
- if (!d.ContainsKey(key))
- d.Add(key, ex.Message);
+ d[key] = $"EXCEPTION: {ex.Message}";
}
}
return d;
}
- private static Dictionary ToDictionary(this NameValueCollection values, IEnumerable exclusions) {
+ private static Dictionary ToDictionary(this NameValueCollection values, string[] exclusions) {
var d = new Dictionary();
-
- var exclusionsArray = exclusions as string[] ?? exclusions.ToArray();
+
foreach (string key in values.AllKeys) {
- if (String.IsNullOrEmpty(key) || key.AnyWildcardMatches(_ignoredFormFields) || key.AnyWildcardMatches(exclusionsArray))
+ if (String.IsNullOrEmpty(key) || key.AnyWildcardMatches(_ignoredFormFields) || key.AnyWildcardMatches(exclusions))
continue;
try {
string value = values.Get(key);
- if (value != null && !d.ContainsKey(key) && value.Length < MAX_DATA_ITEM_LENGTH)
- d.Add(key, value);
+ if (value == null || d.ContainsKey(key) || value.Length >= MAX_DATA_ITEM_LENGTH)
+ continue;
+
+ d[key] = value;
} catch (Exception ex) {
- if (!d.ContainsKey(key))
- d.Add(key, "EXCEPTION: " + ex.Message);
+ d[key] = $"EXCEPTION: {ex.Message}";
}
}
diff --git a/src/Platforms/Exceptionless.WebApi/RequestInfoCollector.cs b/src/Platforms/Exceptionless.WebApi/RequestInfoCollector.cs
index e7754f51..7f5298ee 100644
--- a/src/Platforms/Exceptionless.WebApi/RequestInfoCollector.cs
+++ b/src/Platforms/Exceptionless.WebApi/RequestInfoCollector.cs
@@ -12,6 +12,8 @@
namespace Exceptionless.ExtendedData {
internal static class RequestInfoCollector {
+ private const int MAX_DATA_ITEM_LENGTH = 1000;
+
public static RequestInfo Collect(HttpActionContext context, ExceptionlessConfiguration config) {
if (context == null)
return null;
@@ -37,17 +39,31 @@ public static RequestInfo Collect(HttpActionContext context, ExceptionlessConfig
info.Referrer = context.Request.Headers.Referrer.ToString();
var exclusionList = config.DataExclusions as string[] ?? config.DataExclusions.ToArray();
+ if (config.IncludeHeaders)
+ info.Headers = context.Request.Headers.ToDictionary(exclusionList);
+
if (config.IncludeCookies)
info.Cookies = context.Request.Headers.GetCookies().ToDictionary(exclusionList);
+
if (config.IncludeQueryString)
info.QueryString = context.Request.RequestUri.ParseQueryString().ToDictionary(exclusionList);
- // TODO Collect form data.
+ // TODO: support getting post data asyncly.
+ //if (config.IncludePostData && context.Request.Method != HttpMethod.Get)
+ // info.PostData = GetPostData(context, config, exclusionList);
+
return info;
}
- private static readonly List _ignoredFormFields = new List {
- "__*"
+ private static readonly List _ignoredHeaders = new List {
+ "Authorization",
+ "Cookie",
+ "Host",
+ "Method",
+ "Path",
+ "Proxy-Authorization",
+ "Referer",
+ "User-Agent"
};
private static readonly List _ignoredCookies = new List {
@@ -56,33 +72,63 @@ public static RequestInfo Collect(HttpActionContext context, ExceptionlessConfig
"*SessionId*"
};
- private static Dictionary ToDictionary(this IEnumerable cookies, IEnumerable exclusions) {
+ private static readonly List _ignoredFormFields = new List {
+ "__*"
+ };
+
+ private static Dictionary ToDictionary(this HttpRequestHeaders headers, string[] exclusions) {
+ var d = new Dictionary();
+
+ foreach (var header in headers) {
+ if (String.IsNullOrEmpty(header.Key) || _ignoredHeaders.Contains(header.Key) || header.Key.AnyWildcardMatches(exclusions))
+ continue;
+
+ string[] values = header.Value.Where(hv => hv != null && hv.Length < MAX_DATA_ITEM_LENGTH).ToArray();
+ if (values.Length == 0)
+ continue;
+
+ d[header.Key] = values;
+ }
+
+ return d;
+ }
+
+ private static Dictionary ToDictionary(this IEnumerable cookies, string[] exclusions) {
var d = new Dictionary();
- foreach (CookieHeaderValue cookie in cookies) {
- foreach (CookieState innerCookie in cookie.Cookies.Where(k => k != null && !String.IsNullOrEmpty(k.Name) && !k.Name.AnyWildcardMatches(_ignoredCookies) && !k.Name.AnyWildcardMatches(exclusions))) {
- if (!d.ContainsKey(innerCookie.Name))
- d.Add(innerCookie.Name, innerCookie.Value);
+ foreach (var cookie in cookies) {
+ foreach (var innerCookie in cookie.Cookies) {
+ if (innerCookie == null || String.IsNullOrEmpty(innerCookie.Name) || innerCookie.Name.AnyWildcardMatches(_ignoredCookies) || innerCookie.Name.AnyWildcardMatches(exclusions))
+ continue;
+
+ if (d.ContainsKey(innerCookie.Name))
+ continue;
+
+ if (innerCookie.Value == null || innerCookie.Value.Length >= MAX_DATA_ITEM_LENGTH)
+ continue;
+
+ d.Add(innerCookie.Name, innerCookie.Value);
}
}
return d;
}
- private static Dictionary ToDictionary(this NameValueCollection values, IEnumerable exclusions) {
+ private static Dictionary ToDictionary(this NameValueCollection values, string[] exclusions) {
var d = new Dictionary();
-
- var patternsToMatch = exclusions as string[] ?? exclusions.ToArray();
+
foreach (string key in values.AllKeys) {
- if (String.IsNullOrEmpty(key) || key.AnyWildcardMatches(_ignoredFormFields) || key.AnyWildcardMatches(patternsToMatch))
+ if (String.IsNullOrEmpty(key) || key.AnyWildcardMatches(_ignoredFormFields) || key.AnyWildcardMatches(exclusions))
continue;
try {
string value = values.Get(key);
- d.Add(key, value);
+ if (value == null || value.Length >= MAX_DATA_ITEM_LENGTH)
+ continue;
+
+ d[key] = value;
} catch (Exception ex) {
- if (!d.ContainsKey(key))
- d.Add(key, ex.Message);
+ d[key] = $"EXCEPTION: {ex.Message}";
}
}