pistacheio / pistache

A high-performance REST toolkit written in C++
https://pistacheio.github.io/pistache/
Apache License 2.0
3.17k stars 698 forks source link

Add example for serving a full stack web application, combining static content with rest api #446

Open svdHero opened 5 years ago

svdHero commented 5 years ago

In our team we would like to use Pistache.io as a lightweight web server on some embedded device with very tough hardware requirements, serving a full stack web application as IoT UI for the embedded device. That means serving both a REST API and the corresponding SPA web client as static content via Pistache.

The static content should be available, e.g., under the URL /content/ and the REST API under /api/v1/. How would I do this in Pistache with wildcards such that requests for /content/* are mapped to some local folder while all requests for /api/v1/ go to endpoint handler methods?

Can I somehow use the functions in the namespace Routes for this? I haven't really worked with Pistache before and http://pistache.io seems to be down, including all the documentation.

Any code example for the above full stack use case would be highly appreciated. Maybe even add it to the repo's examples folder?

hydratim commented 5 years ago

As far as I'm aware there is no directory serving support in Pistache - It's not really in scope for the project.

So you'd need to draft that yourself, which should be too hard as all the HTTP support is present (MIME, Streams, etc.). Your main concerns would be how to respect filesystem boundaries, I.E.: If you wanted to serve the subtree of /var/www/static via htttp://my.url/static how would you stop me from making a request such as htttp://my.url/static/../../../etc/passwd to retrieve /etc/shadow or if you accept uploads how would you stop me from uploading my own /root/.ssh/authorized_keys.

Having said that; There are numerous other similar risks to running a directory service that projects such as nginx and apache have taken over a decade to identify and solve.

As I've mentioned in your previous issues on the subject of using pistache as a primary webserver for an IOT product - This project is not ready for that, and there are far too many risks that you'd be exposing yourselves too. We haven't even released a V0.1 and yet you're trying to treat it as a production ready V1.0. Please re-evaluate - we don't want to get blamed for your product having a severe security breach. Are you certain you can't put a lightweight service such as nginx or lighttpd in front?

dennisjenkins75 commented 5 years ago

I put all of my static content into a TAR file, embedded that into my binary via a linker trick, and use libtar to index the contents at process startup. I then have one route which serves static content using a wildcard, and it handles getting the bytes from the process image. I do not have directories in my static content, so I do not need to worry about path traversal. This works well for my use case. I only have 5 static files (main page html, css, js and two supplemental CSS files).

hydratim commented 5 years ago

Hi Dennis,

That's a unique solution, I'm not sure I would have gone about it that way, but it's definitely a solid way of serving a small amount of content securely.

While I think your solution could be useful to @svdHero I doubt he has the RAM necessary to support that.

svdHero commented 5 years ago

Thank you guys for all your explanations. Let me quickly add:

We haven't even released a V0.1 and yet you're trying to treat it as a production ready V1.0.

That is - if I may say so - a false assertion you're making here. In fact, the contrary is the case. I am a responsible and careful developer and that is exactly why I am NOT treating it as production ready but asking all these questions ahead of time BEFORE I use Pistache in production. Ever since @dennisjenkins75 pointed out the memory leaks to me in #226, I have been following progress in #399. I will only start considering Pistache for IoT, once #399 is closed and Pistache has matured a bit. However, I want to play with it now in order to get a better understanding if it could be a viable option in the future.

we don't want to get blamed for your product having a severe security breach.

I would never do such a thing. I take full responsibility for the tech stack choices I make in my own products. I do understand the intention of your statement, though. :wink:

Are you certain you can't put a lightweight service such as nginx or lighttpd in front?

I will give it a try. However, our embedded system only has 64 MB of RAM and for historical reasons there is already a local C# GUI running under Mono which is quite memory-hungry. At the end of the day, I have something between 10 MB and 30 MB of RAM available for the whole web stack, depending on how much I strip down the local C# GUI.

As I (similar to @dennisjenkins75 ) probably will have only a small number of static files for my SPA, I might also spell out all routes to the individual static files like so https://github.com/oktal/pistache/blob/1df04a35cd54f476dc788c0175f37395df701f7d/examples/http_server.cc#L140-L146 combining this with an additional wildcard route /content/* for serving the index.html, while for example defining /content/main.js and /content/main.cssas explicit routes. That would be a viable solution, too, wouldn't it? Or am I missing something?

Thanks a lot again for all your work and effort to keep this project alive and bring it to production ready (some day). :+1: I really appreciate it.