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:
- Design a stable public API in
libhttp-lite. - Implement HTTP request parsing and response building.
- Clarify ownership of buffers and headers.
- 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
- Parse request line and headers.
- Build response with status line and headers.
- Expose a stable API via opaque handles.
- 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
- Read until
\r\n\r\n. - Parse request line and headers.
- Validate method and path.
- 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:
- Opaque handles
- Keep struct definitions private.
- Ownership
- Who owns header strings and body buffers?
- ABI stability
- How do you evolve the API without breaking users?
5.5 Questions to Guide Your Design
Before implementing, think through these:
- Will request/response objects be mutable?
- How will you handle header storage and lookup?
- 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:
- “How do you design a stable C API?”
- “How do you parse HTTP requests safely?”
- “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:
- Parse request line and headers.
- Build response strings.
Checkpoint: Parser passes sample requests.
Phase 2: Core Functionality (7-10 days)
Goals:
- Server/client APIs
Tasks:
- Implement server wrapper.
- Add client GET/POST.
Checkpoint: Client can call server.
Phase 3: Polish & ABI (6-8 days)
Goals:
- Stable API and error handling
Tasks:
- Add version checks.
- 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
- Valid GET: Parsed correctly.
- Malformed header: Error returned.
- 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 -vand 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.
9.2 Related Open Source Projects
- 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
10.4 Related Projects in This Series
- 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.