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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [net/] [http/] [fcgi/] [fcgi.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 implements the FastCGI protocol.
6
// Currently only the responder role is supported.
7
// The protocol is defined at http://www.fastcgi.com/drupal/node/6?q=node/22
8
package fcgi
9
 
10
// This file defines the raw protocol and some utilities used by the child and
11
// the host.
12
 
13
import (
14
        "bufio"
15
        "bytes"
16
        "encoding/binary"
17
        "errors"
18
        "io"
19
        "sync"
20
)
21
 
22
// recType is a record type, as defined by
23
// http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S8
24
type recType uint8
25
 
26
const (
27
        typeBeginRequest    recType = 1
28
        typeAbortRequest    recType = 2
29
        typeEndRequest      recType = 3
30
        typeParams          recType = 4
31
        typeStdin           recType = 5
32
        typeStdout          recType = 6
33
        typeStderr          recType = 7
34
        typeData            recType = 8
35
        typeGetValues       recType = 9
36
        typeGetValuesResult recType = 10
37
        typeUnknownType     recType = 11
38
)
39
 
40
// keep the connection between web-server and responder open after request
41
const flagKeepConn = 1
42
 
43
const (
44
        maxWrite = 65535 // maximum record body
45
        maxPad   = 255
46
)
47
 
48
const (
49
        roleResponder = iota + 1 // only Responders are implemented.
50
        roleAuthorizer
51
        roleFilter
52
)
53
 
54
const (
55
        statusRequestComplete = iota
56
        statusCantMultiplex
57
        statusOverloaded
58
        statusUnknownRole
59
)
60
 
61
const headerLen = 8
62
 
63
type header struct {
64
        Version       uint8
65
        Type          recType
66
        Id            uint16
67
        ContentLength uint16
68
        PaddingLength uint8
69
        Reserved      uint8
70
}
71
 
72
type beginRequest struct {
73
        role     uint16
74
        flags    uint8
75
        reserved [5]uint8
76
}
77
 
78
func (br *beginRequest) read(content []byte) error {
79
        if len(content) != 8 {
80
                return errors.New("fcgi: invalid begin request record")
81
        }
82
        br.role = binary.BigEndian.Uint16(content)
83
        br.flags = content[2]
84
        return nil
85
}
86
 
87
// for padding so we don't have to allocate all the time
88
// not synchronized because we don't care what the contents are
89
var pad [maxPad]byte
90
 
91
func (h *header) init(recType recType, reqId uint16, contentLength int) {
92
        h.Version = 1
93
        h.Type = recType
94
        h.Id = reqId
95
        h.ContentLength = uint16(contentLength)
96
        h.PaddingLength = uint8(-contentLength & 7)
97
}
98
 
99
// conn sends records over rwc
100
type conn struct {
101
        mutex sync.Mutex
102
        rwc   io.ReadWriteCloser
103
 
104
        // to avoid allocations
105
        buf bytes.Buffer
106
        h   header
107
}
108
 
109
func newConn(rwc io.ReadWriteCloser) *conn {
110
        return &conn{rwc: rwc}
111
}
112
 
113
func (c *conn) Close() error {
114
        c.mutex.Lock()
115
        defer c.mutex.Unlock()
116
        return c.rwc.Close()
117
}
118
 
119
type record struct {
120
        h   header
121
        buf [maxWrite + maxPad]byte
122
}
123
 
124
func (rec *record) read(r io.Reader) (err error) {
125
        if err = binary.Read(r, binary.BigEndian, &rec.h); err != nil {
126
                return err
127
        }
128
        if rec.h.Version != 1 {
129
                return errors.New("fcgi: invalid header version")
130
        }
131
        n := int(rec.h.ContentLength) + int(rec.h.PaddingLength)
132
        if _, err = io.ReadFull(r, rec.buf[:n]); err != nil {
133
                return err
134
        }
135
        return nil
136
}
137
 
138
func (r *record) content() []byte {
139
        return r.buf[:r.h.ContentLength]
140
}
141
 
142
// writeRecord writes and sends a single record.
143
func (c *conn) writeRecord(recType recType, reqId uint16, b []byte) error {
144
        c.mutex.Lock()
145
        defer c.mutex.Unlock()
146
        c.buf.Reset()
147
        c.h.init(recType, reqId, len(b))
148
        if err := binary.Write(&c.buf, binary.BigEndian, c.h); err != nil {
149
                return err
150
        }
151
        if _, err := c.buf.Write(b); err != nil {
152
                return err
153
        }
154
        if _, err := c.buf.Write(pad[:c.h.PaddingLength]); err != nil {
155
                return err
156
        }
157
        _, err := c.rwc.Write(c.buf.Bytes())
158
        return err
159
}
160
 
161
func (c *conn) writeBeginRequest(reqId uint16, role uint16, flags uint8) error {
162
        b := [8]byte{byte(role >> 8), byte(role), flags}
163
        return c.writeRecord(typeBeginRequest, reqId, b[:])
164
}
165
 
166
func (c *conn) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) error {
167
        b := make([]byte, 8)
168
        binary.BigEndian.PutUint32(b, uint32(appStatus))
169
        b[4] = protocolStatus
170
        return c.writeRecord(typeEndRequest, reqId, b)
171
}
172
 
