using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; using JetBrains.Annotations; using Newtonsoft.Json; using WireMock.Http; using WireMock.Settings; using WireMock.Transformers; using WireMock.Util; using WireMock.Validation; namespace WireMock.ResponseBuilders { /// /// The Response. /// public class Response : IResponseBuilder { private HttpClient _httpClientForProxy; /// /// The delay /// public TimeSpan? Delay { get; private set; } /// /// Gets a value indicating whether [use transformer]. /// public bool UseTransformer { get; private set; } /// /// The Proxy URL to use. /// public string ProxyUrl { get; private set; } /// /// The client X509Certificate2 Thumbprint or SubjectName to use. /// public string ClientX509Certificate2ThumbprintOrSubjectName { 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; } /// /// 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; } /// /// The with status code. /// /// The code. /// A .\ [PublicAPI] public IResponseBuilder WithStatusCode(int code) { ResponseMessage.StatusCode = code; return this; } /// /// The with status code. /// /// The code. /// A . [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 WithCallback(req => new ResponseMessage { Body = bodyFactory(req), BodyDestination = destination, BodyEncoding = encoding ?? Encoding.UTF8 }); } /// public IResponseBuilder WithBody(byte[] body, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null) { Check.NotNull(body, nameof(body)); ResponseMessage.BodyDestination = destination; switch (destination) { case BodyDestinationFormat.String: var enc = encoding ?? Encoding.UTF8; ResponseMessage.BodyAsBytes = null; ResponseMessage.Body = enc.GetString(body); ResponseMessage.BodyEncoding = enc; break; default: ResponseMessage.BodyAsBytes = body; ResponseMessage.BodyEncoding = null; break; } return this; } /// public IResponseBuilder WithBodyFromFile(string filename, bool cache = true) { Check.NotNull(filename, nameof(filename)); ResponseMessage.BodyEncoding = null; ResponseMessage.BodyAsFileIsCached = cache; if (cache) { ResponseMessage.Body = null; ResponseMessage.BodyAsBytes = File.ReadAllBytes(filename); ResponseMessage.BodyAsFile = null; } else { ResponseMessage.Body = null; ResponseMessage.BodyAsBytes = null; ResponseMessage.BodyAsFile = filename; } 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.BodyEncoding = encoding; switch (destination) { case BodyDestinationFormat.Bytes: ResponseMessage.Body = null; ResponseMessage.BodyAsJson = null; ResponseMessage.BodyAsBytes = encoding.GetBytes(body); break; case BodyDestinationFormat.Json: ResponseMessage.Body = null; ResponseMessage.BodyAsJson = JsonConvert.DeserializeObject(body); ResponseMessage.BodyAsBytes = null; break; default: ResponseMessage.Body = body; ResponseMessage.BodyAsJson = null; ResponseMessage.BodyAsBytes = null; break; } return this; } /// public IResponseBuilder WithBodyAsJson(object body, Encoding encoding = null, bool? indented = null) { Check.NotNull(body, nameof(body)); ResponseMessage.BodyDestination = null; ResponseMessage.BodyAsJson = body; ResponseMessage.BodyEncoding = encoding; ResponseMessage.BodyAsJsonIndented = indented; return this; } /// public IResponseBuilder WithBodyAsJson(object body, bool indented) { return WithBodyAsJson(body, null, indented); } /// public IResponseBuilder WithBodyFromBase64(string bodyAsbase64, Encoding encoding = null) { Check.NotNull(bodyAsbase64, nameof(bodyAsbase64)); encoding = encoding ?? Encoding.UTF8; ResponseMessage.BodyDestination = null; ResponseMessage.Body = encoding.GetString(Convert.FromBase64String(bodyAsbase64)); ResponseMessage.BodyEncoding = encoding; return this; } /// public IResponseBuilder WithTransformer() { UseTransformer = true; 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 WithProxy(string proxyUrl, string clientX509Certificate2ThumbprintOrSubjectName = null) { Check.NotNullOrEmpty(proxyUrl, nameof(proxyUrl)); ProxyUrl = proxyUrl; ClientX509Certificate2ThumbprintOrSubjectName = clientX509Certificate2ThumbprintOrSubjectName; _httpClientForProxy = HttpClientHelper.CreateHttpClient(clientX509Certificate2ThumbprintOrSubjectName); return this; } /// public IResponseBuilder WithProxy(IProxyAndRecordSettings settings) { Check.NotNull(settings, nameof(settings)); return WithProxy(settings.Url, settings.ClientX509Certificate2ThumbprintOrSubjectName); } /// public IResponseBuilder WithCallback(Func callbackHandler) { Check.NotNull(callbackHandler, nameof(callbackHandler)); Callback = callbackHandler; return this; } /// /// The provide response. /// /// The request. /// The . public async Task ProvideResponseAsync(RequestMessage requestMessage) { Check.NotNull(requestMessage, nameof(requestMessage)); if (Delay != null) { await Task.Delay(Delay.Value); } if (Callback != null) { var callbackResponseMessage = Callback(requestMessage); // Copy StatusCode from ResponseMessage callbackResponseMessage.StatusCode = ResponseMessage.StatusCode; // Copy Headers from ResponseMessage (if defined) if (ResponseMessage.Headers != null) { callbackResponseMessage.Headers = ResponseMessage.Headers; } return callbackResponseMessage; } 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); } if (UseTransformer) { return ResponseMessageTransformer.Transform(requestMessage, ResponseMessage); } // Just return normal defined ResponseMessage return ResponseMessage; } } }