Skip to content

Instantly share code, notes, and snippets.

@define-private-public
Last active April 9, 2024 08:38
Show Gist options
  • Save define-private-public/d05bc52dd0bed1c4699d49e2737e80e7 to your computer and use it in GitHub Desktop.
Save define-private-public/d05bc52dd0bed1c4699d49e2737e80e7 to your computer and use it in GitHub Desktop.
A Simple HTTP server in C#
// Filename: HttpServer.cs
// Author: Benjamin N. Summerton <define-private-public>
// License: Unlicense (http://unlicense.org/)
using System;
using System.IO;
using System.Text;
using System.Net;
using System.Threading.Tasks;
namespace HttpListenerExample
{
class HttpServer
{
public static HttpListener listener;
public static string url = "http://localhost:8000/";
public static int pageViews = 0;
public static int requestCount = 0;
public static string pageData =
"<!DOCTYPE>" +
"<html>" +
" <head>" +
" <title>HttpListener Example</title>" +
" </head>" +
" <body>" +
" <p>Page Views: {0}</p>" +
" <form method=\"post\" action=\"shutdown\">" +
" <input type=\"submit\" value=\"Shutdown\" {1}>" +
" </form>" +
" </body>" +
"</html>";
public static async Task HandleIncomingConnections()
{
bool runServer = true;
// While a user hasn't visited the `shutdown` url, keep on handling requests
while (runServer)
{
// Will wait here until we hear from a connection
HttpListenerContext ctx = await listener.GetContextAsync();
// Peel out the requests and response objects
HttpListenerRequest req = ctx.Request;
HttpListenerResponse resp = ctx.Response;
// Print out some info about the request
Console.WriteLine("Request #: {0}", ++requestCount);
Console.WriteLine(req.Url.ToString());
Console.WriteLine(req.HttpMethod);
Console.WriteLine(req.UserHostName);
Console.WriteLine(req.UserAgent);
Console.WriteLine();
// If `shutdown` url requested w/ POST, then shutdown the server after serving the page
if ((req.HttpMethod == "POST") && (req.Url.AbsolutePath == "/shutdown"))
{
Console.WriteLine("Shutdown requested");
runServer = false;
}
// Make sure we don't increment the page views counter if `favicon.ico` is requested
if (req.Url.AbsolutePath != "/favicon.ico")
pageViews += 1;
// Write the response info
string disableSubmit = !runServer ? "disabled" : "";
byte[] data = Encoding.UTF8.GetBytes(String.Format(pageData, pageViews, disableSubmit));
resp.ContentType = "text/html";
resp.ContentEncoding = Encoding.UTF8;
resp.ContentLength64 = data.LongLength;
// Write out to the response stream (asynchronously), then close it
await resp.OutputStream.WriteAsync(data, 0, data.Length);
resp.Close();
}
}
public static void Main(string[] args)
{
// Create a Http server and start listening for incoming connections
listener = new HttpListener();
listener.Prefixes.Add(url);
listener.Start();
Console.WriteLine("Listening for connections on {0}", url);
// Handle requests
Task listenTask = HandleIncomingConnections();
listenTask.GetAwaiter().GetResult();
// Close the listener
listener.Close();
}
}
}
@JewerlyBony
Copy link

Thanks! I have one issue with redirecting https calls into http. for example if the client requested https://myserver/login will automatically redirected to http://myserver/login

@define-private-public
Copy link
Author

Thanks! I have one issue with redirecting https calls into http. for example if the client requested https://myserver/login will automatically redirected to http://myserver/login

https requires SSL certs and whatnot, and that's always a pain to setup and use. This is meant for something to run locally on a computer, not an externally facing thing, so I don't think that https is something to worry about for this use case.

@Elias-Traunbauer
Copy link

SSL Encryption

How can I get this Server to work with https://myIp:myPort/ ?

@tebeco
Copy link

tebeco commented Jan 22, 2021

How can I get this Server to work with https://myIp:myPort/ ?

you could just use Kestrel with AspNetCore you'll have a proper webserver (TLS is part of it)

md foo
cd foo
git init
dotnet new gitignore
dotnet new sln
dotnet new web -n TheNameHere
dotnet sln add ./TheNameHere
git add .
git commit -m "I now have a proper http server with TLS enabled and https redirection setup"

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/?view=aspnetcore-5.0&tabs=linux

