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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2009 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 httputil provides HTTP utility functions, complementing the
6
// more common ones in the net/http package.
7
package httputil
8
 
9
import (
10
        "bufio"
11
        "errors"
12
        "io"
13
        "net"
14
        "net/http"
15
        "net/textproto"
16
        "os"
17
        "sync"
18
)
19
 
20
var (
21
        ErrPersistEOF = &http.ProtocolError{ErrorString: "persistent connection closed"}
22
        ErrPipeline   = &http.ProtocolError{ErrorString: "pipeline error"}
23
)
24
 
25
// This is an API usage error - the local side is closed.
26
// ErrPersistEOF (above) reports that the remote side is closed.
27
var errClosed = errors.New("i/o operation on closed connection")
28
 
29
// A ServerConn reads requests and sends responses over an underlying
30
// connection, until the HTTP keepalive logic commands an end. ServerConn
31
// also allows hijacking the underlying connection by calling Hijack
32
// to regain control over the connection. ServerConn supports pipe-lining,
33
// i.e. requests can be read out of sync (but in the same order) while the
34
// respective responses are sent.
35
//
36
// ServerConn is low-level and should not be needed by most applications.
37
// See Server.
38
type ServerConn struct {
39
        lk              sync.Mutex // read-write protects the following fields
40
        c               net.Conn
41
        r               *bufio.Reader
42
        re, we          error // read/write errors
43
        lastbody        io.ReadCloser
44
        nread, nwritten int
45
        pipereq         map[*http.Request]uint
46
 
47
        pipe textproto.Pipeline
48
}
49
 
50
// NewServerConn returns a new ServerConn reading and writing c.  If r is not
51
// nil, it is the buffer to use when reading c.
52
func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
53
        if r == nil {
54
                r = bufio.NewReader(c)
55
        }
56
        return &ServerConn{c: c, r: r, pipereq: make(map[*http.Request]uint)}
57
}
58
 
59
// Hijack detaches the ServerConn and returns the underlying connection as well
60
// as the read-side bufio which may have some left over data. Hijack may be
61
// called before Read has signaled the end of the keep-alive logic. The user
62
// should not call Hijack while Read or Write is in progress.
63
func (sc *ServerConn) Hijack() (c net.Conn, r *bufio.Reader) {
64
        sc.lk.Lock()
65
        defer sc.lk.Unlock()
66
        c = sc.c
67
        r = sc.r
68
        sc.c = nil
69
        sc.r = nil
70
        return
71
}
72
 
73
// Close calls Hijack and then also closes the underlying connection
74
func (sc *ServerConn) Close() error {
75
        c, _ := sc.Hijack()
76
        if c != nil {
77
                return c.Close()
78
        }
79
        return nil
80
}
81
 
82
// Read returns the next request on the wire. An ErrPersistEOF is returned if
83
// it is gracefully determined that there are no more requests (e.g. after the
84
// first request on an HTTP/1.0 connection, or after a Connection:close on a
85
// HTTP/1.1 connection).
86
func (sc *ServerConn) Read() (req *http.Request, err error) {
87
 
88
        // Ensure ordered execution of Reads and Writes
89
        id := sc.pipe.Next()
90
        sc.pipe.StartRequest(id)
91
        defer func() {
92
                sc.pipe.EndRequest(id)
93
                if req == nil {
94
                        sc.pipe.StartResponse(id)
95
                        sc.pipe.EndResponse(id)
96
                } else {
97
                        // Remember the pipeline id of this request
98
                        sc.lk.Lock()
99
                        sc.pipereq[req] = id
100
                        sc.lk.Unlock()
101
                }
102
        }()
103
 
104
        sc.lk.Lock()
105
        if sc.we != nil { // no point receiving if write-side broken or closed
106
                defer sc.lk.Unlock()
107
                return nil, sc.we
108
        }
109
        if sc.re != nil {
110
                defer sc.lk.Unlock()
111
                return nil, sc.re
112
        }
113
        if sc.r == nil { // connection closed by user in the meantime
114
                defer sc.lk.Unlock()
115
                return nil, errClosed
116
        }
117
        r := sc.r
118
        lastbody := sc.lastbody
119
        sc.lastbody = nil
120
        sc.lk.Unlock()
121
 
122
        // Make sure body is fully consumed, even if user does not call body.Close
123
        if lastbody != nil {
124
                // body.Close is assumed to be idempotent and multiple calls to
125
                // it should return the error that its first invocation
126
                // returned.
127
                err = lastbody.Close()
128
                if err != nil {
129
                        sc.lk.Lock()
130
                        defer sc.lk.Unlock()
131
                        sc.re = err
132
                        return nil, err
133
                }
134
        }
135
 
136
        req, err = http.ReadRequest(r)
137
        sc.lk.Lock()
138
        defer sc.lk.Unlock()
139
        if err != nil {
140
                if err == io.ErrUnexpectedEOF {
141
                        // A close from the opposing client is treated as a
142
                        // graceful close, even if there was some unparse-able
143
                        // data before the close.
144
                        sc.re = ErrPersistEOF
145
                        return nil, sc.re
146
                } else {
147
                        sc.re = err
148
                        return req, err
149
                }
150
        }
151
        sc.lastbody = req.Body
152
        sc.nread++
153
        if req.Close {
154
                sc.re = ErrPersistEOF
155
                return req, sc.re
156
        }
157
        return req, err
158
}
159
 