173
func (c *conn) writePairs(recType recType, reqId uint16, pairs map[string]string) error {
174
        w := newWriter(c, recType, reqId)
175
        b := make([]byte, 8)
176
        for k, v := range pairs {
177
                n := encodeSize(b, uint32(len(k)))
178
                n += encodeSize(b[n:], uint32(len(v)))
179
                if _, err := w.Write(b[:n]); err != nil {
180
                        return err
181
                }
182
                if _, err := w.WriteString(k); err != nil {
183
                        return err
184
                }
185
                if _, err := w.WriteString(v); err != nil {
186
                        return err
187
                }
188
        }
189
        w.Close()
190
        return nil
191
}
192
 
193
func readSize(s []byte) (uint32, int) {
194
        if len(s) == 0 {
195
                return 0, 0
196
        }
197
        size, n := uint32(s[0]), 1
198
        if size&(1<<7) != 0 {
199
                if len(s) < 4 {
200
                        return 0, 0
201
                }
202
                n = 4
203
                size = binary.BigEndian.Uint32(s)
204
                size &^= 1 << 31
205
        }
206
        return size, n
207
}
208
 
209
func readString(s []byte, size uint32) string {
210
        if size > uint32(len(s)) {
211
                return ""
212
        }
213
        return string(s[:size])
214
}
215
 
216
func encodeSize(b []byte, size uint32) int {
217
        if size > 127 {
218
                size |= 1 << 31
219
                binary.BigEndian.PutUint32(b, size)
220
                return 4
221
        }
222
        b[0] = byte(size)
223
        return 1
224
}
225
 
226
// bufWriter encapsulates bufio.Writer but also closes the underlying stream when
227
// Closed.
228
type bufWriter struct {
229
        closer io.Closer
230
        *bufio.Writer
231
}
232
 
233
func (w *bufWriter) Close() error {
234
        if err := w.Writer.Flush(); err != nil {
235
                w.closer.Close()
236
                return err
237
        }
238
        return w.closer.Close()
239
}
240
 
241
func newWriter(c *conn, recType recType, reqId uint16) *bufWriter {
242
        s := &streamWriter{c: c, recType: recType, reqId: reqId}
243
        w := bufio.NewWriterSize(s, maxWrite)
244
        return &bufWriter{s, w}
245
}
246
 
247
// streamWriter abstracts out the separation of a stream into discrete records.
248
// It only writes maxWrite bytes at a time.
249
type streamWriter struct {
250
        c       *conn
251
        recType recType
252
        reqId   uint16
253
}
254
 
255
func (w *streamWriter) Write(p []byte) (int, error) {
256
        nn := 0
257
        for len(p) > 0 {
258
                n := len(p)
259
                if n > maxWrite {
260
                        n = maxWrite
261
                }
262
                if err := w.c.writeRecord(w.recType, w.reqId, p[:n]); err != nil {
263
                        return nn, err
264
                }
265
                nn += n
266
                p = p[n:]
267
        }
268
        return nn, nil
269
}
270
 
271
func (w *streamWriter) Close() error {
272
        // send empty record to close the stream
273
        return w.c.writeRecord(w.recType, w.reqId, nil)
274
}

powered by: WebSVN 2.1.0

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