[go: up one dir, main page]

Skip to content

A simple HTTP Server API written in C++ for learning purposes

Notifications You must be signed in to change notification settings

WilsonOh/CPP_HTTP_Server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This is a simple HTTP server written in C++ for learning purposes.

Features ✨

  • Very simple expressjs-like API, albeit with way fewer features
  • Support for GET, POST, PUT, DELETE methods (should be trivial to add more if needed)
  • Psuedo-asynchronous with the help of select, which also helps keep the resources used low
  • Easily serve static directories (examples below)
  • Easy to include in project

Note This library works only on Linux and macOS!

Dependencies

  • C++ 17
  • cmake 3.23.2 (for integrating this library into your project)

Installation

CMake Integration

This project should be used through its CMake integration.
Simply add the following lines to your project CMakeLists.txt file:

include(FetchContent)

cmake_minimum_required(VERSION 3.23.2)

project(<Your Project Name> CXX)

FetchContent_Declare(
  HttpServer
  GIT_REPOSITORY https://github.com/WilsonOh/CPP_HTTP_Server.git
  GIT_TAG main
)

FetchContent_MakeAvailable(HttpServer)

add_executable(${PROJECT_NAME} <Your Source Files>...)

target_link_libraries(${PROJECT_NAME} PRIVATE HttpServer)

Documentation

The documentation for the API is in the fully commented HttpServer.hpp header file.
In the Usage section below I will go through some example usages.

Usage

First off, a simple "hello world" example. Install the library into your project using CMake as shown above, and then run the following code:

// main.cpp
#include <HttpServer.hpp>

int main(void) {
  auto svr = HttpServer();
  svr.get("/", [](const HttpRequest &req, HttpResponse &res) {
    res.text("Hello, World!");
  });
  svr.run();
}

Explanation:

We first create an instance of HttpServer which initializes its fields to the default values.

HttpServer Default Values

  • Number of listeners: 3
  • Text displayed when the requested page is not found: "Wilson's Server: page request is not found"

After that, we define a GET route at the root path / by passing in "/" as the first argument.

We then pass in a lambda which takes in a const HttpRequest & and HttpResponse & and has no return value.
NOTE: It is important to use the correct const qualifier and specify the parameters as references.

Within the lambda, we have access the the HttpRequest and HttpResponse structs and all their methods, but for this example we simply call res.text() with the message we want to send.
This sets the Content-Type of the response header to text/plain and sends the message as the reponse body.

Static Directory Hosting

Suppose we have a static directory with the following structure

static
├── 404.html
├── favicon.ico
├── index.html
├── script.js
└── styles.css

We can serve the static directory and set the 404 page to static/404.html with 20 listeners with the following snippet:

#include <HttpServer.hpp>

int main(void) {
  auto svr = HttpServer()
                 .setNumListeners(20)
                 .set404Page("./static/404.html")
                 .mount_static_directory("static");
  svr.run();
}

Explanation

setNumListeners and set404Page are self explanatory.
mount_static_directory mounts the static directory on / by default if there is only one argument, but a second argument for the mount point can be passed in.
run sets the socket to listen at port 3000 by default with no arguments, but a port number can be passed in if needed.

Note static directory hosting works with nested directories too!

Another Example

#include <HttpServer.hpp>

int main(void) {

  HttpResponse res;
  res.set_header("Foo", "Bar");
  res.html_string("<h1>PAGE NOT FOUND</h1>");

  auto svr = HttpServer()
                 .setNumListeners(20)
                 .set404Response(res)
                 .mount_static_directory("build", "/www");

  svr.post("/users", [](const HttpRequest &req, HttpResponse &res) {
    res.json(R"({ "foo": "bar" })");
  });

  svr.run(8080);
}

Explanation

Here, instead of setting the path to the 404 page, we can make our own HttpResponse object and fully define its behaviour and set it as the response for 404 requests.
The static directory is mounted at /www instead of / here, and a POST route is defined for the /users route which returns a json in the response body.
Lastly, the server is set to run at port 8000.

Other methods

There are a lot of "convenience methods" for the HttpResponse object, such as res.image to send an image from the host directory or res.downloadable which sends a file as an attachment to the client.

res.redirect can redirect the browser to a relative route or another URL, and res.set_header can be used to add to the HTTP response headers or override any existing ones.

Feel free to look through the header file for the full list of methods available!

TODO

  • Get a basic server to start up
  • Create a class to enclose the server creation
  • Make setting headers easy
  • Create HTTP method functions, which takes in a route and lambda
  • Support (single) static file hosting
  • Support static directory hosting (for js and css files)
  • Support http methods other than go (using separate route maps for each method)
  • Support file hosting (for downloading)
  • Provide verbose debugging information
  • Multithreading (maybe maybe not???)
  • Support paramerized URLs

No support for encryption planned as of now

About

A simple HTTP Server API written in C++ for learning purposes

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published