Search code examples
c#webservernattcplistener

400 Bad Request (Invalid Host) using simple webserver in C#


I've got a small C# console app to work as a webserver. It responds well on the NAT with devices in the same network, but when I try to access it in a browser from the external IP i get a 400.

The router is configured to port forward, otherwise I get a 404.

localhost:8888/test works fine. also 192.168.0.x:8888/test for any device.

xxx.xxx.xxx.xxx:8888/test fails with HTTP Error 400. The request hostname is invalid.

Any suggestions?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace httpsrv
    {
    class Program
        {
        static void Main(string[] args)
            {
            WebServer ws = new WebServer(SendResponse, "http://localhost:8888/test/");
            ws.Run();
            Console.WriteLine("Pi server started");
            Console.ReadKey();
            ws.Stop();
            }

        public static string SendResponse(HttpListenerRequest request)
            {
            return string.Format("<HTML><BODY>Hosted from rasp. pi!<br>{0}</BODY></HTML>", DateTime.Now);
            }
        }
    }

Webserver class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace httpsrv
    {
    public class WebServer
        {
        private readonly HttpListener _listener = new HttpListener();
        private readonly Func<HttpListenerRequest, string> _responderMethod;

        public WebServer(string[] prefixes, Func<HttpListenerRequest, string> method)
            {
            if (!HttpListener.IsSupported)
                throw new NotSupportedException(
                    "Needs Windows XP SP2, Server 2003 or later.");

            if (prefixes == null || prefixes.Length == 0)
                throw new ArgumentException("prefixes");

            if (method == null)
                throw new ArgumentException("method");

            foreach (string s in prefixes)
                _listener.Prefixes.Add(s);

            _responderMethod = method;
            _listener.Start();
            }

        public WebServer(Func<HttpListenerRequest, string> method, params string[] prefixes)
            : this(prefixes, method) { }

        public void Run()
            {
            ThreadPool.QueueUserWorkItem((o) =>
            {
                Console.WriteLine("Webserver running...");
                try
                    {
                    while (_listener.IsListening)
                        {
                        ThreadPool.QueueUserWorkItem((c) =>
                        {
                            var ctx = c as HttpListenerContext;
                            try
                                {
                                string rstr = _responderMethod(ctx.Request);
                                byte[] buf = Encoding.UTF8.GetBytes(rstr);
                                ctx.Response.ContentLength64 = buf.Length;
                                ctx.Response.OutputStream.Write(buf, 0, buf.Length);
                                }
                            catch { } 
                            finally
                                {
                                ctx.Response.OutputStream.Close();
                                }
                        }, _listener.GetContext());
                       }
                    }
                catch { }
            });
            }

        public void Stop()
            {
            _listener.Stop();
            _listener.Close();
            }
        }
    }

Solution

    1. Either your DNS or name resolution is bad.
    2. There are no routes to forward that traffic to your web server
    3. Check your port forwarding you should be forwarding port 8888 to the internal IP
    4. Last but not least check your firewall, it should allow port 8888
    5. Looking at your code, it seems you are hard coding the request, make that a variable so that you can change it on the fly