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 for CGI (the child process perspective)
6
7package cgi
8
9import (
10	"bufio"
11	"bytes"
12	"net/http"
13	"net/http/httptest"
14	"strings"
15	"testing"
16)
17
18func TestRequest(t *testing.T) {
19	env := map[string]string{
20		"SERVER_PROTOCOL": "HTTP/1.1",
21		"REQUEST_METHOD":  "GET",
22		"HTTP_HOST":       "example.com",
23		"HTTP_REFERER":    "elsewhere",
24		"HTTP_USER_AGENT": "goclient",
25		"HTTP_FOO_BAR":    "baz",
26		"REQUEST_URI":     "/path?a=b",
27		"CONTENT_LENGTH":  "123",
28		"CONTENT_TYPE":    "text/xml",
29		"REMOTE_ADDR":     "5.6.7.8",
30		"REMOTE_PORT":     "54321",
31	}
32	req, err := RequestFromMap(env)
33	if err != nil {
34		t.Fatalf("RequestFromMap: %v", err)
35	}
36	if g, e := req.UserAgent(), "goclient"; e != g {
37		t.Errorf("expected UserAgent %q; got %q", e, g)
38	}
39	if g, e := req.Method, "GET"; e != g {
40		t.Errorf("expected Method %q; got %q", e, g)
41	}
42	if g, e := req.Header.Get("Content-Type"), "text/xml"; e != g {
43		t.Errorf("expected Content-Type %q; got %q", e, g)
44	}
45	if g, e := req.ContentLength, int64(123); e != g {
46		t.Errorf("expected ContentLength %d; got %d", e, g)
47	}
48	if g, e := req.Referer(), "elsewhere"; e != g {
49		t.Errorf("expected Referer %q; got %q", e, g)
50	}
51	if req.Header == nil {
52		t.Fatalf("unexpected nil Header")
53	}
54	if g, e := req.Header.Get("Foo-Bar"), "baz"; e != g {
55		t.Errorf("expected Foo-Bar %q; got %q", e, g)
56	}
57	if g, e := req.URL.String(), "http://example.com/path?a=b"; e != g {
58		t.Errorf("expected URL %q; got %q", e, g)
59	}
60	if g, e := req.FormValue("a"), "b"; e != g {
61		t.Errorf("expected FormValue(a) %q; got %q", e, g)
62	}
63	if req.Trailer == nil {
64		t.Errorf("unexpected nil Trailer")
65	}
66	if req.TLS != nil {
67		t.Errorf("expected nil TLS")
68	}
69	if e, g := "5.6.7.8:54321", req.RemoteAddr; e != g {
70		t.Errorf("RemoteAddr: got %q; want %q", g, e)
71	}
72}
73
74func TestRequestWithTLS(t *testing.T) {
75	env := map[string]string{
76		"SERVER_PROTOCOL": "HTTP/1.1",
77		"REQUEST_METHOD":  "GET",
78		"HTTP_HOST":       "example.com",
79		"HTTP_REFERER":    "elsewhere",
80		"REQUEST_URI":     "/path?a=b",
81		"CONTENT_TYPE":    "text/xml",
82		"HTTPS":           "1",
83		"REMOTE_ADDR":     "5.6.7.8",
84	}
85	req, err := RequestFromMap(env)
86	if err != nil {
87		t.Fatalf("RequestFromMap: %v", err)
88	}
89	if g, e := req.URL.String(), "https://example.com/path?a=b"; e != g {
90		t.Errorf("expected URL %q; got %q", e, g)
91	}
92	if req.TLS == nil {
93		t.Errorf("expected non-nil TLS")
94	}
95}
96
97func TestRequestWithoutHost(t *testing.T) {
98	env := map[string]string{
99		"SERVER_PROTOCOL": "HTTP/1.1",
100		"HTTP_HOST":       "",
101		"REQUEST_METHOD":  "GET",
102		"REQUEST_URI":     "/path?a=b",
103		"CONTENT_LENGTH":  "123",
104	}
105	req, err := RequestFromMap(env)
106	if err != nil {
107		t.Fatalf("RequestFromMap: %v", err)
108	}
109	if req.URL == nil {
110		t.Fatalf("unexpected nil URL")
111	}
112	if g, e := req.URL.String(), "/path?a=b"; e != g {
113		t.Errorf("URL = %q; want %q", g, e)
114	}
115}
116
117func TestRequestWithoutRequestURI(t *testing.T) {
118	env := map[string]string{
119		"SERVER_PROTOCOL": "HTTP/1.1",
120		"HTTP_HOST":       "example.com",
121		"REQUEST_METHOD":  "GET",
122		"SCRIPT_NAME":     "/dir/scriptname",
123		"PATH_INFO":       "/p1/p2",
124		"QUERY_STRING":    "a=1&b=2",
125		"CONTENT_LENGTH":  "123",
126	}
127	req, err := RequestFromMap(env)
128	if err != nil {
129		t.Fatalf("RequestFromMap: %v", err)
130	}
131	if req.URL == nil {
132		t.Fatalf("unexpected nil URL")
133	}
134	if g, e := req.URL.String(), "http://example.com/dir/scriptname/p1/p2?a=1&b=2"; e != g {
135		t.Errorf("URL = %q; want %q", g, e)
136	}
137}
138
139func TestRequestWithoutRemotePort(t *testing.T) {
140	env := map[string]string{
141		"SERVER_PROTOCOL": "HTTP/1.1",
142		"HTTP_HOST":       "example.com",
143		"REQUEST_METHOD":  "GET",
144		"REQUEST_URI":     "/path?a=b",
145		"CONTENT_LENGTH":  "123",
146		"REMOTE_ADDR":     "5.6.7.8",
147	}
148	req, err := RequestFromMap(env)
149	if err != nil {
150		t.Fatalf("RequestFromMap: %v", err)
151	}
152	if e, g := "5.6.7.8:0", req.RemoteAddr; e != g {
153		t.Errorf("RemoteAddr: got %q; want %q", g, e)
154	}
155}
156
157func TestResponse(t *testing.T) {
158	var tests = []struct {
159		name   string
160		body   string
161		wantCT string
162	}{
163		{
164			name:   "no body",
165			wantCT: "text/plain; charset=utf-8",
166		},
167		{
168			name:   "html",
169			body:   "<html><head><title>test page</title></head><body>This is a body</body></html>",
170			wantCT: "text/html; charset=utf-8",
171		},
172		{
173			name:   "text",
174			body:   strings.Repeat("gopher", 86),
175			wantCT: "text/plain; charset=utf-8",
176		},
177		{
178			name:   "jpg",
179			body:   "\xFF\xD8\xFF" + strings.Repeat("B", 1024),
180			wantCT: "image/jpeg",
181		},
182	}
183	for _, tt := range tests {
184		t.Run(tt.name, func(t *testing.T) {
185			var buf bytes.Buffer
186			resp := response{
187				req:    httptest.NewRequest("GET", "/", nil),
188				header: http.Header{},
189				bufw:   bufio.NewWriter(&buf),
190			}
191			n, err := resp.Write([]byte(tt.body))
192			if err != nil {
193				t.Errorf("Write: unexpected %v", err)
194			}
195			if want := len(tt.body); n != want {
196				t.Errorf("reported short Write: got %v want %v", n, want)
197			}
198			resp.writeCGIHeader(nil)
199			resp.Flush()
200			if got := resp.Header().Get("Content-Type"); got != tt.wantCT {
201				t.Errorf("wrong content-type: got %q, want %q", got, tt.wantCT)
202			}
203			if !bytes.HasSuffix(buf.Bytes(), []byte(tt.body)) {
204				t.Errorf("body was not correctly written")
205			}
206		})
207	}
208}
209