package http

import (
	"bufio"
	"context"
	"io"
	"net"
	stdhttp "net/http"
	"testing"
	"time"
)

func TestReviewR8AbsoluteHeaderTimeout(t *testing.T) {
	for _, wrapped := range []bool{false, true} {
		name := "standard-net-http"
		if wrapped {
			name = "silo-listener"
		}
		t.Run(name, func(t *testing.T) {
			handler := stdhttp.HandlerFunc(func(w stdhttp.ResponseWriter, r *stdhttp.Request) { w.WriteHeader(204) })
			var addr string
			if wrapped {
				srv := NewServer([]string{"127.0.0.1:0"}).UseHandler(handler).
					UseTCPOptions(TCPOptions{IdleTimeout: 2 * time.Second}).
					UseReadHeaderTimeout(100 * time.Millisecond).UseReadTimeout(2 * time.Second).UseWriteTimeout(2 * time.Second)
				serve, err := srv.Init(context.Background(), func(_ string, err error) { t.Error(err) })
				if err != nil {
					t.Fatal(err)
				}
				addr = srv.listener.Addr().String()
				go serve()
				defer srv.Server.Close()
			} else {
				ln, err := net.Listen("tcp", "127.0.0.1:0")
				if err != nil {
					t.Fatal(err)
				}
				srv := &stdhttp.Server{Handler: handler, ReadHeaderTimeout: 100 * time.Millisecond, ReadTimeout: 2 * time.Second, WriteTimeout: 2 * time.Second}
				addr = ln.Addr().String()
				go srv.Serve(ln)
				defer srv.Close()
			}
			conn, err := net.DialTimeout("tcp", addr, time.Second)
			if err != nil {
				t.Fatal(err)
			}
			defer conn.Close()
			conn.SetDeadline(time.Now().Add(3 * time.Second))
			if _, err := io.WriteString(conn, "GET / HTTP/1.1\r\nHost: localhost\r\nX-Slow: "); err != nil {
				t.Fatal(err)
			}
			time.Sleep(400 * time.Millisecond)
			io.WriteString(conn, "done\r\nConnection: close\r\n\r\n")
			resp, err := stdhttp.ReadResponse(bufio.NewReader(conn), nil)
			if err != nil {
				t.Logf("request rejected after header timeout: %v", err)
				return
			}
			defer resp.Body.Close()
			t.Errorf("100ms request-header deadline accepted header completed after 400ms: HTTP %d", resp.StatusCode)
		})
	}
}
