close connection after HEAD handler executed
$ dotnet new webapiaot
# insert a HEAD mapping
$ sed -i 's|todosApi.MapGet("/".*|&\ntodosApi.MapMethods("/", ["HEAD"], context => Task.CompletedTask);|' Program.cs
# on mac: sed -i '' 's|todos...
$ dotnet run
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5000
..
$ curl -X HEAD -v http://localhost:5000/todos
..
no chunk, no close, no size. Assume close to signal end
# and it hangs
we can use -I, --head (fetch only header) option like curl -I http://localhost:5000/todos to get the expected result, but the server should just close the connection when HEAD has been executed.
This is per spec, HEAD requests do not produce a response body, nor should they close the connection. Using the --head option is the correct client usage.
curl's manpage reports
This option only changes the actual word used in the HTTP request, it does not alter the way curl behaves. For example if you want to make a proper HEAD request, using -X HEAD does not suffice. You need to use the -I, --head option.
thanks. with a different php app, i was seeing a weird behavior of nginx where it sends non-empty response body to the client which was obviously a violation because server was doing more than it was supposed to. when i switched to kestrel, it felt like kestrel is quite close to what a model implementation expects. the curl example was a repro as a client.
This is per spec, HEAD requests do not produce a response body, nor should they close the connection.
i must have missed something, but the spec does not require closing the connection after a HEAD request. Chris' statement that HEAD requests should not close the connection seem to aligns with the spec’s focus on efficiency and typical behavior. The curl behavior described (assuming close to signal the end) is a practical approach in the absence of other indicators (keep alive / persistent connection), but it’s not dictated by the spec. Instead, it's a client-side heuristic for determining the end of the response.
So, while the spec does not explicitly state that connections must remain open after a HEAD request execution, it does not forbid it either, leaving room for practical implementations like the one described by curl.