github.com/ck00004/CobaltStrikeParser-Go@v1.0.14/lib/http/cgi/integration_test.go (about)

     1  // Copyright 2011 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  // Tests a Go CGI program running under a Go CGI host process.
     6  // Further, the two programs are the same binary, just checking
     7  // their environment to figure out what mode to run in.
     8  
     9  package cgi
    10  
    11  import (
    12  	"bytes"
    13  	"errors"
    14  	"fmt"
    15  	"internal/testenv"
    16  	"io"
    17  	"os"
    18  	"strings"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/ck00004/CobaltStrikeParser-Go/lib/url"
    23  
    24  	"github.com/ck00004/CobaltStrikeParser-Go/lib/http"
    25  	"github.com/ck00004/CobaltStrikeParser-Go/lib/http/httptest"
    26  )
    27  
    28  // This test is a CGI host (testing host.go) that runs its own binary
    29  // as a child process testing the other half of CGI (child.go).
    30  func TestHostingOurselves(t *testing.T) {
    31  	testenv.MustHaveExec(t)
    32  
    33  	h := &Handler{
    34  		Path: os.Args[0],
    35  		Root: "/test.go",
    36  		Args: []string{"-test.run=TestBeChildCGIProcess"},
    37  	}
    38  	expectedMap := map[string]string{
    39  		"test":                  "Hello CGI-in-CGI",
    40  		"param-a":               "b",
    41  		"param-foo":             "bar",
    42  		"env-GATEWAY_INTERFACE": "CGI/1.1",
    43  		"env-HTTP_HOST":         "example.com",
    44  		"env-PATH_INFO":         "",
    45  		"env-QUERY_STRING":      "foo=bar&a=b",
    46  		"env-REMOTE_ADDR":       "1.2.3.4",
    47  		"env-REMOTE_HOST":       "1.2.3.4",
    48  		"env-REMOTE_PORT":       "1234",
    49  		"env-REQUEST_METHOD":    "GET",
    50  		"env-REQUEST_URI":       "/test.go?foo=bar&a=b",
    51  		"env-SCRIPT_FILENAME":   os.Args[0],
    52  		"env-SCRIPT_NAME":       "/test.go",
    53  		"env-SERVER_NAME":       "example.com",
    54  		"env-SERVER_PORT":       "80",
    55  		"env-SERVER_SOFTWARE":   "go",
    56  	}
    57  	replay := runCgiTest(t, h, "GET /test.go?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n", expectedMap)
    58  
    59  	if expected, got := "text/plain; charset=utf-8", replay.Header().Get("Content-Type"); got != expected {
    60  		t.Errorf("got a Content-Type of %q; expected %q", got, expected)
    61  	}
    62  	if expected, got := "X-Test-Value", replay.Header().Get("X-Test-Header"); got != expected {
    63  		t.Errorf("got a X-Test-Header of %q; expected %q", got, expected)
    64  	}
    65  }
    66  
    67  type customWriterRecorder struct {
    68  	w io.Writer
    69  	*httptest.ResponseRecorder
    70  }
    71  
    72  func (r *customWriterRecorder) Write(p []byte) (n int, err error) {
    73  	return r.w.Write(p)
    74  }
    75  
    76  type limitWriter struct {
    77  	w io.Writer
    78  	n int
    79  }
    80  
    81  func (w *limitWriter) Write(p []byte) (n int, err error) {
    82  	if len(p) > w.n {
    83  		p = p[:w.n]
    84  	}
    85  	if len(p) > 0 {
    86  		n, err = w.w.Write(p)
    87  		w.n -= n
    88  	}
    89  	if w.n == 0 {
    90  		err = errors.New("past write limit")
    91  	}
    92  	return
    93  }
    94  
    95  // If there's an error copying the child's output to the parent, test
    96  // that we kill the child.
    97  func TestKillChildAfterCopyError(t *testing.T) {
    98  	testenv.MustHaveExec(t)
    99  
   100  	h := &Handler{
   101  		Path: os.Args[0],
   102  		Root: "/test.go",
   103  		Args: []string{"-test.run=TestBeChildCGIProcess"},
   104  	}
   105  	req, _ := http.NewRequest("GET", "http://example.com/test.cgi?write-forever=1", nil)
   106  	rec := httptest.NewRecorder()
   107  	var out bytes.Buffer
   108  	const writeLen = 50 << 10
   109  	rw := &customWriterRecorder{&limitWriter{&out, writeLen}, rec}
   110  
   111  	h.ServeHTTP(rw, req)
   112  	if out.Len() != writeLen || out.Bytes()[0] != 'a' {
   113  		t.Errorf("unexpected output: %q", out.Bytes())
   114  	}
   115  }
   116  
   117  // Test that a child handler writing only headers works.
   118  // golang.org/issue/7196
   119  func TestChildOnlyHeaders(t *testing.T) {
   120  	testenv.MustHaveExec(t)
   121  
   122  	h := &Handler{
   123  		Path: os.Args[0],
   124  		Root: "/test.go",
   125  		Args: []string{"-test.run=TestBeChildCGIProcess"},
   126  	}
   127  	expectedMap := map[string]string{
   128  		"_body": "",
   129  	}
   130  	replay := runCgiTest(t, h, "GET /test.go?no-body=1 HTTP/1.0\nHost: example.com\n\n", expectedMap)
   131  	if expected, got := "X-Test-Value", replay.Header().Get("X-Test-Header"); got != expected {
   132  		t.Errorf("got a X-Test-Header of %q; expected %q", got, expected)
   133  	}
   134  }
   135  
   136  // Test that a child handler does not receive a nil Request Body.
   137  // golang.org/issue/39190
   138  func TestNilRequestBody(t *testing.T) {
   139  	testenv.MustHaveExec(t)
   140  
   141  	h := &Handler{
   142  		Path: os.Args[0],
   143  		Root: "/test.go",
   144  		Args: []string{"-test.run=TestBeChildCGIProcess"},
   145  	}
   146  	expectedMap := map[string]string{
   147  		"nil-request-body": "false",
   148  	}
   149  	_ = runCgiTest(t, h, "POST /test.go?nil-request-body=1 HTTP/1.0\nHost: example.com\n\n", expectedMap)
   150  	_ = runCgiTest(t, h, "POST /test.go?nil-request-body=1 HTTP/1.0\nHost: example.com\nContent-Length: 0\n\n", expectedMap)
   151  }
   152  
   153  func TestChildContentType(t *testing.T) {
   154  	testenv.MustHaveExec(t)
   155  
   156  	h := &Handler{
   157  		Path: os.Args[0],
   158  		Root: "/test.go",
   159  		Args: []string{"-test.run=TestBeChildCGIProcess"},
   160  	}
   161  	var tests = []struct {
   162  		name   string
   163  		body   string
   164  		wantCT string
   165  	}{
   166  		{
   167  			name:   "no body",
   168  			wantCT: "text/plain; charset=utf-8",
   169  		},
   170  		{
   171  			name:   "html",
   172  			body:   "<html><head><title>test page</title></head><body>This is a body</body></html>",
   173  			wantCT: "text/html; charset=utf-8",
   174  		},
   175  		{
   176  			name:   "text",
   177  			body:   strings.Repeat("gopher", 86),
   178  			wantCT: "text/plain; charset=utf-8",
   179  		},
   180  		{
   181  			name:   "jpg",
   182  			body:   "\xFF\xD8\xFF" + strings.Repeat("B", 1024),
   183  			wantCT: "image/jpeg",
   184  		},
   185  	}
   186  	for _, tt := range tests {
   187  		t.Run(tt.name, func(t *testing.T) {
   188  			expectedMap := map[string]string{"_body": tt.body}
   189  			req := fmt.Sprintf("GET /test.go?exact-body=%s HTTP/1.0\nHost: example.com\n\n", url.QueryEscape(tt.body))
   190  			replay := runCgiTest(t, h, req, expectedMap)
   191  			if got := replay.Header().Get("Content-Type"); got != tt.wantCT {
   192  				t.Errorf("got a Content-Type of %q; expected it to start with %q", got, tt.wantCT)
   193  			}
   194  		})
   195  	}
   196  }
   197  
   198  // golang.org/issue/7198
   199  func Test500WithNoHeaders(t *testing.T)     { want500Test(t, "/immediate-disconnect") }
   200  func Test500WithNoContentType(t *testing.T) { want500Test(t, "/no-content-type") }
   201  func Test500WithEmptyHeaders(t *testing.T)  { want500Test(t, "/empty-headers") }
   202  
   203  func want500Test(t *testing.T, path string) {
   204  	h := &Handler{
   205  		Path: os.Args[0],
   206  		Root: "/test.go",
   207  		Args: []string{"-test.run=TestBeChildCGIProcess"},
   208  	}
   209  	expectedMap := map[string]string{
   210  		"_body": "",
   211  	}
   212  	replay := runCgiTest(t, h, "GET "+path+" HTTP/1.0\nHost: example.com\n\n", expectedMap)
   213  	if replay.Code != 500 {
   214  		t.Errorf("Got code %d; want 500", replay.Code)
   215  	}
   216  }
   217  
   218  type neverEnding byte
   219  
   220  func (b neverEnding) Read(p []byte) (n int, err error) {
   221  	for i := range p {
   222  		p[i] = byte(b)
   223  	}
   224  	return len(p), nil
   225  }
   226  
   227  // Note: not actually a test.
   228  func TestBeChildCGIProcess(t *testing.T) {
   229  	if os.Getenv("REQUEST_METHOD") == "" {
   230  		// Not in a CGI environment; skipping test.
   231  		return
   232  	}
   233  	switch os.Getenv("REQUEST_URI") {
   234  	case "/immediate-disconnect":
   235  		os.Exit(0)
   236  	case "/no-content-type":
   237  		fmt.Printf("Content-Length: 6\n\nHello\n")
   238  		os.Exit(0)
   239  	case "/empty-headers":
   240  		fmt.Printf("\nHello")
   241  		os.Exit(0)
   242  	}
   243  	Serve(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
   244  		if req.FormValue("nil-request-body") == "1" {
   245  			fmt.Fprintf(rw, "nil-request-body=%v\n", req.Body == nil)
   246  			return
   247  		}
   248  		rw.Header().Set("X-Test-Header", "X-Test-Value")
   249  		req.ParseForm()
   250  		if req.FormValue("no-body") == "1" {
   251  			return
   252  		}
   253  		if eb, ok := req.Form["exact-body"]; ok {
   254  			io.WriteString(rw, eb[0])
   255  			return
   256  		}
   257  		if req.FormValue("write-forever") == "1" {
   258  			io.Copy(rw, neverEnding('a'))
   259  			for {
   260  				time.Sleep(5 * time.Second) // hang forever, until killed
   261  			}
   262  		}
   263  		fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n")
   264  		for k, vv := range req.Form {
   265  			for _, v := range vv {
   266  				fmt.Fprintf(rw, "param-%s=%s\n", k, v)
   267  			}
   268  		}
   269  		for _, kv := range os.Environ() {
   270  			fmt.Fprintf(rw, "env-%s\n", kv)
   271  		}
   272  	}))
   273  	os.Exit(0)
   274  }