Skip to content
Newer
Older
100644 279 lines (237 sloc) 6.03 KB
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
1 package web
2
3 import (
4 "bytes"
5 "bufio"
6 "encoding/binary"
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 28, 2009
7 "fmt"
8 "http"
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
9 "log"
10 "net"
c0bbacd More work on fcgi
Michael Hoisie authored Dec 28, 2009
11 "os"
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
12 )
13
14 const (
c0bbacd More work on fcgi
Michael Hoisie authored Dec 28, 2009
15 FcgiBeginRequest = iota + 1
16 FcgiAbortRequest
17 FcgiEndRequest
18 FcgiParams
19 FcgiStdin
20 FcgiStdout
21 FcgiStderr
22 FcgiData
23 FcgiGetValues
24 FcgiGetValuesResult
25 FcgiUnknownType
26 FcgiMaxType = FcgiUnknownType
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
27 )
28
c0bbacd More work on fcgi
Michael Hoisie authored Dec 28, 2009
29 const (
30 FcgiRequestComplete = iota
31 FcgiCantMpxConn
32 FcgiOverloaded
33 FcgiUnknownRole
34 )
35
36 type fcgiHeader struct {
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
37 Version uint8
38 Type uint8
39 RequestId uint16
40 ContentLength uint16
41 PaddingLength uint8
42 Reserved uint8
43 }
44
c0bbacd More work on fcgi
Michael Hoisie authored Dec 28, 2009
45 func (h fcgiHeader) bytes() []byte {
46 order := binary.BigEndian
47 buf := make([]byte, 8)
48 buf[0] = h.Version
49 buf[1] = h.Type
50 order.PutUint16(buf[2:4], h.RequestId)
51 order.PutUint16(buf[4:6], h.ContentLength)
52 buf[6] = h.PaddingLength
53 buf[7] = h.Reserved
54 return buf
55 }
56
57 type fcgiEndRequest struct {
58 appStatus uint32
59 protocolStatus uint8
60 reserved [3]uint8
61 }
62
63 func (er fcgiEndRequest) bytes() []byte {
64 buf := make([]byte, 8)
65 binary.BigEndian.PutUint32(buf, er.appStatus)
66 buf[4] = er.protocolStatus
67 return buf
68 }
69
70 type fcgiConn struct {
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
71 requestId uint16
72 fd net.Conn
73 headers map[string]string
74 wroteHeaders bool
c0bbacd More work on fcgi
Michael Hoisie authored Dec 28, 2009
75 }
76
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
77 func (conn *fcgiConn) fcgiWrite(data []byte) (err os.Error) {
78 l := len(data)
c0bbacd More work on fcgi
Michael Hoisie authored Dec 28, 2009
79 // round to the nearest 8
80 padding := make([]byte, uint8(-l&7))
81 hdr := fcgiHeader{
82 Version: 1,
83 Type: FcgiStdout,
84 RequestId: conn.requestId,
85 ContentLength: uint16(l),
86 PaddingLength: uint8(len(padding)),
87 }
88
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
89 //write the header
90 hdrBytes := hdr.bytes()
91 _, err = conn.fd.Write(hdrBytes)
92
93 if err != nil {
94 return err
95 }
96
97 _, err = conn.fd.Write(data)
98 if err != nil {
99 return err
100 }
101
102 _, err = conn.fd.Write(padding)
103 if err != nil {
104 return err
105 }
106
107 return err
108 }
109
110 func (conn *fcgiConn) Write(data []byte) (n int, err os.Error) {
111 var buf bytes.Buffer
112 if !conn.wroteHeaders {
113 conn.wroteHeaders = true
114 for k, v := range conn.headers {
115 buf.WriteString(k + ": " + v + "\r\n")
116 }
117 buf.WriteString("\r\n")
118 conn.fcgiWrite(buf.Bytes())
119 }
120
121 err = conn.fcgiWrite(data)
122
123 if err != nil {
124 return 0, err
125 }
126
127 return len(data), nil
128 }
129
130 func (conn *fcgiConn) WriteString(data string) {
131 var buf bytes.Buffer
132 buf.WriteString(data)
133 conn.Write(buf.Bytes())
134 }
c0bbacd More work on fcgi
Michael Hoisie authored Dec 28, 2009
135
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
136 func (conn *fcgiConn) StartResponse(status int) {
137 var buf bytes.Buffer
138 text := statusText[status]
139 fmt.Fprintf(&buf, "HTTP/1.1 %d %s\r\n", status, text)
140 conn.fcgiWrite(buf.Bytes())
c0bbacd More work on fcgi
Michael Hoisie authored Dec 28, 2009
141 }
142
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
143 func (conn *fcgiConn) SetHeader(hdr string, val string) {
144 conn.headers[hdr] = val
c0bbacd More work on fcgi
Michael Hoisie authored Dec 28, 2009
145 }
146
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
147 func (conn *fcgiConn) complete() {
c0bbacd More work on fcgi
Michael Hoisie authored Dec 28, 2009
148 content := fcgiEndRequest{appStatus: 200, protocolStatus: FcgiRequestComplete}.bytes()
149 l := len(content)
150
151 hdr := fcgiHeader{
152 Version: 1,
153 Type: FcgiEndRequest,
154 RequestId: uint16(conn.requestId),
155 ContentLength: uint16(l),
156 PaddingLength: 0,
157 }
158
159 conn.fd.Write(hdr.bytes())
160 conn.fd.Write(content)
161 }
162
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
163 func (conn *fcgiConn) Close() {}
164
165 func readFcgiParams(data []byte) map[string]string {
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
166 var params = make(map[string]string)
167
168 for idx := 0; len(data) > idx; {
169 var keySize int = int(data[idx])
170 if keySize>>7 == 0 {
171 idx += 1
172 } else {
173 binary.Read(bytes.NewBuffer(data[idx:idx+4]), binary.BigEndian, &keySize)
174 idx += 4
175 }
176
177 var valSize int = int(data[idx])
178 if valSize>>7 == 0 {
179 idx += 1
180 } else {
181 binary.Read(bytes.NewBuffer(data[idx:idx+4]), binary.BigEndian, &valSize)
182 idx += 4
183 }
184
185 key := data[idx : idx+keySize]
186 idx += keySize
187 val := data[idx : idx+valSize]
188 idx += valSize
189 params[string(key)] = string(val)
190 }
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
191
192 return params
193 }
194
195 func buildRequest(headers map[string]string) *Request {
196 method, _ := headers["REQUEST_METHOD"]
197 host, _ := headers["HTTP_HOST"]
198 path, _ := headers["REQUEST_URI"]
199 port, _ := headers["SERVER_PORT"]
200 proto, _ := headers["SERVER_PROTOCOL"]
201 rawurl := "http://" + host + ":" + port + path
202
203 url, _ := http.ParseURL(rawurl)
204 useragent, _ := headers["USER_AGENT"]
205
206 req := Request{Method: method,
207 RawURL: rawurl,
208 URL: url,
209 Proto: proto,
210 Host: host,
211 UserAgent: useragent,
212 Header: make(map[string]string),
213 }
214
215 return &req
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
216 }
217
218 func handleFcgiRequest(fd net.Conn) {
219
220 br := bufio.NewReader(fd)
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
221 var req *Request
d357ba5 test fcgi return values
Michael Hoisie authored Dec 28, 2009
222 var fc *fcgiConn
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
223 for {
c0bbacd More work on fcgi
Michael Hoisie authored Dec 28, 2009
224 var h fcgiHeader
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
225 err := binary.Read(br, binary.BigEndian, &h)
226 if err != nil {
227 log.Stderrf(err.String())
d357ba5 test fcgi return values
Michael Hoisie authored Dec 28, 2009
228 break
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
229 }
230 content := make([]byte, h.ContentLength)
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
231 br.Read(content)
232
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
233 //read padding
234 if h.PaddingLength > 0 {
235 padding := make([]byte, h.PaddingLength)
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
236 br.Read(padding)
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
237 }
238
239 switch h.Type {
c0bbacd More work on fcgi
Michael Hoisie authored Dec 28, 2009
240 case FcgiBeginRequest:
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
241 fc = &fcgiConn{h.RequestId, fd, make(map[string]string), false}
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
242 case FcgiParams:
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
243 if h.ContentLength > 0 {
244 params := readFcgiParams(content)
245 req = buildRequest(params)
246 }
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
247 case FcgiStdin:
2841237 Fastcgi is in a working state. It can run the examples as well as ser…
Michael Hoisie authored Dec 29, 2009
248 if h.ContentLength > 0 {
249 var buf bytes.Buffer
250 buf.Write(content)
251 req.Body = &buf
252 } else if h.ContentLength == 0 {
253 routeHandler(req, fc)
254 fc.complete()
255 }
9468865 Added very early (incomplete) implementation of fcgi
Michael Hoisie authored Dec 28, 2009
256 case FcgiData:
257 case FcgiAbortRequest:
258 }
259 }
260 }
261
262 func listenAndServeFcgi(addr string) {
263 l, err := net.Listen("tcp", addr)
264 if err != nil {
265 log.Stderrf(err.String())
266 return
267 }
268
269 for {
270 fd, err := l.Accept()
271 if err != nil {
272 log.Stderrf(err.String())
273 break
274 }
275 go handleFcgiRequest(fd)
276
277 }
278 }
Something went wrong with that request. Please try again.