Previous versions:
Please star this project if you find it useful. Thank you.
This is a simple HTTP Listener that is created as a .NET Standard 2.0 Library for cross platform use.
The HTTP listener is capable of listening for HTTP on TCP as well as UDP, including UDP multicast, which makes it suitable for use with for instance UPnP.
The HTTP listner is created with Reactive Extensions making it easy to use and efficient for handling the asynchronous nature of HTTP.
Simple Http Listener Rx is the next version of Simple HTTP Listener PCL.
So much was changed between 5.1.1 and this library, that it made more sense to both rename and create an all new library. However, the goal of the two libraries is the same.
There is a reason this library is called simple. Turning a TCP or UDP connection into a observable HTTP listener is done by simply adding the ToHttpListenerObservable
Extension Method to a TcPListener
or a UdpClient
. That's it. See the examples below or the test client included in the library. code
using ISimpleHttpListener.Rx.Enum;
using SimpleHttpListener.Rx.Extension;
using SimpleHttpListener.Rx.Model;
using SimpleHttpListener.Rx.Service;
For a simple TCP based HTTP Listner see this example.
Notice that it is bad practice to create an async Suscriber - i.e. .Subscribe(async x => ...)
. To avoid create a .Select(r => Observable.FromAsync(() => ...).Concat
instead as in the example below.
static void TcpListenerTest()
{
var uri = new Uri("http://mylocalipaddress:8000");
var tcpListener = new TcpListener(uri.Host.GetIPv4Address(), uri.Port)
{
ExclusiveAddressUse = false
};
var httpSender = new HttpSender();
var cts = new CancellationTokenSource();
var disposable = tcpListener
.ToHttpListenerObservable(cts.Token)
.Do(r =>
{
Console.WriteLine($"Remote Address: {r.RemoteIpEndPoint.Address}");
Console.WriteLine($"Remote Port: {r.RemoteIpEndPoint.Port}");
Console.WriteLine("--------------***-------------");
})
// Send reply to browser
.Select(r => Observable.FromAsync(() => SendResponseAsync(r, httpSender)))
.Concat()
.Subscribe(r =>
{
Console.WriteLine("Reply sent.");
},
ex =>
{
Console.WriteLine($"Exception: {ex}");
},
() =>
{
Console.WriteLine("Completed.");
});
}
static async Task SendResponseAsync(IHttpRequestResponse request, HttpSender httpSender)
{
if (request.RequestType == RequestType.TCP)
{
var response = new HttpResponse
{
StatusCode = (int)HttpStatusCode.OK,
ResponseReason = HttpStatusCode.OK.ToString(),
Headers = new Dictionary<string, string>
{
{"Date", DateTime.UtcNow.ToString("r")},
{"Content-Type", "text/html; charset=UTF-8" },
},
Body = new MemoryStream(Encoding.UTF8.GetBytes($"<html>\r\n<body>\r\n<h1>Hello, World! {DateTime.Now}</h1>\r\n</body>\r\n</html>"))
};
await httpSender.SendTcpResponseAsync(request, response).ConfigureAwait(false);
}
}
An UDP Listener is created like this. The following UDP listener will listen for UPnP SSDP multicasts on the local network.
var localHost = IPAddress.Parse("192.168.0.59");
var localEndPoint = new IPEndPoint(localHost, 1900);
var multicastIpAddress = IPAddress.Parse("239.255.255.250");
udpClient = new UdpClient
{
ExclusiveAddressUse = false,
MulticastLoopback = true
};
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.JoinMulticastGroup(IPAddress.Parse(UdpSSDPMultiCastAddress));
udpClient.Client.Bind(_localEnpoint);
udpMulticastHttpListenerDisposable = udpClient.ToHttpListenerObservable(ct, ErrorCorrection.HeaderCompletionError)
.Subscribe(r =>
{
Console.WriteLine($"Remote Address: {r.RemoteIpEndPoint.Address}");
Console.WriteLine($"Remote Port: {r.RemoteIpEndPoint.Port}");
Console.WriteLine("--------------***-------------");
},
ex =>
{
Console.WriteLine($"Exception: {ex}");
},
() =>
{
Console.WriteLine("Completed.");
});
Notice the ErrorCorrection.HeaderCompletionError
. It's optional. It's there to manage the the situation where an HTTP message header fail to end with \r\n\r\n
.