| # AGENTS.md - Apache HTTP Server | |
| This is the source for the Apache HTTP Server (httpd), written in C on | |
| top of APR and APR-util. Development happens on `trunk`; fixes are | |
| proposed for backport to the `2.4.x` stable branch afterwards, so make | |
| changes against `trunk` unless told otherwise. | |
| Layout: | |
| - `server/` — core server; `server/mpm/` holds the MPMs | |
| - `modules/<category>/` — modules, e.g. `modules/ssl`, `modules/proxy` | |
| - `include/` — public API headers | |
| - `os/` — platform-specific code | |
| - `support/` — utilities such as `htpasswd`, `rotatelogs`, `apxs` | |
| - `test/` — `test/pyhttpd` framework and `test/modules` test suites | |
| - `docs/manual/` — the manual (XML sources) | |
| - `changes-entries/` — pending CHANGES entries | |
| ## Code style | |
| Follow the [httpd style guide](https://httpd.apache.org/dev/styleguide.html), | |
| and match the surrounding code. | |
| Code must compile in C89: no `//` comments, no declarations after | |
| statements, no C99 features such as `bool`, designated initializers or | |
| variable-length arrays. `--enable-maintainer-mode` builds with | |
| `-std=c89 -Werror`, which catches the first two but not every C99 | |
| extension GCC accepts. A C99 feature may be used only under | |
| `#ifdef AP_HAVE_C99` (or `AP_HAVE_DESIGNATED_INITIALIZER`), both defined | |
| in `include/ap_config.h`, with a C89 fallback in the `#else` branch; see | |
| `include/http_log.h`. | |
| ## Building | |
| A git checkout has no `configure` script; generate it with `buildconf`, | |
| pointing it at an APR source tree (apr-util is looked for alongside it), | |
| then configure and build: | |
| ``` | |
| ./buildconf --with-apr=/path/to/apr | |
| ./configure --enable-maintainer-mode | |
| make -j$(nproc) | |
| ``` | |
| Every `Makefile` in the tree is generated from a `Makefile.in`. Editing | |
| `Makefile.in` alone does nothing — `make` reads the generated `Makefile`, | |
| which is stale until regenerated. After editing any `Makefile.in`, | |
| regenerate all Makefiles from the top level: | |
| ``` | |
| ./config.status | |
| ``` | |
| Then verify the target actually shows up in the regenerated `Makefile` | |
| before relying on it (e.g. `grep '^new-target:' Makefile`). | |
| If any autoconf-level input has changed (`configure.in`, an `.m4` file, | |
| etc.), rerun `configure` exactly as it was originally invoked, rather than | |
| guessing the flags: | |
| ``` | |
| ./config.nice | |
| ``` | |
| ## Testing | |
| Always provide test cases based on pyhttpd where possible; especially | |
| when fixing bugs, adding features, or changing code with poor existing | |
| test coverage. | |
| Tests should be placed in the `test/modules/xxx` directory matching | |
| the `modules/xxx` module source, or `test/modules/core` for core | |
| server or MPM changes. On Unix, verify these pass locally by running | |
| `make check-pytest PYTEST_DIRS=test/modules/xxx` — this can be done | |
| without running `make install` first. | |
| ## Validating changes | |
| After editing any `.github/workflows/*.yml` file or any script the | |
| workflows run, check them before committing: | |
| ``` | |
| ./test/gha-sanity-check.sh | |
| ``` | |
| It catches YAML and shell syntax errors before they reach CI, where the | |
| turnaround is minutes rather than seconds. If python3 has no `yaml` | |
| module the workflow files are skipped, so check for `SKIP` in the output. | |
| For a script the workflows do not run, `bash -n path/to/script.sh` | |
| directly. | |
| ## Documentation | |
| Update the manual when adding or removing configuration directives, or | |
| changing their behaviour. Read `docs/manual/AGENTS.md` before editing | |
| the manual. | |
| Edit only the English source, `foo.xml`. Leave alone the generated | |
| `.html*` files, the `.xml.meta` files, and the translations | |
| (`foo.xml.fr` etc.), which their translators update. | |
| A new directive or module gets a `<compatibility>` line naming the | |
| release it first appears in, e.g. `Available in version 2.5.1 and | |
| later.` for trunk. | |
| After editing any XML under `docs/`, check it is well-formed and valid | |
| against its DTD: | |
| ``` | |
| ./test/gha-docs-check.sh docs/manual/mod/mod_foo.xml | |
| ``` | |
| With no arguments it checks every file under `docs/`. It needs | |
| `xmllint` and the XHTML DTDs from an XML catalog (`xhtml1-dtds` on | |
| Fedora); nothing is fetched from the network. | |
| ## Change entries | |
| Every *user-visible* change must be documented in CHANGES. Read | |
| `README.CHANGES` before adding one: it defines the `changes-entries/` | |
| mechanism, the `*) mod_foo: ...` template, the `core:` prefix for | |
| `server/*.[ch]`, and the crediting rules. | |
| **Write it for the user, not the developer.** A changes entry states the | |
| user-visible effect — what an admin, a client, or a module author sees | |
| differently — not how the code achieves it. This is the opposite of the | |
| commit message. Name no functions, struct fields, or internal identifiers: | |
| a reader does not know what `err_headers_out` is, so "added the header to | |
| `err_headers_out`" is wrong where "kept the header on error responses" is | |
| right. Don't describe the mechanism at all; name any directive or header | |
| involved, and keep it to three lines at most. The how belongs in the | |
| commit message, which sits right beside it. | |
| **A changes entry is not always required.** Only user-visible (or | |
| module-author-visible) changes need one: bug fixes, new directives or | |
| modules, behaviour changes, API changes. Anything with no externally | |
| visible effect needs none — code cleanups and refactoring, test-only | |
| changes, CI/workflow changes, comment and documentation fixes. When in | |
| doubt, ask rather than adding one by reflex. | |
| ## Pull requests | |
| Before creating a pull request, show the proposed subject and description | |
| and wait for approval. Pushing the branch first is fine; it is the PR text | |
| that needs confirming. | |
| Adding commits to a PR that is already pushed is fine as long as they are | |
| covered by the workflows' `paths-ignore` and so will not trigger CI: | |
| `changes-entries/*`, `STATUS`, `CHANGES`, `README*`, `**.md` (and check | |
| `.github/workflows/*.yml` for the current list). A change confined to | |
| `docs/**` is also fine: it runs only the quick Sanity workflow, not the | |
| build. A change that touches anything else waits for the user's say-so, | |
| since it costs a CI run on their PR. | |
| Never force-push a branch that has been pushed (amending or rebasing a | |
| published commit needs one) without explicit confirmation. To change | |
| something already committed and pushed, add a new commit instead, or ask. | |
| Keep the description short: a few sentences on what the change does, plus | |
| anything a reviewer cannot get from the diff, such as a constraint which | |
| explains why it was done this way. Nothing else. No restating the commit | |
| message, no listing the tests when their names already say it, no account | |
| of how it was verified, no marketing. If it runs past about ten lines, cut | |
| it. | |
| Write it in GitHub-Flavored Markdown. Put anything the reader would type or | |
| that names code in `backticks` — variables, directive names, function and | |
| symbol names, filenames, command names, header names such as | |
| `Authentication-Info`. Put config snippets, commands and sample output in | |
| fenced code blocks, tagged with a language where one fits (` ```apache ` for | |
| httpd config). A `##` heading is fine when the description genuinely has more | |
| than one part worth separating, but a few sentences needs none, so most PRs | |
| have no headings. | |
| Do not hard-wrap it. GitHub renders the description as Markdown and reflows | |
| it to the reader's width, so text wrapped at a fixed column comes out ragged. | |
| Write each paragraph as one long line and let it wrap, with a blank line | |
| between paragraphs; a list item is likewise one long line. This is the | |
| opposite of a commit message, which is plain text and stays wrapped by hand. | |
| This applies to the body however it is supplied. Writing it into a file for | |
| `gh pr create --body-file` (or a heredoc) invites wrapping it at the | |
| terminal width out of habit — don't. Each paragraph stays one line in the | |
| file, however long. |