// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License. // For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root. using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using JetBrains.Annotations; using WireMock.Http; using WireMock.ResponseProviders; using WireMock.Settings; using WireMock.Transformers; using WireMock.Types; using WireMock.Util; using WireMock.Validation; namespace WireMock.ResponseBuilders { /// /// The Response. /// public partial class Response : IResponseBuilder { /// /// The delay /// public TimeSpan? Delay { get; private set; } /// /// Gets a value indicating whether [use transformer]. /// public bool UseTransformer { get; private set; } /// /// Gets a value indicating whether to use the Handlerbars transformer for the content from the referenced BodyAsFile. /// public bool UseTransformerForBodyAsFile { get; private set; } /// /// Gets the response message. /// public ResponseMessage ResponseMessage { get; } /// /// A delegate to execute to generate the response. /// public Func Callback { get; private set; } /// /// Defines if the method WithCallback(...) is used. /// public bool WithCallbackUsed { get; private set; } /// /// Creates this instance. /// /// ResponseMessage /// A . [PublicAPI] public static IResponseBuilder Create([CanBeNull] ResponseMessage responseMessage = null) { var message = responseMessage ?? new ResponseMessage(); // { StatusCode = (int)HttpStatusCode.OK }; return new Response(message); } /// /// Creates this instance with the specified function. /// /// The callback function. /// A . [PublicAPI] public static IResponseBuilder Create([NotNull] Func func) { Check.NotNull(func, nameof(func)); return new Response(func()); } /// /// Initializes a new instance of the class. /// /// /// The response. /// private Response(ResponseMessage responseMessage) { ResponseMessage = responseMessage; } /// [PublicAPI] public IResponseBuilder WithStatusCode(int code) { ResponseMessage.StatusCode = code; return this; } /// [PublicAPI] public IResponseBuilder WithStatusCode(string code) { ResponseMessage.StatusCode = code; return this; } /// [PublicAPI] public IResponseBuilder WithStatusCode(HttpStatusCode code) { return WithStatusCode((int)code); } /// /// The with Success status code (200). /// /// A . [PublicAPI] public IResponseBuilder WithSuccess() { return WithStatusCode((int)HttpStatusCode.OK); } /// /// The with NotFound status code (404). /// /// The . [PublicAPI] public IResponseBuilder WithNotFound() { return WithStatusCode((int)HttpStatusCode.NotFound); } /// public IResponseBuilder WithHeader(string name, params string[] values) { Check.NotNull(name, nameof(name)); ResponseMessage.AddHeader(name, values); return this; } /// public IResponseBuilder WithHeaders(IDictionary headers) { Check.NotNull(headers, nameof(headers)); ResponseMessage.Headers = headers.ToDictionary(header => header.Key, header => new WireMockList(header.Value)); return this; } /// public IResponseBuilder WithHeaders(IDictionary headers) { Check.NotNull(headers, nameof(headers)); ResponseMessage.Headers = headers.ToDictionary(header => header.Key, header => new WireMockList(header.Value)); return this; } /// public IResponseBuilder WithHeaders(IDictionary> headers) { ResponseMessage.Headers = headers; return this; } /// public IResponseBuilder WithBody(Func bodyFactory, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null) { Check.NotNull(bodyFactory, nameof(bodyFactory)); return WithCallbackInternal(false, req => new ResponseMessage { BodyData = new BodyData { DetectedBodyType = BodyType.String, BodyAsString = bodyFactory(req), Encoding = encoding ?? Encoding.UTF8 } }); } /// public IResponseBuilder WithBody(byte[] body, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null) { Check.NotNull(body, nameof(body)); ResponseMessage.BodyDestination = destination; ResponseMessage.BodyData = new BodyData(); switch (destination) { case BodyDestinationFormat.String: var enc = encoding ?? Encoding.UTF8; ResponseMessage.BodyData.DetectedBodyType = BodyType.String; ResponseMessage.BodyData.BodyAsString = enc.GetString(body); ResponseMessage.BodyData.Encoding = enc; break; default: ResponseMessage.BodyData.DetectedBodyType = BodyType.Bytes; ResponseMessage.BodyData.BodyAsBytes = body; break; } return this; } /// public IResponseBuilder WithBodyFromFile(string filename, bool cache = true) { Check.NotNull(filename, nameof(filename)); ResponseMessage.BodyData = new BodyData { BodyAsFileIsCached = cache, BodyAsFile = filename }; if (cache && !UseTransformer) { ResponseMessage.BodyData.DetectedBodyType = BodyType.Bytes; } else { ResponseMessage.BodyData.DetectedBodyType = BodyType.File; } return this; } /// public IResponseBuilder WithBody(string body, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null) { Check.NotNull(body, nameof(body)); encoding = encoding ?? Encoding.UTF8; ResponseMessage.BodyDestination = destination; ResponseMessage.BodyData = new BodyData { Encoding = encoding }; switch (destination) { case BodyDestinationFormat.Bytes: ResponseMessage.BodyData.DetectedBodyType = BodyType.Bytes; ResponseMessage.BodyData.BodyAsBytes = encoding.GetBytes(body); break; case BodyDestinationFormat.Json: ResponseMessage.BodyData.DetectedBodyType = BodyType.Json; ResponseMessage.BodyData.BodyAsJson = JsonUtils.DeserializeObject(body); break; default: ResponseMessage.BodyData.DetectedBodyType = BodyType.String; ResponseMessage.BodyData.BodyAsString = body; break; } return this; } /// public IResponseBuilder WithBodyAsJson(object body, Encoding encoding = null, bool? indented = null) { Check.NotNull(body, nameof(body)); ResponseMessage.BodyDestination = null; ResponseMessage.BodyData = new BodyData { Encoding = encoding, DetectedBodyType = BodyType.Json, BodyAsJson = body, BodyAsJsonIndented = indented }; return this; } /// public IResponseBuilder WithBodyAsJson(object body, bool indented) { return WithBodyAsJson(body, null, indented); } /// public IResponseBuilder WithTransformer(bool transformContentFromBodyAsFile = false) { UseTransformer = true; UseTransformerForBodyAsFile = transformContentFromBodyAsFile; return this; } /// public IResponseBuilder WithDelay(TimeSpan delay) { Check.Condition(delay, d => d > TimeSpan.Zero, nameof(delay)); Delay = delay; return this; } /// public IResponseBuilder WithDelay(int milliseconds) { return WithDelay(TimeSpan.FromMilliseconds(milliseconds)); } /// public IResponseBuilder WithCallback(Func callbackHandler) { Check.NotNull(callbackHandler, nameof(callbackHandler)); return WithCallbackInternal(true, callbackHandler); } /// private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func callbackHandler) { Check.NotNull(callbackHandler, nameof(callbackHandler)); WithCallbackUsed = withCallbackUsed; Callback = callbackHandler; return this; } /// public async Task ProvideResponseAsync(RequestMessage requestMessage, IWireMockServerSettings settings) { Check.NotNull(requestMessage, nameof(requestMessage)); Check.NotNull(settings, nameof(settings)); if (Delay != null) { await Task.Delay(Delay.Value); } if (ProxyUrl != null && _httpClientForProxy != null) { var requestUri = new Uri(requestMessage.Url); var proxyUri = new Uri(ProxyUrl); var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery); return await HttpClientHelper.SendAsync( _httpClientForProxy, requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri, !settings.DisableJsonBodyParsing.GetValueOrDefault(false), !settings.DisableRequestBodyDecompressing.GetValueOrDefault(false) ); } ResponseMessage responseMessage; if (Callback == null) { responseMessage = ResponseMessage; } else { responseMessage = Callback(requestMessage); if (!WithCallbackUsed) { // Copy StatusCode from ResponseMessage responseMessage.StatusCode = ResponseMessage.StatusCode; // Copy Headers from ResponseMessage (if defined) if (ResponseMessage.Headers != null) { responseMessage.Headers = ResponseMessage.Headers; } } } if (UseTransformer) { var factory = new HandlebarsContextFactory(settings.FileSystemHandler, settings.HandlebarsRegistrationCallback); var responseMessageTransformer = new ResponseMessageTransformer(factory); return responseMessageTransformer.Transform(requestMessage, responseMessage, UseTransformerForBodyAsFile); } if (!UseTransformer && ResponseMessage.BodyData?.BodyAsFileIsCached == true) { ResponseMessage.BodyData.BodyAsBytes = settings.FileSystemHandler.ReadResponseBodyAsFile(responseMessage.BodyData.BodyAsFile); } return responseMessage; } } }