Closed
Description
Go version
go version go1.22.5 linux/amd64
Output of go env
in your module/workspace:
N/A
What did you do?
I have published a small reproducer to this repository: https://github.com/uhthomas/go-unsolicited-http
The instructions are in the README, but for brevity:
Run the server:
code
main.go
package main
import (
"context"
"flag"
"fmt"
"io"
"log"
"net/http"
"sync/atomic"
)
type Server struct {
requestCount uint64
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
requestID := atomic.AddUint64(&s.requestCount, 1)
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
res, err := http.Get("https://go.dev")
if err != nil {
panic(err)
}
n, err := io.Copy(w, res.Body)
fmt.Printf("%d: %d bytes written, err=%v\n", requestID, n, err)
}
func Main(ctx context.Context) error {
addr := flag.String("addr", ":8080", "address to listen on")
flag.Parse()
log.Println("listening on", *addr)
return http.ListenAndServe(*addr, &Server{})
}
func main() {
if err := Main(context.Background()); err != nil {
log.Fatal(err)
}
}
❯ go run github.com/uhthomas/go-unsolicited-http/cmd/server@main
Run the client:
code
main.go
package main
import (
"context"
"fmt"
"log"
"net/http"
"time"
)
func Main(ctx context.Context) error {
for i := 0; ; i++ {
fmt.Println("attempt", i)
if _, err := http.Head("http://localhost:8080"); err != nil {
return fmt.Errorf("head: %w", err)
}
time.Sleep(200 * time.Millisecond)
}
}
func main() {
if err := Main(context.Background()); err != nil {
log.Fatal(err)
}
}
❯ go run github.com/uhthomas/go-unsolicited-http/cmd/client@main
What did you see happen?
Server:
1: 54 bytes written, err=<nil>
2: 0 bytes written, err=readfrom tcp [::1]:8080->[::1]:48336: write tcp [::1]:8080->[::1]:48336: write: broken pipe
3: 54 bytes written, err=<nil>
4: 54 bytes written, err=<nil>
5: 54 bytes written, err=<nil>
6: 54 bytes written, err=<nil>
7: 54 bytes written, err=<nil>
8: 54 bytes written, err=<nil>
9: 54 bytes written, err=<nil>
10: 0 bytes written, err=readfrom tcp [::1]:8080->[::1]:33742: write tcp [::1]:8080->[::1]:33742: write: broken pipe
Client:
attempt 0
2024/07/26 16:17:17 Unsolicited response received on idle HTTP channel starting with "<!DOCTYPE html>\n<html>\n <head>\n <title>Thomas</tit"; err=<nil>
attempt 1
2024/07/26 16:17:17 Unsolicited response received on idle HTTP channel starting with "<!DOCTYPE html>\n<html>\n <head>\n <title>Thomas</tit"; err=<nil>
attempt 2
2024/07/26 16:17:17 Unsolicited response received on idle HTTP channel starting with "<!DOCTYPE html>\n<html>\n <head>\n <title>Thomas</tit"; err=<nil>
attempt 3
2024/07/26 16:17:17 Unsolicited response received on idle HTTP channel starting with "<!DOCTYPE html>\n<html>\n <head>\n <title>Thomas</tit"; err=<nil>
attempt 4
2024/07/26 16:17:17 Unsolicited response received on idle HTTP channel starting with "<!DOCTYPE html>\n<html>\n <head>\n <title>Thomas</tit"; err=<nil>
attempt 5
2024/07/26 16:17:17 Unsolicited response received on idle HTTP channel starting with "<!DOCTYPE html>\n<html>\n <head>\n <title>Thomas</tit"; err=<nil>
attempt 6
attempt 7
2024/07/26 16:17:18 do: Head "http://localhost:8080": net/http: HTTP/1.x transport connection broken: malformed HTTP status code "html>"
exit status 1
What did you expect to see?
There should be no Unsolicited response received on idle HTTP channel starting with
messages, and the request should not fail with net/http: HTTP/1.x transport connection broken: malformed HTTP status code "html>"
.