Source file src/net/http/cgi/cgi_main.go

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package cgi
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"net/http"
    11  	"os"
    12  	"path"
    13  	"slices"
    14  	"strings"
    15  	"time"
    16  )
    17  
    18  func cgiMain() {
    19  	switch path.Join(os.Getenv("SCRIPT_NAME"), os.Getenv("PATH_INFO")) {
    20  	case "/bar", "/test.cgi", "/myscript/bar", "/test.cgi/extrapath":
    21  		testCGI()
    22  		return
    23  	}
    24  	childCGIProcess()
    25  }
    26  
    27  // testCGI is a CGI program translated from a Perl program to complete host_test.
    28  // test cases in host_test should be provided by testCGI.
    29  func testCGI() {
    30  	req, err := Request()
    31  	if err != nil {
    32  		panic(err)
    33  	}
    34  
    35  	err = req.ParseForm()
    36  	if err != nil {
    37  		panic(err)
    38  	}
    39  
    40  	params := req.Form
    41  	if params.Get("loc") != "" {
    42  		fmt.Printf("Location: %s\r\n\r\n", params.Get("loc"))
    43  		return
    44  	}
    45  
    46  	fmt.Printf("Content-Type: text/html\r\n")
    47  	fmt.Printf("X-CGI-Pid: %d\r\n", os.Getpid())
    48  	fmt.Printf("X-Test-Header: X-Test-Value\r\n")
    49  	fmt.Printf("\r\n")
    50  
    51  	if params.Get("writestderr") != "" {
    52  		fmt.Fprintf(os.Stderr, "Hello, stderr!\n")
    53  	}
    54  
    55  	if params.Get("bigresponse") != "" {
    56  		// 17 MB, for OS X: golang.org/issue/4958
    57  		line := strings.Repeat("A", 1024)
    58  		for i := 0; i < 17*1024; i++ {
    59  			fmt.Printf("%s\r\n", line)
    60  		}
    61  		return
    62  	}
    63  
    64  	fmt.Printf("test=Hello CGI\r\n")
    65  
    66  	keys := make([]string, 0, len(params))
    67  	for k := range params {
    68  		keys = append(keys, k)
    69  	}
    70  	slices.Sort(keys)
    71  	for _, key := range keys {
    72  		fmt.Printf("param-%s=%s\r\n", key, params.Get(key))
    73  	}
    74  
    75  	envs := envMap(os.Environ())
    76  	keys = make([]string, 0, len(envs))
    77  	for k := range envs {
    78  		keys = append(keys, k)
    79  	}
    80  	slices.Sort(keys)
    81  	for _, key := range keys {
    82  		fmt.Printf("env-%s=%s\r\n", key, envs[key])
    83  	}
    84  
    85  	cwd, _ := os.Getwd()
    86  	fmt.Printf("cwd=%s\r\n", cwd)
    87  }
    88  
    89  type neverEnding byte
    90  
    91  func (b neverEnding) Read(p []byte) (n int, err error) {
    92  	for i := range p {
    93  		p[i] = byte(b)
    94  	}
    95  	return len(p), nil
    96  }
    97  
    98  // childCGIProcess is used by integration_test to complete unit tests.
    99  func childCGIProcess() {
   100  	if os.Getenv("REQUEST_METHOD") == "" {
   101  		// Not in a CGI environment; skipping test.
   102  		return
   103  	}
   104  	switch os.Getenv("REQUEST_URI") {
   105  	case "/immediate-disconnect":
   106  		os.Exit(0)
   107  	case "/no-content-type":
   108  		fmt.Printf("Content-Length: 6\n\nHello\n")
   109  		os.Exit(0)
   110  	case "/empty-headers":
   111  		fmt.Printf("\nHello")
   112  		os.Exit(0)
   113  	}
   114  	Serve(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
   115  		if req.FormValue("nil-request-body") == "1" {
   116  			fmt.Fprintf(rw, "nil-request-body=%v\n", req.Body == nil)
   117  			return
   118  		}
   119  		rw.Header().Set("X-Test-Header", "X-Test-Value")
   120  		req.ParseForm()
   121  		if req.FormValue("no-body") == "1" {
   122  			return
   123  		}
   124  		if eb, ok := req.Form["exact-body"]; ok {
   125  			io.WriteString(rw, eb[0])
   126  			return
   127  		}
   128  		if req.FormValue("write-forever") == "1" {
   129  			io.Copy(rw, neverEnding('a'))
   130  			for {
   131  				time.Sleep(5 * time.Second) // hang forever, until killed
   132  			}
   133  		}
   134  		fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n")
   135  		for k, vv := range req.Form {
   136  			for _, v := range vv {
   137  				fmt.Fprintf(rw, "param-%s=%s\n", k, v)
   138  			}
   139  		}
   140  		for _, kv := range os.Environ() {
   141  			fmt.Fprintf(rw, "env-%s\n", kv)
   142  		}
   143  	}))
   144  	os.Exit(0)
   145  }
   146  

View as plain text