Repository: caddyserver/caddy (language: go)

Issue:
templates: bad content-length with httpError
When a template returns an error with `{{httpError xxx}}`, the `content-length` header of the response will be set to a specific number, while the response body is empty.

Request to caddy docs:
```
curl -v https://caddyserver.com/docs/404
*   Trying 165.227.20.207:443...
* TCP_NODELAY set
* Connected to caddyserver.com (165.227.20.207) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=caddyserver.com
*  start date: Aug 31 02:32:51 2023 GMT
*  expire date: Nov 29 02:32:50 2023 GMT
*  subjectAltName: host "caddyserver.com" matched cert's "caddyserver.com"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55f349347610)
> GET /docs/404 HTTP/2
> Host: caddyserver.com
> user-agent: curl/7.68.0
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
* HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
* stopped the pause stream!
* Connection #0 to host caddyserver.com left intact
curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
```

Request to my server with following template
```
{{httpError 404}}
```
```
curl -v http://localhost/404.tpl.json
*   Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /404.tpl.json HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Accept-Ranges: bytes
< Cache-Control: public,no-cache
< Content-Length: 18
< Content-Type: application/json
< Etag: "s2pib0i"
< Last-Modified: Wed, 18 Oct 2023 04:11:24 GMT
< Server: Caddy
< Date: Wed, 18 Oct 2023 04:11:26 GMT
< 
* transfer closed with 18 bytes remaining to read
* Closing connection 0
curl: (18) transfer closed with 18 bytes remaining to read
```

```
caddy version v2.7.5 h1:HoysvZkLcN2xJExEepaFHK92Qgs7xAiCFydN5x5Hs6Q=
```



Discussion / hints:

Fix patch:
diff --git a/modules/caddyhttp/templates/tplcontext.go b/modules/caddyhttp/templates/tplcontext.go
index 63e645d37f8..8b3d6bfc486 100644
--- a/modules/caddyhttp/templates/tplcontext.go
+++ b/modules/caddyhttp/templates/tplcontext.go
@@ -444,6 +444,14 @@ func (c TemplateContext) funcFileStat(filename string) (fs.FileInfo, error) {
 // funcHTTPError returns a structured HTTP handler error. EXPERIMENTAL; SUBJECT TO CHANGE.
 // Example usage: `{{if not (fileExists $includeFile)}}{{httpError 404}}{{end}}`
 func (c TemplateContext) funcHTTPError(statusCode int) (bool, error) {
+	// Delete some headers that may have been set by the underlying
+	// handler (such as file_server) which may break the error response.
+	c.RespHeader.Header.Del("Content-Length")
+	c.RespHeader.Header.Del("Content-Type")
+	c.RespHeader.Header.Del("Etag")
+	c.RespHeader.Header.Del("Last-Modified")
+	c.RespHeader.Header.Del("Accept-Ranges")
+
 	return false, caddyhttp.Error(statusCode, nil)
 }
 


Test patch: