Hackney Development Guide

View Source

This guide covers development setup, testing, and contributing to hackney.

Prerequisites

  • Erlang/OTP 27 or later
  • rebar3 3.24.0 or later
  • CMake 3.14 or later
  • Go (for building BoringSSL)
  • zlib development headers

Platform-specific requirements

macOS:

brew install erlang cmake go zlib

Ubuntu/Debian:

sudo apt-get install erlang cmake golang zlib1g-dev build-essential

FreeBSD:

pkg install erlang-runtime28 rebar3 cmake git gmake go llvm18

Building

Clone the repository with submodules:

git clone --recursive https://github.com/benoitc/hackney.git
cd hackney

Build the project:

rebar3 compile

This will:

  1. Compile all Erlang source files
  2. Build the QUIC NIF (BoringSSL + lsquic + hackney_quic)

Running Tests

Run all tests:

rebar3 eunit

Run specific test modules:

rebar3 eunit --module=hackney_quic_tests
rebar3 eunit --module=hackney_http3_tests

Running tests with httpbin

Some tests require the httpbin server. Start it before running tests:

pip3 install httpbin gunicorn
gunicorn -b 127.0.0.1:8000 httpbin:app &
rebar3 eunit

Local Docker Testing

A Dockerfile is provided for testing on Linux locally, which mirrors the GitHub CI environment.

Building the Docker image

docker build -f Dockerfile.test -t hackney-test .

Running tests in Docker

Run all tests:

docker run --rm hackney-test

Run specific test modules:

docker run --rm hackney-test bash -c "rebar3 eunit --module=hackney_quic_tests"

Interactive debugging in Docker

Start an interactive shell:

docker run --rm -it hackney-test bash

Then you can:

  • Run tests manually: rebar3 eunit
  • Start an Erlang shell: rebar3 shell
  • Inspect the build: ls -la priv/

Debugging with core dumps

Enable core dumps for debugging segfaults:

docker run --rm --ulimit core=-1 hackney-test bash -c "
    ulimit -c unlimited
    rebar3 eunit || (ls -la core* 2>/dev/null; gdb -batch -ex bt /usr/local/bin/erl core*)
"

QUIC/HTTP3 Development

The QUIC implementation uses:

  • BoringSSL - Google's fork of OpenSSL (required for QUIC TLS 1.3)
  • lsquic - LiteSpeed QUIC library

NIF Source Files

  • c_src/hackney_quic_nif.c - NIF entry points
  • c_src/quic_conn.c - Connection management
  • c_src/quic_conn.h - Connection structures and declarations
  • c_src/atoms.h - Atom definitions

Building the NIF

The NIF is built automatically by rebar3 using CMake. To rebuild from scratch:

rm -rf _build/cmake priv/*.so
rebar3 compile

CMake Configuration

The CMake build is configured in c_src/CMakeLists.txt. Key options:

  • CMAKE_BUILD_TYPE - Release (default) or Debug
  • CMAKE_POSITION_INDEPENDENT_CODE - Always ON for NIF shared library

Debugging the NIF

Build with debug symbols:

rm -rf _build/cmake
CMAKE_BUILD_TYPE=Debug rebar3 compile

Use LLDB/GDB to debug:

lldb -- erl -pa _build/default/lib/*/ebin

Code Style

Erlang

  • Follow standard Erlang conventions
  • Use edoc for function documentation
  • Keep lines under 100 characters

C

  • Use C17 standard
  • Use enif_alloc/enif_free for memory allocation (not malloc/free)
  • Always check return values
  • Use atomic operations for thread-safe flags

Submitting Changes

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Make your changes
  4. Run tests locally and in Docker
  5. Commit with clear messages
  6. Push and create a pull request

Commit Message Format

type: short description

Longer description if needed.

Types: fix, feat, docs, test, refactor, ci, chore

Continuous Integration

CI runs on:

  • Linux x86_64 (OTP 27.2, 28.0)
  • Linux ARM64 (OTP 27.2)
  • macOS ARM64 (OTP 27)
  • FreeBSD 14.2 (OTP 28)

All CI jobs must pass before merging.