mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-01-11 22:30:41 +01:00
Add support for GZip and Deflate (#439)
* gzip - wip * wip * tests * fix gzip and deflate * CheckIfShouldKillVBCSCompiler * DisableRequestBodyDecompressing
This commit is contained in:
31
.vscode/launch.json
vendored
31
.vscode/launch.json
vendored
@@ -1,22 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": ".NET Core Launch (WireMock.Net.StandAlone.NETCoreApp)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build_WireMock.Net.StandAlone.NETCoreApp",
|
||||
"program": "${workspaceRoot}/examples/WireMock.Net.StandAlone.NETCoreApp/bin/Debug/netcoreapp2.0/WireMock.Net.StandAlone.NETCoreApp.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"stopAtEntry": false,
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}"
|
||||
}
|
||||
]
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -68,7 +68,7 @@ namespace WireMock.Http
|
||||
return client;
|
||||
}
|
||||
|
||||
public static async Task<ResponseMessage> SendAsync([NotNull] HttpClient client, [NotNull] RequestMessage requestMessage, string url, bool deserializeJson)
|
||||
public static async Task<ResponseMessage> SendAsync([NotNull] HttpClient client, [NotNull] RequestMessage requestMessage, string url, bool deserializeJson, bool decompressGzipAndDeflate)
|
||||
{
|
||||
Check.NotNull(client, nameof(client));
|
||||
Check.NotNull(requestMessage, nameof(requestMessage));
|
||||
@@ -83,7 +83,7 @@ namespace WireMock.Http
|
||||
var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead);
|
||||
|
||||
// Create ResponseMessage
|
||||
return await HttpResponseMessageHelper.CreateAsync(httpResponseMessage, requiredUri, originalUri, deserializeJson);
|
||||
return await HttpResponseMessageHelper.CreateAsync(httpResponseMessage, requiredUri, originalUri, deserializeJson, decompressGzipAndDeflate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace WireMock.Http
|
||||
{
|
||||
internal static class HttpResponseMessageHelper
|
||||
{
|
||||
public static async Task<ResponseMessage> CreateAsync(HttpResponseMessage httpResponseMessage, Uri requiredUri, Uri originalUri, bool deserializeJson)
|
||||
public static async Task<ResponseMessage> CreateAsync(HttpResponseMessage httpResponseMessage, Uri requiredUri, Uri originalUri, bool deserializeJson, bool decompressGzipAndDeflate)
|
||||
{
|
||||
var responseMessage = new ResponseMessage { StatusCode = (int)httpResponseMessage.StatusCode };
|
||||
|
||||
@@ -24,7 +24,21 @@ namespace WireMock.Http
|
||||
contentTypeHeader = headers.First(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase)).Value;
|
||||
}
|
||||
|
||||
responseMessage.BodyData = await BodyParser.Parse(stream, contentTypeHeader?.FirstOrDefault(), deserializeJson);
|
||||
IEnumerable<string> contentEncodingHeader = null;
|
||||
if (headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
contentEncodingHeader = headers.First(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase)).Value;
|
||||
}
|
||||
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = stream,
|
||||
ContentType = contentTypeHeader?.FirstOrDefault(),
|
||||
DeserializeJson = deserializeJson,
|
||||
ContentEncoding = contentEncodingHeader?.FirstOrDefault(),
|
||||
DecompressGZipAndDeflate = decompressGzipAndDeflate
|
||||
};
|
||||
responseMessage.BodyData = await BodyParser.Parse(bodyParserSettings);
|
||||
}
|
||||
|
||||
foreach (var header in headers)
|
||||
|
||||
@@ -43,5 +43,7 @@ namespace WireMock.Owin
|
||||
bool? AllowOnlyDefinedHttpStatusCodeInResponse { get; set; }
|
||||
|
||||
bool? DisableJsonBodyParsing { get; set; }
|
||||
|
||||
bool? DisableRequestBodyDecompressing { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using WireMock.Http;
|
||||
using WireMock.Models;
|
||||
using WireMock.Util;
|
||||
#if !USE_ASPNETCORE
|
||||
@@ -27,12 +28,18 @@ namespace WireMock.Owin.Mappers
|
||||
string method = request.Method;
|
||||
|
||||
Dictionary<string, string[]> headers = null;
|
||||
IEnumerable<string> contentEncodingHeader = null;
|
||||
if (request.Headers.Any())
|
||||
{
|
||||
headers = new Dictionary<string, string[]>();
|
||||
foreach (var header in request.Headers)
|
||||
{
|
||||
headers.Add(header.Key, header.Value);
|
||||
|
||||
if (string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentEncodingHeader = header.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +56,15 @@ namespace WireMock.Owin.Mappers
|
||||
BodyData body = null;
|
||||
if (request.Body != null && BodyParser.ShouldParseBody(method, options.AllowBodyForAllHttpMethods == true))
|
||||
{
|
||||
body = await BodyParser.Parse(request.Body, request.ContentType, !options.DisableJsonBodyParsing.GetValueOrDefault(false));
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = request.Body,
|
||||
ContentType = request.ContentType,
|
||||
DeserializeJson = !options.DisableJsonBodyParsing.GetValueOrDefault(false),
|
||||
ContentEncoding = contentEncodingHeader?.FirstOrDefault(),
|
||||
DecompressGZipAndDeflate = !options.DisableRequestBodyDecompressing.GetValueOrDefault(false)
|
||||
};
|
||||
body = await BodyParser.Parse(bodyParserSettings);
|
||||
}
|
||||
|
||||
return new RequestMessage(urldetails, method, clientIP, body, headers, cookies) { DateTime = DateTime.UtcNow };
|
||||
|
||||
@@ -46,7 +46,10 @@ namespace WireMock.Owin
|
||||
/// <inheritdoc cref="IWireMockMiddlewareOptions.AllowOnlyDefinedHttpStatusCodeInResponse"/>
|
||||
public bool? AllowOnlyDefinedHttpStatusCodeInResponse { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IWireMockMiddlewareOptions.DisableResponseBodyParsing"/>
|
||||
/// <inheritdoc cref="IWireMockMiddlewareOptions.DisableJsonBodyParsing"/>
|
||||
public bool? DisableJsonBodyParsing { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IWireMockMiddlewareOptions.DisableRequestBodyDecompressing"/>
|
||||
public bool? DisableRequestBodyDecompressing { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -112,6 +112,11 @@ namespace WireMock
|
||||
/// </summary>
|
||||
public string DetectedBodyTypeFromContentType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The detected compression from the Content-Encoding header. Convenience getter for Handlebars.
|
||||
/// </summary>
|
||||
public string DetectedCompression { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Host
|
||||
/// </summary>
|
||||
@@ -170,6 +175,7 @@ namespace WireMock
|
||||
BodyAsBytes = BodyData?.BodyAsBytes;
|
||||
DetectedBodyType = BodyData?.DetectedBodyType.ToString();
|
||||
DetectedBodyTypeFromContentType = BodyData?.DetectedBodyTypeFromContentType.ToString();
|
||||
DetectedCompression = BodyData?.DetectedCompression;
|
||||
|
||||
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
|
||||
Cookies = cookies;
|
||||
|
||||
@@ -347,7 +347,13 @@ namespace WireMock.ResponseBuilders
|
||||
var proxyUri = new Uri(ProxyUrl);
|
||||
var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery);
|
||||
|
||||
return await HttpClientHelper.SendAsync(_httpClientForProxy, requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri, !settings.DisableJsonBodyParsing.GetValueOrDefault(false));
|
||||
return await HttpClientHelper.SendAsync(
|
||||
_httpClientForProxy,
|
||||
requestMessage,
|
||||
proxyUriWithRequestPathAndQuery.AbsoluteUri,
|
||||
!settings.DisableJsonBodyParsing.GetValueOrDefault(false),
|
||||
!settings.DisableRequestBodyDecompressing.GetValueOrDefault(false)
|
||||
);
|
||||
}
|
||||
|
||||
ResponseMessage responseMessage;
|
||||
|
||||
@@ -275,7 +275,13 @@ namespace WireMock.Server
|
||||
var proxyUri = new Uri(settings.ProxyAndRecordSettings.Url);
|
||||
var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery);
|
||||
|
||||
var responseMessage = await HttpClientHelper.SendAsync(_httpClientForProxy, requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri, !settings.DisableJsonBodyParsing.GetValueOrDefault(false));
|
||||
var responseMessage = await HttpClientHelper.SendAsync(
|
||||
_httpClientForProxy,
|
||||
requestMessage,
|
||||
proxyUriWithRequestPathAndQuery.AbsoluteUri,
|
||||
!settings.DisableJsonBodyParsing.GetValueOrDefault(false),
|
||||
!settings.DisableRequestBodyDecompressing.GetValueOrDefault(false)
|
||||
);
|
||||
|
||||
if (HttpStatusRangeParser.IsMatch(settings.ProxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) &&
|
||||
(settings.ProxyAndRecordSettings.SaveMapping || settings.ProxyAndRecordSettings.SaveMappingToFile))
|
||||
|
||||
@@ -1,155 +1,161 @@
|
||||
using System;
|
||||
using HandlebarsDotNet;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Logging;
|
||||
|
||||
namespace WireMock.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// IWireMockServerSettings
|
||||
/// </summary>
|
||||
public interface IWireMockServerSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the port.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
int? Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the use SSL.
|
||||
/// </summary>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
[PublicAPI]
|
||||
bool? UseSSL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to start admin interface.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? StartAdminInterface { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the static mappings should be read at startup.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? ReadStaticMappings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Watch the static mapping files + folder for changes when running.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? WatchStaticMappings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A value indicating whether subdirectories within the static mappings path should be monitored.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? WatchStaticMappingsInSubdirectories { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the proxy and record settings.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
IProxyAndRecordSettings ProxyAndRecordSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the urls.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
string[] Urls { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// StartTimeout
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
int StartTimeout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow Partial Mapping (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? AllowPartialMapping { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The username needed for __admin access.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
string AdminUsername { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The password needed for __admin access.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
string AdminPassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The RequestLog expiration in hours (optional).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
int? RequestLogExpirationDuration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The MaxRequestLog count (optional).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
int? MaxRequestLogCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action which is called (with the IAppBuilder or IApplicationBuilder) before the internal WireMockMiddleware is initialized. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
Action<object> PreWireMockMiddlewareInit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action which is called (with the IAppBuilder or IApplicationBuilder) after the internal WireMockMiddleware is initialized. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
Action<object> PostWireMockMiddlewareInit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IWireMockLogger which logs Debug, Info, Warning or Error
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
IWireMockLogger Logger { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Handler to interact with the file system to read and write static mapping files.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
IFileSystemHandler FileSystemHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action which can be used to add additional Handlebars registrations. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
Action<IHandlebars, IFileSystemHandler> HandlebarsRegistrationCallback { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow the usage of CSharpCodeMatcher (default is not allowed).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? AllowCSharpCodeMatcher { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow a Body for all HTTP Methods. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? AllowBodyForAllHttpMethods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow only a HttpStatus Code in the response which is defined. (default set to false).
|
||||
/// - false : also null, 0, empty or invalid HttpStatus codes are allowed.
|
||||
/// - true : only codes defined in <see cref="System.Net.HttpStatusCode"/> are allowed.
|
||||
/// </summary>
|
||||
/// [PublicAPI]
|
||||
bool? AllowOnlyDefinedHttpStatusCodeInResponse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to true to disable Json deserialization when processing requests. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? DisableJsonBodyParsing { get; set; }
|
||||
}
|
||||
using System;
|
||||
using HandlebarsDotNet;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Logging;
|
||||
|
||||
namespace WireMock.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// IWireMockServerSettings
|
||||
/// </summary>
|
||||
public interface IWireMockServerSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the port.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
int? Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the use SSL.
|
||||
/// </summary>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
[PublicAPI]
|
||||
bool? UseSSL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to start admin interface.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? StartAdminInterface { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the static mappings should be read at startup.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? ReadStaticMappings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Watch the static mapping files + folder for changes when running.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? WatchStaticMappings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A value indicating whether subdirectories within the static mappings path should be monitored.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? WatchStaticMappingsInSubdirectories { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the proxy and record settings.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
IProxyAndRecordSettings ProxyAndRecordSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the urls.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
string[] Urls { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// StartTimeout
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
int StartTimeout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow Partial Mapping (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? AllowPartialMapping { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The username needed for __admin access.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
string AdminUsername { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The password needed for __admin access.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
string AdminPassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The RequestLog expiration in hours (optional).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
int? RequestLogExpirationDuration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The MaxRequestLog count (optional).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
int? MaxRequestLogCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action which is called (with the IAppBuilder or IApplicationBuilder) before the internal WireMockMiddleware is initialized. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
Action<object> PreWireMockMiddlewareInit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action which is called (with the IAppBuilder or IApplicationBuilder) after the internal WireMockMiddleware is initialized. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
Action<object> PostWireMockMiddlewareInit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IWireMockLogger which logs Debug, Info, Warning or Error
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
IWireMockLogger Logger { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Handler to interact with the file system to read and write static mapping files.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
IFileSystemHandler FileSystemHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action which can be used to add additional Handlebars registrations. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
Action<IHandlebars, IFileSystemHandler> HandlebarsRegistrationCallback { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow the usage of CSharpCodeMatcher (default is not allowed).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? AllowCSharpCodeMatcher { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow a Body for all HTTP Methods. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? AllowBodyForAllHttpMethods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow only a HttpStatus Code in the response which is defined. (default set to false).
|
||||
/// - false : also null, 0, empty or invalid HttpStatus codes are allowed.
|
||||
/// - true : only codes defined in <see cref="System.Net.HttpStatusCode"/> are allowed.
|
||||
/// </summary>
|
||||
/// [PublicAPI]
|
||||
bool? AllowOnlyDefinedHttpStatusCodeInResponse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to true to disable Json deserialization when processing requests. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? DisableJsonBodyParsing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disable support for GZip and Deflate request body decompression. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
bool? DisableRequestBodyDecompressing { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -103,10 +103,15 @@ namespace WireMock.Settings
|
||||
public bool? AllowBodyForAllHttpMethods { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IWireMockServerSettings.AllowOnlyDefinedHttpStatusCodeInResponse"/>
|
||||
[PublicAPI]
|
||||
public bool? AllowOnlyDefinedHttpStatusCodeInResponse { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IWireMockServerSettings.DisableJsonBodyParsing"/>
|
||||
[PublicAPI]
|
||||
public bool? DisableJsonBodyParsing { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IWireMockServerSettings.DisableRequestBodyDecompressing"/>
|
||||
[PublicAPI]
|
||||
public bool? DisableRequestBodyDecompressing { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -52,5 +52,10 @@ namespace WireMock.Util
|
||||
/// The detected body type (detection based on Content-Type).
|
||||
/// </summary>
|
||||
public BodyType DetectedBodyTypeFromContentType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The detected compression.
|
||||
/// </summary>
|
||||
public string DetectedCompression { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using WireMock.Http;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Types;
|
||||
@@ -108,15 +109,17 @@ namespace WireMock.Util
|
||||
return BodyType.Bytes;
|
||||
}
|
||||
|
||||
public static async Task<BodyData> Parse([NotNull] Stream stream, [CanBeNull] string contentType = null, bool deserializeJson = true)
|
||||
public static async Task<BodyData> Parse([NotNull] BodyParserSettings settings)
|
||||
{
|
||||
Check.NotNull(stream, nameof(stream));
|
||||
Check.NotNull(settings, nameof(settings));
|
||||
|
||||
var bodyWithContentEncoding = await ReadBytesAsync(settings.Stream, settings.ContentEncoding, settings.DecompressGZipAndDeflate);
|
||||
var data = new BodyData
|
||||
{
|
||||
BodyAsBytes = await ReadBytesAsync(stream),
|
||||
BodyAsBytes = bodyWithContentEncoding.Value,
|
||||
DetectedCompression = bodyWithContentEncoding.Key,
|
||||
DetectedBodyType = BodyType.Bytes,
|
||||
DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(contentType)
|
||||
DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(settings.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
|
||||
@@ -141,7 +144,7 @@ namespace WireMock.Util
|
||||
data.DetectedBodyType = BodyType.String;
|
||||
|
||||
// If string is not null or empty, try to deserialize the string to a JObject
|
||||
if (deserializeJson && !string.IsNullOrEmpty(data.BodyAsString))
|
||||
if (settings.DeserializeJson && !string.IsNullOrEmpty(data.BodyAsString))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -161,12 +164,21 @@ namespace WireMock.Util
|
||||
|
||||
return data;
|
||||
}
|
||||
private static async Task<byte[]> ReadBytesAsync(Stream stream)
|
||||
|
||||
private static async Task<KeyValuePair<string, byte[]>> ReadBytesAsync(Stream stream, string contentEncoding = null, bool decompressGZipAndDeflate = true)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
await stream.CopyToAsync(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
byte[] data = memoryStream.ToArray();
|
||||
|
||||
string type = contentEncoding?.ToLowerInvariant();
|
||||
if (decompressGZipAndDeflate && (type == "gzip" || type == "deflate"))
|
||||
{
|
||||
return new KeyValuePair<string, byte[]>(type, CompressionUtils.Decompress(type, data));
|
||||
}
|
||||
|
||||
return new KeyValuePair<string, byte[]>(null, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
17
src/WireMock.Net/Util/BodyParserSettings.cs
Normal file
17
src/WireMock.Net/Util/BodyParserSettings.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.IO;
|
||||
|
||||
namespace WireMock.Util
|
||||
{
|
||||
internal class BodyParserSettings
|
||||
{
|
||||
public Stream Stream { get; set; }
|
||||
|
||||
public string ContentType { get; set; }
|
||||
|
||||
public string ContentEncoding { get; set; }
|
||||
|
||||
public bool DecompressGZipAndDeflate { get; set; } = true;
|
||||
|
||||
public bool DeserializeJson { get; set; } = true;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using FastDeepCloner;
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace WireMock.Util
|
||||
{
|
||||
internal static class CloneUtils
|
||||
{
|
||||
private static FastDeepClonerSettings settings = new FastDeepCloner.FastDeepClonerSettings()
|
||||
{
|
||||
FieldType = FastDeepCloner.FieldType.FieldInfo,
|
||||
OnCreateInstance = new FastDeepCloner.Extensions.CreateInstance((Type type) =>
|
||||
{
|
||||
#if !NETSTANDARD1_3
|
||||
return FormatterServices.GetUninitializedObject(type);
|
||||
#else
|
||||
|
||||
#endif
|
||||
})
|
||||
};
|
||||
|
||||
public static T DeepClone<T>(T objectToBeCloned) where T : class
|
||||
{
|
||||
//return CloneExtensionsEx.CloneFactory.GetClone(objectToBeCloned);
|
||||
// Expression.Lambda<Func<object>>(Expression.New(type)).Compile()
|
||||
return FastDeepCloner.DeepCloner.Clone(objectToBeCloned, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
49
src/WireMock.Net/Util/CompressionUtils.cs
Normal file
49
src/WireMock.Net/Util/CompressionUtils.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace WireMock.Util
|
||||
{
|
||||
internal static class CompressionUtils
|
||||
{
|
||||
public static byte[] Compress(string contentEncoding, byte[] data)
|
||||
{
|
||||
using (var compressedStream = new MemoryStream())
|
||||
using (var zipStream = Create(contentEncoding, compressedStream, CompressionMode.Compress))
|
||||
{
|
||||
zipStream.Write(data, 0, data.Length);
|
||||
|
||||
#if !NETSTANDARD1_3
|
||||
zipStream.Close();
|
||||
#endif
|
||||
return compressedStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Decompress(string contentEncoding, byte[] data)
|
||||
{
|
||||
using (var compressedStream = new MemoryStream(data))
|
||||
using (var zipStream = Create(contentEncoding, compressedStream, CompressionMode.Decompress))
|
||||
using (var resultStream = new MemoryStream())
|
||||
{
|
||||
zipStream.CopyTo(resultStream);
|
||||
return resultStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static Stream Create(string contentEncoding, Stream stream, CompressionMode mode)
|
||||
{
|
||||
switch (contentEncoding)
|
||||
{
|
||||
case "gzip":
|
||||
return new GZipStream(stream, mode);
|
||||
|
||||
case "deflate":
|
||||
return new DeflateStream(stream, mode);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"ContentEncoding '{contentEncoding}' is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace WireMock.Util
|
||||
{
|
||||
public class IndexableDictionary<TKey, TValue> : Dictionary<TKey, TValue>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the value associated with the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index"> The index of the value to get.</param>
|
||||
/// <returns>The value associated with the specified index.</returns>
|
||||
public TValue this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
// get the item for that index.
|
||||
if (index < 0 || index > Count)
|
||||
{
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
return Values.Cast<TValue>().ToArray()[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
|
||||
namespace WireMock.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// http://johnculviner.com/achieving-named-lock-locker-functionality-in-c-4-0/
|
||||
/// </summary>
|
||||
internal class NamedReaderWriterLocker
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, ReaderWriterLockSlim> _lockDict = new ConcurrentDictionary<string, ReaderWriterLockSlim>();
|
||||
|
||||
public ReaderWriterLockSlim GetLock(string name)
|
||||
{
|
||||
return _lockDict.GetOrAdd(name, s => new ReaderWriterLockSlim());
|
||||
}
|
||||
|
||||
public TResult RunWithReadLock<TResult>(string name, Func<TResult> body)
|
||||
{
|
||||
var rwLock = GetLock(name);
|
||||
try
|
||||
{
|
||||
rwLock.EnterReadLock();
|
||||
return body();
|
||||
}
|
||||
finally
|
||||
{
|
||||
rwLock.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
public void RunWithReadLock(string name, Action body)
|
||||
{
|
||||
var rwLock = GetLock(name);
|
||||
try
|
||||
{
|
||||
rwLock.EnterReadLock();
|
||||
body();
|
||||
}
|
||||
finally
|
||||
{
|
||||
rwLock.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
public TResult RunWithWriteLock<TResult>(string name, Func<TResult> body)
|
||||
{
|
||||
var rwLock = GetLock(name);
|
||||
try
|
||||
{
|
||||
rwLock.EnterWriteLock();
|
||||
return body();
|
||||
}
|
||||
finally
|
||||
{
|
||||
rwLock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
public void RunWithWriteLock(string name, Action body)
|
||||
{
|
||||
var rwLock = GetLock(name);
|
||||
try
|
||||
{
|
||||
rwLock.EnterWriteLock();
|
||||
body();
|
||||
}
|
||||
finally
|
||||
{
|
||||
rwLock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveLock(string name)
|
||||
{
|
||||
_lockDict.TryRemove(name, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@
|
||||
<Description>Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.</Description>
|
||||
<AssemblyTitle>WireMock.Net</AssemblyTitle>
|
||||
<Authors>Stef Heyenrath</Authors>
|
||||
<!--<TargetFrameworks>net451;net452;net46;net461;netstandard1.3;netstandard2.0;netcoreapp2.1</TargetFrameworks>-->
|
||||
<!--<TargetFrameworks>net451;net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>-->
|
||||
<TargetFrameworks>net451;net452;net46;net461;netstandard1.3;netstandard2.0;;netstandard2.1</TargetFrameworks>
|
||||
<TargetFrameworks>net451;net452;net46;net461;netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<AssemblyName>WireMock.Net</AssemblyName>
|
||||
<PackageId>WireMock.Net</PackageId>
|
||||
@@ -29,7 +27,8 @@
|
||||
<None Include="WireMock.Net-Logo.png" Pack="true" PackagePath="../../"/>
|
||||
</ItemGroup>-->
|
||||
|
||||
<!--https://github.com/aspnet/RoslynCodeDomProvider/issues/51-->
|
||||
<!-- https://github.com/aspnet/RoslynCodeDomProvider/issues/51 -->
|
||||
<!-- This is needed else we cannot build net452 in Azure DevOps Pipeline -->
|
||||
<Target Name="CheckIfShouldKillVBCSCompiler" />
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
@@ -53,26 +52,22 @@
|
||||
<DefineConstants>USE_ASPNETCORE;NET46</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Util\CloneUtils.cs" />
|
||||
<Compile Remove="Util\IndexableDictionary.cs" />
|
||||
<Compile Remove="Util\NamedReaderWriterLocker.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<!--<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />-->
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.12" />
|
||||
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.10" />
|
||||
<PackageReference Include="JmesPath.Net" Version="1.0.125" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
|
||||
<PackageReference Include="SonarAnalyzer.CSharp" Version="7.8.0.7320">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.12" />
|
||||
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.10" />
|
||||
<PackageReference Include="JmesPath.Net" Version="1.0.125" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
|
||||
|
||||
@@ -243,18 +243,36 @@ namespace WireMock.Net.Tests.RequestMatchers
|
||||
// assign
|
||||
BodyData bodyData;
|
||||
if (body is byte[] b)
|
||||
bodyData = await BodyParser.Parse(new MemoryStream(b), null, true);
|
||||
{
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = new MemoryStream(b),
|
||||
ContentType = null,
|
||||
DeserializeJson = true
|
||||
};
|
||||
bodyData = await BodyParser.Parse(bodyParserSettings);
|
||||
}
|
||||
else if (body is string s)
|
||||
bodyData = await BodyParser.Parse(new MemoryStream(Encoding.UTF8.GetBytes(s)), null, true);
|
||||
{
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = new MemoryStream(Encoding.UTF8.GetBytes(s)),
|
||||
ContentType = null,
|
||||
DeserializeJson = true
|
||||
};
|
||||
bodyData = await BodyParser.Parse(bodyParserSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
var requestMessage = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.1", bodyData);
|
||||
|
||||
// act
|
||||
var result = new RequestMatchResult();
|
||||
var score = matcher.GetMatchingScore(requestMessage, result);
|
||||
|
||||
|
||||
// assert
|
||||
Check.That(score).IsEqualTo(shouldMatch ? 1d : 0d);
|
||||
}
|
||||
@@ -265,7 +283,7 @@ namespace WireMock.Net.Tests.RequestMatchers
|
||||
{
|
||||
var json = "{'a':'b'}";
|
||||
var str = "HelloWorld";
|
||||
var bytes = new byte[] {0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00};
|
||||
var bytes = new byte[] { 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00 };
|
||||
|
||||
return new TheoryData<object, RequestMessageBodyMatcher, bool>
|
||||
{
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using NFluent;
|
||||
using System;
|
||||
using NFluent;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
using Xunit;
|
||||
@@ -19,10 +22,15 @@ namespace WireMock.Net.Tests.Util
|
||||
public async Task BodyParser_Parse_ContentTypeJson(string contentType, string bodyAsJson, BodyType detectedBodyType, BodyType detectedBodyTypeFromContentType)
|
||||
{
|
||||
// Arrange
|
||||
var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsJson));
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsJson)),
|
||||
ContentType = contentType,
|
||||
DeserializeJson = true
|
||||
};
|
||||
|
||||
// Act
|
||||
var body = await BodyParser.Parse(memoryStream, contentType, true);
|
||||
var body = await BodyParser.Parse(bodyParserSettings);
|
||||
|
||||
// Assert
|
||||
Check.That(body.BodyAsBytes).IsNotNull();
|
||||
@@ -38,10 +46,15 @@ namespace WireMock.Net.Tests.Util
|
||||
public async Task BodyParser_Parse_ContentTypeString(string contentType, string bodyAsString, BodyType detectedBodyType, BodyType detectedBodyTypeFromContentType)
|
||||
{
|
||||
// Arrange
|
||||
var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsString));
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsString)),
|
||||
ContentType = contentType,
|
||||
DeserializeJson = true
|
||||
};
|
||||
|
||||
// Act
|
||||
var body = await BodyParser.Parse(memoryStream, contentType, true);
|
||||
var body = await BodyParser.Parse(bodyParserSettings);
|
||||
|
||||
// Assert
|
||||
Check.That(body.BodyAsBytes).IsNotNull();
|
||||
@@ -52,16 +65,21 @@ namespace WireMock.Net.Tests.Util
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new byte[] {34, 97, 34}, BodyType.Json)]
|
||||
[InlineData(new byte[] {97}, BodyType.String)]
|
||||
[InlineData(new byte[] {0xFF, 0xD8, 0xFF, 0xE0}, BodyType.Bytes)]
|
||||
[InlineData(new byte[] { 34, 97, 34 }, BodyType.Json)]
|
||||
[InlineData(new byte[] { 97 }, BodyType.String)]
|
||||
[InlineData(new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 }, BodyType.Bytes)]
|
||||
public async Task BodyParser_Parse_DetectedBodyType(byte[] content, BodyType detectedBodyType)
|
||||
{
|
||||
// arrange
|
||||
var memoryStream = new MemoryStream(content);
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = new MemoryStream(content),
|
||||
ContentType = null,
|
||||
DeserializeJson = true
|
||||
};
|
||||
|
||||
// act
|
||||
var body = await BodyParser.Parse(memoryStream, null, true);
|
||||
var body = await BodyParser.Parse(bodyParserSettings);
|
||||
|
||||
// assert
|
||||
Check.That(body.DetectedBodyType).IsEqualTo(detectedBodyType);
|
||||
@@ -74,10 +92,15 @@ namespace WireMock.Net.Tests.Util
|
||||
public async Task BodyParser_Parse_DetectedBodyTypeNoJsonParsing(byte[] content, BodyType detectedBodyType)
|
||||
{
|
||||
// arrange
|
||||
var memoryStream = new MemoryStream(content);
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = new MemoryStream(content),
|
||||
ContentType = null,
|
||||
DeserializeJson = false
|
||||
};
|
||||
|
||||
// act
|
||||
var body = await BodyParser.Parse(memoryStream, null, false);
|
||||
var body = await BodyParser.Parse(bodyParserSettings);
|
||||
|
||||
// assert
|
||||
Check.That(body.DetectedBodyType).IsEqualTo(detectedBodyType);
|
||||
@@ -108,10 +131,15 @@ Content-Type: text/html
|
||||
|
||||
-----------------------------9051914041544843365972754266--";
|
||||
|
||||
var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(body));
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = new MemoryStream(Encoding.UTF8.GetBytes(body)),
|
||||
ContentType = contentType,
|
||||
DeserializeJson = true
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await BodyParser.Parse(memoryStream, contentType, true);
|
||||
var result = await BodyParser.Parse(bodyParserSettings);
|
||||
|
||||
// Assert
|
||||
Check.That(result.DetectedBodyType).IsEqualTo(BodyType.String);
|
||||
@@ -127,11 +155,15 @@ Content-Type: text/html
|
||||
// Arrange
|
||||
string contentType = "multipart/form-data";
|
||||
string body = char.ConvertFromUtf32(0x1D161); //U+1D161 = MUSICAL SYMBOL SIXTEENTH NOTE
|
||||
|
||||
var memoryStream = new MemoryStream(Encoding.UTF32.GetBytes(body));
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = new MemoryStream(Encoding.UTF8.GetBytes(body)),
|
||||
ContentType = contentType,
|
||||
DeserializeJson = true
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await BodyParser.Parse(memoryStream, contentType, true);
|
||||
var result = await BodyParser.Parse(bodyParserSettings);
|
||||
|
||||
// Assert
|
||||
Check.That(result.DetectedBodyType).IsEqualTo(BodyType.Bytes);
|
||||
@@ -142,14 +174,19 @@ Content-Type: text/html
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "hello", BodyType.String, BodyType.Bytes)]
|
||||
public async Task BodyParser_Parse_ContentTypeIsNull(string contentType, string bodyAsString, BodyType detectedBodyType, BodyType detectedBodyTypeFromContentType)
|
||||
[InlineData("hello", BodyType.String, BodyType.Bytes)]
|
||||
public async Task BodyParser_Parse_ContentTypeIsNull(string bodyAsString, BodyType detectedBodyType, BodyType detectedBodyTypeFromContentType)
|
||||
{
|
||||
// Arrange
|
||||
var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsString));
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsString)),
|
||||
ContentType = null,
|
||||
DeserializeJson = true
|
||||
};
|
||||
|
||||
// Act
|
||||
var body = await BodyParser.Parse(memoryStream, contentType, true);
|
||||
var body = await BodyParser.Parse(bodyParserSettings);
|
||||
|
||||
// Assert
|
||||
Check.That(body.BodyAsBytes).IsNotNull();
|
||||
@@ -159,6 +196,60 @@ Content-Type: text/html
|
||||
Check.That(body.DetectedBodyTypeFromContentType).IsEqualTo(detectedBodyTypeFromContentType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("gzip")]
|
||||
[InlineData("deflate")]
|
||||
public async Task BodyParser_Parse_ContentEncoding_GZip_And_DecompressGzipAndDeflate_Is_True_Should_Decompress(string compression)
|
||||
{
|
||||
// Arrange
|
||||
var bytes = Encoding.ASCII.GetBytes("0");
|
||||
var compressed = CompressionUtils.Compress(compression, bytes);
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = new MemoryStream(compressed),
|
||||
ContentType = "text/plain",
|
||||
DeserializeJson = false,
|
||||
ContentEncoding = compression.ToUpperInvariant(),
|
||||
DecompressGZipAndDeflate = true
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await BodyParser.Parse(bodyParserSettings);
|
||||
|
||||
// Assert
|
||||
result.DetectedBodyType.Should().Be(BodyType.String);
|
||||
result.DetectedBodyTypeFromContentType.Should().Be(BodyType.String);
|
||||
result.BodyAsBytes.Should().BeEquivalentTo(new byte[] { 48 });
|
||||
result.BodyAsJson.Should().BeNull();
|
||||
result.BodyAsString.Should().Be("0");
|
||||
result.DetectedCompression.Should().Be(compression);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("gzip")]
|
||||
[InlineData("deflate")]
|
||||
public async Task BodyParser_Parse_ContentEncoding_GZip_And_DecompressGzipAndDeflate_Is_False_Should_Not_Decompress(string compression)
|
||||
{
|
||||
// Arrange
|
||||
var bytes = Encoding.ASCII.GetBytes(Guid.NewGuid().ToString());
|
||||
var compressed = CompressionUtils.Compress(compression, bytes);
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = new MemoryStream(compressed),
|
||||
ContentType = "text/plain",
|
||||
DeserializeJson = false,
|
||||
ContentEncoding = compression.ToUpperInvariant(),
|
||||
DecompressGZipAndDeflate = false
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await BodyParser.Parse(bodyParserSettings);
|
||||
|
||||
// Assert
|
||||
result.BodyAsBytes.Should().BeEquivalentTo(compressed);
|
||||
result.DetectedCompression.Should().BeNull();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("HEAD", false)]
|
||||
[InlineData("GET", false)]
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NFluent;
|
||||
using WireMock.RequestBuilders;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Server;
|
||||
using WireMock.Util;
|
||||
using Xunit;
|
||||
|
||||
namespace WireMock.Net.Tests
|
||||
@@ -252,5 +256,35 @@ namespace WireMock.Net.Tests
|
||||
Check.That(response.StatusCode).Equals(HttpStatusCode.Created);
|
||||
Check.That(await response.Content.ReadAsStringAsync()).Contains("Mapping added");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("gzip")]
|
||||
[InlineData("deflate")]
|
||||
public async Task WireMockServer_Should_SupportRequestGZipAndDeflate(string contentEncoding)
|
||||
{
|
||||
// Arrange
|
||||
const string body = "hello wiremock";
|
||||
byte[] compressed = CompressionUtils.Compress(contentEncoding, Encoding.UTF8.GetBytes(body));
|
||||
|
||||
var server = WireMockServer.Start();
|
||||
server.Given(
|
||||
Request.Create()
|
||||
.WithPath("/foo")
|
||||
.WithBody("hello wiremock")
|
||||
)
|
||||
.RespondWith(
|
||||
Response.Create().WithBody("OK")
|
||||
);
|
||||
|
||||
var content = new StreamContent(new MemoryStream(compressed));
|
||||
content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
|
||||
content.Headers.ContentEncoding.Add(contentEncoding);
|
||||
|
||||
// Act
|
||||
var response = await new HttpClient().PostAsync($"{server.Urls[0]}/foo", content);
|
||||
|
||||
// Assert
|
||||
Check.That(await response.Content.ReadAsStringAsync()).Contains("OK");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user