using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Http;
using WireMock.Matchers.Request;
using WireMock.Validation;
namespace WireMock.Server
{
///
/// The fluent mock server.
///
public partial class FluentMockServer
{
///
/// The _http server.
///
private readonly TinyHttpServer _httpServer;
///
/// The _mappings.
///
private readonly IList _mappings = new List();
///
/// The _request logs.
///
private readonly IList _requestLogs = new List();
///
/// The _request mapper.
///
private readonly HttpListenerRequestMapper _requestMapper = new HttpListenerRequestMapper();
///
/// The _response mapper.
///
private readonly HttpListenerResponseMapper _responseMapper = new HttpListenerResponseMapper();
///
/// The _sync root.
///
private readonly object _syncRoot = new object();
///
/// The _request processing delay.
///
private TimeSpan _requestProcessingDelay = TimeSpan.Zero;
///
/// Gets the port.
///
public int Port { get; }
///
/// Gets the request logs.
///
public IEnumerable RequestLogs
{
get
{
lock (((ICollection)_requestLogs).SyncRoot)
{
return new ReadOnlyCollection(_requestLogs);
}
}
}
///
/// Gets the routes.
///
public IEnumerable Mappings
{
get
{
lock (((ICollection)_mappings).SyncRoot)
{
return new ReadOnlyCollection(_mappings);
}
}
}
///
/// Start this FluentMockServer.
///
/// The port.
/// The SSL support.
/// The .
[PublicAPI]
public static FluentMockServer Start(int port = 0, bool ssl = false)
{
Check.Condition(port, p => p >= 0, nameof(port));
if (port == 0)
port = Ports.FindFreeTcpPort();
return new FluentMockServer(false, port, ssl);
}
///
/// Start this FluentMockServer with the admin interface.
///
/// The port.
/// The SSL support.
/// The .
[PublicAPI]
public static FluentMockServer StartWithAdminInterface(int port = 0, bool ssl = false)
{
Check.Condition(port, p => p >= 0, nameof(port));
if (port == 0)
port = Ports.FindFreeTcpPort();
return new FluentMockServer(true, port, ssl);
}
private FluentMockServer(bool startAdmin, int port, bool ssl)
{
string protocol = ssl ? "https" : "http";
_httpServer = new TinyHttpServer(protocol + "://localhost:" + port + "/", HandleRequestAsync);
Port = port;
_httpServer.Start();
if (startAdmin)
{
InitAdmin();
}
}
///
/// Stop this server.
///
public void Stop()
{
_httpServer.Stop();
}
///
/// The reset.
///
public void Reset()
{
lock (((ICollection)_requestLogs).SyncRoot)
{
_requestLogs.Clear();
}
lock (((ICollection)_mappings).SyncRoot)
{
_mappings.Clear();
}
}
///
/// The search logs for.
///
///
/// The matcher.
///
///
/// The .
///
public IEnumerable SearchLogsFor(IRequestMatcher spec)
{
lock (((ICollection)_requestLogs).SyncRoot)
{
return _requestLogs.Where(spec.IsMatch);
}
}
///
/// The add request processing delay.
///
///
/// The delay.
///
public void AddRequestProcessingDelay(TimeSpan delay)
{
lock (_syncRoot)
{
_requestProcessingDelay = delay;
}
}
///
/// The given.
///
/// The request matcher.
/// The .
public IRespondWithAProvider Given(IRequestMatcher requestMatcher)
{
return new RespondWithAProvider(RegisterMapping, requestMatcher);
}
///
/// The register mapping.
///
///
/// The mapping.
///
private void RegisterMapping(Mapping mapping)
{
lock (((ICollection)_mappings).SyncRoot)
{
_mappings.Add(mapping);
}
}
///
/// The log request.
///
///
/// The request.
///
private void LogRequest(RequestMessage requestMessage)
{
lock (((ICollection)_requestLogs).SyncRoot)
{
_requestLogs.Add(requestMessage);
}
}
///
/// The handle request.
///
/// The HttpListenerContext.
private async void HandleRequestAsync(HttpListenerContext ctx)
{
lock (_syncRoot)
{
Task.Delay(_requestProcessingDelay).Wait();
}
var request = _requestMapper.Map(ctx.Request);
LogRequest(request);
try
{
var targetRoute = _mappings.FirstOrDefault(route => route.IsRequestHandled(request));
if (targetRoute == null)
{
ctx.Response.StatusCode = 404;
byte[] content = Encoding.UTF8.GetBytes("Mock Server: page not found");
ctx.Response.OutputStream.Write(content, 0, content.Length);
}
else
{
var response = await targetRoute.ResponseTo(request);
_responseMapper.Map(response, ctx.Response);
}
}
catch (Exception ex)
{
ctx.Response.StatusCode = 500;
byte[] content = Encoding.UTF8.GetBytes(ex.ToString());
ctx.Response.OutputStream.Write(content, 0, content.Length);
}
finally
{
ctx.Response.Close();
}
}
}
}