miha1
Posts: 22
Joined: Mon Feb 22, 2016 12:56 pm

Simple embedded HTTP server library

Mon Feb 22, 2016 1:15 pm

Hello,

I have written simple embedded http library for Windows IoT.
Currently it includes GET requests, subset of POST requests, cookies, sessions,
timers, very basic (but extendable) template and json support and support for reading embedded resources.
It allso supports basic user authentication.

User code is called from listeners, that are provided request and response classes.
Timer events are not provided any parameters as they are not associated to HTTP requests.

Sessions can be automatically generated and set to expire after 2 hours of inactivity, but that can be configured.

Allso provided is (at the moment) very small parts library.

Usage is very simple, to crate basic server that responds to http conenctions, you have to write:

Code: Select all

HttpServer server  = new HttpServer();
server.start();
That will start the server on port 8000 and display simple hello world stye page.
To do anything more, you just add listeners, timers, ...
For example:

Code: Select all

HttpServer server  = new HttpServer();
server.AddPath("/demo.html", DemoListener);
server.start();
Now your DemoListener will get called whenever user requests yourserver:8000/demo.html page.

you can find code on github page: https://github.com/strehar/HttpServer

I hope someone finds this usefull. Let me know how it goes.

Dest regards.
---------
Miha

dobova86
Posts: 59
Joined: Wed Dec 05, 2012 5:32 pm

Re: Simple embedded HTTP server library

Tue Feb 23, 2016 2:37 pm

Oh nice starting! I will give a try as soon as I've a bit of time.
I'm trying to implement a HttpListener class like the one in the .NET microframework 4.x

miha1
Posts: 22
Joined: Mon Feb 22, 2016 12:56 pm

Re: Simple embedded HTTP server library

Wed Feb 24, 2016 9:38 am

Thank you for reply.
This library uses events and listeners, since each request is processed in separate Task. If you enable debug, you'll see Task and Thread ID in the debug messages for requests.

From what I can see HttpListener runs in same thread as your program and blocks it while waiting for data, unless you take care of that in your code. While this is not problem, I find it easier to let library take care of this and not worry about it too much in my application code.

Best regards.

-----
Miha

nitinsontakke
Posts: 4
Joined: Mon Feb 29, 2016 3:19 pm

Re: Simple embedded HTTP server library

Tue Mar 01, 2016 8:30 am

Hello,

Thanks for the post. For my home automation project, I took the Anurag Wasanwala's project from https://microsoft.hackster.io. However, his is a single app with UI which can be seen only on RP monitor, which is not quite convenient. So I wanted a web-site which can run on RP and make calls to a separate dll (headless app) project. Response from dll will be formatted and shown back (just as you stated in your reply).

I have downloaded and run your project (thanks!). I am not been able to find precise location where you delegate the request to another app for process and take response back. Is it there already in any of demo files you provided? If you could just point me in a right direction, please.

Nitin

miha1
Posts: 22
Joined: Mon Feb 22, 2016 12:56 pm

Re: Simple embedded HTTP server library

Tue Mar 01, 2016 11:57 am

Hello,

I have redesigned demo project on github(https://github.com/strehar/HttpServer) and split it into several classes, I hope it will be easier to understand how it works.

If you allready have background app, you need to create instance of the HttpServer class in your app, then register method with it.

If you do not have background app yet, then you can do following:
- install windows iot project templates from https://visualstudiogallery.msdn.micros ... 8ac4b01dec if you have not allready. This will add needed templates to your visual studio.
- if you're starting from scratch, create new Background Application project from Templates/Visual C#/Windows/Windows IoT Core/
- double click on Package.appxmanifest in new project, go to Capabilities tab and select Internet (client&server). This will
alow your app to recive connections from network.
- If you added project to existing solution, right click on solution and select "Single Startup Project" and select your new project from the dropdown.
- Next we need to tell the .net runtime that wour projct will run in the background, even after our initalization is complete. to do this you need to modify the "StartupTask.cs" file that was generated automatically in new project.

Here is example:
StartupTask.cs

Code: Select all

using Windows.ApplicationModel.Background;
using Windows.Foundation;
using Windows.System.Threading;

// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409

namespace WebServerDemo
{
    public sealed class StartupTask : IBackgroundTask
    {
        BackgroundTaskDeferral _serviceDeferral;
        StartDemo server; // This will be your app where you set up things.
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            taskInstance.Canceled += OnCanceled;
            _serviceDeferral = taskInstance.GetDeferral();  // We tell runtime not to quit when the Run method finsihes. It will wait for all asynchronus tasks to finish.
            server = new StartDemo();
            IAsyncAction asyncAction = ThreadPool.RunAsync((workItem) =>
            {
                server.Start();
            });
        }

        private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
        {
            _serviceDeferral.Complete();
        }
    }
}
StartDemo.cs