160
// Pending returns the number of unanswered requests
161
// that have been received on the connection.
162
func (sc *ServerConn) Pending() int {
163
        sc.lk.Lock()
164
        defer sc.lk.Unlock()
165
        return sc.nread - sc.nwritten
166
}
167
 
168
// Write writes resp in response to req. To close the connection gracefully, set the
169
// Response.Close field to true. Write should be considered operational until
170
// it returns an error, regardless of any errors returned on the Read side.
171
func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
172
 
173
        // Retrieve the pipeline ID of this request/response pair
174
        sc.lk.Lock()
175
        id, ok := sc.pipereq[req]
176
        delete(sc.pipereq, req)
177
        if !ok {
178
                sc.lk.Unlock()
179
                return ErrPipeline
180
        }
181
        sc.lk.Unlock()
182
 
183
        // Ensure pipeline order
184
        sc.pipe.StartResponse(id)
185
        defer sc.pipe.EndResponse(id)
186
 
187
        sc.lk.Lock()
188
        if sc.we != nil {
189
                defer sc.lk.Unlock()
190
                return sc.we
191
        }
192
        if sc.c == nil { // connection closed by user in the meantime
193
                defer sc.lk.Unlock()
194
                return os.EBADF
195
        }
196
        c := sc.c
197
        if sc.nread <= sc.nwritten {
198
                defer sc.lk.Unlock()
199
                return errors.New("persist server pipe count")
200
        }
201
        if resp.Close {
202
                // After signaling a keep-alive close, any pipelined unread
203
                // requests will be lost. It is up to the user to drain them
204
                // before signaling.
205
                sc.re = ErrPersistEOF
206
        }
207
        sc.lk.Unlock()
208
 
209
        err := resp.Write(c)
210
        sc.lk.Lock()
211
        defer sc.lk.Unlock()
212
        if err != nil {
213
                sc.we = err
214
                return err
215
        }
216
        sc.nwritten++
217
 
218
        return nil
219
}
220
 
221
// A ClientConn sends request and receives headers over an underlying
222
// connection, while respecting the HTTP keepalive logic. ClientConn
223
// supports hijacking the connection calling Hijack to
224
// regain control of the underlying net.Conn and deal with it as desired.
225
//
226
// ClientConn is low-level and should not be needed by most applications.
227
// See Client.
228
type ClientConn struct {
229
        lk              sync.Mutex // read-write protects the following fields
230
        c               net.Conn
231
        r               *bufio.Reader
232
        re, we          error // read/write errors
233
        lastbody        io.ReadCloser
234
        nread, nwritten int
235
        pipereq         map[*http.Request]uint
236
 
237
        pipe     textproto.Pipeline
238
        writeReq func(*http.Request, io.Writer) error
239
}
240
 
241
// NewClientConn returns a new ClientConn reading and writing c.  If r is not
242
// nil, it is the buffer to use when reading c.
243
func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
244
        if r == nil {
245
                r = bufio.NewReader(c)
246
        }
247
        return &ClientConn{
248
                c:        c,
249
                r:        r,
250
                pipereq:  make(map[*http.Request]uint),
251
                writeReq: (*http.Request).Write,
252
        }
253
}
254
 
255
// NewProxyClientConn works like NewClientConn but writes Requests
256
// using Request's WriteProxy method.
257
func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
258
        cc := NewClientConn(c, r)
259
        cc.writeReq = (*http.Request).WriteProxy
260
        return cc
261
}
262
 
263
// Hijack detaches the ClientConn and returns the underlying connection as well
264
// as the read-side bufio which may have some left over data. Hijack may be
265
// called before the user or Read have signaled the end of the keep-alive
266
// logic. The user should not call Hijack while Read or Write is in progress.
267
func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader) {
268
        cc.lk.Lock()
269
        defer cc.lk.Unlock()
270
        c = cc.c
271
        r = cc.r
272
        cc.c = nil
273
        cc.r = nil
274
        return
275
}
276
 
277
// Close calls Hijack and then also closes the underlying connection
278
func (cc *ClientConn) Close() error {
279
        c, _ := cc.Hijack()
280
        if c != nil {
281
                return c.Close()
282
        }
283
        return nil
284
}
285
 
