serverino 0.7.1

Small and ready-to-go http server


To use this package, run the following command in your project's root directory:

Manual usage
Put the following dependency into your project's dependences section:

serverino <img align="left" alt="Logo" width="100" src="https://github.com/trikko/serverino/assets/647157/a6f462fa-8b76-43c3-9855-0671e704aa6c" height="96">

BUILD & TEST LICENSE Donate

quickstart – minimal example – wiki - more examples - docs – shielding serverino using proxy
  • πŸš€ Quick build & start: build & run your server in seconds.
  • πŸ™Œ Zero dependencies: serverino doesn’t rely on any external library.
  • πŸ’ͺ High performance: capable of managing tens of thousands of connections per second.
  • 🌐 Cross-platform: every release is tested on Linux, Windows, and MacOS.

Quickstart

dub init your_app_name -t serverino
cd your_app_name
dub run

A simple webserver in just three lines

import serverino;
mixin ServerinoMain;
void simple(Request request, Output output) { output ~= request.dump(); }

Documentation you need

  • Serverino docs - Serverino reference, generated from code
  • Examples - Some ready-to-try examples
  • Tips - Some snippets you want to read

Defining more than one endpoint

[!IMPORTANT] All the functions marked with `@endpoint will be called one by one, in order of @priority` (higher to lower), until one of them modifies the output.

module app;

import std;
import serverino;

mixin ServerinoMain;

// This endpoint handles the root of the server. Try: http://localhost:8080/
@endpoint @route!"/"
void homepage(Request request, Output output)
{
	output ~= `<html><body>`;
	output ~= `<a href="/private/profile">Private page</a><br>`;
	output ~= `<a href="/private/asdasd">Private (404) page</a>`;
	output ~= `</body></html>`;
}

// This endpoint shows a private page: it's protected by the auth endpoint below.
@endpoint @route!"/private/profile"
void user(Request request, Output output) 
{ 
	output ~= "Hello user!"; 
}

// This endpoint shows a private page: it's protected by the auth endpoint below.
@endpoint 
void blah(Request request, Output output)
{
	// Same as marking this endpoint with @route!"/private/dump" 
	if (request.uri != "/private/dump") 
		return;

	output ~= request.dump();
}

// This endpoint simply checks if the user and password are correct for all the private pages.
// Since it has a higher priority than the previous endpoints, it will be called first.
@priority(10)
@endpoint @route!(r => r.uri.startsWith("/private/"))
void auth(Request request, Output output)
{
	if (request.user != "user" || request.password != "password")
	{
		// If the user and password are not correct, we return a 401 status code and a www-authenticate header.
		output.status = 401;
		output.addHeader("www-authenticate",`Basic realm="my serverino"`);
	}

	// If the user and password are correct, we call the next matching endpoint.
	// (the next matching endpoint will be called only if the current endpoint doesn't write anything)
}

// This endpoint has the highest priority between the endpoints and it logs all the requests.
@priority(12) @endpoint
void requestLog(Request request)
{
	// There's no http output, so the next endpoint will be called.
	info("Request: ", request.uri);
}

Websockets

[!NOTE] Priority works in the same way as the HTTP endpoints: the first websocket endpoint that touches the connection will handle it

// Accept a new connection only if the request URI is "/echo"
// Every websocket will start a new indipendent process
@onWebSocketUpgrade bool onUpgrade(Request req) {
	return req.uri == "/echo";
}

// Handle the WebSocket connection
// Just like a normal endpoint, but with a WebSocket parameter
@endpoint void echo(Request r, WebSocket ws) {

	// Keep the websocket running
	while (true) {

		// Try to receive a message from the client
		if (WebSocketMessage msg = ws.receiveMessage())
		{
			// If we received a message, send it back to the client
			ws.send("I received your message: `" ~ msg.asString ~ "`");
		}
	}

	// When the function returns, the WebSocket connection is closed
}

Shielding the whole thing

[!CAUTION] I recommend securing serverino behind a full web server. Below, I provide two examples of how to run serverino with nginx and apache.

Using nginx

It's pretty easy. Just add these lines inside your nginx configuration:

server {
   listen 80 default_server;
   listen [::]:80 default_server;
   
   location /your_path/ {
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      
      proxy_pass http://localhost:8080;
   }
   ...
   ...
}

If you want to enable keepalive (between nginx and serverino) you must use an upstream:

upstream your_upstream_name {
  server localhost:8080;
  keepalive 64;
}


server {
   listen 80 default_server;
   listen [::]:80 default_server;

   location /your_path/ {
      proxy_set_header Connection "";
      proxy_http_version 1.1;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      
      proxy_pass http://your_upstream_name;
    }
    
    ...
    ...
 }

Using apache2

Enable proxy module for apache2:

sudo a2enmod proxy
sudo a2enmod proxy_http

Add a proxy in your virtualhost configuration:

<VirtualHost *:80>
   ProxyPass "/"  "http://localhost:8080/"
   ...
</VirtualHost>
Authors:
  • Andrea Fontana
Sub packages:
serverino:init-exec, serverino:test-01, serverino:test-02
Dependencies:
serverino:init-exec
Versions:
0.7.1 2024-Apr-16
0.7.0 2024-Apr-13
0.6.5 2024-Mar-28
0.6.4 2024-Mar-21
0.6.3 2024-Mar-16
Show all 29 versions
Download Stats:
  • 8 downloads today

  • 27 downloads this week

  • 79 downloads this month

  • 689 downloads total

Score:
2.9
Short URL:
serverino.dub.pm