Operator is a web server. You provide a directory and Operator serves it over HTTP.

Related tags

Web Servers operator
Overview

Operator

Operator is a web server. You provide a directory and Operator serves it over HTTP.

It serves static files the way you'd expect, but it can also serve dynamic content that is generated at request time by handlebars templates or executables.

More information is available on the Operator website.

Installation

Operator is a single self-contained binary. You can download a build from the releases list, unzip it, and run it from any working directory.

Usage

The CLI has three subcommands:

  1. eval evaluates a handlebars template from STDIN.
  2. get renders content from a content directory.
  3. serve starts an HTTP server.

serve is where the real action is, but the other two come in handy at times.

These commands all require a content directory, which is just the folder where your website lives. There are a bunch of sample content directories in samples/.

To learn more, run operator --help or operator --help .

Developer Quick Start

Let's run a server for one of the samples:

git clone [email protected]:mkantor/operator.git
cd operator
cargo run -- -vv serve \
  --content-directory=samples/realistic-advanced \
  --index-route=/home \
  --error-handler-route=/error-handler \
  --bind-to=127.0.0.1:8080

Then open http://localhost:8080 in your browser of choice.

Disclaimer

Operator is very young and has not been battle-hardened. There are known flaws and obvious missing features that need to be addressed. The major ones are filed as issues. All feedback is greatly appreciated.

This is my first nontrivial Rust project and I'm sure there are places where things could be improved. One of the reasons I created Operator was to get more experience with the language, so if you notice anything iffy (no matter how small), please open an issue to help me out! ❤️


Operator

