Project 5: libhttp-lite

Build a small HTTP client/server library with a stable C API and clear ownership rules.

Quick Reference

Attribute Value
Difficulty Advanced
Time Estimate 3-4 weeks
Language C
Prerequisites Sockets, parsing, API design
Key Topics ABI stability, interface contracts, error design

1. Learning Objectives

By completing this project, you will:

  1. Design a stable public API in libhttp-lite.
  2. Implement HTTP request parsing and response building.
  3. Clarify ownership of buffers and headers.
  4. Provide versioned API and compatibility guarantees.

2. Theoretical Foundation

2.1 Core Concepts

  • Public vs private headers: Keep implementation hidden.
  • Ownership rules: Explicit lifecycle for requests and responses.
  • ABI stability: Avoid struct layout changes in public headers.

2.2 Why This Matters

This is the capstone of interface design. A small HTTP library must be safe, stable, and usable in real applications without constant breakage.

2.3 Historical Context / Background

HTTP libraries like libcurl expose stable C APIs that have survived decades. Your goal is a smaller version with the same design discipline.

2.4 Common Misconceptions

  • “Returning raw pointers is fine”: Without ownership clarity, it is not.
  • “Structs are part of the API”: Opaque handles are safer.

3. Project Specification

3.1 What You Will Build

A small library that supports:

  • Parsing HTTP requests
  • Building HTTP responses
  • Basic client requests (GET/POST)
  • Clean error handling and version checks

3.2 Functional Requirements

  1. Parse request line and headers.
  2. Build response with status line and headers.
  3. Expose a stable API via opaque handles.
  4. Provide error codes and error strings.

3.3 Non-Functional Requirements

  • Stability: ABI-safe API surface.
  • Reliability: Handles malformed HTTP robustly.
  • Usability: Clear docs and examples.

3.4 Example Usage / Output

http_server *srv = http_server_create(8080);
http_server_set_handler(srv, handle_request);
http_server_run(srv);
http_server_destroy(srv);

3.5 Real World Outcome

You can embed libhttp-lite in a small service and trust that the API is stable, ownership is clear, and errors are consistent.


4. Solution Architecture

4.1 High-Level Design

public API -> internal parser -> request/response objects -> network I/O

4.2 Key Components

Component Responsibility Key Decisions
Public API Stable entry points Opaque types
Parser Read HTTP requests Robust tokenization
Builder Create responses Ownership of buffers
Error API Codes + strings Per-handle error state

4.3 Data Structures

typedef struct http_server http_server;

typedef enum {
    HTTP_OK = 0,
    HTTP_ERR_PARSE = -1,
    HTTP_ERR_IO = -2
} http_status;

4.4 Algorithm Overview

Key Algorithm: Request parse

  1. Read until \r\n\r\n.
  2. Parse request line and headers.
  3. Validate method and path.
  4. Populate request object.

Complexity Analysis:

  • Time: O(n) per request
  • Space: O(n) for parsed strings

5. Implementation Guide

5.1 Development Environment Setup

cc -Wall -Wextra -O2 -g -o test_http test_http.c http.c

5.2 Project Structure

libhttp-lite/
├── include/
│   └── http.h
├── src/
│   ├── http.c
│   └── parser.c
├── tests/
│   └── test_http.c
└── README.md

5.3 The Core Question You’re Answering

“How do I design an HTTP API that is stable, safe, and hard to misuse?”

5.4 Concepts You Must Understand First

Stop and research these before coding:

  1. Opaque handles
    • Keep struct definitions private.
  2. Ownership
    • Who owns header strings and body buffers?
  3. ABI stability
    • How do you evolve the API without breaking users?

5.5 Questions to Guide Your Design

Before implementing, think through these:

  1. Will request/response objects be mutable?
  2. How will you handle header storage and lookup?
  3. Should your API expose raw buffers or accessors?

5.6 Thinking Exercise

ABI Safety

If you add a field to http_request, how do you avoid breaking ABI for users?