Code: Select all

namespace WebServerDemo
{
    class StartDemo
    {
        HttpServer server = new HttpServer();
        SimpleTemplate _lights = new SimpleTemplate();

        public void Start()
        {
             server.EmbeddedContent.RegisterAssembly(this.GetType());
             server.EmbeddedContent.RefreshFileList();
             server.AddPath("/homeLightStatus.html", DisplayLightStatus);
             server.AddTimer("readLights", 10000, ReadLightsTimer);
             server.start();

            _lights.LoadString(server.EmbeddedContent.ReadEmbededToByte("/templateHomeLightsStatus.html"));
            _lights.AddAction("livingRoom","LIVINGROOM", "");
       }

      public void ReadLightsTimer()
      {
      /* Read lights here and adjust template actions */
      If (livingRoomLights == "On")
             _lights.UpdateAction("livingRoom", "On");
      else
             _lights.UpdateAction("livingRoom","Off");
      }

      public void DisplayLightStatus(HttpRequest request, HttpResponse response)
     {
           // In this example, we really don't care about anything else, we just display status of lights in living room on the http page
           _lights.ProcessAction(); // This will update template with status of lights or return cached html if nothing changed.
           response.Write(_lights.GetByte(), "text/html");   // Convert html to bytes and send it to user, we allso set the output to "text/html" so it will display correctly in the browser.
     }
}

and template file templateHomeLightsStatus.html:

Code: Select all

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>Lights in the house</title>
</head>
<body>
    <h1>Currently lights in the house are:</h1>
    <hr />
    <p>
        <ul>
            <li>Living room is @#LIVINGROOM</li>
       </ul>
    </p>
</body>
</html>
As you can see, template is just html with tags marked with @# that will get replaced by values in actions associated with those tags. It can be really anything, even html. If you want to pass html with actions, you should disable safe mode in template engine, however. Do not forget to set the BuildAction to "Embedded Resource" in properties window for the files you wish to send over HTTP to client. If you do not, you will get FileNotFound exception.


I think new examples demonstrate this much better, so look at them and let me know if it is unclear.

Allso, take a look at user authentication and IP filters, i added in latest releases, you do not want everyone to see or controll your house. :)

With kind regards,

------
Miha


edit:
I forgot to mention, all you need to include HttpServer in your project are two DLLs in release folder. Then you add them as reference in your project.

edit2:
Fixed bug in sample code.
Last edited by miha1 on Thu Mar 03, 2016 5:07 pm, edited 1 time in total.

nitinsontakke
Posts: 4
Joined: Mon Feb 29, 2016 3:19 pm

Re: Simple embedded HTTP server library

Wed Mar 02, 2016 5:54 am

Thanks a bunch, for the detailed reply.

Will take a while to digest and experiment with. But whenever I have something to share (positive / negative) will ping you back.

I have done loads of business application development over years from DOS to ASP.NET but this UWP app part is bit new to me hence need some hand holding! The C# in it looks like Hebrew to me.

Thanks anyway.

Aymeeeric
Posts: 13
Joined: Mon Feb 29, 2016 8:30 am

Re: Simple embedded HTTP server library

Thu Mar 03, 2016 9:20 am

Hi ! Thanks a lots for your great work.
Is there a method to launch your server in a Headed application ?
Like... launching it on a BackgroundWorker maybe ?