286
// Write writes a request. An ErrPersistEOF error is returned if the connection
287
// has been closed in an HTTP keepalive sense. If req.Close equals true, the
288
// keepalive connection is logically closed after this request and the opposing
289
// server is informed. An ErrUnexpectedEOF indicates the remote closed the
290
// underlying TCP connection, which is usually considered as graceful close.
291
func (cc *ClientConn) Write(req *http.Request) (err error) {
292
 
293
        // Ensure ordered execution of Writes
294
        id := cc.pipe.Next()
295
        cc.pipe.StartRequest(id)
296
        defer func() {
297
                cc.pipe.EndRequest(id)
298
                if err != nil {
299
                        cc.pipe.StartResponse(id)
300
                        cc.pipe.EndResponse(id)
301
                } else {
302
                        // Remember the pipeline id of this request
303
                        cc.lk.Lock()
304
                        cc.pipereq[req] = id
305
                        cc.lk.Unlock()
306
                }
307
        }()
308
 
309
        cc.lk.Lock()
310
        if cc.re != nil { // no point sending if read-side closed or broken
311
                defer cc.lk.Unlock()
312
                return cc.re
313
        }
314
        if cc.we != nil {
315
                defer cc.lk.Unlock()
316
                return cc.we
317
        }
318
        if cc.c == nil { // connection closed by user in the meantime
319
                defer cc.lk.Unlock()
320
                return errClosed
321
        }
322
        c := cc.c
323
        if req.Close {
324
                // We write the EOF to the write-side error, because there
325
                // still might be some pipelined reads
326
                cc.we = ErrPersistEOF
327
        }
328
        cc.lk.Unlock()
329
 
330
        err = cc.writeReq(req, c)
331
        cc.lk.Lock()
332
        defer cc.lk.Unlock()
333
        if err != nil {
334
                cc.we = err
335
                return err
336
        }
337
        cc.nwritten++
338
 
339
        return nil
340
}
341
 
342
// Pending returns the number of unanswered requests
343
// that have been sent on the connection.
344
func (cc *ClientConn) Pending() int {
345
        cc.lk.Lock()
346
        defer cc.lk.Unlock()
347
        return cc.nwritten - cc.nread
348
}
349
 
350
// Read reads the next response from the wire. A valid response might be
351
// returned together with an ErrPersistEOF, which means that the remote
352
// requested that this be the last request serviced. Read can be called
353
// concurrently with Write, but not with another Read.
354
func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
355
        // Retrieve the pipeline ID of this request/response pair
356
        cc.lk.Lock()
357
        id, ok := cc.pipereq[req]
358
        delete(cc.pipereq, req)
359
        if !ok {
360
                cc.lk.Unlock()
361
                return nil, ErrPipeline
362
        }
363
        cc.lk.Unlock()
364
 
365
        // Ensure pipeline order
366
        cc.pipe.StartResponse(id)
367
        defer cc.pipe.EndResponse(id)
368
 
369
        cc.lk.Lock()
370
        if cc.re != nil {
371
                defer cc.lk.Unlock()
372
                return nil, cc.re
373
        }
374
        if cc.r == nil { // connection closed by user in the meantime
375
                defer cc.lk.Unlock()
376
                return nil, errClosed
377
        }
378
        r := cc.r
379
        lastbody := cc.lastbody
380
        cc.lastbody = nil
381
        cc.lk.Unlock()
382
 
383
        // Make sure body is fully consumed, even if user does not call body.Close
384
        if lastbody != nil {
385
                // body.Close is assumed to be idempotent and multiple calls to
386
                // it should return the error that its first invokation
387
                // returned.
388
                err = lastbody.Close()
389
                if err != nil {
390
                        cc.lk.Lock()
391
                        defer cc.lk.Unlock()
392
                        cc.re = err
393
                        return nil, err
394
                }
395
        }
396
 
397
        resp, err = http.ReadResponse(r, req)
398
        cc.lk.Lock()
399
        defer cc.lk.Unlock()
400
        if err != nil {
401
                cc.re = err
402
                return resp, err
403
        }
404
        cc.lastbody = resp.Body
405
 
406
        cc.nread++
407
 
408
        if resp.Close {
409
                cc.re = ErrPersistEOF // don't send any more requests
410
                return resp, cc.re
411
        }
412
        return resp, err
413
}
414
 
415
// Do is convenience method that writes a request and reads a response.
416
func (cc *ClientConn) Do(req *http.Request) (resp *http.Response, err error) {
417
        err = cc.Write(req)
418
        if err != nil {
419
                return
420
        }
421
        return cc.Read(req)
422
}

powered by: WebSVN 2.1.0

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