OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [net/] [http/] [fcgi/] [child.go] - Blame information for rev 747

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.