Skip to content

Commit

Permalink
Merge pull request #7 from BRUHItsABunny/feat/merge-upstream
Browse files Browse the repository at this point in the history
Feat/merge upstream
  • Loading branch information
BRUHItsABunny authored Dec 30, 2024
2 parents 8b48780 + 7469984 commit c43b283
Show file tree
Hide file tree
Showing 72 changed files with 6,059 additions and 1,491 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.21.8"
go-version: "1.22.2"

- name: Build
run: go build -v ./...
Expand Down
2 changes: 1 addition & 1 deletion UPSTREAM
Original file line number Diff line number Diff line change
@@ -1 +1 @@
go1.21.11
go1.22.2
146 changes: 146 additions & 0 deletions cgi/cgi_main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// 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"
"os"
"path"
"sort"
"strings"
"time"

http "github.com/ooni/oohttp"
)

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)
}
6 changes: 3 additions & 3 deletions cgi/child.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func envMap(env []string) map[string]string {
return m
}

// RequestFromMap creates an http.Request from CGI variables.
// RequestFromMap creates an [http.Request] from CGI variables.
// The returned Request's Body field is not populated.
func RequestFromMap(params map[string]string) (*http.Request, error) {
r := new(http.Request)
Expand Down Expand Up @@ -139,10 +139,10 @@ func RequestFromMap(params map[string]string) (*http.Request, error) {
return r, nil
}

// Serve executes the provided Handler on the currently active CGI
// Serve executes the provided [Handler] on the currently active CGI
// request, if any. If there's no current CGI environment
// an error is returned. The provided handler may be nil to use
// http.DefaultServeMux.
// [http.DefaultServeMux].
func Serve(handler http.Handler) error {
req, err := Request()
if err != nil {
Expand Down
14 changes: 5 additions & 9 deletions cgi/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,23 +115,19 @@ func removeLeadingDuplicates(env []string) (ret []string) {
}

func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
root := h.Root
if root == "" {
root = "/"
}

if len(req.TransferEncoding) > 0 && req.TransferEncoding[0] == "chunked" {
rw.WriteHeader(http.StatusBadRequest)
rw.Write([]byte("Chunked request bodies are not supported by CGI."))
return
}

pathInfo := req.URL.Path
if root != "/" && strings.HasPrefix(pathInfo, root) {
pathInfo = pathInfo[len(root):]
}
root := strings.TrimRight(h.Root, "/")
pathInfo := strings.TrimPrefix(req.URL.Path, root)

port := "80"
if req.TLS != nil {
port = "443"
}
if matches := trailingPort.FindStringSubmatch(req.Host); len(matches) != 0 {
port = matches[1]
}
Expand Down
Loading

0 comments on commit c43b283

Please sign in to comment.