| // 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" |
| "sort" |
| "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) |
| } |
| sort.Strings(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) |
| } |
| sort.Strings(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) |
| } |