miha1
Posts: 22
Joined: Mon Feb 22, 2016 12:56 pm

Re: Simple embedded HTTP server library

Thu Mar 03, 2016 1:01 pm

Hello,

Yes, you can. All HTTP requests or Timer events will be served in seperate Tasks or Threads and will not interfere with GUI in any way.

Headed apps can get a bit too long to post full code here, but here are stepps to use this class in it:
  • Add reference to HttpServer.dll to references for your project.
  • Add Internet (client&server) Capabilities (same as in Headless app)
  • Open application entry point (App.xaml.cs in default studio project) and add

    Code: Select all

     sealed partial class App : Application
        {
            //Please take a look at StartDemo class from my previous post
            StartDemo demo = new StartDemo();
    
  • call Start() method (in app constructor, for example)

    Code: Select all

            public App()
            {
                demo.Start();
    
From that point forward, it is same as Headless app.

With kind regards,

------
Miha

Aymeeeric
Posts: 13
Joined: Mon Feb 29, 2016 8:30 am

Re: Simple embedded HTTP server library

Thu Mar 03, 2016 1:12 pm

Thanks a lot !

I will try this immediatly...

Aymeeeric
Posts: 13
Joined: Mon Feb 29, 2016 8:30 am

Re: Simple embedded HTTP server library

Thu Mar 03, 2016 1:49 pm

Hmmm... It doesn't seems to work.
I really don't understand what is the problem :

App.xaml.cs :

Code: Select all

    sealed partial class App : Application
    {

        StartDemo httpServer = new StartDemo();

        public App()
        {
            Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync(
                Microsoft.ApplicationInsights.WindowsCollectors.Metadata |
                Microsoft.ApplicationInsights.WindowsCollectors.Session);
            this.InitializeComponent();
            this.Suspending += OnSuspending;

            httpServer.Start();
        }
StarDemo.cs

Code: Select all

using Feri.MS.Http;

namespace DICMA_STATION.Assets.Scripts.Dicma.HTTPServer
{
    class StartDemo
    {
        HttpServer _ws = new HttpServer();

        public void Start()
        {
            _ws.SetRootPath("PublicHtml", "/index.html");
            _ws.Start();
        }
    }
}
Project architecture (http://tof.canardpc.com/show/e0f41cf0-3 ... c4a19.html) :

Image



Everything seems to run properly but when i'm trying to reach : localhost:8000 / localhost / localhost:index.html there is nothing...
Any idea of what i'm doing wrong ?

miha1
Posts: 22
Joined: Mon Feb 22, 2016 12:56 pm

Re: Simple embedded HTTP server library

Thu Mar 03, 2016 5:05 pm

Hello,

It seems I forgot to put code into example that allows the library to read embedded content from your app. I'll fix my headless app examle in this thread.
You need to add to your code

Code: Select all

            _ws.EmbeddedContent.RegisterAssembly(this.GetType());
            _ws.EmbeddedContent.RefreshFileList();
before _ws.start(), so your StartDemo.cs looks like this:

Code: Select all

using Feri.MS.Http;

namespace DICMA_STATION.Assets.Scripts.Dicma.HTTPServer
{
    class StartDemo
    {
        HttpServer _ws = new HttpServer();

        public void Start()
        {
            _ws.EmbeddedContent.RegisterAssembly(this.GetType());
            _ws.EmbeddedContent.RefreshFileList();
            _ws.SetRootPath("PublicHtml", "/index.html");
            _ws.Start();
        }
    }
}
This will index embedded content in your app and make it available for sending over HTTP.
Allso, the address seems to be incorrect. (localhost:8000 / localhost / localhost:index.html is not correct). in your case, with code you provided, the address would be http://server:8000/index.html or just http://server:8000/. index.html will be autmatically served to any request for root folder of your server.

Did you set Build Action to Embedded Resource in the properties window of the index.html file?

There is another thing. Are you trying to run this on the windows 10 computer and not Windows IoT?
If you are, there is issue with network isolation in universal apps, and there is nothing i can do about it, it's feature of the framework.
If you run it on computer, you will need to test it from another compuer and add "Private networks (client & server) capability to the app. you can read more about it on Microsoft page:
https://msdn.microsoft.com/en-us/librar ... s/hh780593

or githhub page:
https://github.com/Microsoft/Windows-un ... reamSocket

This is quote from MSDN page:
Note Loopback is permitted only for development purposes. Usage by a Windows Runtime app installed outside of Visual Studio is not permitted. Further, a Windows Runtime app can use an IP loopback only as the target address for a client network request. So a Windows Runtime app that uses a DatagramSocket or StreamSocketListener to listen on an IP loopback address is prevented from receiving any incoming packets.
I am using StreamSocketListener in the library.

If you are developing for Windows IoT, i'd recommend that you run/debug on hardware itself and not on local computer. You can allso connect from different computer or setup proxy on the network and connect to the local computer that way.

With kind regards,

------
Miha

Aymeeeric
Posts: 13
Joined: Mon Feb 29, 2016 8:30 am

Re: Simple embedded HTTP server library

Thu Mar 03, 2016 6:03 pm

Many thanks for your reply, i'll try this tomorrow ! And I'll tell you here if it works.
Indeed, I actually debug on the computer, i'm gonna make my test on the RPi from now...

Aymeeeric
Posts: 13
Joined: Mon Feb 29, 2016 8:30 am

Re: Simple embedded HTTP server library

Fri Mar 04, 2016 9:15 am

It works like a charm !
One more time : thanks a lot for your work, and your clear answers.

Qandil
Posts: 2
Joined: Sun Mar 06, 2016 4:41 am

Re: Simple embedded HTTP server library

Sun Mar 06, 2016 4:43 am

Great Job!

I really love the implementation, wondering if there is a possibility to switch it on the default port 80.

That would really be helpful.

Thank again for sharing.

nitinsontakke
Posts: 4
Joined: Mon Feb 29, 2016 3:19 pm

Re: Simple embedded HTTP server library

Sun Mar 06, 2016 7:02 am

Hello,

Thanks for your replay and I do appreciate the fact that you have been so helpful. However, I am still confused about some things:

1/ You described a process to create a Background Task (which I created). You also mention that I take the reference of HttpServer and all it's dependencies in BT project (which I did). Somehow I was under the impression that process flow is as follows:

HttpServer (running on it's own, headed app) -> request received from browser -> request data passed to back-ground task (headless app) -> back-ground task sent response in the format of JSON -> Appropriate html response constructed from JSON -> response returned to the browser. -- This the way our classical web-server client model works.

However, looking at what you have mentioned what is actually running is a back-ground task, which instantiates the httpServer, which takes care of receiving request / sending response (making use of templates to avoid large formatting done in C# code) on a specified port number. Is my understanding clear here?

2/ Does this also mean that for every distinct task that I want to perform, I will need distinct listener function and an associated response template? It is the responsibility of the listener function to make sure that an appropriate data is sent back to fill all the place holders in template file. Right?

Thanks a lot.

miha1
Posts: 22
Joined: Mon Feb 22, 2016 12:56 pm

Re: Simple embedded HTTP server library

Sun Mar 06, 2016 1:55 pm

nitinsontakke wrote:Hello,

Thanks for your replay and I do appreciate the fact that you have been so helpful. However, I am still confused about some things:

1/ You described a process to create a Background Task (which I created). You also mention that I take the reference of HttpServer and all it's dependencies in BT project (which I did). Somehow I was under the impression that process flow is as follows:

HttpServer (running on it's own, headed app) -> request received from browser -> request data passed to back-ground task (headless app) -> back-ground task sent response in the format of JSON -> Appropriate html response constructed from JSON -> response returned to the browser. -- This the way our classical web-server client model works.

However, looking at what you have mentioned what is actually running is a back-ground task, which instantiates the httpServer, which takes care of receiving request / sending response (making use of templates to avoid large formatting done in C# code) on a specified port number. Is my understanding clear here?

2/ Does this also mean that for every distinct task that I want to perform, I will need distinct listener function and an associated response template? It is the responsibility of the listener function to make sure that an appropriate data is sent back to fill all the place holders in template file. Right?

Thanks a lot.
Hello,

The model you describe is for standalone web server (like IIS).
However, this is library that you include in your app, so you get HTTP capability. Think of it as HTTP based user interface for your app. It is not ment to be standalone webserver, even though it does provide a lot of server functionality (it would be possible to use this library to write standalone webserver, most of the functionallity is there). It is not limited to headless apps, you can use it in any kind of app. You can see example of how to use it in Headed app in this thread.

1) You are right, the HttpServer class will start background thread when you call Start() method, that will handle reciving and sending HTTP traffic on specified port. Each request will start in new Task, so they do not interfere with each other or your main thread. It allso means it can handle many requests at same time.

2) You do not need listen for static content (images, css, static HTML, ...), it is automatically processed by default listener. All you need to do is tell it where to look for data. But for dynamic content and for each task you wish to perform, you will need listeners and associated templates. Allso, the listener is responsible for sending the appropriate data back. Templates help with this task.

With kind regards,

------
Miha

nitinsontakke
Posts: 4
Joined: Mon Feb 29, 2016 3:19 pm

Re: Simple embedded HTTP server library

Sun Mar 06, 2016 4:53 pm

Thanks for the quick reply. Appreciated.

miha1
Posts: 22
Joined: Mon Feb 22, 2016 12:56 pm

Re: Simple embedded HTTP server library

Thu Mar 10, 2016 10:51 am

There was update to the library today, new templating engine was added, based on the Universal apps port of the DotLiquid http://dotliquidmarkup.org/ templating engine.

Default http listener was removed and replaced by HttpRootManager, that provides functionnality to:
  • Customize error and server messages, so their design matches your app design
  • Register extension templates and manage cache for those files, so you get dynamic web pages support via templating (in demo project you get *.chtml for Liquid and *.shtml for SimpleTemplate)
  • Register and manage multiple source providers. For now, there is only EmbeddedContent for reading content from assemblies, but you can add any other source (filesystem, network, ...).
  • Abstraction layer for reading content from source providers
  • Return content of virtual folder if there is no default file (in the demo it is WindowsIoT_address:8000/Images/)
  • Register multiple default files (index.html, index.htm, index.chtml, ...)
Most of the system can now be upgraded via plugins (that implement correct interface):
  • IP filter
  • User management
  • Content sources
  • Templates
  • HttpRootManager
Unfortunatly this required some API changes, but I tried to minimize those.
  • Cookies in HttpRequest are now accessed from indexer
  • Content management was moved from HttpServer to HttpRootManager
  • Assemblies are registred from HttpRootManager or from static method in EmbededContent class
Demo project have been updated to show new functionality.


With kind regards,

------
Miha

Aymeeeric
Posts: 13
Joined: Mon Feb 29, 2016 8:30 am

Re: Simple embedded HTTP server library

Thu Mar 10, 2016 12:22 pm

Great work ! Thanks.

Qandil
Posts: 2
Joined: Sun Mar 06, 2016 4:41 am

Re: Simple embedded HTTP server library

Fri Mar 11, 2016 2:15 pm

Wonderful!

Thanks for the update, would it be possible to add an overload to start the server on a different port ?

Thank again for the great job

miha1
Posts: 22
Joined: Mon Feb 22, 2016 12:56 pm

Re: Simple embedded HTTP server library

Fri Mar 11, 2016 6:09 pm

Hello,

It is implemented via optional arguments. Definition of the Start method is

Code: Select all

public void Start(string serviceName = "8000")
If called without argument it will use default port 8000, but you can override that by supplying argument with port number. Just make shure it is not allready in use.

So to use a different port, you can call start with string argument indicating port you wish to use.
For example, to use port 80, you could call the start method

Code: Select all

HttpServer server = new HttpServer();
server.Start("80");
With kind regards,

------
Miha

Pointy
Posts: 10
Joined: Mon May 30, 2016 7:07 pm

Re: Simple embedded HTTP server library

Mon Jun 06, 2016 9:31 pm

First off, let me say thanks for sharing this great project. It has made it very easy for me to monitor and control my Pi from the network.

I have had a couple of instances where it has crashed though. The first time, I think was when my internet connection dropped, and I stupidly didn't make a note of the error. The last time I got a null reference exception in HttpResponse.cs in the Write method. The _stream was null at the line ' _stream.Write(headerArray, 0, headerArray.Length);' I am not sure what caused this crash, as it had been running without problems for several hours.

Any thoughts?

Regards,

Les

miha1
Posts: 22
Joined: Mon Feb 22, 2016 12:56 pm

Re: Simple embedded HTTP server library

Tue Jun 07, 2016 9:49 am

Pointy wrote:First off, let me say thanks for sharing this great project. It has made it very easy for me to monitor and control my Pi from the network.

I have had a couple of instances where it has crashed though. The first time, I think was when my internet connection dropped, and I stupidly didn't make a note of the error. The last time I got a null reference exception in HttpResponse.cs in the Write method. The _stream was null at the line ' _stream.Write(headerArray, 0, headerArray.Length);' I am not sure what caused this crash, as it had been running without problems for several hours.

Any thoughts?

Regards,

Les
Hello,

I checked what could happen and there are two possibilities for this bug.
Either client closed the connection before the server could send a reply or there was problem with processing the request that caused the exception in the HttpRequest.Init() method. Same issue could also cause server to drop connection on malformed request (this should not happen with regular clients, but if the request was malformed, connection would be closed without sending error page).

I fixed the issue and uploaded new version 0.2.0.2 that fixes it. If you have debugging enabled in the HttpServer class you will get debug message whenever this situation happens. It should no longer cause an exception in the Write method.

With kind regards,

------
Miha

Pointy
Posts: 10
Joined: Mon May 30, 2016 7:07 pm

Re: Simple embedded HTTP server library

Tue Jun 07, 2016 6:48 pm

miha1 wrote: Hello,

I checked what could happen and there are two possibilities for this bug.
Either client closed the connection before the server could send a reply or there was problem with processing the request that caused the exception in the HttpRequest.Init() method. Same issue could also cause server to drop connection on malformed request (this should not happen with regular clients, but if the request was malformed, connection would be closed without sending error page).

I fixed the issue and uploaded new version 0.2.0.2 that fixes it. If you have debugging enabled in the HttpServer class you will get debug message whenever this situation happens. It should no longer cause an exception in the Write method.

With kind regards,

------
Miha
Fantastic, I will give it a try and let you know how it goes.

Regards,

Les

Pointy
Posts: 10
Joined: Mon May 30, 2016 7:07 pm

Re: Simple embedded HTTP server library

Sat Jun 11, 2016 6:46 pm

Pointy wrote:
miha1 wrote: Hello,

I checked what could happen and there are two possibilities for this bug.
Either client closed the connection before the server could send a reply or there was problem with processing the request that caused the exception in the HttpRequest.Init() method. Same issue could also cause server to drop connection on malformed request (this should not happen with regular clients, but if the request was malformed, connection would be closed without sending error page).

I fixed the issue and uploaded new version 0.2.0.2 that fixes it. If you have debugging enabled in the HttpServer class you will get debug message whenever this situation happens. It should no longer cause an exception in the Write method.

With kind regards,

------
Miha
Fantastic, I will give it a try and let you know how it goes.

Regards,

Les
It's beent running for 4 days without any problems, so I guess that issue is fixed. Thanks for the quick response.

A very minor thing...

I was getting bombarded with debug messages about requests, even though I had debug set to false.(It was making it hard to spot my own debug messages, with a json request once a second.)

In httpserver.cs I see the following...

Code: Select all

        public HttpServer()
        {
            _log.Open();
            _log._debug = true;
            _mimeType._debug = _debug;
            _sessionManager._debug = _debug;
            //_log._debug = _debug;
            AddTimer("SessionCleanupTimer", 60000, _sessionManager.SessionCleanupTimer);
        }
I commented out the '_log._debug = true;' and uncommented the '_log._debug = _debug;' to fix the issue, as I assumed this was the intended code and the other line was just something added to temporarily turn on debugging.

Regards,

Les

Return to “Windows 10 for IoT”