From 57d1ee249dcdf46c54214d0636f235e5c62af213 Mon Sep 17 00:00:00 2001 From: Alexander Yastrebov Date: Sat, 16 Oct 2021 17:49:39 +0200 Subject: [PATCH] net/http: add Server.DisableGeneralOptionsHandler for custom handling of OPTIONS * Fixes #41773 --- api/next/41773.txt | 1 + src/net/http/serve_test.go | 31 +++++++++++++++++++++++++++++++ src/net/http/server.go | 6 +++++- 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 api/next/41773.txt diff --git a/api/next/41773.txt b/api/next/41773.txt new file mode 100644 index 0000000000..116596e73e --- /dev/null +++ b/api/next/41773.txt @@ -0,0 +1 @@ +pkg net/http, type Server struct, DisableGeneralOptionsHandler bool #41773 diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index f956e66c44..d28bfba759 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -3492,6 +3492,37 @@ func TestOptions(t *testing.T) { } } +func TestOptionsHandler(t *testing.T) { + rc := make(chan *Request, 1) + + ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) { + rc <- r + })) + ts.Config.DisableGeneralOptionsHandler = true + ts.Start() + defer ts.Close() + + conn, err := net.Dial("tcp", ts.Listener.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + + _, err = conn.Write([]byte("OPTIONS * HTTP/1.1\r\nHost: foo.com\r\n\r\n")) + if err != nil { + t.Fatal(err) + } + + select { + case got := <-rc: + if got.Method != "OPTIONS" || got.RequestURI != "*" { + t.Errorf("Expected OPTIONS * request, got %v", got) + } + case <-time.After(5 * time.Second): + t.Error("timeout") + } +} + // Tests regarding the ordering of Write, WriteHeader, Header, and // Flush calls. In Go 1.0, rw.WriteHeader immediately flushed the // (*response).header to the wire. In Go 1.1, the actual wire flush is diff --git a/src/net/http/server.go b/src/net/http/server.go index eedc4e9db9..47b6070e1a 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -2584,6 +2584,10 @@ type Server struct { Handler Handler // handler to invoke, http.DefaultServeMux if nil + // DisableGeneralOptionsHandler, if true, passes "OPTIONS *" requests to the Handler, + // otherwise responds with 200 OK and Content-Length: 0. + DisableGeneralOptionsHandler bool + // TLSConfig optionally provides a TLS configuration for use // by ServeTLS and ListenAndServeTLS. Note that this value is // cloned by ServeTLS and ListenAndServeTLS, so it's not @@ -2916,7 +2920,7 @@ func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { if handler == nil { handler = DefaultServeMux } - if req.RequestURI == "*" && req.Method == "OPTIONS" { + if !sh.srv.DisableGeneralOptionsHandler && req.RequestURI == "*" && req.Method == "OPTIONS" { handler = globalOptionsHandler{} }