mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-25 18:41:01 +01:00
148 lines
5.3 KiB
C#
148 lines
5.3 KiB
C#
using JetBrains.Annotations;
|
|
using MimeKit;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using WireMock.Matchers;
|
|
using WireMock.Validation;
|
|
|
|
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.
|
|
GET - No defined body semantics.
|
|
PUT - Body supported.
|
|
POST - Body supported.
|
|
DELETE - No defined body semantics.
|
|
TRACE - Body not supported.
|
|
OPTIONS - Body supported but no semantics on usage (maybe in the future).
|
|
CONNECT - No defined body semantics
|
|
PATCH - Body supported.
|
|
*/
|
|
private static readonly string[] AllowedBodyParseMethods = { "PUT", "POST", "OPTIONS", "PATCH" };
|
|
|
|
private static readonly IStringMatcher[] MultipartContentTypesMatchers = {
|
|
new WildcardMatcher("multipart/*", true)
|
|
};
|
|
|
|
private static readonly IStringMatcher[] JsonContentTypesMatchers = {
|
|
new WildcardMatcher("application/json", true),
|
|
new WildcardMatcher("application/vnd.*+json", true)
|
|
};
|
|
|
|
private static readonly IStringMatcher[] TextContentTypeMatchers =
|
|
{
|
|
new WildcardMatcher("text/*", true),
|
|
new RegexMatcher("^application\\/(java|type)script$", true),
|
|
new WildcardMatcher("application/*xml", true),
|
|
new WildcardMatcher("application/x-www-form-urlencoded", true)
|
|
};
|
|
|
|
public static bool ParseBodyAsIsValid([CanBeNull] string parseBodyAs)
|
|
{
|
|
return Enum.TryParse(parseBodyAs, out BodyType _);
|
|
}
|
|
|
|
public static bool ShouldParseBody([CanBeNull] string method)
|
|
{
|
|
return AllowedBodyParseMethods.Contains(method, StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
|
|
public static BodyType DetectBodyTypeFromContentType([CanBeNull] string contentTypeValue)
|
|
{
|
|
if (string.IsNullOrEmpty(contentTypeValue) || !ContentType.TryParse(contentTypeValue, out ContentType contentType))
|
|
{
|
|
return BodyType.Bytes;
|
|
}
|
|
|
|
if (TextContentTypeMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MimeType))))
|
|
{
|
|
return BodyType.String;
|
|
}
|
|
|
|
if (JsonContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MimeType))))
|
|
{
|
|
return BodyType.Json;
|
|
}
|
|
|
|
if (MultipartContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MimeType))))
|
|
{
|
|
return BodyType.MultiPart;
|
|
}
|
|
|
|
return BodyType.Bytes;
|
|
}
|
|
|
|
public static async Task<BodyData> Parse([NotNull] Stream stream, [CanBeNull] string contentType)
|
|
{
|
|
Check.NotNull(stream, nameof(stream));
|
|
|
|
var data = new BodyData
|
|
{
|
|
BodyAsBytes = await ReadBytesAsync(stream),
|
|
DetectedBodyType = BodyType.Bytes,
|
|
DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(contentType)
|
|
};
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Try to get the body as String
|
|
try
|
|
{
|
|
data.BodyAsString = DefaultEncoding.GetString(data.BodyAsBytes);
|
|
data.Encoding = DefaultEncoding;
|
|
data.DetectedBodyType = BodyType.String;
|
|
|
|
// If string is not null or empty, try to get as Json
|
|
if (!string.IsNullOrEmpty(data.BodyAsString))
|
|
{
|
|
try
|
|
{
|
|
data.BodyAsJson = JsonConvert.DeserializeObject(data.BodyAsString, new JsonSerializerSettings { Formatting = Formatting.Indented });
|
|
data.DetectedBodyType = BodyType.Json;
|
|
}
|
|
catch
|
|
{
|
|
// JsonConvert failed, just ignore.
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Reading as string failed, just ignore
|
|
}
|
|
|
|
return data;
|
|
}
|
|
private static async Task<byte[]> ReadBytesAsync(Stream stream)
|
|
{
|
|
using (var memoryStream = new MemoryStream())
|
|
{
|
|
await stream.CopyToAsync(memoryStream);
|
|
return memoryStream.ToArray();
|
|
}
|
|
}
|
|
}
|
|
} |