OSDN Git Service

libgo: Update to weekly.2011-11-02.
[pf3gnuchains/gcc-fork.git] / libgo / go / http / fcgi / child.go
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 package fcgi
6
7 // This file implements FastCGI from the perspective of a child process.
8
9 import (
10         "fmt"
11         "http"
12         "http/cgi"
13         "io"
14         "net"
15         "os"
16         "time"
17 )
18
19 // request holds the state for an in-progress request. As soon as it's complete,
20 // it's converted to an http.Request.
21 type request struct {
22         pw        *io.PipeWriter
23         reqId     uint16
24         params    map[string]string
25         buf       [1024]byte
26         rawParams []byte
27         keepConn  bool
28 }
29
30 func newRequest(reqId uint16, flags uint8) *request {
31         r := &request{
32                 reqId:    reqId,
33                 params:   map[string]string{},
34                 keepConn: flags&flagKeepConn != 0,
35         }
36         r.rawParams = r.buf[:0]
37         return r
38 }
39
40 // parseParams reads an encoded []byte into Params.
41 func (r *request) parseParams() {
42         text := r.rawParams
43         r.rawParams = nil
44         for len(text) > 0 {
45                 keyLen, n := readSize(text)
46                 if n == 0 {
47                         return
48                 }
49                 text = text[n:]
50                 valLen, n := readSize(text)
51                 if n == 0 {
52                         return
53                 }
54                 text = text[n:]
55                 key := readString(text, keyLen)
56                 text = text[keyLen:]
57                 val := readString(text, valLen)
58                 text = text[valLen:]
59                 r.params[key] = val
60         }
61 }
62
63 // response implements http.ResponseWriter.
64 type response struct {
65         req         *request
66         header      http.Header
67         w           *bufWriter
68         wroteHeader bool
69 }
70
71 func newResponse(c *child, req *request) *response {
72         return &response{
73                 req:    req,
74                 header: http.Header{},
75                 w:      newWriter(c.conn, typeStdout, req.reqId),
76         }
77 }
78
79 func (r *response) Header() http.Header {
80         return r.header
81 }
82
83 func (r *response) Write(data []byte) (int, error) {
84         if !r.wroteHeader {
85                 r.WriteHeader(http.StatusOK)
86         }
87         return r.w.Write(data)
88 }
89
90 func (r *response) WriteHeader(code int) {
91         if r.wroteHeader {
92                 return
93         }
94         r.wroteHeader = true
95         if code == http.StatusNotModified {
96                 // Must not have body.
97                 r.header.Del("Content-Type")
98                 r.header.Del("Content-Length")
99                 r.header.Del("Transfer-Encoding")
100         } else if r.header.Get("Content-Type") == "" {
101                 r.header.Set("Content-Type", "text/html; charset=utf-8")
102         }
103
104         if r.header.Get("Date") == "" {
105                 r.header.Set("Date", time.UTC().Format(http.TimeFormat))
106         }
107
108         fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
109         r.header.Write(r.w)
110         r.w.WriteString("\r\n")
111 }
112
113 func (r *response) Flush() {
114         if !r.wroteHeader {
115                 r.WriteHeader(http.StatusOK)
116         }
117         r.w.Flush()
118 }
119
120 func (r *response) Close() error {
121         r.Flush()
122         return r.w.Close()
123 }
124
125 type child struct {
126         conn    *conn
127         handler http.Handler
128 }
129
130 func newChild(rwc net.Conn, handler http.Handler) *child {
131         return &child{newConn(rwc), handler}
132 }
133
134 func (c *child) serve() {
135         requests := map[uint16]*request{}
136         defer c.conn.Close()
137         var rec record
138         var br beginRequest
139         for {
140                 if err := rec.read(c.conn.rwc); err != nil {
141                         return
142                 }
143
144                 req, ok := requests[rec.h.Id]
145                 if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
146                         // The spec says to ignore unknown request IDs.
147                         continue
148                 }
149                 if ok && rec.h.Type == typeBeginRequest {
150                         // The server is trying to begin a request with the same ID
151                         // as an in-progress request. This is an error.
152                         return
153                 }
154
155                 switch rec.h.Type {
156                 case typeBeginRequest:
157                         if err := br.read(rec.content()); err != nil {
158                                 return
159                         }
160                         if br.role != roleResponder {
161                                 c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole)
162                                 break
163                         }
164                         requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
165                 case typeParams:
166                         // NOTE(eds): Technically a key-value pair can straddle the boundary
167                         // between two packets. We buffer until we've received all parameters.
168                         if len(rec.content()) > 0 {
169                                 req.rawParams = append(req.rawParams, rec.content()...)
170                                 break
171                         }
172                         req.parseParams()
173                 case typeStdin:
174                         content := rec.content()
175                         if req.pw == nil {
176                                 var body io.ReadCloser
177                                 if len(content) > 0 {
178                                         // body could be an io.LimitReader, but it shouldn't matter
179                                         // as long as both sides are behaving.
180                                         body, req.pw = io.Pipe()
181                                 }
182                                 go c.serveRequest(req, body)
183                         }
184                         if len(content) > 0 {
185                                 // TODO(eds): This blocks until the handler reads from the pipe.
186                                 // If the handler takes a long time, it might be a problem.
187                                 req.pw.Write(content)
188                         } else if req.pw != nil {
189                                 req.pw.Close()
190                         }
191                 case typeGetValues:
192                         values := map[string]string{"FCGI_MPXS_CONNS": "1"}
193                         c.conn.writePairs(0, typeGetValuesResult, values)
194                 case typeData:
195                         // If the filter role is implemented, read the data stream here.
196                 case typeAbortRequest:
197                         delete(requests, rec.h.Id)
198                         c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
199                         if !req.keepConn {
200                                 // connection will close upon return
201                                 return
202                         }
203                 default:
204                         b := make([]byte, 8)
205                         b[0] = rec.h.Type
206                         c.conn.writeRecord(typeUnknownType, 0, b)
207                 }
208         }
209 }
210
211 func (c *child) serveRequest(req *request, body io.ReadCloser) {
212         r := newResponse(c, req)
213         httpReq, err := cgi.RequestFromMap(req.params)
214         if err != nil {
215                 // there was an error reading the request
216                 r.WriteHeader(http.StatusInternalServerError)
217                 c.conn.writeRecord(typeStderr, req.reqId, []byte(err.Error()))
218         } else {
219                 httpReq.Body = body
220                 c.handler.ServeHTTP(r, httpReq)
221         }
222         if body != nil {
223                 body.Close()
224         }
225         r.Close()
226         c.conn.writeEndRequest(req.reqId, 0, statusRequestComplete)
227         if !req.keepConn {
228                 c.conn.Close()
229         }
230 }
231
232 // Serve accepts incoming FastCGI connections on the listener l, creating a new
233 // service thread for each. The service threads read requests and then call handler
234 // to reply to them.
235 // If l is nil, Serve accepts connections on stdin.
236 // If handler is nil, http.DefaultServeMux is used.
237 func Serve(l net.Listener, handler http.Handler) error {
238         if l == nil {
239                 var err error
240                 l, err = net.FileListener(os.Stdin)
241                 if err != nil {
242                         return err
243                 }
244                 defer l.Close()
245         }
246         if handler == nil {
247                 handler = http.DefaultServeMux
248         }
249         for {
250                 rw, err := l.Accept()
251                 if err != nil {
252                         return err
253                 }
254                 c := newChild(rw, handler)
255                 go c.serve()
256         }
257         panic("unreachable")
258 }