Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,23 @@ public static void ConfirmValidRegex(string regex)
}


/// <summary>
/// General purpose string replacement. Simple abstraction of string.Replace().
/// </summary>
/// <param name="inputValue">The name of the header we're operating against.</param>
/// <param name="targetValue">The substitution or whole new header value, depending on "regex" setting.</param>
/// <param name="replacementValue">The substitution or new header value, depending on the "targetValue" setting.</param>
/// <returns>An updated value of the input string, with replacement operations completed if necessary.</returns>
public static string ReplaceValue(string inputValue, string targetValue, string replacementValue)
{
return inputValue.Replace(targetValue, replacementValue);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Betting on additional requests making this a bit more complicated, hence the one line abstraction.

}

/// <summary>
/// General purpose string replacement/subsitution given a set of inputs. Used in many regex substitution sanitizers.
/// </summary>
/// <param name="inputValue">The name of the header we're operating against.</param>
/// <param name="replacementValue">The substitution or whole new header value, depending on "regex" setting.</param>
/// <param name="replacementValue">The substitution or whole input value, depending on "regex" setting.</param>
/// <param name="regex">A regex. Can be defined as a simple regex replace OR if groupName is set, a subsitution operation.</param>
/// <param name="groupName">The capture group that needs to be operated upon. Do not set if you're invoking a simple replacement operation.
/// Note that with this implementation, you can refer to a numbered group if you didn't name it, EG: '0'.</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace Azure.Sdk.Tools.TestProxy.Sanitizers
{
/// <summary>
/// This sanitizer operates on a RecordSession entry and applies itself to the Request and Response bodies contained therein. It ONLY operates on the request/response bodies. Not header or URIs.
/// This sanitizer operates on a RecordSession entry and applies regex replacement to the Request and Response bodies contained therein. It ONLY operates on the request/response bodies. Not header or URIs.
/// </summary>
public class BodyKeySanitizer : RecordedTestSanitizer
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Azure.Sdk.Tools.TestProxy.Sanitizers
{
/// <summary>
/// This sanitizer operates on a RecordSession entry and applies itself to the Request and Response bodies contained therein. It ONLY operates on the request/response bodies. Not header or URIs.
/// This sanitizer operates on a RecordSession entry and applies regex replacement to the Request and Response bodies contained therein. It ONLY operates on the request/response bodies. Not header or URIs.
/// </summary>
public class BodyRegexSanitizer : RecordedTestSanitizer
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Azure.Sdk.Tools.TestProxy.Common;
using System;
using System.Text;

namespace Azure.Sdk.Tools.TestProxy.Sanitizers
{
/// <summary>
/// This sanitizer operates on a RecordSession entry and applies value replacement to the Request and Response bodies contained therein. It ONLY operates on the request/response bodies. Not header or URIs.
/// </summary>
public class BodyStringSanitizer : RecordedTestSanitizer
{
private string _newValue;
private string _targetValue;

/// <summary>
/// This sanitizer offers regex replace within a returned body. Specifically, this means regex applying to the raw JSON. If you are attempting to simply
/// replace a specific key, the BodyKeySanitizer is probably the way to go. Regardless, there are examples present in SanitizerTests.cs.
/// to
/// <param name="value">The substitution value.</param>
/// <param name="target">A target string. This could contain special regex characters like "?()+*" but they will be treated as a literal.
/// <param name="condition">
/// A condition that dictates when this sanitizer applies to a request/response pair. The content of this key should be a JSON object that contains configuration keys.
/// Currently, that only includes the key "uriRegex". This translates to an object that looks like '{ "uriRegex": "when this regex matches, apply the sanitizer" }'. Defaults to "apply always."
/// </param>
public BodyStringSanitizer(string target, string value = "Sanitized", ApplyCondition condition = null)
{
_targetValue = target;
_newValue = value;
Condition = condition;
}

public override string SanitizeTextBody(string contentType, string body)
{
return StringSanitizer.ReplaceValue(inputValue: body, targetValue: _targetValue, replacementValue: _newValue);
}


public override byte[] SanitizeBody(string contentType, byte[] body)
{
return Encoding.UTF8.GetBytes(StringSanitizer.ReplaceValue(inputValue: Encoding.UTF8.GetString(body), targetValue: _targetValue, replacementValue: _newValue));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using Azure.Sdk.Tools.TestProxy.Common;
using System.Collections.Generic;

namespace Azure.Sdk.Tools.TestProxy.Sanitizers
{
/// <summary>
/// This sanitizer operates on a RecordSession entry and applies itself to the Request and Response bodies contained therein. This "general" sanitizer applies the configured string value replacement
/// to headers, body, and URI.
/// </summary>
public class GeneralStringSanitizer : RecordedTestSanitizer
{
private string _newValue;
private string _targetValue;

private BodyStringSanitizer _bodySanitizer;
private UriStringSanitizer _uriSanitizer;

/// <summary>
/// This sanitizer offers a value replace across request/response Body, Headers, and URI. For the body, this means a string replacement applied directly to the raw JSON.
/// </summary>
/// <param name="value">The substitution value.</param>
/// <param name="target">A target string. This could contain special regex characters like "?()+*" but they will be treated as a literal.
/// <param name="condition">
/// A condition that dictates when this sanitizer applies to a request/response pair. The content of this key should be a JSON object that contains configuration keys.
/// Currently, that only includes the key "uriRegex". This translates to an object that looks like '{ "uriRegex": "when this regex matches, apply the sanitizer" }'. Defaults to "apply always."
/// </param>
public GeneralStringSanitizer(string target, string value = "Sanitized", ApplyCondition condition = null)
{
_targetValue = target;
_newValue = value;
Condition = condition;

_bodySanitizer = new BodyStringSanitizer(target, value, condition);
_uriSanitizer = new UriStringSanitizer(target, value, condition);
}

public override void SanitizeHeaders(IDictionary<string, string[]> headers)
{
foreach (var headerKey in headers.Keys)
{
// Accessing 0th key safe due to the fact that we force header values in without splitting them on ;.
// We do this because letting .NET split and then reassemble header values introduces a space into the header itself
// Ex: "application/json;odata=minimalmetadata" with .NET default header parsing becomes "application/json; odata=minimalmetadata"
// Given this breaks signature verification, we have to avoid it.
var originalValue = headers[headerKey][0];

var replacement = StringSanitizer.ReplaceValue(inputValue: originalValue, targetValue: _targetValue, replacementValue: _newValue);

headers[headerKey][0] = replacement;
}
}

public override string SanitizeUri(string uri)
{
return _uriSanitizer.SanitizeUri(uri);
}

public override string SanitizeTextBody(string contentType, string body)
{
return _bodySanitizer.SanitizeTextBody(contentType, body);
}

public override byte[] SanitizeBody(string contentType, byte[] body)
{
return _bodySanitizer.SanitizeBody(contentType, body);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Azure.Sdk.Tools.TestProxy.Common;
using System.Collections.Generic;

namespace Azure.Sdk.Tools.TestProxy.Sanitizers
{
/// <summary>
/// This sanitizer operates on a RecordSession entry and applies value replacement to the headers contained therein. This sanitizer ONLY applies to the request/response headers,
/// body and URI are left untouched.
/// </summary>
public class HeaderStringSanitizer : RecordedTestSanitizer
{
private string _targetKey;
private string _newValue;
private string _targetValue;

/// <summary>
/// Applies a simple value replacement for a target header key. If it does not exist, no actions will be taken.
/// </summary>
/// <param name="key">The name of the header we're operating against.</param>
/// <param name="target">A target string. This could contain special regex characters like "?()+*" but they will be treated as a literal.
/// <param name="value">The substitution value.</param>
/// <param name="condition">
/// A condition that dictates when this sanitizer applies to a request/response pair. The content of this key should be a JSON object that contains configuration keys.
/// Currently, that only includes the key "uriRegex". This translates to an object that looks like '{ "uriRegex": "when this regex matches, apply the sanitizer" }'. Defaults to "apply always."
/// </param>
public HeaderStringSanitizer(string key, string target, string value = "Sanitized", ApplyCondition condition = null)
{
_targetKey = key;
_newValue = value;
Condition = condition;
}

public override void SanitizeHeaders(IDictionary<string, string[]> headers)
{
if (headers.ContainsKey(_targetKey))
{
// Accessing 0th key safe due to the fact that we force header values in without splitting them on ;.
// We do this because letting .NET split and then reassemble header values introduces a space into the header itself
// Ex: "application/json;odata=minimalmetadata" with .NET default header parsing becomes "application/json; odata=minimalmetadata"
// Given this breaks signature verification, we have to avoid it.
var originalValue = headers[_targetKey][0];

var replacement = StringSanitizer.ReplaceValue(inputValue: originalValue, targetValue: _targetValue, replacementValue: _newValue);

headers[_targetKey] = new string[] { replacement };
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Azure.Sdk.Tools.TestProxy.Common;

namespace Azure.Sdk.Tools.TestProxy.Sanitizers
{
/// <summary>
/// General use sanitizer for cleaning URIs via straightforward string replacement.
/// </summary>
public class UriStringSanitizer : RecordedTestSanitizer
{
private string _newValue;
private string _targetValue;

/// <summary>
/// Runs a simple string replacement against the request/response URIs.
/// </summary>
/// <param name="value">The substitution value.</param>
/// <param name="target">A target string. This could contain special regex characters like "?()+*" but they will be treated as a literal.
/// <param name="condition">
/// A condition that dictates when this sanitizer applies to a request/response pair. The content of this key should be a JSON object that contains configuration keys.
/// Currently, that only includes the key "uriRegex". This translates to an object that looks like '{ "uriRegex": "when this regex matches, apply the sanitizer" }'. Defaults to "apply always."
/// </param>
public UriStringSanitizer(string target, string value = "Sanitized", ApplyCondition condition = null)
{
_targetValue = target;
_newValue = value;
Condition = condition;
}

public override string SanitizeUri(string uri)
{
return StringSanitizer.ReplaceValue(inputValue: uri, targetValue: _targetValue, replacementValue: _newValue);
}
}
}