Http11Probe

uWebSockets

Language: C++ Β· View source on GitHub

The C++ library, built from master rather than a pinned release so upstream fixes show up in these results as they land. uWebSockets.js is the Node.js binding over this same core.

Dockerfile

FROM debian:trixie-slim AS build
RUN apt-get update && apt-get install -y --no-install-recommends \
        ca-certificates g++ git make zlib1g-dev \
    && rm -rf /var/lib/apt/lists/*
WORKDIR /src
# Deliberately unpinned: upstream asked that results track master so their
# fixes show up here. Rebuilding picks up whatever master is at that moment.
RUN git clone --depth 1 https://github.com/uNetworking/uWebSockets.git . \
    && git submodule update --init --depth 1 uSockets
RUN make -C uSockets
COPY src/Servers/UWebSocketsCppServer/server.cpp .
RUN g++ -std=c++2b -O3 -Isrc -IuSockets/src server.cpp uSockets/*.o -lz -o /uws-server

FROM debian:trixie-slim
RUN apt-get update && apt-get install -y --no-install-recommends zlib1g \
    && rm -rf /var/lib/apt/lists/*
COPY --from=build /uws-server /usr/local/bin/uws-server
USER nobody
ENTRYPOINT ["uws-server", "8080"]

Source β€” server.cpp

#include "App.h"

#include <charconv>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
#include <string_view>

/* uWS invalidates req as soon as the handler returns, so everything needed
 * later is read out synchronously. Only the body echo is async. */

static std::string parseCookies(std::string_view raw) {
    std::string out;
    size_t pos = 0;
    while (pos < raw.size()) {
        size_t semi = raw.find(';', pos);
        std::string_view pair = raw.substr(pos, semi == std::string_view::npos ? raw.size() - pos : semi - pos);
        size_t start = pair.find_first_not_of(" \t");
        if (start != std::string_view::npos) {
            pair.remove_prefix(start);
            size_t eq = pair.find('=');
            if (eq != std::string_view::npos && eq > 0) {
                out.append(pair.substr(0, eq));
                out.push_back('=');
                out.append(pair.substr(eq + 1));
                out.push_back('\n');
            }
        }
        if (semi == std::string_view::npos) {
            break;
        }
        pos = semi + 1;
    }
    return out;
}

int main(int argc, char **argv) {
    int port = 8080;
    if (argc > 1) {
        std::string_view arg(argv[1]);
        std::from_chars(arg.data(), arg.data() + arg.size(), port);
    }

    uWS::App().any("/cookie", [](auto *res, auto *req) {
        std::string body = parseCookies(req->getHeader("cookie"));
        res->writeHeader("Content-Type", "text/plain");
        res->end(body);
    }).any("/echo", [](auto *res, auto *req) {
        std::string body;
        for (auto [key, value] : *req) {
            body.append(key);
            body.append(": ");
            body.append(value);
            body.push_back('\n');
        }
        res->writeHeader("Content-Type", "text/plain");
        res->end(body);
    /* Wildcards must be registered last. */
    }).any("/*", [](auto *res, auto *req) {
        if (req->getMethod() != "post") {
            res->writeHeader("Content-Type", "text/plain");
            res->end("OK");
            return;
        }

        /* Already inside the socket callback, so uWS corks these writes for us. */
        auto buffer = std::make_shared<std::string>();
        res->onData([res, buffer](std::string_view chunk, bool isFin) {
            buffer->append(chunk);
            if (isFin) {
                res->writeHeader("Content-Type", "text/plain");
                res->end(*buffer);
            }
        });
        res->onAborted([]() {});
    }).listen("0.0.0.0", port, [port](auto *listen_socket) {
        if (!listen_socket) {
            std::cerr << "Failed to listen on port " << port << std::endl;
            std::exit(1);
        }
    }).run();
}

Test Results

Loading results...

Compliance

Smuggling

Malformed Input

Caching

Cookies

Http11Probe β€” HTTP/1.1 compliance & smuggling testerSource on GitHub