9
9
package cgi
10
10
11
11
import (
12
+ "bytes"
13
+ "errors"
12
14
"fmt"
15
+ "io"
13
16
"net/http"
17
+ "net/http/httptest"
14
18
"os"
15
19
"testing"
20
+ "time"
16
21
)
17
22
18
23
// This test is a CGI host (testing host.go) that runs its own binary
@@ -51,7 +56,78 @@ func TestHostingOurselves(t *testing.T) {
51
56
}
52
57
}
53
58
54
- // Test that a child handler only writing headers works.
59
+ type customWriterRecorder struct {
60
+ w io.Writer
61
+ * httptest.ResponseRecorder
62
+ }
63
+
64
+ func (r * customWriterRecorder ) Write (p []byte ) (n int , err error ) {
65
+ return r .w .Write (p )
66
+ }
67
+
68
+ type limitWriter struct {
69
+ w io.Writer
70
+ n int
71
+ }
72
+
73
+ func (w * limitWriter ) Write (p []byte ) (n int , err error ) {
74
+ if len (p ) > w .n {
75
+ p = p [:w .n ]
76
+ }
77
+ if len (p ) > 0 {
78
+ n , err = w .w .Write (p )
79
+ w .n -= n
80
+ }
81
+ if w .n == 0 {
82
+ err = errors .New ("past write limit" )
83
+ }
84
+ return
85
+ }
86
+
87
+ // If there's an error copying the child's output to the parent, test
88
+ // that we kill the child.
89
+ func TestKillChildAfterCopyError (t * testing.T ) {
90
+ defer func () { testHookStartProcess = nil }()
91
+ proc := make (chan * os.Process , 1 )
92
+ testHookStartProcess = func (p * os.Process ) {
93
+ proc <- p
94
+ }
95
+
96
+ h := & Handler {
97
+ Path : os .Args [0 ],
98
+ Root : "/test.go" ,
99
+ Args : []string {"-test.run=TestBeChildCGIProcess" },
100
+ }
101
+ req , _ := http .NewRequest ("GET" , "http://example.com/test.cgi?write-forever=1" , nil )
102
+ rec := httptest .NewRecorder ()
103
+ var out bytes.Buffer
104
+ const writeLen = 50 << 10
105
+ rw := & customWriterRecorder {& limitWriter {& out , writeLen }, rec }
106
+
107
+ donec := make (chan bool , 1 )
108
+ go func () {
109
+ h .ServeHTTP (rw , req )
110
+ donec <- true
111
+ }()
112
+
113
+ select {
114
+ case <- donec :
115
+ if out .Len () != writeLen || out .Bytes ()[0 ] != 'a' {
116
+ t .Errorf ("unexpected output: %q" , out .Bytes ())
117
+ }
118
+ case <- time .After (5 * time .Second ):
119
+ t .Errorf ("timeout. ServeHTTP hung and didn't kill the child process?" )
120
+ select {
121
+ case p := <- proc :
122
+ p .Kill ()
123
+ t .Logf ("killed process" )
124
+ default :
125
+ t .Logf ("didn't kill process" )
126
+ }
127
+ }
128
+ }
129
+
130
+ // Test that a child handler writing only headers works.
55
131
func TestChildOnlyHeaders (t * testing.T ) {
56
132
h := & Handler {
57
133
Path : os .Args [0 ],
@@ -67,6 +143,15 @@ func TestChildOnlyHeaders(t *testing.T) {
67
143
}
68
144
}
69
145
146
+ type neverEnding byte
147
+
148
+ func (b neverEnding ) Read (p []byte ) (n int , err error ) {
149
+ for i := range p {
150
+ p [i ] = byte (b )
151
+ }
152
+ return len (p ), nil
153
+ }
154
+
70
155
// Note: not actually a test.
71
156
func TestBeChildCGIProcess (t * testing.T ) {
72
157
if os .Getenv ("REQUEST_METHOD" ) == "" {
@@ -79,6 +164,12 @@ func TestBeChildCGIProcess(t *testing.T) {
79
164
if req .FormValue ("no-body" ) == "1" {
80
165
return
81
166
}
167
+ if req .FormValue ("write-forever" ) == "1" {
168
+ io .Copy (rw , neverEnding ('a' ))
169
+ for {
170
+ time .Sleep (5 * time .Second ) // hang forever, until killed
171
+ }
172
+ }
82
173
fmt .Fprintf (rw , "test=Hello CGI-in-CGI\n " )
83
174
for k , vv := range req .Form {
84
175
for _ , v := range vv {
0 commit comments