* Delete old unix domain socket files on Windows
While Windows doesn't have the need to reuse a socket file descriptor
by dup()ing it on config reloads, there still is a valid need for an
equivalent to the `syscall.Unlink()` call in listen_unix.go (also in
`reuseUnixSocket`).
If a previous Caddy instance didn't terminate properly, the chances it
will leave behind a socket file are very high, breaking all subsequent
starting attempts. Other than for regular files, Windows seemingly has
no way for a process to flag a UNIX domain socket file with `FILE_DELETE_ON_CLOSE`,
which means this scenario can never be avoided entirely (e.g. in the case
of crashes).
For the long comment on `isAbstractUnixSocket`: the logic itself is likely
of dubious value, but I thought it better to explicitly reference the
issue, as I have just spent half an hour searching the web to figure out
whether abstract names will work or not on Windows. At least, the logic
as-is should now do the sensible thing if these are ever implemented
properly (and it matches what the Golang standard library does internally).
* Add a dial attempt to check for active server processes
As @steadytao pointed out (thanks!), the previous code didn't have
solid proof that an existing unix socket file had really been orphaned,
as it's also possible that there's another server process (still running).
This would still give the Windows implementation parity with the unix
one (as that one also unlinks the socket file without further checks),
but I've performed a couple of small tests and found this way of handling
socket files still problematic at least problematic if Caddy is used as
a reverse proxy in real world scenarios.
In tests with a simple Caddyfile that only declares an admin socket,
starting two caddy instances with the same Caddyfile works and behaves
like one would expect: the second instance removes the first instance's
socket file and "wins" the race.
When Caddy is used as a reverse proxy, though, what'll happen is more
complicated: While the second instance wins the race for the admin
socket, as long as the Caddyfile specifies a TCP downstream socket,
the second process will not be able to take this one over from the first
(also to be expected, that's how socket binding usually works).
This results in a rather broken state: The first process still holds on
to its TCP listening sockets, the second process fails to start because
of the error in its listening attempt, leaving an orphaned admin socket
file in the file system. Afterwards, the second process won't be running
and the first _will_ be running but unable to be controlled because its
admin socket has been replaced. This leaves the system in another state
that is bad from an ops perspective.
With this new change, we try first to connect to any unix socket that
isn't already covered by our current process (with a very low timeout)
and can easily decide if the socket is still in use by another process:
- If the connection is accepted, there's obviously a server process.
- If Windows returns WSACONNREFUSED [^1], there is either no active
server process for the socket file anymore, or the socket file does
not exist.
- Any other errors are likely a sign that there still is a server process
(e.g. a timeout would indicate that it's just slow in accepting new
connection attempts).
[^1]: https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2#wsaeconnrefused
* chore: tidy Windows unix socket reuse helper
---------
Co-authored-by: Zen Dodd <mail@steadytao.com>
* reverseproxy: Add ability to clear dynamic upstreams cache during retries
This is an optional interface for dynamic upstream modules to implement if they cache results.
TODO: More documentation; this is an experiment.
* Add some godoc
* Export interface; update godoc
* admin: Redact sensitive request headers in API logs
* Fix govulncheck and typed atomic lint failures
* Sync Go module metadata after dependency downgrade
* chore: add `AGENTS.md`
Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>
* Apply suggestions from code review
Co-authored-by: Francis Lavoie <lavofr@gmail.com>
Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
* review feedback
Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>
---------
Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>
Co-authored-by: Francis Lavoie <lavofr@gmail.com>
Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
* fix(caddyfile): {block} in snippet
Resolve issue #7557
So, here is the situation:
- Pull request #7206 included some changes to the doImport's function of
Caddyfile's parser. What it does is that if there is no token within a
block that follows the import, and the import contains `{block}`, then
the `{block}` token is discarded.
- After this pull request:
- Issue #7518 noticed that in cases that `{block}` was not imported,
a runtime error was raised due to the assumption that tokens were
always added to `tokensCopy` on every iteration of `importedTokens`.
This was fixed by pull request #7543.
- Issue #7557 notices that {block} can be ignored when imported from a
certain file. There, it's again an issue with how the import works.
When `import snippets` is called, this import instruction doesn't
contains any nested blocks. And when the argument replacer that is
the `importedTokens` loop is called and finds `{block}`, it uses the
block from the file's import (which in this case is nothing),
`{block}` is erased, and unavailable when the import directive is
called for the imported snippet.
The changed in this commit addresses the second issue by checking before
replacing `{block}` if we're currently in a snippet definition, and
appending the `{block}` token to `tokensCopy` if we are.
With this changes, when importing those snippets, the `{block}` token
will be available to be replaced by the nested blocks in `tokensToAdd`
if needed, or erased if there are no nested blocks and `tokensToAdd` is empty.
Tests added in pull requests #7206 and #7543 passes with this new
implementation, confirming that unused `{block}` are accepted if nothing
is passed to `import`, as well as the other usual tests.
A new test was also added based on issue #7557 reporting, and also passes.
Signed-off-by: prettysunflower <me@prettysunflower.moe>
* caddyfile: add imported snippet block placeholder coverage
---------
Signed-off-by: prettysunflower <me@prettysunflower.moe>
Co-authored-by: Zen Dodd <mail@steadytao.com>
`reveal_symlinks` was exposing symlink targets as fully resolved absolute paths, even if the target is a relative path. With this change the link target is shown as-is, without resolving anything.
* caddyfile: improve import/global options UX
Keep standalone global-options braces stable in fmt when they follow import lines.
Also improve validate output for imports before the global options block with a clearer error message.
Add focused formatter and parser regression coverage
* caddyfile: satisfy staticcheck in formatter
* feat: add system and combined CA pool modules
* fix: combining pools using `CertificateProvider`
* fix: lint issue
* chore: caddyfiletests
* doing it for first time, so not sure if its right.
* fix: use `x509` native addCert
* chore: explicit err handling
* Apply suggestion from @mohammed90
---------
Co-authored-by: Mohammed Al Sahaf <mohammed@caffeinatedwonders.com>
* add 'root' key to Helper.State for access in frankenphp's `php_server` directive
* clone state before passing it to child directives, but keep sharing it among sibling directives
* propagate named route state from children to parent
* use BlockState to set "root" instead
* gofmt -w .
* go fmt ./...
* here we go