~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to src/pkg/net/http/fcgi/child.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-20 14:06:23 UTC
  • mfrom: (14.1.23 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130820140623-b414jfxi3m0qkmrq
Tags: 2:1.1.2-2ubuntu1
* Merge from Debian unstable (LP: #1211749, #1202027). Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - d/control,control.cross: Update Breaks/Replaces for Ubuntu
    versions to ensure smooth upgrades, regenerate control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
        "errors"
11
11
        "fmt"
12
12
        "io"
 
13
        "io/ioutil"
13
14
        "net"
14
15
        "net/http"
15
16
        "net/http/cgi"
16
17
        "os"
 
18
        "strings"
17
19
        "time"
18
20
)
19
21
 
152
154
 
153
155
var errCloseConn = errors.New("fcgi: connection should be closed")
154
156
 
 
157
var emptyBody = ioutil.NopCloser(strings.NewReader(""))
 
158
 
155
159
func (c *child) handleRecord(rec *record) error {
156
160
        req, ok := c.requests[rec.h.Id]
157
161
        if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
158
162
                // The spec says to ignore unknown request IDs.
159
163
                return nil
160
164
        }
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
165
 
167
166
        switch rec.h.Type {
168
167
        case typeBeginRequest:
 
168
                if req != nil {
 
169
                        // The server is trying to begin a request with the same ID
 
170
                        // as an in-progress request. This is an error.
 
171
                        return errors.New("fcgi: received ID that is already in-flight")
 
172
                }
 
173
 
169
174
                var br beginRequest
170
175
                if err := br.read(rec.content()); err != nil {
171
176
                        return err
175
180
                        return nil
176
181
                }
177
182
                c.requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
 
183
                return nil
178
184
        case typeParams:
179
185
                // NOTE(eds): Technically a key-value pair can straddle the boundary
180
186
                // between two packets. We buffer until we've received all parameters.
183
189
                        return nil
184
190
                }
185
191
                req.parseParams()
 
192
                return nil
186
193
        case typeStdin:
187
194
                content := rec.content()
188
195
                if req.pw == nil {
191
198
                                // body could be an io.LimitReader, but it shouldn't matter
192
199
                                // as long as both sides are behaving.
193
200
                                body, req.pw = io.Pipe()
 
201
                        } else {
 
202
                                body = emptyBody
194
203
                        }
195
204
                        go c.serveRequest(req, body)
196
205
                }
201
210
                } else if req.pw != nil {
202
211
                        req.pw.Close()
203
212
                }
 
213
                return nil
204
214
        case typeGetValues:
205
215
                values := map[string]string{"FCGI_MPXS_CONNS": "1"}
206
216
                c.conn.writePairs(typeGetValuesResult, 0, values)
 
217
                return nil
207
218
        case typeData:
208
219
                // If the filter role is implemented, read the data stream here.
 
220
                return nil
209
221
        case typeAbortRequest:
 
222
                println("abort")
210
223
                delete(c.requests, rec.h.Id)
211
224
                c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
212
225
                if !req.keepConn {
213
226
                        // connection will close upon return
214
227
                        return errCloseConn
215
228
                }
 
229
                return nil
216
230
        default:
217
231
                b := make([]byte, 8)
218
232
                b[0] = byte(rec.h.Type)
219
233
                c.conn.writeRecord(typeUnknownType, 0, b)
 
234
                return nil
220
235
        }
221
 
        return nil
222
236
}
223
237
 
224
238
func (c *child) serveRequest(req *request, body io.ReadCloser) {
232
246
                httpReq.Body = body
233
247
                c.handler.ServeHTTP(r, httpReq)
234
248
        }
235
 
        if body != nil {
236
 
                body.Close()
237
 
        }
238
249
        r.Close()
239
250
        c.conn.writeEndRequest(req.reqId, 0, statusRequestComplete)
 
251
 
 
252
        // Consume the entire body, so the host isn't still writing to
 
253
        // us when we close the socket below in the !keepConn case,
 
254
        // otherwise we'd send a RST. (golang.org/issue/4183)
 
255
        // TODO(bradfitz): also bound this copy in time. Or send
 
256
        // some sort of abort request to the host, so the host
 
257
        // can properly cut off the client sending all the data.
 
258
        // For now just bound it a little and
 
259
        io.CopyN(ioutil.Discard, body, 100<<20)
 
260
        body.Close()
 
261
 
240
262
        if !req.keepConn {
241
263
                c.conn.Close()
242
264
        }
267
289
                c := newChild(rw, handler)
268
290
                go c.serve()
269
291
        }
270
 
        panic("unreachable")
271
292
}