5.7 The Interview Questions They’ll Ask

Prepare to answer these:

  1. “How do you design a stable C API?”
  2. “How do you parse HTTP requests safely?”
  3. “How do you define ownership in a network library?”

5.8 Hints in Layers

Hint 1: Start with request parser only Build a parser that returns method/path.

Hint 2: Add response builder Create headers and status line.

Hint 3: Add server wrapper Expose a simple http_server_run API.

5.9 Books That Will Help

Topic Book Chapter
HTTP “HTTP: The Definitive Guide” Ch. 1-3
API design “C Interfaces and Implementations” Ch. 1-2

5.10 Implementation Phases

Phase 1: Foundation (5-7 days)

Goals:

  • Parser and response builder

Tasks:

  1. Parse request line and headers.
  2. Build response strings.

Checkpoint: Parser passes sample requests.

Phase 2: Core Functionality (7-10 days)

Goals:

  • Server/client APIs

Tasks:

  1. Implement server wrapper.
  2. Add client GET/POST.

Checkpoint: Client can call server.

Phase 3: Polish & ABI (6-8 days)

Goals:

  • Stable API and error handling

Tasks:

  1. Add version checks.
  2. Clarify ownership in docs.

Checkpoint: API docs pass misuse review.

5.11 Key Implementation Decisions

Decision Options Recommendation Rationale
API types Opaque handles Yes ABI safety
Header storage List vs map List Simpler, predictable

6. Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Tests Parser correctness Request parsing
Integration Tests Client/server GET/POST
Error Tests Bad input Malformed headers

6.2 Critical Test Cases

  1. Valid GET: Parsed correctly.
  2. Malformed header: Error returned.
  3. Large body: Body handled safely.

6.3 Test Data

GET / HTTP/1.1\r\nHost: localhost\r\n\r\n

7. Common Pitfalls & Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Ownership ambiguity Leaks Provide free helpers
Struct exposure ABI break Keep structs private
Partial reads Parse errors Read until header end

7.2 Debugging Strategies

  • Use curl -v and compare request lines.
  • Log parser state transitions.

7.3 Performance Traps

Copying every header string can be expensive; accept it for simplicity at this stage.


8. Extensions & Challenges

8.1 Beginner Extensions

  • Add keep-alive support.
  • Add header lookup helpers.

8.2 Intermediate Extensions

  • Add chunked transfer decoding.
  • Add middleware hooks.

8.3 Advanced Extensions

  • Add TLS support.
  • Add HTTP/2 framing.

9. Real-World Connections

9.1 Industry Applications

  • Embedded servers: Lightweight HTTP stacks.
  • SDKs: Stable C APIs for services.
  • libcurl: Stable C HTTP library.

9.3 Interview Relevance

API design and network protocol parsing are common in systems interviews.


10. Resources

10.1 Essential Reading

  • “HTTP: The Definitive Guide” - Ch. 1-3
  • “C Interfaces and Implementations” - Ch. 1-2

10.2 Video Resources

  • HTTP protocol lectures

10.3 Tools & Documentation

  • man 2 recv, man 2 send
  • KV Client: Ownership and error contracts.
  • Plugin System: ABI versioning patterns.

11. Self-Assessment Checklist

11.1 Understanding

  • I can design a stable C API.
  • I can parse HTTP safely.
  • I can define ownership clearly.

11.2 Implementation

  • Parser and builder work correctly.
  • API docs are unambiguous.
  • Errors are consistent and clear.

11.3 Growth

  • I can add TLS support.
  • I can explain this project in an interview.

12. Submission / Completion Criteria

Minimum Viable Completion:

  • Parse requests and build responses.

Full Completion:

  • Server wrapper and client functions.

Excellence (Going Above & Beyond):

  • Versioned API and TLS.

This guide was generated from SPRINT_4_BOUNDARIES_INTERFACES_PROJECTS.md. For the complete learning path, see the parent directory.