Files
GCDWebServer/CLAUDE.md
2026-06-08 15:21:48 +07:00

5.7 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

GCDWebServer is a lightweight, GCD-based HTTP 1.1 server written in Objective-C (ARC) for embedding in iOS, macOS, and tvOS apps. It has no third-party dependencies. This fork has bumped the deployment targets to iOS 16 / tvOS 16 / macOS 12 (the upstream README still documents the original iOS 8 / tvOS 9 / macOS 10.7 minimums and the CocoaPods podspec still declares 8.0/9.0/10.7).

Not supported by design: keep-alive connections and HTTPS.

Build & Test

There is no Swift Package Manager Package.swift; the build is driven entirely by GCDWebServer.xcodeproj (and CocoaPods for consumers).

Schemes (xcodebuild -list -project GCDWebServer.xcodeproj):

  • GCDWebServer (Mac|iOS|tvOS) — the static library / framework per platform.
  • GCDWebServers (Mac|iOS|tvOS) — the framework target plus the XCTest unit tests (Frameworks/Tests.m).
  • Build All.

Run the unit tests (XCTest):

xcodebuild test -scheme "GCDWebServers (Mac)"

Run a single XCTest method:

xcodebuild test -scheme "GCDWebServers (Mac)" -only-testing:Tests/Tests/testPaths

Full CI test suite (builds for all platforms at oldest + current deployment targets, then runs the request/response replay tests):

./Run-Tests.sh

Run-Tests.sh does the bulk of the real testing. It builds the GCDWebServer (Mac) target, then runs the resulting command-line GCDWebServer executable in test modes (webServer, webDAV, htmlForm, htmlFileUpload, webUploader) against recorded fixtures.

How the fixture-replay tests work

The Tests/ directory holds recorded HTTP exchanges, not code. Each test case is a pair of files: NNN-<method>.request (raw bytes sent to the server) and NNN-<code>.response (expected raw response bytes). The test runner (-mode <mode> -root <payload-dir> -tests <test-dir>) replays each .request against a server rooted at an extracted copy of Tests/Payload.zip and byte-compares the reply to the .response. To add coverage for a new behavior, add a matching .request/.response pair to the relevant Tests/<Mode> directory rather than writing new XCTest code.

Formatting

Source style is enforced by clang-format (Google base style, see .clang-format) for Objective-C and SwiftFormat for the Swift example apps. Run before committing:

./format-source.sh

Note: format-source.sh pins exact tool versions (clang-format 9.0.0, SwiftFormat 0.44.5) and will refuse to run otherwise.

Architecture

The entire library is built around 4 core classes in GCDWebServer/Core/:

  • GCDWebServer — owns the listening socket and the ordered list of handlers. Manages start/stop, options, Bonjour, NAT port mapping, and (on iOS) automatic suspend/resume across foreground/background transitions.
  • GCDWebServerConnection — one instance per open HTTP connection, lives until the connection closes. Drives reading the request and writing the response. Subclassable via hooks (it's exposed but not used directly).
  • GCDWebServerRequest — created once HTTP headers arrive; wraps the request and consumes the body. Subclasses in GCDWebServer/Requests/ choose how the body is handled (in memory, streamed to disk, parsed as a form, etc.).
  • GCDWebServerResponse — produced by a handler; wraps response headers and an optional body. Subclasses in GCDWebServer/Responses/ cover data-in-memory, file-on-disk, streamed, and error responses.

GCDWebServer/Core/GCDWebServerFunctions.{h,m} holds shared C helpers (e.g. GCDWebServerNormalizePath, MIME-type and date helpers). GCDWebServerPrivate.h is the internal/private header (including the logging-facility abstraction). GCDWebServerHTTPStatusCodes.h enumerates status codes.

Handler model

A request is matched and processed by handlers added to the server, evaluated in LIFO order (last added wins). Each handler is two GCD blocks:

  • GCDWebServerMatchBlock — runs as soon as headers are received; inspects method/URL/headers and returns a GCDWebServerRequest subclass instance to claim the request, or nil to pass.
  • GCDWebServerProcessBlock (sync) or GCDWebServerAsyncProcessBlock (async) — runs after the full request body is received and returns a GCDWebServerResponse (or nil/error response → 500).

Handlers run on arbitrary GCD threads, so handler code must be thread-safe and re-entrant.

Extensions (subclasses of GCDWebServer)

  • GCDWebUploader/GCDWebUploader, an HTML5 web UI for uploading/downloading/managing files in a directory. Ships front-end assets in GCDWebUploader.bundle.
  • GCDWebDAVServer/GCDWebDAVServer, a class-1 WebDAV server (partial class-2 for macOS Finder). Depends on libxml2.

Example apps & framework packaging

  • Mac/main.m — macOS command-line example (also serves as the test-runner executable).
  • iOS/, tvOS/ — Swift example apps (AppDelegate.swift, ViewController.swift).
  • Frameworks/ — umbrella header (GCDWebServers.h), module map, and the XCTest target source (Tests.m).

Consumer linking requirements

When integrated manually (not via CocoaPods), consuming apps must link libz, and WebDAV additionally needs libxml2 with $(SDKROOT)/usr/include/libxml2 on the header search path. The GCDWebServer.podspec defines three subspecs: Core (default), WebDAV, and WebUploader.

Logging & debug builds

Define DEBUG=1 in GCC_PREPROCESSOR_DEFINITIONS to enable verbose logging plus internal consistency checks. Runtime verbosity is controlled via +[GCDWebServer setLogLevel:]. If XLFacility is present in the same Xcode project, GCDWebServer routes logging through it automatically (see GCDWebServerPrivate.h).