@ambozz
Copy link

ambozz commented Feb 19, 2021

Good solution, but it doesn't work with other Networks on the same Network for example a Phone.
I tried changing "url" to the local IP Address of the Machine Running the code, but this doesn't work for neither my Phone or my PC.
Does anyone have a Solution to this?

@dinkelspiel
Copy link

How would you link a css stylesheet with ?

@leolamarra
Copy link

I am experimenting with this, but can I somehow display the real time visits count? Now I have to manually refresh the page and this can be really frustrating sometimes

@define-private-public
Copy link
Author

@CoderLel

For that, you'd need to add in some AJAX stuff ( https://en.wikipedia.org/wiki/Ajax_(programming) ) stuff.

@jmikepaz
Copy link

How enabled cors ? Access-Control-Allow-Origin", "*"

@gtato
Copy link

gtato commented Nov 26, 2021

used this for a demo.. thanks man :)

@Develeone
Copy link

Develeone commented Apr 10, 2022

Catch a crutch.

Little piece'o'code to keep things going in local network from other devices.
You need to open a certain port in Windows Firewall.
We don't gonna do it several times, cause it makes duplicate entries, so that's the reason why we will use registry to set the flag on first run.
And yep, you need to create a reference to "c:\windows\system32\FirewallAPI.dll".

` RegistryKey currentUserKey = Registry.CurrentUser;
RegistryKey softwareKey = currentUserKey.OpenSubKey("SOFTWARE", writable: true);
RegistryKey orgKey = softwareKey.OpenSubKey("%YOUR ORG NAME%", writable: true);

        if (orgKey == null)
            orgKey = softwareKey.CreateSubKey("%YOUR ORG NAME%", writable: true);

        RegistryKey appKey = orgKey.OpenSubKey("%YOUR APPNAME%", writable: true);

        if (appKey == null)
            appKey = orgKey.CreateSubKey("%YOUR APPNAME%", writable: true);

        bool? permissionsGranted = null;

        try
        {
            object keyValue = appKey.GetValue("Permissions Granted");

            permissionsGranted = keyValue != null ? Convert.ToBoolean(keyValue) : false;
        }
        catch (Exception e) {
            permissionsGranted = false;
        }

        if (permissionsGranted == false) {
            appKey.SetValue("Permissions Granted", true);

            Type tNetFwPolicy2 = Type.GetTypeFromProgID("HNetCfg.FwPolicy2");
            INetFwPolicy2 fwPolicy2 = (INetFwPolicy2)Activator.CreateInstance(tNetFwPolicy2);
            var currentProfiles = fwPolicy2.CurrentProfileTypes;

            INetFwRule2 inboundRule = (INetFwRule2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FWRule"));
            inboundRule.Enabled = true;
            inboundRule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
            inboundRule.Protocol = 6; // TCP
            inboundRule.LocalPorts = "80";
            inboundRule.Name = "HTTP Server 80 port";
            inboundRule.Profiles = currentProfiles;

            INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
            firewallPolicy.Rules.Add(inboundRule);
        }

        currentUserKey.Close();
        softwareKey.Close();
        orgKey.Close();
        appKey.Close();`

@skrepecki
Copy link

hello world

thanks a lot !! ;)

@rzymski
Copy link

rzymski commented Aug 3, 2022

That's what I was looking for. Thank you very much. Good job.

@AlexanderHS
Copy link

Been fooling around with this and noticed some unanswered questions above. Can only tell you what worked for me.

"I want to send a json string to the http server. How can I get the message from the request?"

I went with something like:

string payload = GetRequestPostData(ctx.Request);
Where you define that function like:

string GetRequestPostData(HttpListenerRequest request)
{
    if (!request.HasEntityBody)
    {
        return null;
    }
    using (System.IO.Stream body = request.InputStream)
    {
        using (var reader = new System.IO.StreamReader(body, request.ContentEncoding))
        {
            return reader.ReadToEnd();
        }
    }
}

doesn't work with other Networks on the same Network for example a Phone.
I tried changing "url" to the local IP Address of the Machine Running the code, but this doesn't work for neither my Phone or my PC.
Does anyone have a Solution to this?

change localhost to something like + or *
e.g.
string url = $"http://+:8000/";
Your OS might complain about permissions though.

If so you can try something like: "netsh http add urlacl url=http://+:8000/ user=your_username_here"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment