Replace the deprecated CoreServices UTI calls (UTTypeCreatePreferredIdentifierForTag / UTTypeCopyPreferredTagWithClass) in GCDWebServerGetMimeTypeForExtension with the modern [UTType typeWithFilenameExtension:].preferredMIMEType, removing the -Wdeprecated-declarations pragma. Behavior is unchanged: known extensions map to the same MIME type, unknown ones fall back to the default. The UniformTypeIdentifiers framework (macOS 11+ / iOS 14+ / tvOS 14+, within the project's deployment targets) is now linked in all three build systems: Xcode (OTHER_LDFLAGS), CocoaPods (Core subspec frameworks), and SwiftPM (linkedFramework). Verified: Run-Tests.sh, swift build, and pod lib lint all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
104 lines
8.7 KiB
Markdown
104 lines
8.7 KiB
Markdown
# 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 targets iOS 16 / tvOS 16 / macOS 12 (set in both `GCDWebServer.xcodeproj` and `GCDWebServer.podspec`).
|
|
|
|
Not supported by design: keep-alive connections and HTTPS.
|
|
|
|
## Build & Test
|
|
|
|
The library can be built three ways: the Xcode project (`GCDWebServer.xcodeproj`), CocoaPods (`GCDWebServer.podspec`), and Swift Package Manager (`Package.swift`). All three compile the same source files in place — see "Swift Package Manager layout" below for how the SPM `include/` directories relate to the real sources.
|
|
|
|
Build via SPM:
|
|
```sh
|
|
swift build # builds GCDWebServer, GCDWebUploader, GCDWebDAVServer
|
|
```
|
|
|
|
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):
|
|
```sh
|
|
xcodebuild test -scheme "GCDWebServers (Mac)"
|
|
```
|
|
|
|
Run a single XCTest method:
|
|
```sh
|
|
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):
|
|
```sh
|
|
./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`) against recorded fixtures.
|
|
|
|
This script was originally written for Xcode 11.3 and was updated for current Xcode/SDKs in this fork:
|
|
- The hardcoded "oldest deployment target" builds now use 12.0 (macOS) / 16.0 (iOS) to match the project (the old 10.7/8.0 values fail on modern SDKs — no `libarclite`).
|
|
- The `webUploader` fixture test is **commented out**: this fork customized `GCDWebUploader` (delete/move/create disabled in commit `ef4b622`), so the recorded `Tests/WebUploader` fixtures no longer match. Re-record them or re-enable the line if those features are restored.
|
|
- The **tvOS build step is commented out** because it requires the tvOS Simulator runtime to be installed (`xcodebuild -downloadPlatform tvOS`); without it the storyboard compile fails with "tvOS … Platform Not Installed". Re-enable once the runtime is present.
|
|
|
|
A project adjustment was also needed for the suite to build under current Xcode: the `Tests (Mac)` target sets `GENERATE_INFOPLIST_FILE = YES`. MIME-type lookup in `GCDWebServerFunctions.m` uses the modern `UTType` API (UniformTypeIdentifiers), so that framework is linked in all three build systems (Xcode `OTHER_LDFLAGS`, the podspec Core subspec, and `Package.swift`).
|
|
|
|
### 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 for Objective-C is defined by `.clang-format` (Google base style, `ColumnLimit: 0`). Format files with `clang-format -style=file -i <files>`. The Swift example apps use 2-space indentation (SwiftFormat).
|
|
|
|
## 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`).
|
|
|
|
## Swift Package Manager layout
|
|
|
|
SPM needs each target's public headers in a single directory, but the real headers live spread across `GCDWebServer/Core`, `GCDWebServer/Requests`, and `GCDWebServer/Responses`. To support SPM **without moving any files** (keeping the Xcode project and CocoaPods working), the public headers are surfaced through symlinks:
|
|
|
|
- `GCDWebServer/include/*.h` are **symlinks** to the real public headers (everything except the private `GCDWebServerPrivate.h`, which is deliberately not linked so it stays out of the public module). `GCDWebUploader/include/GCDWebUploader.h` works the same way.
|
|
- `GCDWebServer/include/module.modulemap` is hand-written with `umbrella "."`. This is required: if SPM auto-generated the module map it would pick `include/GCDWebServer.h` as an umbrella *header* (name matches the module) and only export what that one header imports, hiding the request/response subclasses. The umbrella *directory* exports them all.
|
|
- All cross-header imports inside the library (including the framework umbrella `Frameworks/GCDWebServers.h`) use quoted form (`#import "GCDWebServerRequest.h"`), not framework-style (`#import <GCDWebServers/...>`); the quoted form is what lets the flat `include/` symlink directory resolve them. Keep new imports quoted.
|
|
- `GCDWebUploader.bundle` is a `.copy` resource. Because SPM nests it inside a generated module bundle, `GCDWebUploader.m` has a `#if SWIFT_PACKAGE` branch that finds it via `SWIFTPM_MODULE_BUNDLE` instead of `bundleForClass:`.
|
|
|
|
When adding or renaming a public header, add/remove the matching symlink in the relevant `include/` directory or it won't be visible to SPM consumers. `libxml2` (for WebDAV) needs no special SPM include flag — the macOS/iOS SDK ships a module map that resolves `<libxml/parser.h>` automatically.
|
|
|
|
## 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`).
|