Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proxy : also save multipart as string in mapping file #264

Merged
merged 4 commits into from
Apr 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
</PropertyGroup>

<PropertyGroup>
<VersionPrefix>1.0.11</VersionPrefix>
<VersionPrefix>1.0.12</VersionPrefix>
</PropertyGroup>

<Choose>
Expand Down
16 changes: 13 additions & 3 deletions examples/WireMock.Net.Console.Proxy.Net452/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Newtonsoft.Json;
using System;
using System.Net.Http;
using Newtonsoft.Json;
using WireMock.Server;
using WireMock.Settings;

Expand All @@ -8,14 +10,15 @@ class Program
{
static void Main(string[] args)
{
string[] urls = { "http://localhost:9091/", "https://localhost:9443/" };
var server = FluentMockServer.Start(new FluentMockServerSettings
{
Urls = new[] { "http://localhost:9091/", "https://localhost:9443/" },
Urls = urls,
StartAdminInterface = true,
ReadStaticMappings = false,
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = "https://www.google.com",
Url = "http://postman-echo.com/post",
//ClientX509Certificate2ThumbprintOrSubjectName = "www.yourclientcertname.com OR yourcertificatethumbprint (only if the service you're proxying to requires it)",
SaveMapping = true,
SaveMappingToFile = false,
Expand All @@ -28,6 +31,13 @@ static void Main(string[] args)
System.Console.WriteLine(JsonConvert.SerializeObject(eventRecordArgs.NewItems, Formatting.Indented));
};

var uri = new Uri(urls[0]);
var form = new MultipartFormDataContent
{
{ new StringContent("data"), "test", "test.txt" }
};
new HttpClient().PostAsync(uri, form).GetAwaiter().GetResult();

System.Console.WriteLine("Press any key to stop the server");
System.Console.ReadKey();
server.Stop();
Expand Down
15 changes: 8 additions & 7 deletions src/WireMock.Net/Matchers/ExactObjectMatcher.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Linq;
using JetBrains.Annotations;
using JetBrains.Annotations;
using System.Linq;
using WireMock.Validation;

namespace WireMock.Matchers
Expand All @@ -10,8 +10,9 @@ namespace WireMock.Matchers
/// <seealso cref="IObjectMatcher" />
public class ExactObjectMatcher : IObjectMatcher
{
private readonly object _object;
private readonly byte[] _bytes;
public object ValueAsObject { get; }

public byte[] ValueAsBytes { get; }

/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
Expand All @@ -33,7 +34,7 @@ public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] object value)
{
Check.NotNull(value, nameof(value));

_object = value;
ValueAsObject = value;
MatchBehaviour = matchBehaviour;
}

Expand All @@ -54,14 +55,14 @@ public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] byte[] value)
{
Check.NotNull(value, nameof(value));

_bytes = value;
ValueAsBytes = value;
MatchBehaviour = matchBehaviour;
}

/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
{
bool equals = _object != null ? Equals(_object, input) : _bytes.SequenceEqual((byte[])input);
bool equals = ValueAsObject != null ? Equals(ValueAsObject, input) : ValueAsBytes.SequenceEqual((byte[])input);
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(equals));
}

Expand Down
5 changes: 4 additions & 1 deletion src/WireMock.Net/ResponseMessageBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ namespace WireMock
internal static class ResponseMessageBuilder
{
private static string ContentTypeJson = "application/json";
private static readonly IDictionary<string, WireMockList<string>> ContentTypeJsonHeaders = new Dictionary<string, WireMockList<string>> { { HttpKnownHeaderNames.ContentType, new WireMockList<string> { ContentTypeJson } } };
private static readonly IDictionary<string, WireMockList<string>> ContentTypeJsonHeaders = new Dictionary<string, WireMockList<string>>
{
{ HttpKnownHeaderNames.ContentType, new WireMockList<string> { ContentTypeJson } }
};

internal static ResponseMessage Create(string message, int statusCode = 200, Guid? guid = null)
{
Expand Down
41 changes: 29 additions & 12 deletions src/WireMock.Net/Serialization/MatcherMapper.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System;
using JetBrains.Annotations;
using SimMetrics.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using SimMetrics.Net;
using WireMock.Admin.Mappings;
using WireMock.Matchers;

Expand Down Expand Up @@ -32,6 +32,10 @@ public static IMatcher Map([CanBeNull] MatcherModel matcher)
case "ExactMatcher":
return new ExactMatcher(matchBehaviour, stringPatterns);

case "ExactObjectMatcher":
var bytePattern = Convert.FromBase64String(stringPatterns[0]);
return new ExactObjectMatcher(matchBehaviour, bytePattern);

case "RegexMatcher":
return new RegexMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true);

Expand Down Expand Up @@ -73,20 +77,33 @@ public static MatcherModel Map([CanBeNull] IMatcher matcher)
return null;
}

