diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-08-03 16:54:30 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-08-03 16:54:30 +0200 |
commit | 28592ee1ea1f5cdffcf85472f9de0285d928cf12 (patch) | |
tree | 32944e18b23f7fe4a0818a694aa2a6dfb1835463 /src/pkg/http/cgi | |
parent | e836bee4716dc0d4d913537ad3ad1925a7ac32d0 (diff) | |
download | golang-upstream/59.tar.gz |
Imported Upstream version 59upstream/59
Diffstat (limited to 'src/pkg/http/cgi')
-rw-r--r-- | src/pkg/http/cgi/child.go | 11 | ||||
-rw-r--r-- | src/pkg/http/cgi/child_test.go | 8 | ||||
-rw-r--r-- | src/pkg/http/cgi/host.go | 44 | ||||
-rw-r--r-- | src/pkg/http/cgi/host_test.go | 78 | ||||
-rwxr-xr-x | src/pkg/http/cgi/testdata/test.cgi | 51 |
5 files changed, 153 insertions, 39 deletions
diff --git a/src/pkg/http/cgi/child.go b/src/pkg/http/cgi/child.go index e1ad7ad32..8b74d7054 100644 --- a/src/pkg/http/cgi/child.go +++ b/src/pkg/http/cgi/child.go @@ -45,13 +45,6 @@ func envMap(env []string) map[string]string { return m } -// These environment variables are manually copied into Request -var skipHeader = map[string]bool{ - "HTTP_HOST": true, - "HTTP_REFERER": true, - "HTTP_USER_AGENT": true, -} - // 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, os.Error) { @@ -73,8 +66,6 @@ func RequestFromMap(params map[string]string) (*http.Request, os.Error) { r.Header = http.Header{} r.Host = params["HTTP_HOST"] - r.Referer = params["HTTP_REFERER"] - r.UserAgent = params["HTTP_USER_AGENT"] if lenstr := params["CONTENT_LENGTH"]; lenstr != "" { clen, err := strconv.Atoi64(lenstr) @@ -90,7 +81,7 @@ func RequestFromMap(params map[string]string) (*http.Request, os.Error) { // Copy "HTTP_FOO_BAR" variables to "Foo-Bar" Headers for k, v := range params { - if !strings.HasPrefix(k, "HTTP_") || skipHeader[k] { + if !strings.HasPrefix(k, "HTTP_") || k == "HTTP_HOST" { continue } r.Header.Add(strings.Replace(k[5:], "_", "-", -1), v) diff --git a/src/pkg/http/cgi/child_test.go b/src/pkg/http/cgi/child_test.go index d12947814..eee043bc9 100644 --- a/src/pkg/http/cgi/child_test.go +++ b/src/pkg/http/cgi/child_test.go @@ -28,23 +28,19 @@ func TestRequest(t *testing.T) { if err != nil { t.Fatalf("RequestFromMap: %v", err) } - if g, e := req.UserAgent, "goclient"; e != g { + if g, e := req.UserAgent(), "goclient"; e != g { t.Errorf("expected UserAgent %q; got %q", e, g) } if g, e := req.Method, "GET"; e != g { t.Errorf("expected Method %q; got %q", e, g) } - if g, e := req.Header.Get("User-Agent"), ""; e != g { - // Tests that we don't put recognized headers in the map - t.Errorf("expected User-Agent %q; got %q", e, g) - } if g, e := req.Header.Get("Content-Type"), "text/xml"; e != g { t.Errorf("expected Content-Type %q; got %q", e, g) } if g, e := req.ContentLength, int64(123); e != g { t.Errorf("expected ContentLength %d; got %d", e, g) } - if g, e := req.Referer, "elsewhere"; e != g { + if g, e := req.Referer(), "elsewhere"; e != g { t.Errorf("expected Referer %q; got %q", e, g) } if req.Header == nil { diff --git a/src/pkg/http/cgi/host.go b/src/pkg/http/cgi/host.go index 7ab3f9247..059fc758e 100644 --- a/src/pkg/http/cgi/host.go +++ b/src/pkg/http/cgi/host.go @@ -16,7 +16,6 @@ package cgi import ( "bufio" - "bytes" "exec" "fmt" "http" @@ -47,6 +46,12 @@ type Handler struct { Path string // path to the CGI executable Root string // root URI prefix of handler or empty for "/" + // Dir specifies the CGI executable's working directory. + // If Dir is empty, the base directory of Path is used. + // If Path has no base directory, the current working + // directory is used. + Dir string + Env []string // extra environment variables to set, if any, as "key=value" InheritEnv []string // environment variables to inherit from host, as "key" Logger *log.Logger // optional log for errors or nil to use log.Print @@ -106,20 +111,13 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { env = append(env, "HTTPS=on") } - if len(req.Cookie) > 0 { - b := new(bytes.Buffer) - for idx, c := range req.Cookie { - if idx > 0 { - b.Write([]byte("; ")) - } - fmt.Fprintf(b, "%s=%s", c.Name, c.Value) - } - env = append(env, "HTTP_COOKIE="+b.String()) - } - for k, v := range req.Header { k = strings.Map(upperCaseAndUnderscore, k) - env = append(env, "HTTP_"+k+"="+strings.Join(v, ", ")) + joinStr := ", " + if k == "COOKIE" { + joinStr = "; " + } + env = append(env, "HTTP_"+k+"="+strings.Join(v, joinStr)) } if req.ContentLength > 0 { @@ -133,11 +131,11 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { env = append(env, h.Env...) } - path := os.Getenv("PATH") - if path == "" { - path = "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin" + envPath := os.Getenv("PATH") + if envPath == "" { + envPath = "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin" } - env = append(env, "PATH="+path) + env = append(env, "PATH="+envPath) for _, e := range h.InheritEnv { if v := os.Getenv(e); v != "" { @@ -151,7 +149,13 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } } - cwd, pathBase := filepath.Split(h.Path) + var cwd, path string + if h.Dir != "" { + path = h.Path + cwd = h.Dir + } else { + cwd, path = filepath.Split(h.Path) + } if cwd == "" { cwd = "." } @@ -162,7 +166,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } cmd := &exec.Cmd{ - Path: pathBase, + Path: path, Args: append([]string{h.Path}, h.Args...), Dir: cwd, Env: env, @@ -205,7 +209,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if len(line) == 0 { break } - parts := strings.Split(string(line), ":", 2) + parts := strings.SplitN(string(line), ":", 2) if len(parts) < 2 { h.printf("cgi: bogus header line: %s", string(line)) continue diff --git a/src/pkg/http/cgi/host_test.go b/src/pkg/http/cgi/host_test.go index bbdb715cf..b08d8bbf6 100644 --- a/src/pkg/http/cgi/host_test.go +++ b/src/pkg/http/cgi/host_test.go @@ -13,8 +13,10 @@ import ( "http" "http/httptest" "os" + "path/filepath" "strings" "testing" + "runtime" ) func newRequest(httpreq string) *http.Request { @@ -46,7 +48,7 @@ readlines: } linesRead++ trimmedLine := strings.TrimRight(line, "\r\n") - split := strings.Split(trimmedLine, "=", 2) + split := strings.SplitN(trimmedLine, "=", 2) if len(split) != 2 { t.Fatalf("Unexpected %d parts from invalid line number %v: %q; existing map=%v", len(split), linesRead, line, m) @@ -301,3 +303,77 @@ func TestInternalRedirect(t *testing.T) { } runCgiTest(t, h, "GET /test.cgi?loc=/foo HTTP/1.0\nHost: example.com\n\n", expectedMap) } + +func TestDirUnix(t *testing.T) { + if runtime.GOOS == "windows" { + return + } + + cwd, _ := os.Getwd() + h := &Handler{ + Path: "testdata/test.cgi", + Root: "/test.cgi", + Dir: cwd, + } + expectedMap := map[string]string{ + "cwd": cwd, + } + runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap) + + cwd, _ = os.Getwd() + cwd = filepath.Join(cwd, "testdata") + h = &Handler{ + Path: "testdata/test.cgi", + Root: "/test.cgi", + } + expectedMap = map[string]string{ + "cwd": cwd, + } + runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap) +} + +func TestDirWindows(t *testing.T) { + if runtime.GOOS != "windows" { + return + } + + cgifile, _ := filepath.Abs("testdata/test.cgi") + + var perl string + var err os.Error + perl, err = exec.LookPath("perl") + if err != nil { + return + } + perl, _ = filepath.Abs(perl) + + cwd, _ := os.Getwd() + h := &Handler{ + Path: perl, + Root: "/test.cgi", + Dir: cwd, + Args: []string{cgifile}, + Env: []string{"SCRIPT_FILENAME=" + cgifile}, + } + expectedMap := map[string]string{ + "cwd": cwd, + } + runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap) + + // If not specify Dir on windows, working directory should be + // base directory of perl. + cwd, _ = filepath.Split(perl) + if cwd != "" && cwd[len(cwd)-1] == filepath.Separator { + cwd = cwd[:len(cwd)-1] + } + h = &Handler{ + Path: perl, + Root: "/test.cgi", + Args: []string{cgifile}, + Env: []string{"SCRIPT_FILENAME=" + cgifile}, + } + expectedMap = map[string]string{ + "cwd": cwd, + } + runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap) +} diff --git a/src/pkg/http/cgi/testdata/test.cgi b/src/pkg/http/cgi/testdata/test.cgi index a1b2ff893..36c107f76 100755 --- a/src/pkg/http/cgi/testdata/test.cgi +++ b/src/pkg/http/cgi/testdata/test.cgi @@ -6,9 +6,9 @@ # Test script run as a child process under cgi_test.go use strict; -use CGI; +use Cwd; -my $q = CGI->new; +my $q = MiniCGI->new; my $params = $q->Vars; if ($params->{"loc"}) { @@ -39,3 +39,50 @@ foreach my $k (sort keys %ENV) { $clean_env =~ s/[\n\r]//g; print "env-$k=$clean_env\n"; } + +# NOTE: don't call getcwd() for windows. +# msys return /c/go/src/... not C:\go\... +my $dir; +if ($^O eq 'MSWin32' || $^O eq 'msys') { + my $cmd = $ENV{'COMSPEC'} || 'c:\\windows\\system32\\cmd.exe'; + $cmd =~ s!\\!/!g; + $dir = `$cmd /c cd`; + chomp $dir; +} else { + $dir = getcwd(); +} +print "cwd=$dir\n"; + + +# A minimal version of CGI.pm, for people without the perl-modules +# package installed. (CGI.pm used to be part of the Perl core, but +# some distros now bundle perl-base and perl-modules separately...) +package MiniCGI; + +sub new { + my $class = shift; + return bless {}, $class; +} + +sub Vars { + my $self = shift; + my $pairs; + if ($ENV{CONTENT_LENGTH}) { + $pairs = do { local $/; <STDIN> }; + } else { + $pairs = $ENV{QUERY_STRING}; + } + my $vars = {}; + foreach my $kv (split(/&/, $pairs)) { + my ($k, $v) = split(/=/, $kv, 2); + $vars->{_urldecode($k)} = _urldecode($v); + } + return $vars; +} + +sub _urldecode { + my $v = shift; + $v =~ tr/+/ /; + $v =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; + return $v; +} |