-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
Go version
go version go1.23.3 darwin/amd64
Output of go env in your module/workspace:
GO111MODULE='on'
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/Library/Caches/go-build'
GOENV='/home/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/home/workspace/go/pkg/mod'
GOOS='darwin'
GOPATH='/home/workspace/go'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/.gobrew/current/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/.gobrew/current/go/pkg/tool/darwin_amd64'
GOVCS=''
GOVERSION='go1.23.3'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/Library/Application Support/go/telemetry'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='clang'
CXX='clang++'
CGO_ENABLED='1'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/wj/rjq3z3b5009frvvq79l2pdwm0000gp/T/go-build1764778311=/tmp/go-build -gno-record-gcc-switches -fno-common'What did you do?
- Create locally signed cert for TLS:
openssl req -x509 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -days 365 -nodes -subj '/CN=localhost' - Set-up TLS server:
cat server.go
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "server running!\n")
}
func main() {
http.HandleFunc("/", handler)
err := http.ListenAndServeTLS(":8443", "localhost.crt", "localhost.key", nil)
if err != nil {
fmt.Println("Error:", err)
}
}
- Run TLS server:
go run server.go
What did you see happen?
- Try HTTP/1.1 request with non-zero
Content-Lengthand no body. This hangs indefinitely, with the server waiting for the 10-byte request body:
❯ curl -vk --http1.1 -H'Content-Length: 10' https://localhost:8443
* Host localhost:8443 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:8443...
* Connected to localhost (::1) port 8443
* ALPN: curl offers http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES128-GCM-SHA256 / [blank] / UNDEF
* ALPN: server accepted http/1.1
* Server certificate:
* subject: CN=localhost
* start date: Mar 6 17:00:03 2025 GMT
* expire date: Mar 6 17:00:03 2026 GMT
* issuer: CN=localhost
* SSL certificate verify result: self signed certificate (18), continuing anyway.
* using HTTP/1.x
> GET / HTTP/1.1
> Host: localhost:8443
> User-Agent: curl/8.7.1
> Accept: */*
> Content-Length: 10
>
* Request completely sent off
^C⏎
- Try HTTP/2 request with non-zero
Content-Lengthand no body. This returns immediately with successful response:
❯ curl -vk --http2 -H'Content-Length: 10' https://localhost:8443
* Host localhost:8443 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:8443...
* Connected to localhost (::1) port 8443
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES128-GCM-SHA256 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificate:
* subject: CN=localhost
* start date: Mar 6 17:00:03 2025 GMT
* expire date: Mar 6 17:00:03 2026 GMT
* issuer: CN=localhost
* SSL certificate verify result: self signed certificate (18), continuing anyway.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://localhost:8443/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: localhost:8443]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.7.1]
* [HTTP/2] [1] [accept: */*]
* [HTTP/2] [1] [content-length: 10]
> GET / HTTP/2
> Host: localhost:8443
> User-Agent: curl/8.7.1
> Accept: */*
> Content-Length: 10
>
* Request completely sent off
< HTTP/2 200
< content-type: text/plain; charset=utf-8
< content-length: 16
< date: Thu, 06 Mar 2025 21:27:40 GMT
<
server running!
* Connection #0 to host localhost left intact
What did you expect to see?
It seems like this may be an HTTP/2 spec violation according to RFC 9113:
A request or response that includes message content can include a content-length header field. A request or response is also malformed if the value of a content-length header field does not equal the sum of the DATA frame payload lengths that form the content, unless the message is defined as having no content. For example, 204 or 304 responses contain no content, as does the response to a HEAD request. A response that is defined to have no content, as described in Section 6.4.1 of [HTTP], MAY have a non-zero content-length header field, even though no content is included in DATA frames.
I would expect that the HTTPS server continue waiting for the rest of the request or recognize after some timeout that the request is malformed due to failing this condition:
the value of a content-length header field does not equal the sum of the DATA frame payload lengths that form the content
I would not expect the server to return with a 200-level response.