// If the matcher is a IStringMatcher, get the patterns.
// If the matcher is a IValueMatcher, get the value (can be string or object).
// Else empty array
object[] patterns = matcher is IStringMatcher stringMatcher ?
stringMatcher.GetPatterns().Cast<object>().ToArray() :
matcher is IValueMatcher valueMatcher ? new[] { valueMatcher.Value } :
new object[0];
bool? ignorecase = matcher is IIgnoreCaseMatcher ignoreCaseMatcher ? ignoreCaseMatcher.IgnoreCase : (bool?)null;
object[] patterns = new object[0]; // Default empty array
switch (matcher)
{
// If the matcher is a IStringMatcher, get the patterns.
case IStringMatcher stringMatcher:
patterns = stringMatcher.GetPatterns().Cast<object>().ToArray();
break;

// If the matcher is a IValueMatcher, get the value (can be string or object).
case IValueMatcher valueMatcher:
patterns = new[] { valueMatcher.Value };
break;

// If the matcher is a ExactObjectMatcher, get the ValueAsObject or ValueAsBytes.
case ExactObjectMatcher exactObjectMatcher:
patterns = new[] { exactObjectMatcher.ValueAsObject ?? exactObjectMatcher.ValueAsBytes };
break;
}

bool? ignoreCase = matcher is IIgnoreCaseMatcher ignoreCaseMatcher ? ignoreCaseMatcher.IgnoreCase : (bool?)null;

bool? rejectOnMatch = matcher.MatchBehaviour == MatchBehaviour.RejectOnMatch ? true : (bool?)null;

return new MatcherModel
{
RejectOnMatch = rejectOnMatch,
IgnoreCase = ignorecase,
IgnoreCase = ignoreCase,
Name = matcher.Name,
Pattern = patterns.Length == 1 ? patterns.First() : null,
Patterns = patterns.Length > 1 ? patterns : null
Expand Down
18 changes: 12 additions & 6 deletions src/WireMock.Net/Server/FluentMockServer.Admin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -277,13 +277,19 @@ private IMapping ToMapping(RequestMessage requestMessage, ResponseMessage respon
}
});

if (requestMessage.BodyData?.DetectedBodyType == BodyType.Json)
switch (requestMessage.BodyData?.DetectedBodyType)
{
request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson));
}
else if (requestMessage.BodyData?.DetectedBodyType == BodyType.String)
{
request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsString));
case BodyType.Json:
request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson));
break;

case BodyType.String:
request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsString));
break;

case BodyType.Bytes:
request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes));
break;
}

var response = Response.Create(responseMessage);
Expand Down
13 changes: 12 additions & 1 deletion src/WireMock.Net/Util/BodyParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace WireMock.Util
internal static class BodyParser
{
private static readonly Encoding DefaultEncoding = Encoding.UTF8;
private static readonly Encoding[] SupportedBodyAsStringEncodingForMultipart = { Encoding.UTF8, Encoding.ASCII };

/*
HEAD - No defined body semantics.
Expand Down Expand Up @@ -91,9 +92,19 @@ public static async Task<BodyData> Parse([NotNull] Stream stream, [CanBeNull] st
DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(contentType)
};

// In case of MultiPart: never try to read as String but keep as-is
// In case of MultiPart: check if the BodyAsBytes is a valid UTF8 or ASCII string, in that case read as String else keep as-is
if (data.DetectedBodyTypeFromContentType == BodyType.MultiPart)
{
if (BytesEncodingUtils.TryGetEncoding(data.BodyAsBytes, out Encoding encoding) &&
SupportedBodyAsStringEncodingForMultipart.Select(x => x.Equals(encoding)).Any())
{
data.BodyAsString = encoding.GetString(data.BodyAsBytes);
data.Encoding = encoding;
data.DetectedBodyType = BodyType.String;

return data;
}

return data;
}

Expand Down
Loading