// Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package cgi import ( "fmt" "io" "net/http" "os" "path" "slices" "strings" "time" ) func cgiMain() { switch path.Join(os.Getenv("SCRIPT_NAME"), os.Getenv("PATH_INFO")) { case "/bar", "/test.cgi", "/myscript/bar", "/test.cgi/extrapath": testCGI() return } childCGIProcess() } // testCGI is a CGI program translated from a Perl program to complete host_test. // test cases in host_test should be provided by testCGI. func testCGI() { req, err := Request() if err != nil { panic(err) } err = req.ParseForm() if err != nil { panic(err) } params := req.Form if params.Get("loc") != "" { fmt.Printf("Location: %s\r\n\r\n", params.Get("loc")) return } fmt.Printf("Content-Type: text/html\r\n") fmt.Printf("X-CGI-Pid: %d\r\n", os.Getpid()) fmt.Printf("X-Test-Header: X-Test-Value\r\n") fmt.Printf("\r\n") if params.Get("writestderr") != "" { fmt.Fprintf(os.Stderr, "Hello, stderr!\n") } if params.Get("bigresponse") != "" { // 17 MB, for OS X: golang.org/issue/4958 line := strings.Repeat("A", 1024) for i := 0; i < 17*1024; i++ { fmt.Printf("%s\r\n", line) } return } fmt.Printf("test=Hello CGI\r\n") keys := make([]string, 0, len(params)) for k := range params { keys = append(keys, k) } slices.Sort(keys) for _, key := range keys { fmt.Printf("param-%s=%s\r\n", key, params.Get(key)) } envs := envMap(os.Environ()) keys = make([]string, 0, len(envs)) for k := range envs { keys = append(keys, k) } slices.Sort(keys) for _, key := range keys { fmt.Printf("env-%s=%s\r\n", key, envs[key]) } cwd, _ := os.Getwd() fmt.Printf("cwd=%s\r\n", cwd) } type neverEnding byte func (b neverEnding) Read(p []byte) (n int, err error) { for i := range p { p[i] = byte(b) } return len(p), nil } // childCGIProcess is used by integration_test to complete unit tests. func childCGIProcess() { if os.Getenv("REQUEST_METHOD") == "" { // Not in a CGI environment; skipping test. return } switch os.Getenv("REQUEST_URI") { case "/immediate-disconnect": os.Exit(0) case "/no-content-type": fmt.Printf("Content-Length: 6\n\nHello\n") os.Exit(0) case "/empty-headers": fmt.Printf("\nHello") os.Exit(0) } Serve(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { if req.FormValue("nil-request-body") == "1" { fmt.Fprintf(rw, "nil-request-body=%v\n", req.Body == nil) return } rw.Header().Set("X-Test-Header", "X-Test-Value") req.ParseForm() if req.FormValue("no-body") == "1" { return } if eb, ok := req.Form["exact-body"]; ok { io.WriteString(rw, eb[0]) return } if req.FormValue("write-forever") == "1" { io.Copy(rw, neverEnding('a')) for { time.Sleep(5 * time.Second) // hang forever, until killed } } fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n") for k, vv := range req.Form { for _, v := range vv { fmt.Fprintf(rw, "param-%s=%s\n", k, v) } } for _, kv := range os.Environ() { fmt.Fprintf(rw, "env-%s\n", kv) } })) os.Exit(0) }