1
1
package web
2
2
3
3
import (
4
- "bufio"
5
- "bytes"
6
- "encoding/binary"
7
- "errors"
8
- "fmt"
9
- "io"
10
- "io/ioutil"
11
4
"net"
12
- "net/http"
13
- "net/http/cgi"
14
- "strings"
5
+ "net/http/fcgi"
15
6
)
16
7
17
- const (
18
- fcgiBeginRequest = iota + 1
19
- fcgiAbortRequest
20
- fcgiEndRequest
21
- fcgiParams
22
- fcgiStdin
23
- fcgiStdout
24
- fcgiStderr
25
- fcgiData
26
- fcgiGetValues
27
- fcgiGetValuesResult
28
- fcgiUnknownType
29
- fcgiMaxType = fcgiUnknownType
30
- )
31
-
32
- const (
33
- fcgiRequestComplete = iota
34
- fcgiCantMpxConn
35
- fcgiOverloaded
36
- fcgiUnknownRole
37
- )
38
-
39
- type fcgiHeader struct {
40
- Version uint8
41
- Type uint8
42
- RequestId uint16
43
- ContentLength uint16
44
- PaddingLength uint8
45
- Reserved uint8
46
- }
47
-
48
- func (h fcgiHeader ) bytes () []byte {
49
- order := binary .BigEndian
50
- buf := make ([]byte , 8 )
51
- buf [0 ] = h .Version
52
- buf [1 ] = h .Type
53
- order .PutUint16 (buf [2 :4 ], h .RequestId )
54
- order .PutUint16 (buf [4 :6 ], h .ContentLength )
55
- buf [6 ] = h .PaddingLength
56
- buf [7 ] = h .Reserved
57
- return buf
58
- }
59
-
60
- func newFcgiRecord (typ int , requestId int , data []byte ) []byte {
61
- var record bytes.Buffer
62
- l := len (data )
63
- // round to the nearest 8
64
- padding := make ([]byte , uint8 (- l & 7 ))
65
- hdr := fcgiHeader {
66
- Version : 1 ,
67
- Type : uint8 (typ ),
68
- RequestId : uint16 (requestId ),
69
- ContentLength : uint16 (l ),
70
- PaddingLength : uint8 (len (padding )),
71
- }
72
-
73
- //write the header
74
- record .Write (hdr .bytes ())
75
- record .Write (data )
76
- record .Write (padding )
77
-
78
- return record .Bytes ()
79
- }
80
-
81
- type fcgiEndReq struct {
82
- appStatus uint32
83
- protocolStatus uint8
84
- reserved [3 ]uint8
85
- }
86
-
87
- func (er fcgiEndReq ) bytes () []byte {
88
- buf := make ([]byte , 8 )
89
- binary .BigEndian .PutUint32 (buf , er .appStatus )
90
- buf [4 ] = er .protocolStatus
91
- return buf
92
- }
93
-
94
- type fcgiConn struct {
95
- requestId uint16
96
- req * http.Request
97
- fd io.ReadWriteCloser
98
- headers http.Header
99
- wroteHeaders bool
100
- }
101
-
102
- func (conn * fcgiConn ) fcgiWrite (data []byte ) (err error ) {
103
- l := len (data )
104
- // round to the nearest 8
105
- padding := make ([]byte , uint8 (- l & 7 ))
106
- hdr := fcgiHeader {
107
- Version : 1 ,
108
- Type : fcgiStdout ,
109
- RequestId : conn .requestId ,
110
- ContentLength : uint16 (l ),
111
- PaddingLength : uint8 (len (padding )),
112
- }
113
-
114
- //write the header
115
- hdrBytes := hdr .bytes ()
116
- _ , err = conn .fd .Write (hdrBytes )
117
-
118
- if err != nil {
119
- return err
120
- }
121
-
122
- _ , err = conn .fd .Write (data )
123
- if err != nil {
124
- return err
125
- }
126
-
127
- _ , err = conn .fd .Write (padding )
128
- if err != nil {
129
- return err
130
- }
131
-
132
- return err
133
- }
134
-
135
- func (conn * fcgiConn ) Write (data []byte ) (n int , err error ) {
136
- if ! conn .wroteHeaders {
137
- conn .WriteHeader (200 )
138
- }
139
-
140
- if conn .req .Method == "HEAD" {
141
- return 0 , errors .New ("Body Not Allowed" )
142
- }
143
- err = conn .fcgiWrite (data )
144
- if err != nil {
145
- return 0 , err
146
- }
147
-
148
- return len (data ), nil
149
- }
150
-
151
- func (conn * fcgiConn ) WriteHeader (status int ) {
152
- if ! conn .wroteHeaders {
153
- conn .wroteHeaders = true
154
-
155
- var buf bytes.Buffer
156
- text := statusText [status ]
157
- fmt .Fprintf (& buf , "HTTP/1.1 %d %s\r \n " , status , text )
158
-
159
- for k , v := range conn .headers {
160
- for _ , i := range v {
161
- buf .WriteString (k + ": " + i + "\r \n " )
162
- }
163
- }
164
- buf .WriteString ("\r \n " )
165
- conn .fcgiWrite (buf .Bytes ())
166
- }
167
- }
168
-
169
- func (conn * fcgiConn ) Header () http.Header {
170
- return conn .headers
171
- }
172
-
173
- func (conn * fcgiConn ) complete () {
174
- content := fcgiEndReq {appStatus : 200 , protocolStatus : fcgiRequestComplete }.bytes ()
175
- l := len (content )
176
-
177
- hdr := fcgiHeader {
178
- Version : 1 ,
179
- Type : fcgiEndRequest ,
180
- RequestId : uint16 (conn .requestId ),
181
- ContentLength : uint16 (l ),
182
- PaddingLength : 0 ,
183
- }
184
-
185
- conn .fd .Write (hdr .bytes ())
186
- conn .fd .Write (content )
187
- conn .fd .Close ()
188
- }
189
-
190
- func (conn * fcgiConn ) Close () {}
191
-
192
- func readFcgiParamSize (data []byte , index int ) (int , int ) {
193
-
194
- var size int
195
- var shift = 0
196
-
197
- if data [index ]>> 7 == 0 {
198
- size = int (data [index ])
199
- shift = 1
200
- } else {
201
- var s uint32
202
- binary .Read (bytes .NewBuffer (data [index :index + 4 ]), binary .BigEndian , & s )
203
- s ^= 1 << 31
204
- size = int (s )
205
- shift = 4
206
- }
207
- return size , shift
208
-
209
- }
210
-
211
- //read the fcgi parameters contained in data, and store them in storage
212
- func readFcgiParams (data []byte , storage map [string ]string ) {
213
- for idx := 0 ; len (data ) > idx ; {
214
- keySize , shift := readFcgiParamSize (data , idx )
215
- idx += shift
216
- valSize , shift := readFcgiParamSize (data , idx )
217
- idx += shift
218
- key := data [idx : idx + keySize ]
219
- idx += keySize
220
- val := data [idx : idx + valSize ]
221
- idx += valSize
222
- storage [string (key )] = string (val )
223
- }
224
- }
225
-
226
- func (s * Server ) handleFcgiConnection (fd io.ReadWriteCloser ) {
227
- br := bufio .NewReader (fd )
228
- var req * http.Request
229
- var fc * fcgiConn
230
- var body bytes.Buffer
231
- headers := map [string ]string {}
232
-
233
- for {
234
- var h fcgiHeader
235
- err := binary .Read (br , binary .BigEndian , & h )
236
- if err == io .EOF {
237
- break
238
- }
239
- if err != nil {
240
- s .Logger .Println ("FCGI Error" , err .Error ())
241
- break
242
- }
243
- content := make ([]byte , h .ContentLength )
244
- _ , err = io .ReadFull (br , content )
245
- if err != nil {
246
- s .Logger .Println ("FCGI Error" , err .Error ())
247
- break
248
- }
249
-
250
- //read padding
251
- if h .PaddingLength > 0 {
252
- padding := make ([]byte , h .PaddingLength )
253
- _ , err = io .ReadFull (br , padding )
254
- if err != nil {
255
- s .Logger .Println ("FCGI Error" , err .Error ())
256
- break
257
- }
258
- }
259
-
260
- switch h .Type {
261
- case fcgiBeginRequest :
262
- fc = & fcgiConn {h .RequestId , req , fd , make (map [string ][]string ), false }
263
-
264
- case fcgiParams :
265
- if h .ContentLength > 0 {
266
- readFcgiParams (content , headers )
267
- }
268
- case fcgiStdin :
269
- if h .ContentLength > 0 {
270
- body .Write (content )
271
- } else if h .ContentLength == 0 {
272
-
273
- req , _ = cgi .RequestFromMap (headers )
274
- req .Body = ioutil .NopCloser (& body )
275
- fc .req = req
276
- s .routeHandler (req , fc )
277
- //we close the connection after processing
278
- //TODO: is there a way to keep it open for future requests?
279
- fc .complete ()
280
- return
281
- }
282
- case fcgiData :
283
- if h .ContentLength > 0 {
284
- body .Write (content )
285
- }
286
- case fcgiAbortRequest :
287
- }
288
- }
289
- }
290
-
291
8
func (s * Server ) listenAndServeFcgi (addr string ) error {
292
9
var l net.Listener
293
10
var err error
294
11
295
12
//if the path begins with a "/", assume it's a unix address
296
- if strings . HasPrefix ( addr , "/" ) {
13
+ if addr [ 0 ] == '/' {
297
14
l , err = net .Listen ("unix" , addr )
298
15
} else {
299
16
l , err = net .Listen ("tcp" , addr )
@@ -306,13 +23,5 @@ func (s *Server) listenAndServeFcgi(addr string) error {
306
23
s .Logger .Println ("FCGI listen error" , err .Error ())
307
24
return err
308
25
}
309
- for {
310
- fd , err := l .Accept ()
311
- if err != nil {
312
- s .Logger .Println ("FCGI accept error" , err .Error ())
313
- break
314
- }
315
- go s .handleFcgiConnection (fd )
316
- }
317
- return nil
26
+ return fcgi .Serve (s .l , s )
318
27
}
0 commit comments