Comments
  • There's no way to use request data

    There's no way to use request data

    Dynamic content (executables and templates) should be able to access request data (headers, the request payload, the query string, etc).

    See #7 for some notes on security concerns.

    opened by mkantor 5
  • Operator needs benchmarks & load tests

    Operator needs benchmarks & load tests

    There's currently no programmatic way to measure how scalable/performant Operator is and therefore it's hard to notice regressions. Benchmarks and load testing would address this.

    Ideally these would run in CI and pull requests that cause more than X% performance regression would get flagged. I'm concerned that the GitHub Actions runners are so heavily virtualized that benchmark numbers will be all over the place, but clap, actix, etc run benchmarks there so presumably it works for them.

    Cargo provides some scaffolding for this, and criterion looks handy.

    opened by mkantor 2
  • `OPTIONS *` requests cause panics

    `OPTIONS *` requests cause panics

    To reproduce:

    cargo run -- serve -vvv --content-directory=samples/realistic-basic --bind-to=127.0.0.1:8080
    
    curl -X OPTIONS --request-target '*' http://localhost:8080
    

    For more info on this somewhat-special type of request, see this MDN page.

    bug 
    opened by mkantor 1
  • Handle query parameters, including them in render data.

    Handle query parameters, including them in render data.

    Query strings on request URIs are parsed and provided to templates and executables as render data at request.query-parameters. This value will typically be a map of key/value pairs.

    This commit also backwards-incompatibly relocates the request route's placement in render data from the top-level request-route property to request.route.

    opened by mkantor 1
  • No release automation

    No release automation

    I published v0.0.1 myself by running cargo publish from my laptop. It'd be better to trigger releases from a controlled environment where it can be guaranteed that CI checks have passed, etc.

    This could be implemented as a GitHub Action that is triggered when a new version tag is pushed (or something along those lines). Here are a few examples of that sort of thing in the wild:

    • https://github.com/rust-lang/chalk/blob/v0.25.0/.github/workflows/publish.yml
    • https://github.com/BurntSushi/ripgrep/blob/12.1.1/.github/workflows/release.yml
    • https://github.com/rust-analyzer/rust-analyzer/blob/2020-08-31/.github/workflows/release.yaml
    • https://github.com/rust-analyzer/rust-analyzer/blob/2020-08-31/.github/workflows/publish.yml
    • https://github.com/rust-github/template/blob/master/.github/workflows/cd.yml
    opened by mkantor 1
  • Security policy is not documented

    Security policy is not documented

    This project could use a security audit and some documentation about "this is what it means for Operator to be secure" and "this is how to keep your site from getting hacked".

    The current stance is something like "Operator is only as secure as the stuff in your content directory, so be careful", but it would be nice to come up with a set of best practices to go along with that. Some ideas:

    • Always create a dedicated user with limited permissions to run the server and/or run it inside a locked-down container/chroot jail.
    • Make sure that nobody except you has write permissions for the content directory and everything inside it (and, again, don't run Operator as yourself in production).
    • Any executables you put in the content directory must be trustworthy, and you should think carefully about what effects they can have. An executable that can run rm -rf / or fork bomb your system is not good!

    Executables are scary

    Of particular concern are executables, since they could be abused to cause lasting damage, data exfiltration, or resource exhaustion.

    Capability-wise, executables are intentionally very limited right now in order to sidestep some of the scarier concerns (e.g. they have no way to observe any request data, which makes request-based code injection impossible). However, these limitations mean that some clearly-desirable functionality is impossible to implement (collecting form data, user agent sniffing, inspecting cookies, using query strings, etc). It would be nice to give executables more capabilities, but this is blocked on a coherent security story.

    Operator could do some sandboxing when running executables to make them safer (e.g. unsetting environment variables might be a good start, but we could go all out with something like Linux namespaces and/or seccomp (although cross-platform-ness is an important consideration too)). Operator could also perform a mini audit of the content directory during startup (e.g. logging a warning if any of its contents are writable). It might also be totally acceptable to do none of this and put the burden on users to make sure their executables are trusted; that just needs to be documented loudly.

    opened by mkantor 1
  • Improve trigger condition for CI workflow.

    Improve trigger condition for CI workflow.

    CI didn't trigger for https://github.com/mkantor/operator/pull/100 because the commit didn't come from a push to this repository. I originally did have pull_request as a triggering event, but removed it way back in daf8783 because it was kicking off duplicate jobs. I should have instead configured it like this so that only direct pushes to the mainline branch trigger CI (and all pull requests do).

    opened by mkantor 0
  • Stop accepting non-`GET` request methods.

    Stop accepting non-`GET` request methods.

    Side note: it was surprising that app.default_service(web::get().to(handler)) means that handler will be called for non-GET requests. I filed https://github.com/actix/actix-web/issues/2598 about this.

    opened by mkantor 0
  • Wait longer for the server to start in integration tests/benchmarks.

    Wait longer for the server to start in integration tests/benchmarks.

    I should really do this properly with a retry/backoff loop or something instead of guessing how long it will take, but that's a project for another day.

    opened by mkantor 0
  • Only Unix-like operating systems are supported

    Only Unix-like operating systems are supported

    The way that the content directory is loaded expects Unixy filesystem semantics (e.g. executeableness indicated by a permission bit, / as the path separator, etc). There may be other platform-specific stuff in the codebase too (so far I've only developed/run Operator on macOS and Ubuntu).

    I don't think it'll be difficult to make things more portable, but CI should be set up to run checks on multiple platforms so that once things are working they stay working.

    opened by mkantor 1
  • Tradeoffs between handlebars partials and `get` helper stink

    Tradeoffs between handlebars partials and `get` helper stink

    Currently the get helper and handlebars partial syntax ({{> blah}}) serve similar purposes (including content from other files), but they don't fully overlap:

    • Both can embed content from other templates.
    • The get helper can also embed content from executables or static files, but partials can't.
    • Handlebars partials can pass parameters and/or a block to included templates, but get can't.
    • get is passed a route, but partial syntax uses filesystem paths ({{get "/foo/bar"}} vs {{> foo/bar.html.hbs}}).
    • Handlebars partials have the concept of an "inline partial", and there's no analogue for get.

    This is confusing and annoying. It would be great to eliminate these tradeoffs so that you don't need to think about when to use each one, either by combining them or making one a superset of the other.

    opened by mkantor 2
  • Websites should reflect all content changes without a server restart

    Websites should reflect all content changes without a server restart

    Currently a running server will pick up some types of content changes but not others. For example, if you make an in-place edit to a static file or executable the update will be immediately visible on your website, but if you add a new file or edit a handlebars template you have to restart the server to see the changes. Ideally Operator would notice all types of changes and automatically refresh its internal state (updating indexes, re-compiling templates, etc) on the fly.

    Restarting the server isn't a big deal for my use cases, so this issue lower priority for me. It'd be convenient while developing sites, though (it's basically hot reloading).

    This needs some design work. Some things to consider:

    • What if the changes made the content directory invalid? Should the server self-destruct or just warn and keep its old state?
    • How to keep the heavy process of crawling the filesystem and creating the registries/index from bogging down the server? Can this be given a lower priority than request handling?
    • How to update the state in a way that doesn't impact in-flight requests?
    • Should probably debounce refreshes to avoid churn when users do things like copy a bunch of files into the content directory at once.

    If the watching part is problematic or flaky for some reason, an explicit poke could be used to trigger refresh instead (or maybe "as well"). Some other programs (ab)use SIGHUP for this.

    opened by mkantor 1
  • Template rendering should be async

    Template rendering should be async

    Right now handlebars templates are rendered on the thread that's handling the request. I think this could result in denial-of-service if all threads in the actix worker pool are busy rendering templates when a new request comes in. I haven't personally observed this, but it can be confirmed with some load testing (maybe using templates that get content from a slow executable or large static file).

    The handlebars library is inherently blocking, but Operator's availability could still be improved by moving rendering to another thread (and preferably deferring it until the Stream is polled).

    Unfortunately there are tradeoffs regarding how render errors are surfaced. Currently clients get a nice HTTP 500 if a template explodes, but with this change they'd become stream errors (which are not as obvious in browsers). Executables already work like that (an executable which exits with failure is still 200 OK), so maybe that's okay.

    opened by mkantor 3
Releases(0.6.1)
🌟 For when you really just want to serve some files over HTTP right now!

miniserve - a CLI tool to serve files and dirs over HTTP For when you really just want to serve some files over HTTP right now! miniserve is a small,

Sven-Hendrik Haase 4.1k Dec 31, 2022
Archibald is my attempt at learning Rust and writing a HTTP 1.1 web server.

Archibald To be a butler, is to be able to maintain an even-temper, at all times. One must have exceptional personal hygiene and look sharp and profes

Daniel Cuthbert 4 Jun 20, 2022
A blazingly fast static web server with routing, templating, and security in a single binary you can set up with zero code. :zap::crab:

binserve ⚡ ?? A blazingly fast static web server with routing, templating, and security in a single binary you can set up with zero code. ?? UPDATE: N

Mufeed VH 722 Dec 27, 2022
The purpose of this example is to provide details as to how one would go about using GraphQL with the Rust Language.

Zero to GraphQL Using Rust The purpose of this example is to provide details as to how one would go about using GraphQL with the Rust Language. Thus,

Conrad Taylor 1 Jan 7, 2022
Add Facebook and Google authentication to your HTTP REST API in Actix-web

I created this project while learning Rust. Project shows how to handle Facebook and Google token verification in Rust using Actix-Web. Hope this help

null 37 Dec 31, 2022
Host These Things Please - a basic http server for hosting a folder fast and simply

http Host These Things Please - a basic HTTP server for hosting a folder fast and simply Selected features See the manpage for full list. Symlinks fol

thecoshman 367 Dec 23, 2022
OxHTTP is a very simple synchronous HTTP client and server

OxHTTP is a very simple synchronous implementation of HTTP 1.1 in Rust. It provides both a client and a server.

Oxigraph 13 Nov 29, 2022
Completely OBSOLETE Rust HTTP library (server and client)

OBSOLETION NOTICE This library is DEAD. It was a useful experiment and is now being replaced under the scope of the Teepee (experimentation grounds at

Chris Morgan 390 Dec 1, 2022
Simple http server in Rust (Windows/Mac/Linux)

How it looks like? Screenshot Command Line Arguments Simple HTTP(s) Server 0.6.1 USAGE: simple-http-server [FLAGS] [OPTIONS] [--] [root] FLAGS:

LinFeng Qian 788 Dec 28, 2022
Fully async-await http server framework

Saphir is a fully async-await http server framework for rust The goal is to give low-level control to your web stack (as hyper does) without the time

Richer Archambault 83 Dec 19, 2022
Low level HTTP server library in Rust

tiny-http Documentation Tiny but strong HTTP server in Rust. Its main objectives are to be 100% compliant with the HTTP standard and to provide an eas

null 785 Dec 29, 2022
Node.js http server framework powered by Hyper native binding.

hnsjs POC project. Install this test package yarn add @hnsjs/core Support matrix node10 node12 node14 node15 Windows x64 ✓ ✓ ✓ ✓ Windows x32 ✓ ✓ ✓ ✓

LongYinan 18 Nov 23, 2022
Akasio is a simple HTTP server that redirects traffic based on a JSON redirect table. This is its Rust implementation.

This page is inaccurate and is pending updates. Akasio (Rust) Description Akasio is a simple HTTP server that redirects traffic based on a JSON redire

K4YT3X 5 May 2, 2022
RUSTENGINE is the high-assurance HTTP server.

RUSTENGINE Table of Contents RUSTENGINE Table of Contents About RUSTENGINE Inspiration with Rust Features Compares with Nginx Build & Run About this R

FUNNY SYSTEMS 10 Aug 27, 2021
A synchronous HTTP server built on hyper.

Astra Astra is a synchronous HTTP server built on top of hyper. use astra::{Body, Response, Server}; fn main() { Server::bind("localhost:3000")

Ibraheem Ahmed 23 Nov 27, 2022
Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.

Actix Web Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust Features Supports HTTP/1.x and HTTP/2 Streaming and pipelining

Actix 16.3k Jan 8, 2023
Simple and fast web server

see Overview Simple and fast web server as a single executable with no extra dependencies required. Features Built with Tokio and Hyper TLS encryption

null 174 Dec 9, 2022
Salvo is a powerful and simplest web server framework in Rust world

Salvo is an extremely simple and powerful Rust web backend framework. Only basic Rust knowledge is required to develop backend services.

Salvo 1.2k Jan 5, 2023
VRS is a simple, minimal, free and open source static web server written in Rust

VRS is a simple, minimal, free and open source static web server written in Rust which uses absolutely no dependencies and revolves around Rust's std::net built-in utility.

null 36 Nov 8, 2022