using multistream muxer
* ID service stream * make the relay service use msmux * fix nc tests Note from jbenet: Maybe we should remove the old protocol/muxer and see what breaks. It shouldn't be used by anything now. License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com> Signed-off-by: Juan Batiz-Benet <juan@benet.ai>
Jeromy committed
Jun 17, 2015 at 09:19 UTC
de50b2156299829c000b8d2df493b4c46e3f24e9
43 files changed
+5351
-279
Godeps/Godeps.json
+13
-1
@@ -95,6 +95,10 @@
95
"ImportPath": "github.com/cryptix/mdns",
96
"Rev": "04ff72a32679d57d009c0ac0fc5c4cda10350bad"
97
},
98
+ {
99
+ "ImportPath": "github.com/docker/spdystream",
100
+ "Rev": "e372247595b2edd26f6d022288e97eed793d70a2"
101
+ },
102
{
103
"ImportPath": "github.com/dustin/go-humanize",
104
"Rev": "00897f070f09f194c26d65afae734ba4c32404e8"
@@ -220,7 +224,7 @@
224
},
225
{
226
"ImportPath": "github.com/jbenet/go-stream-muxer",
223
- "Rev": "4a97500beeb081571128d41d539787e137f18404"
227
+ "Rev": "e2e261765847234749629e0190fef193a4548303"
228
},
229
{
230
"ImportPath": "github.com/jbenet/go-temp-err-catcher",
@@ -334,6 +338,14 @@
338
"ImportPath": "github.com/whyrusleeping/go-metrics",
339
"Rev": "1cd8009604ec2238b5a71305a0ecd974066e0e16"
340
},
341
+ {
342
+ "ImportPath": "github.com/whyrusleeping/go-multiplex",
343
+ "Rev": "474b9aebeb391746f304ddf7c764a5da12319857"
344
+ },
345
+ {
346
+ "ImportPath": "github.com/whyrusleeping/go-multistream",
347
+ "Rev": "c9eea2e3be705b7cfd730351b510cfa12ca038f4"
348
+ },
349
{
350
"ImportPath": "github.com/whyrusleeping/multiaddr-filter",
351
"Rev": "9e26222151125ecd3fc1fd190179b6bdd55f5608"
Godeps/_workspace/src/github.com/chriscool/go-sleep/.gitignore
new
+1
@@ -0,0 +1 @@
1
+go-sleep
Godeps/_workspace/src/github.com/docker/spdystream/CONTRIBUTING.md
new
+13
@@ -0,0 +1,13 @@
1
+# Contributing to SpdyStream
2
+
3
+Want to hack on spdystream? Awesome! Here are instructions to get you
4
+started.
5
+
6
+SpdyStream is a part of the [Docker](https://docker.io) project, and follows
7
+the same rules and principles. If you're already familiar with the way
8
+Docker does things, you'll feel right at home.
9
+
10
+Otherwise, go read
11
+[Docker's contributions guidelines](https://github.com/dotcloud/docker/blob/master/CONTRIBUTING.md).
12
+
13
+Happy hacking!
Godeps/_workspace/src/github.com/docker/spdystream/LICENSE
new
+191
@@ -0,0 +1,191 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ Copyright 2014 Docker, Inc.
180
+
181
+ Licensed under the Apache License, Version 2.0 (the "License");
182
+ you may not use this file except in compliance with the License.
183
+ You may obtain a copy of the License at
184
+
185
+ http://www.apache.org/licenses/LICENSE-2.0
186
+
187
+ Unless required by applicable law or agreed to in writing, software
188
+ distributed under the License is distributed on an "AS IS" BASIS,
189
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190
+ See the License for the specific language governing permissions and
191
+ limitations under the License.
Godeps/_workspace/src/github.com/docker/spdystream/MAINTAINERS
new
+1
@@ -0,0 +1 @@
1
+Derek McGowan <derek@docker.com> (@dmcg)
Godeps/_workspace/src/github.com/docker/spdystream/README.md
new
+78
@@ -0,0 +1,78 @@
1
+# SpdyStream
2
+
3
+A multiplexed stream library using spdy
4
+
5
+## Usage
6
+
7
+Client example (connecting to mirroring server without auth)
8
+
9
+```go
10
+package main
11
+
12
+import (
13
+ "fmt"
14
+ "github.com/docker/spdystream"
15
+ "net"
16
+ "net/http"
17
+)
18
+
19
+func main() {
20
+ conn, err := net.Dial("tcp", "localhost:8080")
21
+ if err != nil {
22
+ panic(err)
23
+ }
24
+ spdyConn, err := spdystream.NewConnection(conn, false)
25
+ if err != nil {
26
+ panic(err)
27
+ }
28
+ go spdyConn.Serve(spdystream.NoOpStreamHandler)
29
+ stream, err := spdyConn.CreateStream(http.Header{}, nil, false)
30
+ if err != nil {
31
+ panic(err)
32
+ }
33
+
34
+ stream.Wait()
35
+
36
+ fmt.Fprint(stream, "Writing to stream")
37
+
38
+ buf := make([]byte, 25)
39
+ stream.Read(buf)
40
+ fmt.Println(string(buf))
41
+
42
+ stream.Close()
43
+}
44
+```
45
+
46
+Server example (mirroring server without auth)
47
+
48
+```go
49
+package main
50
+
51
+import (
52
+ "github.com/docker/spdystream"
53
+ "net"
54
+)
55
+
56
+func main() {
57
+ listener, err := net.Listen("tcp", "localhost:8080")
58
+ if err != nil {
59
+ panic(err)
60
+ }
61
+ for {
62
+ conn, err := listener.Accept()
63
+ if err != nil {
64
+ panic(err)
65
+ }
66
+ spdyConn, err := spdystream.NewConnection(conn, true)
67
+ if err != nil {
68
+ panic(err)
69
+ }
70
+ go spdyConn.Serve(spdystream.MirrorStreamHandler)
71
+ }
72
+}
73
+```
74
+
75
+## Copyright and license
76
+
77
+Code and documentation copyright 2013-2014 Docker, inc. Code released under the Apache 2.0 license.
78
+Docs released under Creative commons.
Godeps/_workspace/src/github.com/docker/spdystream/connection.go
new
+902
@@ -0,0 +1,902 @@
1
+package spdystream
2
+
3
+import (
4
+ "errors"
5
+ "fmt"
6
+ "io"
7
+ "net"
8
+ "net/http"
9
+ "sync"
10
+ "time"
11
+
12
+ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/docker/spdystream/spdy"
13
+)
14
+
15
+var (
16
+ ErrInvalidStreamId = errors.New("Invalid stream id")
17
+ ErrTimeout = errors.New("Timeout occured")
18
+ ErrReset = errors.New("Stream reset")
19
+ ErrWriteClosedStream = errors.New("Write on closed stream")
20
+)
21
+
22
+const (
23
+ FRAME_WORKERS = 5
24
+ QUEUE_SIZE = 50
25
+)
26
+
27
+type StreamHandler func(stream *Stream)
28
+
29
+type AuthHandler func(header http.Header, slot uint8, parent uint32) bool
30
+
31
+type idleAwareFramer struct {
32
+ f *spdy.Framer
33
+ conn *Connection
34
+ writeLock sync.Mutex
35
+ resetChan chan struct{}
36
+ setTimeoutChan chan time.Duration
37
+ timeout time.Duration
38
+}
39
+
40
+func newIdleAwareFramer(framer *spdy.Framer) *idleAwareFramer {
41
+ iaf := &idleAwareFramer{
42
+ f: framer,
43
+ resetChan: make(chan struct{}, 2),
44
+ setTimeoutChan: make(chan time.Duration),
45
+ }
46
+ return iaf
47
+}
48
+
49
+func (i *idleAwareFramer) monitor() {
50
+ var (
51
+ timer *time.Timer
52
+ expired <-chan time.Time
53
+ resetChan = i.resetChan
54
+ )
55
+Loop:
56
+ for {
57
+ select {
58
+ case timeout := <-i.setTimeoutChan:
59
+ i.timeout = timeout
60
+ if timeout == 0 {
61
+ if timer != nil {
62
+ timer.Stop()
63
+ }
64
+ } else {
65
+ if timer == nil {
66
+ timer = time.NewTimer(timeout)
67
+ expired = timer.C
68
+ } else {
69
+ timer.Reset(timeout)
70
+ }
71
+ }
72
+ case <-resetChan:
73
+ if timer != nil && i.timeout > 0 {
74
+ timer.Reset(i.timeout)
75
+ }
76
+ case <-expired:
77
+ i.conn.streamCond.L.Lock()
78
+ streams := i.conn.streams
79
+ i.conn.streams = make(map[spdy.StreamId]*Stream)
80
+ i.conn.streamCond.Broadcast()
81
+ i.conn.streamCond.L.Unlock()
82
+ go func() {
83
+ for _, stream := range streams {
84
+ stream.resetStream()
85
+ }
86
+ i.conn.Close()
87
+ }()
88
+ case <-i.conn.closeChan:
89
+ if timer != nil {
90
+ timer.Stop()
91
+ }
92
+
93
+ // Start a goroutine to drain resetChan. This is needed because we've seen
94
+ // some unit tests with large numbers of goroutines get into a situation
95
+ // where resetChan fills up, at least 1 call to Write() is still trying to
96
+ // send to resetChan, the connection gets closed, and this case statement
97
+ // attempts to grab the write lock that Write() already has, causing a
98
+ // deadlock.
99
+ //
100
+ // See https://github.com/docker/spdystream/issues/49 for more details.
101
+ go func() {
102
+ for _ = range resetChan {
103
+ }
104
+ }()
105
+
106
+ i.writeLock.Lock()
107
+ close(resetChan)
108
+ i.resetChan = nil
109
+ i.writeLock.Unlock()
110
+
111
+ break Loop
112
+ }
113
+ }
114
+
115
+ // Drain resetChan
116
+ for _ = range resetChan {
117
+ }
118
+}
119
+
120
+func (i *idleAwareFramer) WriteFrame(frame spdy.Frame) error {
121
+ i.writeLock.Lock()
122
+ defer i.writeLock.Unlock()
123
+ if i.resetChan == nil {
124
+ return io.EOF
125
+ }
126
+ err := i.f.WriteFrame(frame)
127
+ if err != nil {
128
+ return err
129
+ }
130
+
131
+ i.resetChan <- struct{}{}
132
+
133
+ return nil
134
+}
135
+
136
+func (i *idleAwareFramer) ReadFrame() (spdy.Frame, error) {
137
+ frame, err := i.f.ReadFrame()
138
+ if err != nil {
139
+ return nil, err
140
+ }
141
+
142
+ // resetChan should never be closed since it is only closed
143
+ // when the connection has closed its closeChan. This closure
144
+ // only occurs after all Reads have finished
145
+ // TODO (dmcgowan): refactor relationship into connection
146
+ i.resetChan <- struct{}{}
147
+
148
+ return frame, nil
149
+}
150
+
151
+type Connection struct {
152
+ conn net.Conn
153
+ framer *idleAwareFramer
154
+
155
+ closeChan chan bool
156
+ goneAway bool
157
+ lastStreamChan chan<- *Stream
158
+ goAwayTimeout time.Duration
159
+ closeTimeout time.Duration
160
+
161
+ streamLock *sync.RWMutex
162
+ streamCond *sync.Cond
163
+ streams map[spdy.StreamId]*Stream
164
+
165
+ nextIdLock sync.Mutex
166
+ receiveIdLock sync.Mutex
167
+ nextStreamId spdy.StreamId
168
+ receivedStreamId spdy.StreamId
169
+
170
+ pingIdLock sync.Mutex
171
+ pingId uint32
172
+ pingChans map[uint32]chan error
173
+
174
+ shutdownLock sync.Mutex
175
+ shutdownChan chan error
176
+ hasShutdown bool
177
+}
178
+
179
+// NewConnection creates a new spdy connection from an existing
180
+// network connection.
181
+func NewConnection(conn net.Conn, server bool) (*Connection, error) {
182
+ framer, framerErr := spdy.NewFramer(conn, conn)
183
+ if framerErr != nil {
184
+ return nil, framerErr
185
+ }
186
+ idleAwareFramer := newIdleAwareFramer(framer)
187
+ var sid spdy.StreamId
188
+ var rid spdy.StreamId
189
+ var pid uint32
190
+ if server {
191
+ sid = 2
192
+ rid = 1
193
+ pid = 2
194
+ } else {
195
+ sid = 1
196
+ rid = 2
197
+ pid = 1
198
+ }
199
+
200
+ streamLock := new(sync.RWMutex)
201
+ streamCond := sync.NewCond(streamLock)
202
+
203
+ session := &Connection{
204
+ conn: conn,
205
+ framer: idleAwareFramer,
206
+
207
+ closeChan: make(chan bool),
208
+ goAwayTimeout: time.Duration(0),
209
+ closeTimeout: time.Duration(0),
210
+
211
+ streamLock: streamLock,
212
+ streamCond: streamCond,
213
+ streams: make(map[spdy.StreamId]*Stream),
214
+ nextStreamId: sid,
215
+ receivedStreamId: rid,
216
+
217
+ pingId: pid,
218
+ pingChans: make(map[uint32]chan error),
219
+
220
+ shutdownChan: make(chan error),
221
+ }
222
+ idleAwareFramer.conn = session
223
+ go idleAwareFramer.monitor()
224
+
225
+ return session, nil
226
+}
227
+
228
+// Ping sends a ping frame across the connection and
229
+// returns the response time
230
+func (s *Connection) Ping() (time.Duration, error) {
231
+ pid := s.pingId
232
+ s.pingIdLock.Lock()
233
+ if s.pingId > 0x7ffffffe {
234
+ s.pingId = s.pingId - 0x7ffffffe
235
+ } else {
236
+ s.pingId = s.pingId + 2
237
+ }
238
+ s.pingIdLock.Unlock()
239
+ pingChan := make(chan error)
240
+ s.pingChans[pid] = pingChan
241
+ defer delete(s.pingChans, pid)
242
+
243
+ frame := &spdy.PingFrame{Id: pid}
244
+ startTime := time.Now()
245
+ writeErr := s.framer.WriteFrame(frame)
246
+ if writeErr != nil {
247
+ return time.Duration(0), writeErr
248
+ }
249
+ select {
250
+ case <-s.closeChan:
251
+ return time.Duration(0), errors.New("connection closed")
252
+ case err, ok := <-pingChan:
253
+ if ok && err != nil {
254
+ return time.Duration(0), err
255
+ }
256
+ break
257
+ }
258
+ return time.Now().Sub(startTime), nil
259
+}
260
+
261
+// Serve handles frames sent from the server, including reply frames
262
+// which are needed to fully initiate connections. Both clients and servers
263
+// should call Serve in a separate goroutine before creating streams.
264
+func (s *Connection) Serve(newHandler StreamHandler) {
265
+ // Parition queues to ensure stream frames are handled
266
+ // by the same worker, ensuring order is maintained
267
+ frameQueues := make([]*PriorityFrameQueue, FRAME_WORKERS)
268
+ for i := 0; i < FRAME_WORKERS; i++ {
269
+ frameQueues[i] = NewPriorityFrameQueue(QUEUE_SIZE)
270
+ // Ensure frame queue is drained when connection is closed
271
+ go func(frameQueue *PriorityFrameQueue) {
272
+ <-s.closeChan
273
+ frameQueue.Drain()
274
+ }(frameQueues[i])
275
+
276
+ go s.frameHandler(frameQueues[i], newHandler)
277
+ }
278
+
279
+ var partitionRoundRobin int
280
+ for {
281
+ readFrame, err := s.framer.ReadFrame()
282
+ if err != nil {
283
+ if err != io.EOF {
284
+ fmt.Errorf("frame read error: %s", err)
285
+ } else {
286
+ debugMessage("EOF received")
287
+ }
288
+ break
289
+ }
290
+ var priority uint8
291
+ var partition int
292
+ switch frame := readFrame.(type) {
293
+ case *spdy.SynStreamFrame:
294
+ if s.checkStreamFrame(frame) {
295
+ priority = frame.Priority
296
+ partition = int(frame.StreamId % FRAME_WORKERS)
297
+ debugMessage("(%p) Add stream frame: %d ", s, frame.StreamId)
298
+ s.addStreamFrame(frame)
299
+ } else {
300
+ debugMessage("(%p) Rejected stream frame: %d ", s, frame.StreamId)
301
+ continue
302
+ }
303
+ case *spdy.SynReplyFrame:
304
+ priority = s.getStreamPriority(frame.StreamId)
305
+ partition = int(frame.StreamId % FRAME_WORKERS)
306
+ case *spdy.DataFrame:
307
+ priority = s.getStreamPriority(frame.StreamId)
308
+ partition = int(frame.StreamId % FRAME_WORKERS)
309
+ case *spdy.RstStreamFrame:
310
+ priority = s.getStreamPriority(frame.StreamId)
311
+ partition = int(frame.StreamId % FRAME_WORKERS)
312
+ case *spdy.HeadersFrame:
313
+ priority = s.getStreamPriority(frame.StreamId)
314
+ partition = int(frame.StreamId % FRAME_WORKERS)
315
+ case *spdy.PingFrame:
316
+ priority = 0
317
+ partition = partitionRoundRobin
318
+ partitionRoundRobin = (partitionRoundRobin + 1) % FRAME_WORKERS
319
+ case *spdy.GoAwayFrame:
320
+ priority = 0
321
+ partition = partitionRoundRobin
322
+ partitionRoundRobin = (partitionRoundRobin + 1) % FRAME_WORKERS
323
+ default:
324
+ priority = 7
325
+ partition = partitionRoundRobin
326
+ partitionRoundRobin = (partitionRoundRobin + 1) % FRAME_WORKERS
327
+ }
328
+ frameQueues[partition].Push(readFrame, priority)
329
+ }
330
+ close(s.closeChan)
331
+
332
+ s.streamCond.L.Lock()
333
+ // notify streams that they're now closed, which will
334
+ // unblock any stream Read() calls
335
+ for _, stream := range s.streams {
336
+ stream.closeRemoteChannels()
337
+ }
338
+ s.streams = make(map[spdy.StreamId]*Stream)
339
+ s.streamCond.Broadcast()
340
+ s.streamCond.L.Unlock()
341
+}
342
+
343
+func (s *Connection) frameHandler(frameQueue *PriorityFrameQueue, newHandler StreamHandler) {
344
+ for {
345
+ popFrame := frameQueue.Pop()
346
+ if popFrame == nil {
347
+ return
348
+ }
349
+
350
+ var frameErr error
351
+ switch frame := popFrame.(type) {
352
+ case *spdy.SynStreamFrame:
353
+ frameErr = s.handleStreamFrame(frame, newHandler)
354
+ case *spdy.SynReplyFrame:
355
+ frameErr = s.handleReplyFrame(frame)
356
+ case *spdy.DataFrame:
357
+ frameErr = s.handleDataFrame(frame)
358
+ case *spdy.RstStreamFrame:
359
+ frameErr = s.handleResetFrame(frame)
360
+ case *spdy.HeadersFrame:
361
+ frameErr = s.handleHeaderFrame(frame)
362
+ case *spdy.PingFrame:
363
+ frameErr = s.handlePingFrame(frame)
364
+ case *spdy.GoAwayFrame:
365
+ frameErr = s.handleGoAwayFrame(frame)
366
+ default:
367
+ frameErr = fmt.Errorf("unhandled frame type: %T", frame)
368
+ }
369
+
370
+ if frameErr != nil {
371
+ fmt.Errorf("frame handling error: %s", frameErr)
372
+ }
373
+ }
374
+}
375
+
376
+func (s *Connection) getStreamPriority(streamId spdy.StreamId) uint8 {
377
+ stream, streamOk := s.getStream(streamId)
378
+ if !streamOk {
379
+ return 7
380
+ }
381
+ return stream.priority
382
+}
383
+
384
+func (s *Connection) addStreamFrame(frame *spdy.SynStreamFrame) {
385
+ var parent *Stream
386
+ if frame.AssociatedToStreamId != spdy.StreamId(0) {
387
+ parent, _ = s.getStream(frame.AssociatedToStreamId)
388
+ }
389
+
390
+ stream := &Stream{
391
+ streamId: frame.StreamId,
392
+ parent: parent,
393
+ conn: s,
394
+ startChan: make(chan error),
395
+ headers: frame.Headers,
396
+ finished: (frame.CFHeader.Flags & spdy.ControlFlagUnidirectional) != 0x00,
397
+ replyCond: sync.NewCond(new(sync.Mutex)),
398
+ dataChan: make(chan []byte),
399
+ headerChan: make(chan http.Header),
400
+ closeChan: make(chan bool),
401
+ }
402
+ if frame.CFHeader.Flags&spdy.ControlFlagFin != 0x00 {
403
+ stream.closeRemoteChannels()
404
+ }
405
+
406
+ s.addStream(stream)
407
+}
408
+
409
+// checkStreamFrame checks to see if a stream frame is allowed.
410
+// If the stream is invalid, then a reset frame with protocol error
411
+// will be returned.
412
+func (s *Connection) checkStreamFrame(frame *spdy.SynStreamFrame) bool {
413
+ s.receiveIdLock.Lock()
414
+ defer s.receiveIdLock.Unlock()
415
+ if s.goneAway {
416
+ return false
417
+ }
418
+ validationErr := s.validateStreamId(frame.StreamId)
419
+ if validationErr != nil {
420
+ go func() {
421
+ resetErr := s.sendResetFrame(spdy.ProtocolError, frame.StreamId)
422
+ if resetErr != nil {
423
+ fmt.Errorf("reset error: %s", resetErr)
424
+ }
425
+ }()
426
+ return false
427
+ }
428
+ return true
429
+}
430
+
431
+func (s *Connection) handleStreamFrame(frame *spdy.SynStreamFrame, newHandler StreamHandler) error {
432
+ stream, ok := s.getStream(frame.StreamId)
433
+ if !ok {
434
+ return fmt.Errorf("Missing stream: %d", frame.StreamId)
435
+ }
436
+
437
+ newHandler(stream)
438
+
439
+ return nil
440
+}
441
+
442
+func (s *Connection) handleReplyFrame(frame *spdy.SynReplyFrame) error {
443
+ debugMessage("(%p) Reply frame received for %d", s, frame.StreamId)
444
+ stream, streamOk := s.getStream(frame.StreamId)
445
+ if !streamOk {
446
+ debugMessage("Reply frame gone away for %d", frame.StreamId)
447
+ // Stream has already gone away
448
+ return nil
449
+ }
450
+ if stream.replied {
451
+ // Stream has already received reply
452
+ return nil
453
+ }
454
+ stream.replied = true
455
+
456
+ // TODO Check for error
457
+ if (frame.CFHeader.Flags & spdy.ControlFlagFin) != 0x00 {
458
+ s.remoteStreamFinish(stream)
459
+ }
460
+
461
+ close(stream.startChan)
462
+
463
+ return nil
464
+}
465
+
466
+func (s *Connection) handleResetFrame(frame *spdy.RstStreamFrame) error {
467
+ stream, streamOk := s.getStream(frame.StreamId)
468
+ if !streamOk {
469
+ // Stream has already been removed
470
+ return nil
471
+ }
472
+ s.removeStream(stream)
473
+ stream.closeRemoteChannels()
474
+
475
+ if !stream.replied {
476
+ stream.replied = true
477
+ stream.startChan <- ErrReset
478
+ close(stream.startChan)
479
+ }
480
+
481
+ stream.finishLock.Lock()
482
+ stream.finished = true
483
+ stream.finishLock.Unlock()
484
+
485
+ return nil
486
+}
487
+
488
+func (s *Connection) handleHeaderFrame(frame *spdy.HeadersFrame) error {
489
+ stream, streamOk := s.getStream(frame.StreamId)
490
+ if !streamOk {
491
+ // Stream has already gone away
492
+ return nil
493
+ }
494
+ if !stream.replied {
495
+ // No reply received...Protocol error?
496
+ return nil
497
+ }
498
+
499
+ // TODO limit headers while not blocking (use buffered chan or goroutine?)
500
+ select {
501
+ case <-stream.closeChan:
502
+ return nil
503
+ case stream.headerChan <- frame.Headers:
504
+ }
505
+
506
+ if (frame.CFHeader.Flags & spdy.ControlFlagFin) != 0x00 {
507
+ s.remoteStreamFinish(stream)
508
+ }
509
+
510
+ return nil
511
+}
512
+
513
+func (s *Connection) handleDataFrame(frame *spdy.DataFrame) error {
514
+ debugMessage("(%p) Data frame received for %d", s, frame.StreamId)
515
+ stream, streamOk := s.getStream(frame.StreamId)
516
+ if !streamOk {
517
+ debugMessage("Data frame gone away for %d", frame.StreamId)
518
+ // Stream has already gone away
519
+ return nil
520
+ }
521
+ if !stream.replied {
522
+ debugMessage("Data frame not replied %d", frame.StreamId)
523
+ // No reply received...Protocol error?
524
+ return nil
525
+ }
526
+
527
+ debugMessage("(%p) (%d) Data frame handling", stream, stream.streamId)
528
+ if len(frame.Data) > 0 {
529
+ stream.dataLock.RLock()
530
+ select {
531
+ case <-stream.closeChan:
532
+ debugMessage("(%p) (%d) Data frame not sent (stream shut down)", stream, stream.streamId)
533
+ case stream.dataChan <- frame.Data:
534
+ debugMessage("(%p) (%d) Data frame sent", stream, stream.streamId)
535
+ }
536
+ stream.dataLock.RUnlock()
537
+ }
538
+ if (frame.Flags & spdy.DataFlagFin) != 0x00 {
539
+ s.remoteStreamFinish(stream)
540
+ }
541
+ return nil
542
+}
543
+
544
+func (s *Connection) handlePingFrame(frame *spdy.PingFrame) error {
545
+ if s.pingId&0x01 != frame.Id&0x01 {
546
+ return s.framer.WriteFrame(frame)
547
+ }
548
+ pingChan, pingOk := s.pingChans[frame.Id]
549
+ if pingOk {
550
+ close(pingChan)
551
+ }
552
+ return nil
553
+}
554
+
555
+func (s *Connection) handleGoAwayFrame(frame *spdy.GoAwayFrame) error {
556
+ debugMessage("(%p) Go away received", s)
557
+ s.receiveIdLock.Lock()
558
+ if s.goneAway {
559
+ s.receiveIdLock.Unlock()
560
+ return nil
561
+ }
562
+ s.goneAway = true
563
+ s.receiveIdLock.Unlock()
564
+
565
+ if s.lastStreamChan != nil {
566
+ stream, _ := s.getStream(frame.LastGoodStreamId)
567
+ go func() {
568
+ s.lastStreamChan <- stream
569
+ }()
570
+ }
571
+
572
+ // Do not block frame handler waiting for closure
573
+ go s.shutdown(s.goAwayTimeout)
574
+
575
+ return nil
576
+}
577
+
578
+func (s *Connection) remoteStreamFinish(stream *Stream) {
579
+ stream.closeRemoteChannels()
580
+
581
+ stream.finishLock.Lock()
582
+ if stream.finished {
583
+ // Stream is fully closed, cleanup
584
+ s.removeStream(stream)
585
+ }
586
+ stream.finishLock.Unlock()
587
+}
588
+
589
+// CreateStream creates a new spdy stream using the parameters for
590
+// creating the stream frame. The stream frame will be sent upon
591
+// calling this function, however this function does not wait for
592
+// the reply frame. If waiting for the reply is desired, use
593
+// the stream Wait or WaitTimeout function on the stream returned
594
+// by this function.
595
+func (s *Connection) CreateStream(headers http.Header, parent *Stream, fin bool) (*Stream, error) {
596
+ streamId := s.getNextStreamId()
597
+ if streamId == 0 {
598
+ return nil, fmt.Errorf("Unable to get new stream id")
599
+ }
600
+
601
+ stream := &Stream{
602
+ streamId: streamId,
603
+ parent: parent,
604
+ conn: s,
605
+ startChan: make(chan error),
606
+ headers: headers,
607
+ dataChan: make(chan []byte),
608
+ headerChan: make(chan http.Header),
609
+ closeChan: make(chan bool),
610
+ }
611
+
612
+ debugMessage("(%p) (%p) Create stream", s, stream)
613
+
614
+ s.addStream(stream)
615
+
616
+ return stream, s.sendStream(stream, fin)
617
+}
618
+
619
+func (s *Connection) shutdown(closeTimeout time.Duration) {
620
+ // TODO Ensure this isn't called multiple times
621
+ s.shutdownLock.Lock()
622
+ if s.hasShutdown {
623
+ s.shutdownLock.Unlock()
624
+ return
625
+ }
626
+ s.hasShutdown = true
627
+ s.shutdownLock.Unlock()
628
+
629
+ var timeout <-chan time.Time
630
+ if closeTimeout > time.Duration(0) {
631
+ timeout = time.After(closeTimeout)
632
+ }
633
+ streamsClosed := make(chan bool)
634
+
635
+ go func() {
636
+ s.streamCond.L.Lock()
637
+ for len(s.streams) > 0 {
638
+ debugMessage("Streams opened: %d, %#v", len(s.streams), s.streams)
639
+ s.streamCond.Wait()
640
+ }
641
+ s.streamCond.L.Unlock()
642
+ close(streamsClosed)
643
+ }()
644
+
645
+ var err error
646
+ select {
647
+ case <-streamsClosed:
648
+ // No active streams, close should be safe
649
+ err = s.conn.Close()
650
+ case <-timeout:
651
+ // Force ungraceful close
652
+ err = s.conn.Close()
653
+ // Wait for cleanup to clear active streams
654
+ <-streamsClosed
655
+ }
656
+
657
+ if err != nil {
658
+ duration := 10 * time.Minute
659
+ time.AfterFunc(duration, func() {
660
+ select {
661
+ case err, ok := <-s.shutdownChan:
662
+ if ok {
663
+ fmt.Errorf("Unhandled close error after %s: %s", duration, err)
664
+ }
665
+ default:
666
+ }
667
+ })
668
+ s.shutdownChan <- err
669
+ }
670
+ close(s.shutdownChan)
671
+
672
+ return
673
+}
674
+
675
+// Closes spdy connection by sending GoAway frame and initiating shutdown
676
+func (s *Connection) Close() error {
677
+ s.receiveIdLock.Lock()
678
+ if s.goneAway {
679
+ s.receiveIdLock.Unlock()
680
+ return nil
681
+ }
682
+ s.goneAway = true
683
+ s.receiveIdLock.Unlock()
684
+
685
+ var lastStreamId spdy.StreamId
686
+ if s.receivedStreamId > 2 {
687
+ lastStreamId = s.receivedStreamId - 2
688
+ }
689
+
690
+ goAwayFrame := &spdy.GoAwayFrame{
691
+ LastGoodStreamId: lastStreamId,
692
+ Status: spdy.GoAwayOK,
693
+ }
694
+
695
+ err := s.framer.WriteFrame(goAwayFrame)
696
+ if err != nil {
697
+ return err
698
+ }
699
+
700
+ go s.shutdown(s.closeTimeout)
701
+
702
+ return nil
703
+}
704
+
705
+// CloseWait closes the connection and waits for shutdown
706
+// to finish. Note the underlying network Connection
707
+// is not closed until the end of shutdown.
708
+func (s *Connection) CloseWait() error {
709
+ closeErr := s.Close()
710
+ if closeErr != nil {
711
+ return closeErr
712
+ }
713
+ shutdownErr, ok := <-s.shutdownChan
714
+ if ok {
715
+ return shutdownErr
716
+ }
717
+ return nil
718
+}
719
+
720
+// Wait waits for the connection to finish shutdown or for
721
+// the wait timeout duration to expire. This needs to be
722
+// called either after Close has been called or the GOAWAYFRAME
723
+// has been received. If the wait timeout is 0, this function
724
+// will block until shutdown finishes. If wait is never called
725
+// and a shutdown error occurs, that error will be logged as an
726
+// unhandled error.
727
+func (s *Connection) Wait(waitTimeout time.Duration) error {
728
+ var timeout <-chan time.Time
729
+ if waitTimeout > time.Duration(0) {
730
+ timeout = time.After(waitTimeout)
731
+ }
732
+
733
+ select {
734
+ case err, ok := <-s.shutdownChan:
735
+ if ok {
736
+ return err
737
+ }
738
+ case <-timeout:
739
+ return ErrTimeout
740
+ }
741
+ return nil
742
+}
743
+
744
+// NotifyClose registers a channel to be called when the remote
745
+// peer inidicates connection closure. The last stream to be
746
+// received by the remote will be sent on the channel. The notify
747
+// timeout will determine the duration between go away received
748
+// and the connection being closed.
749
+func (s *Connection) NotifyClose(c chan<- *Stream, timeout time.Duration) {
750
+ s.goAwayTimeout = timeout
751
+ s.lastStreamChan = c
752
+}
753
+
754
+// SetCloseTimeout sets the amount of time close will wait for
755
+// streams to finish before terminating the underlying network
756
+// connection. Setting the timeout to 0 will cause close to
757
+// wait forever, which is the default.
758
+func (s *Connection) SetCloseTimeout(timeout time.Duration) {
759
+ s.closeTimeout = timeout
760
+}
761
+
762
+// SetIdleTimeout sets the amount of time the connection may sit idle before
763
+// it is forcefully terminated.
764
+func (s *Connection) SetIdleTimeout(timeout time.Duration) {
765
+ s.framer.setTimeoutChan <- timeout
766
+}
767
+
768
+func (s *Connection) sendHeaders(headers http.Header, stream *Stream, fin bool) error {
769
+ var flags spdy.ControlFlags
770
+ if fin {
771
+ flags = spdy.ControlFlagFin
772
+ }
773
+
774
+ headerFrame := &spdy.HeadersFrame{
775
+ StreamId: stream.streamId,
776
+ Headers: headers,
777
+ CFHeader: spdy.ControlFrameHeader{Flags: flags},
778
+ }
779
+
780
+ return s.framer.WriteFrame(headerFrame)
781
+}
782
+
783
+func (s *Connection) sendReply(headers http.Header, stream *Stream, fin bool) error {
784
+ var flags spdy.ControlFlags
785
+ if fin {
786
+ flags = spdy.ControlFlagFin
787
+ }
788
+
789
+ replyFrame := &spdy.SynReplyFrame{
790
+ StreamId: stream.streamId,
791
+ Headers: headers,
792
+ CFHeader: spdy.ControlFrameHeader{Flags: flags},
793
+ }
794
+
795
+ return s.framer.WriteFrame(replyFrame)
796
+}
797
+
798
+func (s *Connection) sendResetFrame(status spdy.RstStreamStatus, streamId spdy.StreamId) error {
799
+ resetFrame := &spdy.RstStreamFrame{
800
+ StreamId: streamId,
801
+ Status: status,
802
+ }
803
+
804
+ return s.framer.WriteFrame(resetFrame)
805
+}
806
+
807
+func (s *Connection) sendReset(status spdy.RstStreamStatus, stream *Stream) error {
808
+ return s.sendResetFrame(status, stream.streamId)
809
+}
810
+
811
+func (s *Connection) sendStream(stream *Stream, fin bool) error {
812
+ var flags spdy.ControlFlags
813
+ if fin {
814
+ flags = spdy.ControlFlagFin
815
+ stream.finished = true
816
+ }
817
+
818
+ var parentId spdy.StreamId
819
+ if stream.parent != nil {
820
+ parentId = stream.parent.streamId
821
+ }
822
+
823
+ streamFrame := &spdy.SynStreamFrame{
824
+ StreamId: spdy.StreamId(stream.streamId),
825
+ AssociatedToStreamId: spdy.StreamId(parentId),
826
+ Headers: stream.headers,
827
+ CFHeader: spdy.ControlFrameHeader{Flags: flags},
828
+ }
829
+
830
+ return s.framer.WriteFrame(streamFrame)
831
+}
832
+
833
+// getNextStreamId returns the next sequential id
834
+// every call should produce a unique value or an error
835
+func (s *Connection) getNextStreamId() spdy.StreamId {
836
+ s.nextIdLock.Lock()
837
+ defer s.nextIdLock.Unlock()
838
+ sid := s.nextStreamId
839
+ if sid > 0x7fffffff {
840
+ return 0
841
+ }
842
+ s.nextStreamId = s.nextStreamId + 2
843
+ return sid
844
+}
845
+
846
+// PeekNextStreamId returns the next sequential id and keeps the next id untouched
847
+func (s *Connection) PeekNextStreamId() spdy.StreamId {
848
+ sid := s.nextStreamId
849
+ return sid
850
+}
851
+
852
+func (s *Connection) validateStreamId(rid spdy.StreamId) error {
853
+ if rid > 0x7fffffff || rid < s.receivedStreamId {
854
+ return ErrInvalidStreamId
855
+ }
856
+ s.receivedStreamId = rid + 2
857
+ return nil
858
+}
859
+
860
+func (s *Connection) addStream(stream *Stream) {
861
+ s.streamCond.L.Lock()
862
+ s.streams[stream.streamId] = stream
863
+ debugMessage("(%p) (%p) Stream added, broadcasting: %d", s, stream, stream.streamId)
864
+ s.streamCond.Broadcast()
865
+ s.streamCond.L.Unlock()
866
+}
867
+
868
+func (s *Connection) removeStream(stream *Stream) {
869
+ s.streamCond.L.Lock()
870
+ delete(s.streams, stream.streamId)
871
+ debugMessage("Stream removed, broadcasting: %d", stream.streamId)
872
+ s.streamCond.Broadcast()
873
+ s.streamCond.L.Unlock()
874
+}
875
+
876
+func (s *Connection) getStream(streamId spdy.StreamId) (stream *Stream, ok bool) {
877
+ s.streamLock.RLock()
878
+ stream, ok = s.streams[streamId]
879
+ s.streamLock.RUnlock()
880
+ return
881
+}
882
+
883
+// FindStream looks up the given stream id and either waits for the
884
+// stream to be found or returns nil if the stream id is no longer
885
+// valid.
886
+func (s *Connection) FindStream(streamId uint32) *Stream {
887
+ var stream *Stream
888
+ var ok bool
889
+ s.streamCond.L.Lock()
890
+ stream, ok = s.streams[spdy.StreamId(streamId)]
891
+ debugMessage("(%p) Found stream %d? %t", s, spdy.StreamId(streamId), ok)
892
+ for !ok && streamId >= uint32(s.receivedStreamId) {
893
+ s.streamCond.Wait()
894
+ stream, ok = s.streams[spdy.StreamId(streamId)]
895
+ }
896
+ s.streamCond.L.Unlock()
897
+ return stream
898
+}
899
+
900
+func (s *Connection) CloseChan() <-chan bool {
901
+ return s.closeChan
902
+}
Godeps/_workspace/src/github.com/docker/spdystream/handlers.go
new
+38
@@ -0,0 +1,38 @@
1
+package spdystream
2
+
3
+import (
4
+ "io"
5
+ "net/http"
6
+)
7
+
8
+// MirrorStreamHandler mirrors all streams.
9
+func MirrorStreamHandler(stream *Stream) {
10
+ replyErr := stream.SendReply(http.Header{}, false)
11
+ if replyErr != nil {
12
+ return
13
+ }
14
+
15
+ go func() {
16
+ io.Copy(stream, stream)
17
+ stream.Close()
18
+ }()
19
+ go func() {
20
+ for {
21
+ header, receiveErr := stream.ReceiveHeader()
22
+ if receiveErr != nil {
23
+ return
24
+ }
25
+ sendErr := stream.SendHeader(header, false)
26
+ if sendErr != nil {
27
+ return
28
+ }
29
+ }
30
+ }()
31
+}
32
+
33
+// NoopStreamHandler does nothing when stream connects, most
34
+// likely used with RejectAuthHandler which will not allow any
35
+// streams to make it to the stream handler.
36
+func NoOpStreamHandler(stream *Stream) {
37
+ stream.SendReply(http.Header{}, false)
38
+}
Godeps/_workspace/src/github.com/docker/spdystream/priority.go
new
+98
@@ -0,0 +1,98 @@
1
+package spdystream
2
+
3
+import (
4
+ "container/heap"
5
+ "sync"
6
+
7
+ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/docker/spdystream/spdy"
8
+)
9
+
10
+type prioritizedFrame struct {
11
+ frame spdy.Frame
12
+ priority uint8
13
+ insertId uint64
14
+}
15
+
16
+type frameQueue []*prioritizedFrame
17
+
18
+func (fq frameQueue) Len() int {
19
+ return len(fq)
20
+}
21
+
22
+func (fq frameQueue) Less(i, j int) bool {
23
+ if fq[i].priority == fq[j].priority {
24
+ return fq[i].insertId < fq[j].insertId
25
+ }
26
+ return fq[i].priority < fq[j].priority
27
+}
28
+
29
+func (fq frameQueue) Swap(i, j int) {
30
+ fq[i], fq[j] = fq[j], fq[i]
31
+}
32
+
33
+func (fq *frameQueue) Push(x interface{}) {
34
+ *fq = append(*fq, x.(*prioritizedFrame))
35
+}
36
+
37
+func (fq *frameQueue) Pop() interface{} {
38
+ old := *fq
39
+ n := len(old)
40
+ *fq = old[0 : n-1]
41
+ return old[n-1]
42
+}
43
+
44
+type PriorityFrameQueue struct {
45
+ queue *frameQueue
46
+ c *sync.Cond
47
+ size int
48
+ nextInsertId uint64
49
+ drain bool
50
+}
51
+
52
+func NewPriorityFrameQueue(size int) *PriorityFrameQueue {
53
+ queue := make(frameQueue, 0, size)
54
+ heap.Init(&queue)
55
+
56
+ return &PriorityFrameQueue{
57
+ queue: &queue,
58
+ size: size,
59
+ c: sync.NewCond(&sync.Mutex{}),
60
+ }
61
+}
62
+
63
+func (q *PriorityFrameQueue) Push(frame spdy.Frame, priority uint8) {
64
+ q.c.L.Lock()
65
+ defer q.c.L.Unlock()
66
+ for q.queue.Len() >= q.size {
67
+ q.c.Wait()
68
+ }
69
+ pFrame := &prioritizedFrame{
70
+ frame: frame,
71
+ priority: priority,
72
+ insertId: q.nextInsertId,
73
+ }
74
+ q.nextInsertId = q.nextInsertId + 1
75
+ heap.Push(q.queue, pFrame)
76
+ q.c.Signal()
77
+}
78
+
79
+func (q *PriorityFrameQueue) Pop() spdy.Frame {
80
+ q.c.L.Lock()
81
+ defer q.c.L.Unlock()
82
+ for q.queue.Len() == 0 {
83
+ if q.drain {
84
+ return nil
85
+ }
86
+ q.c.Wait()
87
+ }
88
+ frame := heap.Pop(q.queue).(*prioritizedFrame).frame
89
+ q.c.Signal()
90
+ return frame
91
+}
92
+
93
+func (q *PriorityFrameQueue) Drain() {
94
+ q.c.L.Lock()
95
+ defer q.c.L.Unlock()
96
+ q.drain = true
97
+ q.c.Broadcast()
98
+}
Godeps/_workspace/src/github.com/docker/spdystream/priority_test.go
new
+108
@@ -0,0 +1,108 @@
1
+package spdystream
2
+
3
+import (
4
+ "sync"
5
+ "testing"
6
+ "time"
7
+
8
+ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/docker/spdystream/spdy"
9
+)
10
+
11
+func TestPriorityQueueOrdering(t *testing.T) {
12
+ queue := NewPriorityFrameQueue(150)
13
+ data1 := &spdy.DataFrame{}
14
+ data2 := &spdy.DataFrame{}
15
+ data3 := &spdy.DataFrame{}
16
+ data4 := &spdy.DataFrame{}
17
+ queue.Push(data1, 2)
18
+ queue.Push(data2, 1)
19
+ queue.Push(data3, 1)
20
+ queue.Push(data4, 0)
21
+
22
+ if queue.Pop() != data4 {
23
+ t.Fatalf("Wrong order, expected data4 first")
24
+ }
25
+ if queue.Pop() != data2 {
26
+ t.Fatalf("Wrong order, expected data2 second")
27
+ }
28
+ if queue.Pop() != data3 {
29
+ t.Fatalf("Wrong order, expected data3 third")
30
+ }
31
+ if queue.Pop() != data1 {
32
+ t.Fatalf("Wrong order, expected data1 fourth")
33
+ }
34
+
35
+ // Insert 50 Medium priority frames
36
+ for i := spdy.StreamId(50); i < 100; i++ {
37
+ queue.Push(&spdy.DataFrame{StreamId: i}, 1)
38
+ }
39
+ // Insert 50 low priority frames
40
+ for i := spdy.StreamId(100); i < 150; i++ {
41
+ queue.Push(&spdy.DataFrame{StreamId: i}, 2)
42
+ }
43
+ // Insert 50 high priority frames
44
+ for i := spdy.StreamId(0); i < 50; i++ {
45
+ queue.Push(&spdy.DataFrame{StreamId: i}, 0)
46
+ }
47
+
48
+ for i := spdy.StreamId(0); i < 150; i++ {
49
+ frame := queue.Pop()
50
+ if frame.(*spdy.DataFrame).StreamId != i {
51
+ t.Fatalf("Wrong frame\nActual: %d\nExpecting: %d", frame.(*spdy.DataFrame).StreamId, i)
52
+ }
53
+ }
54
+}
55
+
56
+func TestPriorityQueueSync(t *testing.T) {
57
+ queue := NewPriorityFrameQueue(150)
58
+ var wg sync.WaitGroup
59
+ insertRange := func(start, stop spdy.StreamId, priority uint8) {
60
+ for i := start; i < stop; i++ {
61
+ queue.Push(&spdy.DataFrame{StreamId: i}, priority)
62
+ }
63
+ wg.Done()
64
+ }
65
+ wg.Add(3)
66
+ go insertRange(spdy.StreamId(100), spdy.StreamId(150), 2)
67
+ go insertRange(spdy.StreamId(0), spdy.StreamId(50), 0)
68
+ go insertRange(spdy.StreamId(50), spdy.StreamId(100), 1)
69
+
70
+ wg.Wait()
71
+ for i := spdy.StreamId(0); i < 150; i++ {
72
+ frame := queue.Pop()
73
+ if frame.(*spdy.DataFrame).StreamId != i {
74
+ t.Fatalf("Wrong frame\nActual: %d\nExpecting: %d", frame.(*spdy.DataFrame).StreamId, i)
75
+ }
76
+ }
77
+}
78
+
79
+func TestPriorityQueueBlocking(t *testing.T) {
80
+ queue := NewPriorityFrameQueue(15)
81
+ for i := 0; i < 15; i++ {
82
+ queue.Push(&spdy.DataFrame{}, 2)
83
+ }
84
+ doneChan := make(chan bool)
85
+ go func() {
86
+ queue.Push(&spdy.DataFrame{}, 2)
87
+ close(doneChan)
88
+ }()
89
+ select {
90
+ case <-doneChan:
91
+ t.Fatalf("Push succeeded, expected to block")
92
+ case <-time.After(time.Millisecond):
93
+ break
94
+ }
95
+
96
+ queue.Pop()
97
+
98
+ select {
99
+ case <-doneChan:
100
+ break
101
+ case <-time.After(time.Millisecond):
102
+ t.Fatalf("Push should have succeeded, but timeout reached")
103
+ }
104
+
105
+ for i := 0; i < 15; i++ {
106
+ queue.Pop()
107
+ }
108
+}
Godeps/_workspace/src/github.com/docker/spdystream/spdy/dictionary.go
new
+187
@@ -0,0 +1,187 @@
1
+// Copyright 2013 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 spdy
6
+
7
+// headerDictionary is the dictionary sent to the zlib compressor/decompressor.
8
+var headerDictionary = []byte{
9
+ 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69,
10
+ 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68,
11
+ 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70,
12
+ 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70,
13
+ 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65,
14
+ 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05,
15
+ 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00,
16
+ 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00,
17
+ 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70,
18
+ 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,
19
+ 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63,
20
+ 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,
21
+ 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f,
22
+ 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c,
23
+ 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00,
24
+ 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70,
25
+ 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73,
26
+ 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00,
27
+ 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77,
28
+ 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68,
29
+ 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
30
+ 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63,
31
+ 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72,
32
+ 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f,
33
+ 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
34
+ 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74,
35
+ 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65,
36
+ 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74,
37
+ 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,
38
+ 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10,
39
+ 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,
40
+ 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,
41
+ 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74,
42
+ 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67,
43
+ 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f,
44
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f,
45
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00,
46
+ 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
47
+ 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00,
48
+ 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
49
+ 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00,
50
+ 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
51
+ 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00,
52
+ 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00,
53
+ 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00,
54
+ 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,
55
+ 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69,
56
+ 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66,
57
+ 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68,
58
+ 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69,
59
+ 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00,
60
+ 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f,
61
+ 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73,
62
+ 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d,
63
+ 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d,
64
+ 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00,
65
+ 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67,
66
+ 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d,
67
+ 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,
68
+ 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65,
69
+ 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74,
70
+ 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,
71
+ 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63,
72
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00,
73
+ 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72,
74
+ 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00,
75
+ 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00,
76
+ 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79,
77
+ 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
78
+ 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00,
79
+ 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61,
80
+ 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61,
81
+ 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05,
82
+ 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00,
83
+ 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72,
84
+ 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72,
85
+ 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00,
86
+ 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,
87
+ 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00,
88
+ 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c,
89
+ 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72,
90
+ 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65,
91
+ 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00,
92
+ 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61,
93
+ 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73,
94
+ 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74,
95
+ 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79,
96
+ 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00,
97
+ 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69,
98
+ 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77,
99
+ 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,
100
+ 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00,
101
+ 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,
102
+ 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00,
103
+ 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
104
+ 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30,
105
+ 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76,
106
+ 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00,
107
+ 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31,
108
+ 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72,
109
+ 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62,
110
+ 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73,
111
+ 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69,
112
+ 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65,
113
+ 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00,
114
+ 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69,
115
+ 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32,
116
+ 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35,
117
+ 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30,
118
+ 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33,
119
+ 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37,
120
+ 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30,
121
+ 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34,
122
+ 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31,
123
+ 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31,
124
+ 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34,
125
+ 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34,
126
+ 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e,
127
+ 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f,
128
+ 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65,
129
+ 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61,
130
+ 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20,
131
+ 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65,
132
+ 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f,
133
+ 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d,
134
+ 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34,
135
+ 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52,
136
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30,
137
+ 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68,
138
+ 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30,
139
+ 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64,
140
+ 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e,
141
+ 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64,
142
+ 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65,
143
+ 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72,
144
+ 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f,
145
+ 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74,
146
+ 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65,
147
+ 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20,
148
+ 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20,
149
+ 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,
150
+ 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46,
151
+ 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41,
152
+ 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a,
153
+ 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41,
154
+ 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20,
155
+ 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20,
156
+ 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30,
157
+ 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e,
158
+ 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57,
159
+ 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c,
160
+ 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61,
161
+ 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20,
162
+ 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b,
163
+ 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f,
164
+ 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61,
165
+ 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69,
166
+ 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67,
167
+ 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67,
168
+ 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,
169
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,
170
+ 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,
171
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,
172
+ 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c,
173
+ 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c,
174
+ 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74,
175
+ 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72,
176
+ 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c,
177
+ 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,
178
+ 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65,
179
+ 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65,
180
+ 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64,
181
+ 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,
182
+ 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63,
183
+ 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69,
184
+ 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d,
185
+ 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a,
186
+ 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e,
187
+}
Godeps/_workspace/src/github.com/docker/spdystream/spdy/read.go
new
+348
@@ -0,0 +1,348 @@
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 spdy
6
+
7
+import (
8
+ "compress/zlib"
9
+ "encoding/binary"
10
+ "io"
11
+ "net/http"
12
+ "strings"
13
+)
14
+
15
+func (frame *SynStreamFrame) read(h ControlFrameHeader, f *Framer) error {
16
+ return f.readSynStreamFrame(h, frame)
17
+}
18
+
19
+func (frame *SynReplyFrame) read(h ControlFrameHeader, f *Framer) error {
20
+ return f.readSynReplyFrame(h, frame)
21
+}
22
+
23
+func (frame *RstStreamFrame) read(h ControlFrameHeader, f *Framer) error {
24
+ frame.CFHeader = h
25
+ if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
26
+ return err
27
+ }
28
+ if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil {
29
+ return err
30
+ }
31
+ if frame.Status == 0 {
32
+ return &Error{InvalidControlFrame, frame.StreamId}
33
+ }
34
+ if frame.StreamId == 0 {
35
+ return &Error{ZeroStreamId, 0}
36
+ }
37
+ return nil
38
+}
39
+
40
+func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) error {
41
+ frame.CFHeader = h
42
+ var numSettings uint32
43
+ if err := binary.Read(f.r, binary.BigEndian, &numSettings); err != nil {
44
+ return err
45
+ }
46
+ frame.FlagIdValues = make([]SettingsFlagIdValue, numSettings)
47
+ for i := uint32(0); i < numSettings; i++ {
48
+ if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Id); err != nil {
49
+ return err
50
+ }
51
+ frame.FlagIdValues[i].Flag = SettingsFlag((frame.FlagIdValues[i].Id & 0xff000000) >> 24)
52
+ frame.FlagIdValues[i].Id &= 0xffffff
53
+ if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Value); err != nil {
54
+ return err
55
+ }
56
+ }
57
+ return nil
58
+}
59
+
60
+func (frame *PingFrame) read(h ControlFrameHeader, f *Framer) error {
61
+ frame.CFHeader = h
62
+ if err := binary.Read(f.r, binary.BigEndian, &frame.Id); err != nil {
63
+ return err
64
+ }
65
+ if frame.Id == 0 {
66
+ return &Error{ZeroStreamId, 0}
67
+ }
68
+ if frame.CFHeader.Flags != 0 {
69
+ return &Error{InvalidControlFrame, StreamId(frame.Id)}
70
+ }
71
+ return nil
72
+}
73
+
74
+func (frame *GoAwayFrame) read(h ControlFrameHeader, f *Framer) error {
75
+ frame.CFHeader = h
76
+ if err := binary.Read(f.r, binary.BigEndian, &frame.LastGoodStreamId); err != nil {
77
+ return err
78
+ }
79
+ if frame.CFHeader.Flags != 0 {
80
+ return &Error{InvalidControlFrame, frame.LastGoodStreamId}
81
+ }
82
+ if frame.CFHeader.length != 8 {
83
+ return &Error{InvalidControlFrame, frame.LastGoodStreamId}
84
+ }
85
+ if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil {
86
+ return err
87
+ }
88
+ return nil
89
+}
90
+
91
+func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) error {
92
+ return f.readHeadersFrame(h, frame)
93
+}
94
+
95
+func (frame *WindowUpdateFrame) read(h ControlFrameHeader, f *Framer) error {
96
+ frame.CFHeader = h
97
+ if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
98
+ return err
99
+ }
100
+ if frame.CFHeader.Flags != 0 {
101
+ return &Error{InvalidControlFrame, frame.StreamId}
102
+ }
103
+ if frame.CFHeader.length != 8 {
104
+ return &Error{InvalidControlFrame, frame.StreamId}
105
+ }
106
+ if err := binary.Read(f.r, binary.BigEndian, &frame.DeltaWindowSize); err != nil {
107
+ return err
108
+ }
109
+ return nil
110
+}
111
+
112
+func newControlFrame(frameType ControlFrameType) (controlFrame, error) {
113
+ ctor, ok := cframeCtor[frameType]
114
+ if !ok {
115
+ return nil, &Error{Err: InvalidControlFrame}
116
+ }
117
+ return ctor(), nil
118
+}
119
+
120
+var cframeCtor = map[ControlFrameType]func() controlFrame{
121
+ TypeSynStream: func() controlFrame { return new(SynStreamFrame) },
122
+ TypeSynReply: func() controlFrame { return new(SynReplyFrame) },
123
+ TypeRstStream: func() controlFrame { return new(RstStreamFrame) },
124
+ TypeSettings: func() controlFrame { return new(SettingsFrame) },
125
+ TypePing: func() controlFrame { return new(PingFrame) },
126
+ TypeGoAway: func() controlFrame { return new(GoAwayFrame) },
127
+ TypeHeaders: func() controlFrame { return new(HeadersFrame) },
128
+ TypeWindowUpdate: func() controlFrame { return new(WindowUpdateFrame) },
129
+}
130
+
131
+func (f *Framer) uncorkHeaderDecompressor(payloadSize int64) error {
132
+ if f.headerDecompressor != nil {
133
+ f.headerReader.N = payloadSize
134
+ return nil
135
+ }
136
+ f.headerReader = io.LimitedReader{R: f.r, N: payloadSize}
137
+ decompressor, err := zlib.NewReaderDict(&f.headerReader, []byte(headerDictionary))
138
+ if err != nil {
139
+ return err
140
+ }
141
+ f.headerDecompressor = decompressor
142
+ return nil
143
+}
144
+
145
+// ReadFrame reads SPDY encoded data and returns a decompressed Frame.
146
+func (f *Framer) ReadFrame() (Frame, error) {
147
+ var firstWord uint32
148
+ if err := binary.Read(f.r, binary.BigEndian, &firstWord); err != nil {
149
+ return nil, err
150
+ }
151
+ if firstWord&0x80000000 != 0 {
152
+ frameType := ControlFrameType(firstWord & 0xffff)
153
+ version := uint16(firstWord >> 16 & 0x7fff)
154
+ return f.parseControlFrame(version, frameType)
155
+ }
156
+ return f.parseDataFrame(StreamId(firstWord & 0x7fffffff))
157
+}
158
+
159
+func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) (Frame, error) {
160
+ var length uint32
161
+ if err := binary.Read(f.r, binary.BigEndian, &length); err != nil {
162
+ return nil, err
163
+ }
164
+ flags := ControlFlags((length & 0xff000000) >> 24)
165
+ length &= 0xffffff
166
+ header := ControlFrameHeader{version, frameType, flags, length}
167
+ cframe, err := newControlFrame(frameType)
168
+ if err != nil {
169
+ return nil, err
170
+ }
171
+ if err = cframe.read(header, f); err != nil {
172
+ return nil, err
173
+ }
174
+ return cframe, nil
175
+}
176
+
177
+func parseHeaderValueBlock(r io.Reader, streamId StreamId) (http.Header, error) {
178
+ var numHeaders uint32
179
+ if err := binary.Read(r, binary.BigEndian, &numHeaders); err != nil {
180
+ return nil, err
181
+ }
182
+ var e error
183
+ h := make(http.Header, int(numHeaders))
184
+ for i := 0; i < int(numHeaders); i++ {
185
+ var length uint32
186
+ if err := binary.Read(r, binary.BigEndian, &length); err != nil {
187
+ return nil, err
188
+ }
189
+ nameBytes := make([]byte, length)
190
+ if _, err := io.ReadFull(r, nameBytes); err != nil {
191
+ return nil, err
192
+ }
193
+ name := string(nameBytes)
194
+ if name != strings.ToLower(name) {
195
+ e = &Error{UnlowercasedHeaderName, streamId}
196
+ name = strings.ToLower(name)
197
+ }
198
+ if h[name] != nil {
199
+ e = &Error{DuplicateHeaders, streamId}
200
+ }
201
+ if err := binary.Read(r, binary.BigEndian, &length); err != nil {
202
+ return nil, err
203
+ }
204
+ value := make([]byte, length)
205
+ if _, err := io.ReadFull(r, value); err != nil {
206
+ return nil, err
207
+ }
208
+ valueList := strings.Split(string(value), headerValueSeparator)
209
+ for _, v := range valueList {
210
+ h.Add(name, v)
211
+ }
212
+ }
213
+ if e != nil {
214
+ return h, e
215
+ }
216
+ return h, nil
217
+}
218
+
219
+func (f *Framer) readSynStreamFrame(h ControlFrameHeader, frame *SynStreamFrame) error {
220
+ frame.CFHeader = h
221
+ var err error
222
+ if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
223
+ return err
224
+ }
225
+ if err = binary.Read(f.r, binary.BigEndian, &frame.AssociatedToStreamId); err != nil {
226
+ return err
227
+ }
228
+ if err = binary.Read(f.r, binary.BigEndian, &frame.Priority); err != nil {
229
+ return err
230
+ }
231
+ frame.Priority >>= 5
232
+ if err = binary.Read(f.r, binary.BigEndian, &frame.Slot); err != nil {
233
+ return err
234
+ }
235
+ reader := f.r
236
+ if !f.headerCompressionDisabled {
237
+ err := f.uncorkHeaderDecompressor(int64(h.length - 10))
238
+ if err != nil {
239
+ return err
240
+ }
241
+ reader = f.headerDecompressor
242
+ }
243
+ frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
244
+ if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) {
245
+ err = &Error{WrongCompressedPayloadSize, 0}
246
+ }
247
+ if err != nil {
248
+ return err
249
+ }
250
+ for h := range frame.Headers {
251
+ if invalidReqHeaders[h] {
252
+ return &Error{InvalidHeaderPresent, frame.StreamId}
253
+ }
254
+ }
255
+ if frame.StreamId == 0 {
256
+ return &Error{ZeroStreamId, 0}
257
+ }
258
+ return nil
259
+}
260
+
261
+func (f *Framer) readSynReplyFrame(h ControlFrameHeader, frame *SynReplyFrame) error {
262
+ frame.CFHeader = h
263
+ var err error
264
+ if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
265
+ return err
266
+ }
267
+ reader := f.r
268
+ if !f.headerCompressionDisabled {
269
+ err := f.uncorkHeaderDecompressor(int64(h.length - 4))
270
+ if err != nil {
271
+ return err
272
+ }
273
+ reader = f.headerDecompressor
274
+ }
275
+ frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
276
+ if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) {
277
+ err = &Error{WrongCompressedPayloadSize, 0}
278
+ }
279
+ if err != nil {
280
+ return err
281
+ }
282
+ for h := range frame.Headers {
283
+ if invalidRespHeaders[h] {
284
+ return &Error{InvalidHeaderPresent, frame.StreamId}
285
+ }
286
+ }
287
+ if frame.StreamId == 0 {
288
+ return &Error{ZeroStreamId, 0}
289
+ }
290
+ return nil
291
+}
292
+
293
+func (f *Framer) readHeadersFrame(h ControlFrameHeader, frame *HeadersFrame) error {
294
+ frame.CFHeader = h
295
+ var err error
296
+ if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
297
+ return err
298
+ }
299
+ reader := f.r
300
+ if !f.headerCompressionDisabled {
301
+ err := f.uncorkHeaderDecompressor(int64(h.length - 4))
302
+ if err != nil {
303
+ return err
304
+ }
305
+ reader = f.headerDecompressor
306
+ }
307
+ frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
308
+ if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) {
309
+ err = &Error{WrongCompressedPayloadSize, 0}
310
+ }
311
+ if err != nil {
312
+ return err
313
+ }
314
+ var invalidHeaders map[string]bool
315
+ if frame.StreamId%2 == 0 {
316
+ invalidHeaders = invalidReqHeaders
317
+ } else {
318
+ invalidHeaders = invalidRespHeaders
319
+ }
320
+ for h := range frame.Headers {
321
+ if invalidHeaders[h] {
322
+ return &Error{InvalidHeaderPresent, frame.StreamId}
323
+ }
324
+ }
325
+ if frame.StreamId == 0 {
326
+ return &Error{ZeroStreamId, 0}
327
+ }
328
+ return nil
329
+}
330
+
331
+func (f *Framer) parseDataFrame(streamId StreamId) (*DataFrame, error) {
332
+ var length uint32
333
+ if err := binary.Read(f.r, binary.BigEndian, &length); err != nil {
334
+ return nil, err
335
+ }
336
+ var frame DataFrame
337
+ frame.StreamId = streamId
338
+ frame.Flags = DataFlags(length >> 24)
339
+ length &= 0xffffff
340
+ frame.Data = make([]byte, length)
341
+ if _, err := io.ReadFull(f.r, frame.Data); err != nil {
342
+ return nil, err
343
+ }
344
+ if frame.StreamId == 0 {
345
+ return nil, &Error{ZeroStreamId, 0}
346
+ }
347
+ return &frame, nil
348
+}
Godeps/_workspace/src/github.com/docker/spdystream/spdy/spdy_test.go
new
+644
@@ -0,0 +1,644 @@
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 spdy
6
+
7
+import (
8
+ "bytes"
9
+ "compress/zlib"
10
+ "encoding/base64"
11
+ "io"
12
+ "io/ioutil"
13
+ "net/http"
14
+ "reflect"
15
+ "testing"
16
+)
17
+
18
+var HeadersFixture = http.Header{
19
+ "Url": []string{"http://www.google.com/"},
20
+ "Method": []string{"get"},
21
+ "Version": []string{"http/1.1"},
22
+}
23
+
24
+func TestHeaderParsing(t *testing.T) {
25
+ var headerValueBlockBuf bytes.Buffer
26
+ writeHeaderValueBlock(&headerValueBlockBuf, HeadersFixture)
27
+ const bogusStreamId = 1
28
+ newHeaders, err := parseHeaderValueBlock(&headerValueBlockBuf, bogusStreamId)
29
+ if err != nil {
30
+ t.Fatal("parseHeaderValueBlock:", err)
31
+ }
32
+ if !reflect.DeepEqual(HeadersFixture, newHeaders) {
33
+ t.Fatal("got: ", newHeaders, "\nwant: ", HeadersFixture)
34
+ }
35
+}
36
+
37
+func TestCreateParseSynStreamFrameCompressionDisable(t *testing.T) {
38
+ buffer := new(bytes.Buffer)
39
+ // Fixture framer for no compression test.
40
+ framer := &Framer{
41
+ headerCompressionDisabled: true,
42
+ w: buffer,
43
+ headerBuf: new(bytes.Buffer),
44
+ r: buffer,
45
+ }
46
+ synStreamFrame := SynStreamFrame{
47
+ CFHeader: ControlFrameHeader{
48
+ version: Version,
49
+ frameType: TypeSynStream,
50
+ },
51
+ StreamId: 2,
52
+ Headers: HeadersFixture,
53
+ }
54
+ if err := framer.WriteFrame(&synStreamFrame); err != nil {
55
+ t.Fatal("WriteFrame without compression:", err)
56
+ }
57
+ frame, err := framer.ReadFrame()
58
+ if err != nil {
59
+ t.Fatal("ReadFrame without compression:", err)
60
+ }
61
+ parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
62
+ if !ok {
63
+ t.Fatal("Parsed incorrect frame type:", frame)
64
+ }
65
+ if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
66
+ t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
67
+ }
68
+}
69
+
70
+func TestCreateParseSynStreamFrameCompressionEnable(t *testing.T) {
71
+ buffer := new(bytes.Buffer)
72
+ framer, err := NewFramer(buffer, buffer)
73
+ synStreamFrame := SynStreamFrame{
74
+ CFHeader: ControlFrameHeader{
75
+ version: Version,
76
+ frameType: TypeSynStream,
77
+ },
78
+ StreamId: 2,
79
+ Headers: HeadersFixture,
80
+ }
81
+ if err != nil {
82
+ t.Fatal("Failed to create new framer:", err)
83
+ }
84
+ if err := framer.WriteFrame(&synStreamFrame); err != nil {
85
+ t.Fatal("WriteFrame with compression:", err)
86
+ }
87
+ frame, err := framer.ReadFrame()
88
+ if err != nil {
89
+ t.Fatal("ReadFrame with compression:", err)
90
+ }
91
+ parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
92
+ if !ok {
93
+ t.Fatal("Parsed incorrect frame type:", frame)
94
+ }
95
+ if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
96
+ t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
97
+ }
98
+}
99
+
100
+func TestCreateParseSynReplyFrameCompressionDisable(t *testing.T) {
101
+ buffer := new(bytes.Buffer)
102
+ framer := &Framer{
103
+ headerCompressionDisabled: true,
104
+ w: buffer,
105
+ headerBuf: new(bytes.Buffer),
106
+ r: buffer,
107
+ }
108
+ synReplyFrame := SynReplyFrame{
109
+ CFHeader: ControlFrameHeader{
110
+ version: Version,
111
+ frameType: TypeSynReply,
112
+ },
113
+ StreamId: 2,
114
+ Headers: HeadersFixture,
115
+ }
116
+ if err := framer.WriteFrame(&synReplyFrame); err != nil {
117
+ t.Fatal("WriteFrame without compression:", err)
118
+ }
119
+ frame, err := framer.ReadFrame()
120
+ if err != nil {
121
+ t.Fatal("ReadFrame without compression:", err)
122
+ }
123
+ parsedSynReplyFrame, ok := frame.(*SynReplyFrame)
124
+ if !ok {
125
+ t.Fatal("Parsed incorrect frame type:", frame)
126
+ }
127
+ if !reflect.DeepEqual(synReplyFrame, *parsedSynReplyFrame) {
128
+ t.Fatal("got: ", *parsedSynReplyFrame, "\nwant: ", synReplyFrame)
129
+ }
130
+}
131
+
132
+func TestCreateParseSynReplyFrameCompressionEnable(t *testing.T) {
133
+ buffer := new(bytes.Buffer)
134
+ framer, err := NewFramer(buffer, buffer)
135
+ synReplyFrame := SynReplyFrame{
136
+ CFHeader: ControlFrameHeader{
137
+ version: Version,
138
+ frameType: TypeSynReply,
139
+ },
140
+ StreamId: 2,
141
+ Headers: HeadersFixture,
142
+ }
143
+ if err != nil {
144
+ t.Fatal("Failed to create new framer:", err)
145
+ }
146
+ if err := framer.WriteFrame(&synReplyFrame); err != nil {
147
+ t.Fatal("WriteFrame with compression:", err)
148
+ }
149
+ frame, err := framer.ReadFrame()
150
+ if err != nil {
151
+ t.Fatal("ReadFrame with compression:", err)
152
+ }
153
+ parsedSynReplyFrame, ok := frame.(*SynReplyFrame)
154
+ if !ok {
155
+ t.Fatal("Parsed incorrect frame type:", frame)
156
+ }
157
+ if !reflect.DeepEqual(synReplyFrame, *parsedSynReplyFrame) {
158
+ t.Fatal("got: ", *parsedSynReplyFrame, "\nwant: ", synReplyFrame)
159
+ }
160
+}
161
+
162
+func TestCreateParseRstStream(t *testing.T) {
163
+ buffer := new(bytes.Buffer)
164
+ framer, err := NewFramer(buffer, buffer)
165
+ if err != nil {
166
+ t.Fatal("Failed to create new framer:", err)
167
+ }
168
+ rstStreamFrame := RstStreamFrame{
169
+ CFHeader: ControlFrameHeader{
170
+ version: Version,
171
+ frameType: TypeRstStream,
172
+ },
173
+ StreamId: 1,
174
+ Status: InvalidStream,
175
+ }
176
+ if err := framer.WriteFrame(&rstStreamFrame); err != nil {
177
+ t.Fatal("WriteFrame:", err)
178
+ }
179
+ frame, err := framer.ReadFrame()
180
+ if err != nil {
181
+ t.Fatal("ReadFrame:", err)
182
+ }
183
+ parsedRstStreamFrame, ok := frame.(*RstStreamFrame)
184
+ if !ok {
185
+ t.Fatal("Parsed incorrect frame type:", frame)
186
+ }
187
+ if !reflect.DeepEqual(rstStreamFrame, *parsedRstStreamFrame) {
188
+ t.Fatal("got: ", *parsedRstStreamFrame, "\nwant: ", rstStreamFrame)
189
+ }
190
+}
191
+
192
+func TestCreateParseSettings(t *testing.T) {
193
+ buffer := new(bytes.Buffer)
194
+ framer, err := NewFramer(buffer, buffer)
195
+ if err != nil {
196
+ t.Fatal("Failed to create new framer:", err)
197
+ }
198
+ settingsFrame := SettingsFrame{
199
+ CFHeader: ControlFrameHeader{
200
+ version: Version,
201
+ frameType: TypeSettings,
202
+ },
203
+ FlagIdValues: []SettingsFlagIdValue{
204
+ {FlagSettingsPersistValue, SettingsCurrentCwnd, 10},
205
+ {FlagSettingsPersisted, SettingsUploadBandwidth, 1},
206
+ },
207
+ }
208
+ if err := framer.WriteFrame(&settingsFrame); err != nil {
209
+ t.Fatal("WriteFrame:", err)
210
+ }
211
+ frame, err := framer.ReadFrame()
212
+ if err != nil {
213
+ t.Fatal("ReadFrame:", err)
214
+ }
215
+ parsedSettingsFrame, ok := frame.(*SettingsFrame)
216
+ if !ok {
217
+ t.Fatal("Parsed incorrect frame type:", frame)
218
+ }
219
+ if !reflect.DeepEqual(settingsFrame, *parsedSettingsFrame) {
220
+ t.Fatal("got: ", *parsedSettingsFrame, "\nwant: ", settingsFrame)
221
+ }
222
+}
223
+
224
+func TestCreateParsePing(t *testing.T) {
225
+ buffer := new(bytes.Buffer)
226
+ framer, err := NewFramer(buffer, buffer)
227
+ if err != nil {
228
+ t.Fatal("Failed to create new framer:", err)
229
+ }
230
+ pingFrame := PingFrame{
231
+ CFHeader: ControlFrameHeader{
232
+ version: Version,
233
+ frameType: TypePing,
234
+ },
235
+ Id: 31337,
236
+ }
237
+ if err := framer.WriteFrame(&pingFrame); err != nil {
238
+ t.Fatal("WriteFrame:", err)
239
+ }
240
+ if pingFrame.CFHeader.Flags != 0 {
241
+ t.Fatal("Incorrect frame type:", pingFrame)
242
+ }
243
+ frame, err := framer.ReadFrame()
244
+ if err != nil {
245
+ t.Fatal("ReadFrame:", err)
246
+ }
247
+ parsedPingFrame, ok := frame.(*PingFrame)
248
+ if !ok {
249
+ t.Fatal("Parsed incorrect frame type:", frame)
250
+ }
251
+ if parsedPingFrame.CFHeader.Flags != 0 {
252
+ t.Fatal("Parsed incorrect frame type:", parsedPingFrame)
253
+ }
254
+ if !reflect.DeepEqual(pingFrame, *parsedPingFrame) {
255
+ t.Fatal("got: ", *parsedPingFrame, "\nwant: ", pingFrame)
256
+ }
257
+}
258
+
259
+func TestCreateParseGoAway(t *testing.T) {
260
+ buffer := new(bytes.Buffer)
261
+ framer, err := NewFramer(buffer, buffer)
262
+ if err != nil {
263
+ t.Fatal("Failed to create new framer:", err)
264
+ }
265
+ goAwayFrame := GoAwayFrame{
266
+ CFHeader: ControlFrameHeader{
267
+ version: Version,
268
+ frameType: TypeGoAway,
269
+ },
270
+ LastGoodStreamId: 31337,
271
+ Status: 1,
272
+ }
273
+ if err := framer.WriteFrame(&goAwayFrame); err != nil {
274
+ t.Fatal("WriteFrame:", err)
275
+ }
276
+ if goAwayFrame.CFHeader.Flags != 0 {
277
+ t.Fatal("Incorrect frame type:", goAwayFrame)
278
+ }
279
+ if goAwayFrame.CFHeader.length != 8 {
280
+ t.Fatal("Incorrect frame type:", goAwayFrame)
281
+ }
282
+ frame, err := framer.ReadFrame()
283
+ if err != nil {
284
+ t.Fatal("ReadFrame:", err)
285
+ }
286
+ parsedGoAwayFrame, ok := frame.(*GoAwayFrame)
287
+ if !ok {
288
+ t.Fatal("Parsed incorrect frame type:", frame)
289
+ }
290
+ if parsedGoAwayFrame.CFHeader.Flags != 0 {
291
+ t.Fatal("Incorrect frame type:", parsedGoAwayFrame)
292
+ }
293
+ if parsedGoAwayFrame.CFHeader.length != 8 {
294
+ t.Fatal("Incorrect frame type:", parsedGoAwayFrame)
295
+ }
296
+ if !reflect.DeepEqual(goAwayFrame, *parsedGoAwayFrame) {
297
+ t.Fatal("got: ", *parsedGoAwayFrame, "\nwant: ", goAwayFrame)
298
+ }
299
+}
300
+
301
+func TestCreateParseHeadersFrame(t *testing.T) {
302
+ buffer := new(bytes.Buffer)
303
+ framer := &Framer{
304
+ headerCompressionDisabled: true,
305
+ w: buffer,
306
+ headerBuf: new(bytes.Buffer),
307
+ r: buffer,
308
+ }
309
+ headersFrame := HeadersFrame{
310
+ CFHeader: ControlFrameHeader{
311
+ version: Version,
312
+ frameType: TypeHeaders,
313
+ },
314
+ StreamId: 2,
315
+ }
316
+ headersFrame.Headers = HeadersFixture
317
+ if err := framer.WriteFrame(&headersFrame); err != nil {
318
+ t.Fatal("WriteFrame without compression:", err)
319
+ }
320
+ frame, err := framer.ReadFrame()
321
+ if err != nil {
322
+ t.Fatal("ReadFrame without compression:", err)
323
+ }
324
+ parsedHeadersFrame, ok := frame.(*HeadersFrame)
325
+ if !ok {
326
+ t.Fatal("Parsed incorrect frame type:", frame)
327
+ }
328
+ if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
329
+ t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
330
+ }
331
+}
332
+
333
+func TestCreateParseHeadersFrameCompressionEnable(t *testing.T) {
334
+ buffer := new(bytes.Buffer)
335
+ headersFrame := HeadersFrame{
336
+ CFHeader: ControlFrameHeader{
337
+ version: Version,
338
+ frameType: TypeHeaders,
339
+ },
340
+ StreamId: 2,
341
+ }
342
+ headersFrame.Headers = HeadersFixture
343
+
344
+ framer, err := NewFramer(buffer, buffer)
345
+ if err := framer.WriteFrame(&headersFrame); err != nil {
346
+ t.Fatal("WriteFrame with compression:", err)
347
+ }
348
+ frame, err := framer.ReadFrame()
349
+ if err != nil {
350
+ t.Fatal("ReadFrame with compression:", err)
351
+ }
352
+ parsedHeadersFrame, ok := frame.(*HeadersFrame)
353
+ if !ok {
354
+ t.Fatal("Parsed incorrect frame type:", frame)
355
+ }
356
+ if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
357
+ t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
358
+ }
359
+}
360
+
361
+func TestCreateParseWindowUpdateFrame(t *testing.T) {
362
+ buffer := new(bytes.Buffer)
363
+ framer, err := NewFramer(buffer, buffer)
364
+ if err != nil {
365
+ t.Fatal("Failed to create new framer:", err)
366
+ }
367
+ windowUpdateFrame := WindowUpdateFrame{
368
+ CFHeader: ControlFrameHeader{
369
+ version: Version,
370
+ frameType: TypeWindowUpdate,
371
+ },
372
+ StreamId: 31337,
373
+ DeltaWindowSize: 1,
374
+ }
375
+ if err := framer.WriteFrame(&windowUpdateFrame); err != nil {
376
+ t.Fatal("WriteFrame:", err)
377
+ }
378
+ if windowUpdateFrame.CFHeader.Flags != 0 {
379
+ t.Fatal("Incorrect frame type:", windowUpdateFrame)
380
+ }
381
+ if windowUpdateFrame.CFHeader.length != 8 {
382
+ t.Fatal("Incorrect frame type:", windowUpdateFrame)
383
+ }
384
+ frame, err := framer.ReadFrame()
385
+ if err != nil {
386
+ t.Fatal("ReadFrame:", err)
387
+ }
388
+ parsedWindowUpdateFrame, ok := frame.(*WindowUpdateFrame)
389
+ if !ok {
390
+ t.Fatal("Parsed incorrect frame type:", frame)
391
+ }
392
+ if parsedWindowUpdateFrame.CFHeader.Flags != 0 {
393
+ t.Fatal("Incorrect frame type:", parsedWindowUpdateFrame)
394
+ }
395
+ if parsedWindowUpdateFrame.CFHeader.length != 8 {
396
+ t.Fatal("Incorrect frame type:", parsedWindowUpdateFrame)
397
+ }
398
+ if !reflect.DeepEqual(windowUpdateFrame, *parsedWindowUpdateFrame) {
399
+ t.Fatal("got: ", *parsedWindowUpdateFrame, "\nwant: ", windowUpdateFrame)
400
+ }
401
+}
402
+
403
+func TestCreateParseDataFrame(t *testing.T) {
404
+ buffer := new(bytes.Buffer)
405
+ framer, err := NewFramer(buffer, buffer)
406
+ if err != nil {
407
+ t.Fatal("Failed to create new framer:", err)
408
+ }
409
+ dataFrame := DataFrame{
410
+ StreamId: 1,
411
+ Data: []byte{'h', 'e', 'l', 'l', 'o'},
412
+ }
413
+ if err := framer.WriteFrame(&dataFrame); err != nil {
414
+ t.Fatal("WriteFrame:", err)
415
+ }
416
+ frame, err := framer.ReadFrame()
417
+ if err != nil {
418
+ t.Fatal("ReadFrame:", err)
419
+ }
420
+ parsedDataFrame, ok := frame.(*DataFrame)
421
+ if !ok {
422
+ t.Fatal("Parsed incorrect frame type:", frame)
423
+ }
424
+ if !reflect.DeepEqual(dataFrame, *parsedDataFrame) {
425
+ t.Fatal("got: ", *parsedDataFrame, "\nwant: ", dataFrame)
426
+ }
427
+}
428
+
429
+func TestCompressionContextAcrossFrames(t *testing.T) {
430
+ buffer := new(bytes.Buffer)
431
+ framer, err := NewFramer(buffer, buffer)
432
+ if err != nil {
433
+ t.Fatal("Failed to create new framer:", err)
434
+ }
435
+ headersFrame := HeadersFrame{
436
+ CFHeader: ControlFrameHeader{
437
+ version: Version,
438
+ frameType: TypeHeaders,
439
+ },
440
+ StreamId: 2,
441
+ Headers: HeadersFixture,
442
+ }
443
+ if err := framer.WriteFrame(&headersFrame); err != nil {
444
+ t.Fatal("WriteFrame (HEADERS):", err)
445
+ }
446
+ synStreamFrame := SynStreamFrame{
447
+ ControlFrameHeader{
448
+ Version,
449
+ TypeSynStream,
450
+ 0, // Flags
451
+ 0, // length
452
+ },
453
+ 2, // StreamId
454
+ 0, // AssociatedTOStreamID
455
+ 0, // Priority
456
+ 1, // Slot
457
+ nil, // Headers
458
+ }
459
+ synStreamFrame.Headers = HeadersFixture
460
+
461
+ if err := framer.WriteFrame(&synStreamFrame); err != nil {
462
+ t.Fatal("WriteFrame (SYN_STREAM):", err)
463
+ }
464
+ frame, err := framer.ReadFrame()
465
+ if err != nil {
466
+ t.Fatal("ReadFrame (HEADERS):", err, buffer.Bytes())
467
+ }
468
+ parsedHeadersFrame, ok := frame.(*HeadersFrame)
469
+ if !ok {
470
+ t.Fatalf("expected HeadersFrame; got %T %v", frame, frame)
471
+ }
472
+ if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
473
+ t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
474
+ }
475
+ frame, err = framer.ReadFrame()
476
+ if err != nil {
477
+ t.Fatal("ReadFrame (SYN_STREAM):", err, buffer.Bytes())
478
+ }
479
+ parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
480
+ if !ok {
481
+ t.Fatalf("expected SynStreamFrame; got %T %v", frame, frame)
482
+ }
483
+ if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
484
+ t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
485
+ }
486
+}
487
+
488
+func TestMultipleSPDYFrames(t *testing.T) {
489
+ // Initialize the framers.
490
+ pr1, pw1 := io.Pipe()
491
+ pr2, pw2 := io.Pipe()
492
+ writer, err := NewFramer(pw1, pr2)
493
+ if err != nil {
494
+ t.Fatal("Failed to create writer:", err)
495
+ }
496
+ reader, err := NewFramer(pw2, pr1)
497
+ if err != nil {
498
+ t.Fatal("Failed to create reader:", err)
499
+ }
500
+
501
+ // Set up the frames we're actually transferring.
502
+ headersFrame := HeadersFrame{
503
+ CFHeader: ControlFrameHeader{
504
+ version: Version,
505
+ frameType: TypeHeaders,
506
+ },
507
+ StreamId: 2,
508
+ Headers: HeadersFixture,
509
+ }
510
+ synStreamFrame := SynStreamFrame{
511
+ CFHeader: ControlFrameHeader{
512
+ version: Version,
513
+ frameType: TypeSynStream,
514
+ },
515
+ StreamId: 2,
516
+ Headers: HeadersFixture,
517
+ }
518
+
519
+ // Start the goroutines to write the frames.
520
+ go func() {
521
+ if err := writer.WriteFrame(&headersFrame); err != nil {
522
+ t.Fatal("WriteFrame (HEADERS): ", err)
523
+ }
524
+ if err := writer.WriteFrame(&synStreamFrame); err != nil {
525
+ t.Fatal("WriteFrame (SYN_STREAM): ", err)
526
+ }
527
+ }()
528
+
529
+ // Read the frames and verify they look as expected.
530
+ frame, err := reader.ReadFrame()
531
+ if err != nil {
532
+ t.Fatal("ReadFrame (HEADERS): ", err)
533
+ }
534
+ parsedHeadersFrame, ok := frame.(*HeadersFrame)
535
+ if !ok {
536
+ t.Fatal("Parsed incorrect frame type:", frame)
537
+ }
538
+ if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
539
+ t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
540
+ }
541
+ frame, err = reader.ReadFrame()
542
+ if err != nil {
543
+ t.Fatal("ReadFrame (SYN_STREAM):", err)
544
+ }
545
+ parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
546
+ if !ok {
547
+ t.Fatal("Parsed incorrect frame type.")
548
+ }
549
+ if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
550
+ t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
551
+ }
552
+}
553
+
554
+func TestReadMalformedZlibHeader(t *testing.T) {
555
+ // These were constructed by corrupting the first byte of the zlib
556
+ // header after writing.
557
+ malformedStructs := map[string]string{
558
+ "SynStreamFrame": "gAIAAQAAABgAAAACAAAAAAAAF/nfolGyYmAAAAAA//8=",
559
+ "SynReplyFrame": "gAIAAgAAABQAAAACAAAX+d+iUbJiYAAAAAD//w==",
560
+ "HeadersFrame": "gAIACAAAABQAAAACAAAX+d+iUbJiYAAAAAD//w==",
561
+ }
562
+ for name, bad := range malformedStructs {
563
+ b, err := base64.StdEncoding.DecodeString(bad)
564
+ if err != nil {
565
+ t.Errorf("Unable to decode base64 encoded frame %s: %v", name, err)
566
+ }
567
+ buf := bytes.NewBuffer(b)
568
+ reader, err := NewFramer(buf, buf)
569
+ if err != nil {
570
+ t.Fatalf("NewFramer: %v", err)
571
+ }
572
+ _, err = reader.ReadFrame()
573
+ if err != zlib.ErrHeader {
574
+ t.Errorf("Frame %s, expected: %#v, actual: %#v", name, zlib.ErrHeader, err)
575
+ }
576
+ }
577
+}
578
+
579
+// TODO: these tests are too weak for updating SPDY spec. Fix me.
580
+
581
+type zeroStream struct {
582
+ frame Frame
583
+ encoded string
584
+}
585
+
586
+var streamIdZeroFrames = map[string]zeroStream{
587
+ "SynStreamFrame": {
588
+ &SynStreamFrame{StreamId: 0},
589
+ "gAIAAQAAABgAAAAAAAAAAAAAePnfolGyYmAAAAAA//8=",
590
+ },
591
+ "SynReplyFrame": {
592
+ &SynReplyFrame{StreamId: 0},
593
+ "gAIAAgAAABQAAAAAAAB4+d+iUbJiYAAAAAD//w==",
594
+ },
595
+ "RstStreamFrame": {
596
+ &RstStreamFrame{StreamId: 0},
597
+ "gAIAAwAAAAgAAAAAAAAAAA==",
598
+ },
599
+ "HeadersFrame": {
600
+ &HeadersFrame{StreamId: 0},
601
+ "gAIACAAAABQAAAAAAAB4+d+iUbJiYAAAAAD//w==",
602
+ },
603
+ "DataFrame": {
604
+ &DataFrame{StreamId: 0},
605
+ "AAAAAAAAAAA=",
606
+ },
607
+ "PingFrame": {
608
+ &PingFrame{Id: 0},
609
+ "gAIABgAAAAQAAAAA",
610
+ },
611
+}
612
+
613
+func TestNoZeroStreamId(t *testing.T) {
614
+ t.Log("skipping") // TODO: update to work with SPDY3
615
+ return
616
+
617
+ for name, f := range streamIdZeroFrames {
618
+ b, err := base64.StdEncoding.DecodeString(f.encoded)
619
+ if err != nil {
620
+ t.Errorf("Unable to decode base64 encoded frame %s: %v", f, err)
621
+ continue
622
+ }
623
+ framer, err := NewFramer(ioutil.Discard, bytes.NewReader(b))
624
+ if err != nil {
625
+ t.Fatalf("NewFramer: %v", err)
626
+ }
627
+ err = framer.WriteFrame(f.frame)
628
+ checkZeroStreamId(t, name, "WriteFrame", err)
629
+
630
+ _, err = framer.ReadFrame()
631
+ checkZeroStreamId(t, name, "ReadFrame", err)
632
+ }
633
+}
634
+
635
+func checkZeroStreamId(t *testing.T, frame string, method string, err error) {
636
+ if err == nil {
637
+ t.Errorf("%s ZeroStreamId, no error on %s", method, frame)
638
+ return
639
+ }
640
+ eerr, ok := err.(*Error)
641
+ if !ok || eerr.Err != ZeroStreamId {
642
+ t.Errorf("%s ZeroStreamId, incorrect error %#v, frame %s", method, eerr, frame)
643
+ }
644
+}
Godeps/_workspace/src/github.com/docker/spdystream/spdy/types.go
new
+275
@@ -0,0 +1,275 @@
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 spdy implements the SPDY protocol (currently SPDY/3), described in
6
+// http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3.
7
+package spdy
8
+
9
+import (
10
+ "bytes"
11
+ "compress/zlib"
12
+ "io"
13
+ "net/http"
14
+)
15
+
16
+// Version is the protocol version number that this package implements.
17
+const Version = 3
18
+
19
+// ControlFrameType stores the type field in a control frame header.
20
+type ControlFrameType uint16
21
+
22
+const (
23
+ TypeSynStream ControlFrameType = 0x0001
24
+ TypeSynReply = 0x0002
25
+ TypeRstStream = 0x0003
26
+ TypeSettings = 0x0004
27
+ TypePing = 0x0006
28
+ TypeGoAway = 0x0007
29
+ TypeHeaders = 0x0008
30
+ TypeWindowUpdate = 0x0009
31
+)
32
+
33
+// ControlFlags are the flags that can be set on a control frame.
34
+type ControlFlags uint8
35
+
36
+const (
37
+ ControlFlagFin ControlFlags = 0x01
38
+ ControlFlagUnidirectional = 0x02
39
+ ControlFlagSettingsClearSettings = 0x01
40
+)
41
+
42
+// DataFlags are the flags that can be set on a data frame.
43
+type DataFlags uint8
44
+
45
+const (
46
+ DataFlagFin DataFlags = 0x01
47
+)
48
+
49
+// MaxDataLength is the maximum number of bytes that can be stored in one frame.
50
+const MaxDataLength = 1<<24 - 1
51
+
52
+// headerValueSepator separates multiple header values.
53
+const headerValueSeparator = "\x00"
54
+
55
+// Frame is a single SPDY frame in its unpacked in-memory representation. Use
56
+// Framer to read and write it.
57
+type Frame interface {
58
+ write(f *Framer) error
59
+}
60
+
61
+// ControlFrameHeader contains all the fields in a control frame header,
62
+// in its unpacked in-memory representation.
63
+type ControlFrameHeader struct {
64
+ // Note, high bit is the "Control" bit.
65
+ version uint16 // spdy version number
66
+ frameType ControlFrameType
67
+ Flags ControlFlags
68
+ length uint32 // length of data field
69
+}
70
+
71
+type controlFrame interface {
72
+ Frame
73
+ read(h ControlFrameHeader, f *Framer) error
74
+}
75
+
76
+// StreamId represents a 31-bit value identifying the stream.
77
+type StreamId uint32
78
+
79
+// SynStreamFrame is the unpacked, in-memory representation of a SYN_STREAM
80
+// frame.
81
+type SynStreamFrame struct {
82
+ CFHeader ControlFrameHeader
83
+ StreamId StreamId
84
+ AssociatedToStreamId StreamId // stream id for a stream which this stream is associated to
85
+ Priority uint8 // priority of this frame (3-bit)
86
+ Slot uint8 // index in the server's credential vector of the client certificate
87
+ Headers http.Header
88
+}
89
+
90
+// SynReplyFrame is the unpacked, in-memory representation of a SYN_REPLY frame.
91
+type SynReplyFrame struct {
92
+ CFHeader ControlFrameHeader
93
+ StreamId StreamId
94
+ Headers http.Header
95
+}
96
+
97
+// RstStreamStatus represents the status that led to a RST_STREAM.
98
+type RstStreamStatus uint32
99
+
100
+const (
101
+ ProtocolError RstStreamStatus = iota + 1
102
+ InvalidStream
103
+ RefusedStream
104
+ UnsupportedVersion
105
+ Cancel
106
+ InternalError
107
+ FlowControlError
108
+ StreamInUse
109
+ StreamAlreadyClosed
110
+ InvalidCredentials
111
+ FrameTooLarge
112
+)
113
+
114
+// RstStreamFrame is the unpacked, in-memory representation of a RST_STREAM
115
+// frame.
116
+type RstStreamFrame struct {
117
+ CFHeader ControlFrameHeader
118
+ StreamId StreamId
119
+ Status RstStreamStatus
120
+}
121
+
122
+// SettingsFlag represents a flag in a SETTINGS frame.
123
+type SettingsFlag uint8
124
+
125
+const (
126
+ FlagSettingsPersistValue SettingsFlag = 0x1
127
+ FlagSettingsPersisted = 0x2
128
+)
129
+
130
+// SettingsFlag represents the id of an id/value pair in a SETTINGS frame.
131
+type SettingsId uint32
132
+
133
+const (
134
+ SettingsUploadBandwidth SettingsId = iota + 1
135
+ SettingsDownloadBandwidth
136
+ SettingsRoundTripTime
137
+ SettingsMaxConcurrentStreams
138
+ SettingsCurrentCwnd
139
+ SettingsDownloadRetransRate
140
+ SettingsInitialWindowSize
141
+ SettingsClientCretificateVectorSize
142
+)
143
+
144
+// SettingsFlagIdValue is the unpacked, in-memory representation of the
145
+// combined flag/id/value for a setting in a SETTINGS frame.
146
+type SettingsFlagIdValue struct {
147
+ Flag SettingsFlag
148
+ Id SettingsId
149
+ Value uint32
150
+}
151
+
152
+// SettingsFrame is the unpacked, in-memory representation of a SPDY
153
+// SETTINGS frame.
154
+type SettingsFrame struct {
155
+ CFHeader ControlFrameHeader
156
+ FlagIdValues []SettingsFlagIdValue
157
+}
158
+
159
+// PingFrame is the unpacked, in-memory representation of a PING frame.
160
+type PingFrame struct {
161
+ CFHeader ControlFrameHeader
162
+ Id uint32 // unique id for this ping, from server is even, from client is odd.
163
+}
164
+
165
+// GoAwayStatus represents the status in a GoAwayFrame.
166
+type GoAwayStatus uint32
167
+
168
+const (
169
+ GoAwayOK GoAwayStatus = iota
170
+ GoAwayProtocolError
171
+ GoAwayInternalError
172
+)
173
+
174
+// GoAwayFrame is the unpacked, in-memory representation of a GOAWAY frame.
175
+type GoAwayFrame struct {
176
+ CFHeader ControlFrameHeader
177
+ LastGoodStreamId StreamId // last stream id which was accepted by sender
178
+ Status GoAwayStatus
179
+}
180
+
181
+// HeadersFrame is the unpacked, in-memory representation of a HEADERS frame.
182
+type HeadersFrame struct {
183
+ CFHeader ControlFrameHeader
184
+ StreamId StreamId
185
+ Headers http.Header
186
+}
187
+
188
+// WindowUpdateFrame is the unpacked, in-memory representation of a
189
+// WINDOW_UPDATE frame.
190
+type WindowUpdateFrame struct {
191
+ CFHeader ControlFrameHeader
192
+ StreamId StreamId
193
+ DeltaWindowSize uint32 // additional number of bytes to existing window size
194
+}
195
+
196
+// TODO: Implement credential frame and related methods.
197
+
198
+// DataFrame is the unpacked, in-memory representation of a DATA frame.
199
+type DataFrame struct {
200
+ // Note, high bit is the "Control" bit. Should be 0 for data frames.
201
+ StreamId StreamId
202
+ Flags DataFlags
203
+ Data []byte // payload data of this frame
204
+}
205
+
206
+// A SPDY specific error.
207
+type ErrorCode string
208
+
209
+const (
210
+ UnlowercasedHeaderName ErrorCode = "header was not lowercased"
211
+ DuplicateHeaders = "multiple headers with same name"
212
+ WrongCompressedPayloadSize = "compressed payload size was incorrect"
213
+ UnknownFrameType = "unknown frame type"
214
+ InvalidControlFrame = "invalid control frame"
215
+ InvalidDataFrame = "invalid data frame"
216
+ InvalidHeaderPresent = "frame contained invalid header"
217
+ ZeroStreamId = "stream id zero is disallowed"
218
+)
219
+
220
+// Error contains both the type of error and additional values. StreamId is 0
221
+// if Error is not associated with a stream.
222
+type Error struct {
223
+ Err ErrorCode
224
+ StreamId StreamId
225
+}
226
+
227
+func (e *Error) Error() string {
228
+ return string(e.Err)
229
+}
230
+
231
+var invalidReqHeaders = map[string]bool{
232
+ "Connection": true,
233
+ "Host": true,
234
+ "Keep-Alive": true,
235
+ "Proxy-Connection": true,
236
+ "Transfer-Encoding": true,
237
+}
238
+
239
+var invalidRespHeaders = map[string]bool{
240
+ "Connection": true,
241
+ "Keep-Alive": true,
242
+ "Proxy-Connection": true,
243
+ "Transfer-Encoding": true,
244
+}
245
+
246
+// Framer handles serializing/deserializing SPDY frames, including compressing/
247
+// decompressing payloads.
248
+type Framer struct {
249
+ headerCompressionDisabled bool
250
+ w io.Writer
251
+ headerBuf *bytes.Buffer
252
+ headerCompressor *zlib.Writer
253
+ r io.Reader
254
+ headerReader io.LimitedReader
255
+ headerDecompressor io.ReadCloser
256
+}
257
+
258
+// NewFramer allocates a new Framer for a given SPDY connection, represented by
259
+// a io.Writer and io.Reader. Note that Framer will read and write individual fields
260
+// from/to the Reader and Writer, so the caller should pass in an appropriately
261
+// buffered implementation to optimize performance.
262
+func NewFramer(w io.Writer, r io.Reader) (*Framer, error) {
263
+ compressBuf := new(bytes.Buffer)
264
+ compressor, err := zlib.NewWriterLevelDict(compressBuf, zlib.BestCompression, []byte(headerDictionary))
265
+ if err != nil {
266
+ return nil, err
267
+ }
268
+ framer := &Framer{
269
+ w: w,
270
+ headerBuf: compressBuf,
271
+ headerCompressor: compressor,
272
+ r: r,
273
+ }
274
+ return framer, nil
275
+}
Godeps/_workspace/src/github.com/docker/spdystream/spdy/write.go
new
+318
@@ -0,0 +1,318 @@
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 spdy
6
+
7
+import (
8
+ "encoding/binary"
9
+ "io"
10
+ "net/http"
11
+ "strings"
12
+)
13
+
14
+func (frame *SynStreamFrame) write(f *Framer) error {
15
+ return f.writeSynStreamFrame(frame)
16
+}
17
+
18
+func (frame *SynReplyFrame) write(f *Framer) error {
19
+ return f.writeSynReplyFrame(frame)
20
+}
21
+
22
+func (frame *RstStreamFrame) write(f *Framer) (err error) {
23
+ if frame.StreamId == 0 {
24
+ return &Error{ZeroStreamId, 0}
25
+ }
26
+ frame.CFHeader.version = Version
27
+ frame.CFHeader.frameType = TypeRstStream
28
+ frame.CFHeader.Flags = 0
29
+ frame.CFHeader.length = 8
30
+
31
+ // Serialize frame to Writer.
32
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
33
+ return
34
+ }
35
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
36
+ return
37
+ }
38
+ if frame.Status == 0 {
39
+ return &Error{InvalidControlFrame, frame.StreamId}
40
+ }
41
+ if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
42
+ return
43
+ }
44
+ return
45
+}
46
+
47
+func (frame *SettingsFrame) write(f *Framer) (err error) {
48
+ frame.CFHeader.version = Version
49
+ frame.CFHeader.frameType = TypeSettings
50
+ frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4)
51
+
52
+ // Serialize frame to Writer.
53
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
54
+ return
55
+ }
56
+ if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil {
57
+ return
58
+ }
59
+ for _, flagIdValue := range frame.FlagIdValues {
60
+ flagId := uint32(flagIdValue.Flag)<<24 | uint32(flagIdValue.Id)
61
+ if err = binary.Write(f.w, binary.BigEndian, flagId); err != nil {
62
+ return
63
+ }
64
+ if err = binary.Write(f.w, binary.BigEndian, flagIdValue.Value); err != nil {
65
+ return
66
+ }
67
+ }
68
+ return
69
+}
70
+
71
+func (frame *PingFrame) write(f *Framer) (err error) {
72
+ if frame.Id == 0 {
73
+ return &Error{ZeroStreamId, 0}
74
+ }
75
+ frame.CFHeader.version = Version
76
+ frame.CFHeader.frameType = TypePing
77
+ frame.CFHeader.Flags = 0
78
+ frame.CFHeader.length = 4
79
+
80
+ // Serialize frame to Writer.
81
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
82
+ return
83
+ }
84
+ if err = binary.Write(f.w, binary.BigEndian, frame.Id); err != nil {
85
+ return
86
+ }
87
+ return
88
+}
89
+
90
+func (frame *GoAwayFrame) write(f *Framer) (err error) {
91
+ frame.CFHeader.version = Version
92
+ frame.CFHeader.frameType = TypeGoAway
93
+ frame.CFHeader.Flags = 0
94
+ frame.CFHeader.length = 8
95
+
96
+ // Serialize frame to Writer.
97
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
98
+ return
99
+ }
100
+ if err = binary.Write(f.w, binary.BigEndian, frame.LastGoodStreamId); err != nil {
101
+ return
102
+ }
103
+ if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
104
+ return
105
+ }
106
+ return nil
107
+}
108
+
109
+func (frame *HeadersFrame) write(f *Framer) error {
110
+ return f.writeHeadersFrame(frame)
111
+}
112
+
113
+func (frame *WindowUpdateFrame) write(f *Framer) (err error) {
114
+ frame.CFHeader.version = Version
115
+ frame.CFHeader.frameType = TypeWindowUpdate
116
+ frame.CFHeader.Flags = 0
117
+ frame.CFHeader.length = 8
118
+
119
+ // Serialize frame to Writer.
120
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
121
+ return
122
+ }
123
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
124
+ return
125
+ }
126
+ if err = binary.Write(f.w, binary.BigEndian, frame.DeltaWindowSize); err != nil {
127
+ return
128
+ }
129
+ return nil
130
+}
131
+
132
+func (frame *DataFrame) write(f *Framer) error {
133
+ return f.writeDataFrame(frame)
134
+}
135
+
136
+// WriteFrame writes a frame.
137
+func (f *Framer) WriteFrame(frame Frame) error {
138
+ return frame.write(f)
139
+}
140
+
141
+func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) error {
142
+ if err := binary.Write(w, binary.BigEndian, 0x8000|h.version); err != nil {
143
+ return err
144
+ }
145
+ if err := binary.Write(w, binary.BigEndian, h.frameType); err != nil {
146
+ return err
147
+ }
148
+ flagsAndLength := uint32(h.Flags)<<24 | h.length
149
+ if err := binary.Write(w, binary.BigEndian, flagsAndLength); err != nil {
150
+ return err
151
+ }
152
+ return nil
153
+}
154
+
155
+func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err error) {
156
+ n = 0
157
+ if err = binary.Write(w, binary.BigEndian, uint32(len(h))); err != nil {
158
+ return
159
+ }
160
+ n += 2
161
+ for name, values := range h {
162
+ if err = binary.Write(w, binary.BigEndian, uint32(len(name))); err != nil {
163
+ return
164
+ }
165
+ n += 2
166
+ name = strings.ToLower(name)
167
+ if _, err = io.WriteString(w, name); err != nil {
168
+ return
169
+ }
170
+ n += len(name)
171
+ v := strings.Join(values, headerValueSeparator)
172
+ if err = binary.Write(w, binary.BigEndian, uint32(len(v))); err != nil {
173
+ return
174
+ }
175
+ n += 2
176
+ if _, err = io.WriteString(w, v); err != nil {
177
+ return
178
+ }
179
+ n += len(v)
180
+ }
181
+ return
182
+}
183
+
184
+func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err error) {
185
+ if frame.StreamId == 0 {
186
+ return &Error{ZeroStreamId, 0}
187
+ }
188
+ // Marshal the headers.
189
+ var writer io.Writer = f.headerBuf
190
+ if !f.headerCompressionDisabled {
191
+ writer = f.headerCompressor
192
+ }
193
+ if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
194
+ return
195
+ }
196
+ if !f.headerCompressionDisabled {
197
+ f.headerCompressor.Flush()
198
+ }
199
+
200
+ // Set ControlFrameHeader.
201
+ frame.CFHeader.version = Version
202
+ frame.CFHeader.frameType = TypeSynStream
203
+ frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10)
204
+
205
+ // Serialize frame to Writer.
206
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
207
+ return err
208
+ }
209
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
210
+ return err
211
+ }
212
+ if err = binary.Write(f.w, binary.BigEndian, frame.AssociatedToStreamId); err != nil {
213
+ return err
214
+ }
215
+ if err = binary.Write(f.w, binary.BigEndian, frame.Priority<<5); err != nil {
216
+ return err
217
+ }
218
+ if err = binary.Write(f.w, binary.BigEndian, frame.Slot); err != nil {
219
+ return err
220
+ }
221
+ if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
222
+ return err
223
+ }
224
+ f.headerBuf.Reset()
225
+ return nil
226
+}
227
+
228
+func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err error) {
229
+ if frame.StreamId == 0 {
230
+ return &Error{ZeroStreamId, 0}
231
+ }
232
+ // Marshal the headers.
233
+ var writer io.Writer = f.headerBuf
234
+ if !f.headerCompressionDisabled {
235
+ writer = f.headerCompressor
236
+ }
237
+ if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
238
+ return
239
+ }
240
+ if !f.headerCompressionDisabled {
241
+ f.headerCompressor.Flush()
242
+ }
243
+
244
+ // Set ControlFrameHeader.
245
+ frame.CFHeader.version = Version
246
+ frame.CFHeader.frameType = TypeSynReply
247
+ frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
248
+
249
+ // Serialize frame to Writer.
250
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
251
+ return
252
+ }
253
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
254
+ return
255
+ }
256
+ if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
257
+ return
258
+ }
259
+ f.headerBuf.Reset()
260
+ return
261
+}
262
+
263
+func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err error) {
264
+ if frame.StreamId == 0 {
265
+ return &Error{ZeroStreamId, 0}
266
+ }
267
+ // Marshal the headers.
268
+ var writer io.Writer = f.headerBuf
269
+ if !f.headerCompressionDisabled {
270
+ writer = f.headerCompressor
271
+ }
272
+ if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
273
+ return
274
+ }
275
+ if !f.headerCompressionDisabled {
276
+ f.headerCompressor.Flush()
277
+ }
278
+
279
+ // Set ControlFrameHeader.
280
+ frame.CFHeader.version = Version
281
+ frame.CFHeader.frameType = TypeHeaders
282
+ frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
283
+
284
+ // Serialize frame to Writer.
285
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
286
+ return
287
+ }
288
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
289
+ return
290
+ }
291
+ if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
292
+ return
293
+ }
294
+ f.headerBuf.Reset()
295
+ return
296
+}
297
+
298
+func (f *Framer) writeDataFrame(frame *DataFrame) (err error) {
299
+ if frame.StreamId == 0 {
300
+ return &Error{ZeroStreamId, 0}
301
+ }
302
+ if frame.StreamId&0x80000000 != 0 || len(frame.Data) > MaxDataLength {
303
+ return &Error{InvalidDataFrame, frame.StreamId}
304
+ }
305
+
306
+ // Serialize frame to Writer.
307
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
308
+ return
309
+ }
310
+ flagsAndLength := uint32(frame.Flags)<<24 | uint32(len(frame.Data))
311
+ if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil {
312
+ return
313
+ }
314
+ if _, err = f.w.Write(frame.Data); err != nil {
315
+ return
316
+ }
317
+ return nil
318
+}
Godeps/_workspace/src/github.com/docker/spdystream/spdy_bench_test.go
new
+113
@@ -0,0 +1,113 @@
1
+package spdystream
2
+
3
+import (
4
+ "fmt"
5
+ "io"
6
+ "net"
7
+ "net/http"
8
+ "sync"
9
+ "testing"
10
+)
11
+
12
+func configureServer() (io.Closer, string, *sync.WaitGroup) {
13
+ authenticated = true
14
+ wg := &sync.WaitGroup{}
15
+ server, listen, serverErr := runServer(wg)
16
+
17
+ if serverErr != nil {
18
+ panic(serverErr)
19
+ }
20
+
21
+ return server, listen, wg
22
+}
23
+
24
+func BenchmarkDial10000(b *testing.B) {
25
+ server, addr, wg := configureServer()
26
+
27
+ defer func() {
28
+ server.Close()
29
+ wg.Wait()
30
+ }()
31
+
32
+ for i := 0; i < b.N; i++ {
33
+ conn, dialErr := net.Dial("tcp", addr)
34
+ if dialErr != nil {
35
+ panic(fmt.Sprintf("Error dialing server: %s", dialErr))
36
+ }
37
+ conn.Close()
38
+ }
39
+}
40
+
41
+func BenchmarkDialWithSPDYStream10000(b *testing.B) {
42
+ server, addr, wg := configureServer()
43
+
44
+ defer func() {
45
+ server.Close()
46
+ wg.Wait()
47
+ }()
48
+
49
+ for i := 0; i < b.N; i++ {
50
+ conn, dialErr := net.Dial("tcp", addr)
51
+ if dialErr != nil {
52
+ b.Fatalf("Error dialing server: %s", dialErr)
53
+ }
54
+
55
+ spdyConn, spdyErr := NewConnection(conn, false)
56
+ if spdyErr != nil {
57
+ b.Fatalf("Error creating spdy connection: %s", spdyErr)
58
+ }
59
+ go spdyConn.Serve(NoOpStreamHandler)
60
+
61
+ closeErr := spdyConn.Close()
62
+ if closeErr != nil {
63
+ b.Fatalf("Error closing connection: %s, closeErr")
64
+ }
65
+ }
66
+}
67
+
68
+func benchmarkStreamWithDataAndSize(size uint64, b *testing.B) {
69
+ server, addr, wg := configureServer()
70
+
71
+ defer func() {
72
+ server.Close()
73
+ wg.Wait()
74
+ }()
75
+
76
+ for i := 0; i < b.N; i++ {
77
+ conn, dialErr := net.Dial("tcp", addr)
78
+ if dialErr != nil {
79
+ b.Fatalf("Error dialing server: %s", dialErr)
80
+ }
81
+
82
+ spdyConn, spdyErr := NewConnection(conn, false)
83
+ if spdyErr != nil {
84
+ b.Fatalf("Error creating spdy connection: %s", spdyErr)
85
+ }
86
+
87
+ go spdyConn.Serve(MirrorStreamHandler)
88
+
89
+ stream, err := spdyConn.CreateStream(http.Header{}, nil, false)
90
+
91
+ writer := make([]byte, size)
92
+
93
+ stream.Write(writer)
94
+
95
+ if err != nil {
96
+ panic(err)
97
+ }
98
+
99
+ reader := make([]byte, size)
100
+ stream.Read(reader)
101
+
102
+ stream.Close()
103
+
104
+ closeErr := spdyConn.Close()
105
+ if closeErr != nil {
106
+ b.Fatalf("Error closing connection: %s, closeErr")
107
+ }
108
+ }
109
+}
110
+
111
+func BenchmarkStreamWith1Byte10000(b *testing.B) { benchmarkStreamWithDataAndSize(1, b) }
112
+func BenchmarkStreamWith1KiloByte10000(b *testing.B) { benchmarkStreamWithDataAndSize(1024, b) }
113
+func BenchmarkStreamWith1Megabyte10000(b *testing.B) { benchmarkStreamWithDataAndSize(1024*1024, b) }
Godeps/_workspace/src/github.com/docker/spdystream/spdy_test.go
new
+909
@@ -0,0 +1,909 @@
1
+package spdystream
2
+
3
+import (
4
+ "bufio"
5
+ "bytes"
6
+ "io"
7
+ "net"
8
+ "net/http"
9
+ "net/http/httptest"
10
+ "sync"
11
+ "testing"
12
+ "time"
13
+)
14
+
15
+func TestSpdyStreams(t *testing.T) {
16
+ var wg sync.WaitGroup
17
+ server, listen, serverErr := runServer(&wg)
18
+ if serverErr != nil {
19
+ t.Fatalf("Error initializing server: %s", serverErr)
20
+ }
21
+
22
+ conn, dialErr := net.Dial("tcp", listen)
23
+ if dialErr != nil {
24
+ t.Fatalf("Error dialing server: %s", dialErr)
25
+ }
26
+
27
+ spdyConn, spdyErr := NewConnection(conn, false)
28
+ if spdyErr != nil {
29
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
30
+ }
31
+ go spdyConn.Serve(NoOpStreamHandler)
32
+
33
+ authenticated = true
34
+ stream, streamErr := spdyConn.CreateStream(http.Header{}, nil, false)
35
+ if streamErr != nil {
36
+ t.Fatalf("Error creating stream: %s", streamErr)
37
+ }
38
+
39
+ waitErr := stream.Wait()
40
+ if waitErr != nil {
41
+ t.Fatalf("Error waiting for stream: %s", waitErr)
42
+ }
43
+
44
+ message := []byte("hello")
45
+ writeErr := stream.WriteData(message, false)
46
+ if writeErr != nil {
47
+ t.Fatalf("Error writing data")
48
+ }
49
+
50
+ buf := make([]byte, 10)
51
+ n, readErr := stream.Read(buf)
52
+ if readErr != nil {
53
+ t.Fatalf("Error reading data from stream: %s", readErr)
54
+ }
55
+ if n != 5 {
56
+ t.Fatalf("Unexpected number of bytes read:\nActual: %d\nExpected: 5", n)
57
+ }
58
+ if bytes.Compare(buf[:n], message) != 0 {
59
+ t.Fatalf("Did not receive expected message:\nActual: %s\nExpectd: %s", buf, message)
60
+ }
61
+
62
+ headers := http.Header{
63
+ "TestKey": []string{"TestVal"},
64
+ }
65
+ sendErr := stream.SendHeader(headers, false)
66
+ if sendErr != nil {
67
+ t.Fatalf("Error sending headers: %s", sendErr)
68
+ }
69
+ receiveHeaders, receiveErr := stream.ReceiveHeader()
70
+ if receiveErr != nil {
71
+ t.Fatalf("Error receiving headers: %s", receiveErr)
72
+ }
73
+ if len(receiveHeaders) != 1 {
74
+ t.Fatalf("Unexpected number of headers:\nActual: %d\nExpecting:%d", len(receiveHeaders), 1)
75
+ }
76
+ testVal := receiveHeaders.Get("TestKey")
77
+ if testVal != "TestVal" {
78
+ t.Fatalf("Wrong test value:\nActual: %q\nExpecting: %q", testVal, "TestVal")
79
+ }
80
+
81
+ writeErr = stream.WriteData(message, true)
82
+ if writeErr != nil {
83
+ t.Fatalf("Error writing data")
84
+ }
85
+
86
+ smallBuf := make([]byte, 3)
87
+ n, readErr = stream.Read(smallBuf)
88
+ if readErr != nil {
89
+ t.Fatalf("Error reading data from stream: %s", readErr)
90
+ }
91
+ if n != 3 {
92
+ t.Fatalf("Unexpected number of bytes read:\nActual: %d\nExpected: 3", n)
93
+ }
94
+ if bytes.Compare(smallBuf[:n], []byte("hel")) != 0 {
95
+ t.Fatalf("Did not receive expected message:\nActual: %s\nExpectd: %s", smallBuf[:n], message)
96
+ }
97
+ n, readErr = stream.Read(smallBuf)
98
+ if readErr != nil {
99
+ t.Fatalf("Error reading data from stream: %s", readErr)
100
+ }
101
+ if n != 2 {
102
+ t.Fatalf("Unexpected number of bytes read:\nActual: %d\nExpected: 2", n)
103
+ }
104
+ if bytes.Compare(smallBuf[:n], []byte("lo")) != 0 {
105
+ t.Fatalf("Did not receive expected message:\nActual: %s\nExpected: lo", smallBuf[:n])
106
+ }
107
+
108
+ n, readErr = stream.Read(buf)
109
+ if readErr != io.EOF {
110
+ t.Fatalf("Expected EOF reading from finished stream, read %d bytes", n)
111
+ }
112
+
113
+ // Closing again should return error since stream is already closed
114
+ streamCloseErr := stream.Close()
115
+ if streamCloseErr == nil {
116
+ t.Fatalf("No error closing finished stream")
117
+ }
118
+ if streamCloseErr != ErrWriteClosedStream {
119
+ t.Fatalf("Unexpected error closing stream: %s", streamCloseErr)
120
+ }
121
+
122
+ streamResetErr := stream.Reset()
123
+ if streamResetErr != nil {
124
+ t.Fatalf("Error reseting stream: %s", streamResetErr)
125
+ }
126
+
127
+ authenticated = false
128
+ badStream, badStreamErr := spdyConn.CreateStream(http.Header{}, nil, false)
129
+ if badStreamErr != nil {
130
+ t.Fatalf("Error creating stream: %s", badStreamErr)
131
+ }
132
+
133
+ waitErr = badStream.Wait()
134
+ if waitErr == nil {
135
+ t.Fatalf("Did not receive error creating stream")
136
+ }
137
+ if waitErr != ErrReset {
138
+ t.Fatalf("Unexpected error creating stream: %s", waitErr)
139
+ }
140
+ streamCloseErr = badStream.Close()
141
+ if streamCloseErr == nil {
142
+ t.Fatalf("No error closing bad stream")
143
+ }
144
+
145
+ spdyCloseErr := spdyConn.Close()
146
+ if spdyCloseErr != nil {
147
+ t.Fatalf("Error closing spdy connection: %s", spdyCloseErr)
148
+ }
149
+
150
+ closeErr := server.Close()
151
+ if closeErr != nil {
152
+ t.Fatalf("Error shutting down server: %s", closeErr)
153
+ }
154
+ wg.Wait()
155
+}
156
+
157
+func TestPing(t *testing.T) {
158
+ var wg sync.WaitGroup
159
+ server, listen, serverErr := runServer(&wg)
160
+ if serverErr != nil {
161
+ t.Fatalf("Error initializing server: %s", serverErr)
162
+ }
163
+
164
+ conn, dialErr := net.Dial("tcp", listen)
165
+ if dialErr != nil {
166
+ t.Fatalf("Error dialing server: %s", dialErr)
167
+ }
168
+
169
+ spdyConn, spdyErr := NewConnection(conn, false)
170
+ if spdyErr != nil {
171
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
172
+ }
173
+ go spdyConn.Serve(NoOpStreamHandler)
174
+
175
+ pingTime, pingErr := spdyConn.Ping()
176
+ if pingErr != nil {
177
+ t.Fatalf("Error pinging server: %s", pingErr)
178
+ }
179
+ if pingTime == time.Duration(0) {
180
+ t.Fatalf("Expecting non-zero ping time")
181
+ }
182
+
183
+ closeErr := server.Close()
184
+ if closeErr != nil {
185
+ t.Fatalf("Error shutting down server: %s", closeErr)
186
+ }
187
+ wg.Wait()
188
+}
189
+
190
+func TestHalfClose(t *testing.T) {
191
+ var wg sync.WaitGroup
192
+ server, listen, serverErr := runServer(&wg)
193
+ if serverErr != nil {
194
+ t.Fatalf("Error initializing server: %s", serverErr)
195
+ }
196
+
197
+ conn, dialErr := net.Dial("tcp", listen)
198
+ if dialErr != nil {
199
+ t.Fatalf("Error dialing server: %s", dialErr)
200
+ }
201
+
202
+ spdyConn, spdyErr := NewConnection(conn, false)
203
+ if spdyErr != nil {
204
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
205
+ }
206
+ go spdyConn.Serve(NoOpStreamHandler)
207
+
208
+ authenticated = true
209
+ stream, streamErr := spdyConn.CreateStream(http.Header{}, nil, false)
210
+ if streamErr != nil {
211
+ t.Fatalf("Error creating stream: %s", streamErr)
212
+ }
213
+
214
+ waitErr := stream.Wait()
215
+ if waitErr != nil {
216
+ t.Fatalf("Error waiting for stream: %s", waitErr)
217
+ }
218
+
219
+ message := []byte("hello and will read after close")
220
+ writeErr := stream.WriteData(message, false)
221
+ if writeErr != nil {
222
+ t.Fatalf("Error writing data")
223
+ }
224
+
225
+ streamCloseErr := stream.Close()
226
+ if streamCloseErr != nil {
227
+ t.Fatalf("Error closing stream: %s", streamCloseErr)
228
+ }
229
+
230
+ buf := make([]byte, 40)
231
+ n, readErr := stream.Read(buf)
232
+ if readErr != nil {
233
+ t.Fatalf("Error reading data from stream: %s", readErr)
234
+ }
235
+ if n != 31 {
236
+ t.Fatalf("Unexpected number of bytes read:\nActual: %d\nExpected: 5", n)
237
+ }
238
+ if bytes.Compare(buf[:n], message) != 0 {
239
+ t.Fatalf("Did not receive expected message:\nActual: %s\nExpectd: %s", buf, message)
240
+ }
241
+
242
+ spdyCloseErr := spdyConn.Close()
243
+ if spdyCloseErr != nil {
244
+ t.Fatalf("Error closing spdy connection: %s", spdyCloseErr)
245
+ }
246
+
247
+ closeErr := server.Close()
248
+ if closeErr != nil {
249
+ t.Fatalf("Error shutting down server: %s", closeErr)
250
+ }
251
+ wg.Wait()
252
+}
253
+
254
+func TestUnexpectedRemoteConnectionClosed(t *testing.T) {
255
+ tt := []struct {
256
+ closeReceiver bool
257
+ closeSender bool
258
+ }{
259
+ {closeReceiver: true, closeSender: false},
260
+ {closeReceiver: false, closeSender: true},
261
+ {closeReceiver: false, closeSender: false},
262
+ }
263
+ for tix, tc := range tt {
264
+ listener, listenErr := net.Listen("tcp", "localhost:0")
265
+ if listenErr != nil {
266
+ t.Fatalf("Error listening: %v", listenErr)
267
+ }
268
+
269
+ var serverConn net.Conn
270
+ var connErr error
271
+ go func() {
272
+ serverConn, connErr = listener.Accept()
273
+ if connErr != nil {
274
+ t.Fatalf("Error accepting: %v", connErr)
275
+ }
276
+
277
+ serverSpdyConn, _ := NewConnection(serverConn, true)
278
+ go serverSpdyConn.Serve(func(stream *Stream) {
279
+ stream.SendReply(http.Header{}, tc.closeSender)
280
+ })
281
+ }()
282
+
283
+ conn, dialErr := net.Dial("tcp", listener.Addr().String())
284
+ if dialErr != nil {
285
+ t.Fatalf("Error dialing server: %s", dialErr)
286
+ }
287
+
288
+ spdyConn, spdyErr := NewConnection(conn, false)
289
+ if spdyErr != nil {
290
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
291
+ }
292
+ go spdyConn.Serve(NoOpStreamHandler)
293
+
294
+ authenticated = true
295
+ stream, streamErr := spdyConn.CreateStream(http.Header{}, nil, false)
296
+ if streamErr != nil {
297
+ t.Fatalf("Error creating stream: %s", streamErr)
298
+ }
299
+
300
+ waitErr := stream.Wait()
301
+ if waitErr != nil {
302
+ t.Fatalf("Error waiting for stream: %s", waitErr)
303
+ }
304
+
305
+ if tc.closeReceiver {
306
+ // make stream half closed, receive only
307
+ stream.Close()
308
+ }
309
+
310
+ streamch := make(chan error, 1)
311
+ go func() {
312
+ b := make([]byte, 1)
313
+ _, err := stream.Read(b)
314
+ streamch <- err
315
+ }()
316
+
317
+ closeErr := serverConn.Close()
318
+ if closeErr != nil {
319
+ t.Fatalf("Error shutting down server: %s", closeErr)
320
+ }
321
+
322
+ select {
323
+ case e := <-streamch:
324
+ if e == nil || e != io.EOF {
325
+ t.Fatalf("(%d) Expected to get an EOF stream error", tix)
326
+ }
327
+ }
328
+
329
+ closeErr = conn.Close()
330
+ if closeErr != nil {
331
+ t.Fatalf("Error closing client connection: %s", closeErr)
332
+ }
333
+
334
+ listenErr = listener.Close()
335
+ if listenErr != nil {
336
+ t.Fatalf("Error closing listener: %s", listenErr)
337
+ }
338
+ }
339
+}
340
+
341
+func TestCloseNotification(t *testing.T) {
342
+ listener, listenErr := net.Listen("tcp", "localhost:0")
343
+ if listenErr != nil {
344
+ t.Fatalf("Error listening: %v", listenErr)
345
+ }
346
+ listen := listener.Addr().String()
347
+
348
+ serverConnChan := make(chan net.Conn)
349
+ go func() {
350
+ serverConn, err := listener.Accept()
351
+ if err != nil {
352
+ t.Fatalf("Error accepting: %v", err)
353
+ }
354
+
355
+ serverSpdyConn, err := NewConnection(serverConn, true)
356
+ if err != nil {
357
+ t.Fatalf("Error creating server connection: %v", err)
358
+ }
359
+ go serverSpdyConn.Serve(NoOpStreamHandler)
360
+ <-serverSpdyConn.CloseChan()
361
+ serverConnChan <- serverConn
362
+ }()
363
+
364
+ conn, dialErr := net.Dial("tcp", listen)
365
+ if dialErr != nil {
366
+ t.Fatalf("Error dialing server: %s", dialErr)
367
+ }
368
+
369
+ spdyConn, spdyErr := NewConnection(conn, false)
370
+ if spdyErr != nil {
371
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
372
+ }
373
+ go spdyConn.Serve(NoOpStreamHandler)
374
+
375
+ // close client conn
376
+ err := conn.Close()
377
+ if err != nil {
378
+ t.Fatalf("Error closing client connection: %v", err)
379
+ }
380
+
381
+ var serverConn net.Conn
382
+ select {
383
+ case serverConn = <-serverConnChan:
384
+ }
385
+
386
+ err = serverConn.Close()
387
+ if err != nil {
388
+ t.Fatalf("Error closing serverConn: %v", err)
389
+ }
390
+
391
+ listenErr = listener.Close()
392
+ if listenErr != nil {
393
+ t.Fatalf("Error closing listener: %s", listenErr)
394
+ }
395
+}
396
+
397
+func TestIdleShutdownRace(t *testing.T) {
398
+ var wg sync.WaitGroup
399
+ server, listen, serverErr := runServer(&wg)
400
+ if serverErr != nil {
401
+ t.Fatalf("Error initializing server: %s", serverErr)
402
+ }
403
+
404
+ conn, dialErr := net.Dial("tcp", listen)
405
+ if dialErr != nil {
406
+ t.Fatalf("Error dialing server: %s", dialErr)
407
+ }
408
+
409
+ spdyConn, spdyErr := NewConnection(conn, false)
410
+ if spdyErr != nil {
411
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
412
+ }
413
+ go spdyConn.Serve(NoOpStreamHandler)
414
+
415
+ authenticated = true
416
+ stream, err := spdyConn.CreateStream(http.Header{}, nil, false)
417
+ if err != nil {
418
+ t.Fatalf("Error creating stream: %v", err)
419
+ }
420
+
421
+ spdyConn.SetIdleTimeout(5 * time.Millisecond)
422
+ go func() {
423
+ time.Sleep(5 * time.Millisecond)
424
+ stream.Reset()
425
+ }()
426
+
427
+ select {
428
+ case <-spdyConn.CloseChan():
429
+ case <-time.After(20 * time.Millisecond):
430
+ t.Fatal("Timed out waiting for idle connection closure")
431
+ }
432
+
433
+ closeErr := server.Close()
434
+ if closeErr != nil {
435
+ t.Fatalf("Error shutting down server: %s", closeErr)
436
+ }
437
+ wg.Wait()
438
+}
439
+
440
+func TestIdleNoTimeoutSet(t *testing.T) {
441
+ var wg sync.WaitGroup
442
+ server, listen, serverErr := runServer(&wg)
443
+ if serverErr != nil {
444
+ t.Fatalf("Error initializing server: %s", serverErr)
445
+ }
446
+
447
+ conn, dialErr := net.Dial("tcp", listen)
448
+ if dialErr != nil {
449
+ t.Fatalf("Error dialing server: %s", dialErr)
450
+ }
451
+
452
+ spdyConn, spdyErr := NewConnection(conn, false)
453
+ if spdyErr != nil {
454
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
455
+ }
456
+ go spdyConn.Serve(NoOpStreamHandler)
457
+
458
+ select {
459
+ case <-spdyConn.CloseChan():
460
+ t.Fatal("Unexpected connection closure")
461
+ case <-time.After(10 * time.Millisecond):
462
+ }
463
+
464
+ closeErr := server.Close()
465
+ if closeErr != nil {
466
+ t.Fatalf("Error shutting down server: %s", closeErr)
467
+ }
468
+ wg.Wait()
469
+}
470
+
471
+func TestIdleClearTimeout(t *testing.T) {
472
+ var wg sync.WaitGroup
473
+ server, listen, serverErr := runServer(&wg)
474
+ if serverErr != nil {
475
+ t.Fatalf("Error initializing server: %s", serverErr)
476
+ }
477
+
478
+ conn, dialErr := net.Dial("tcp", listen)
479
+ if dialErr != nil {
480
+ t.Fatalf("Error dialing server: %s", dialErr)
481
+ }
482
+
483
+ spdyConn, spdyErr := NewConnection(conn, false)
484
+ if spdyErr != nil {
485
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
486
+ }
487
+ go spdyConn.Serve(NoOpStreamHandler)
488
+
489
+ spdyConn.SetIdleTimeout(10 * time.Millisecond)
490
+ spdyConn.SetIdleTimeout(0)
491
+ select {
492
+ case <-spdyConn.CloseChan():
493
+ t.Fatal("Unexpected connection closure")
494
+ case <-time.After(20 * time.Millisecond):
495
+ }
496
+
497
+ closeErr := server.Close()
498
+ if closeErr != nil {
499
+ t.Fatalf("Error shutting down server: %s", closeErr)
500
+ }
501
+ wg.Wait()
502
+}
503
+
504
+func TestIdleNoData(t *testing.T) {
505
+ var wg sync.WaitGroup
506
+ server, listen, serverErr := runServer(&wg)
507
+ if serverErr != nil {
508
+ t.Fatalf("Error initializing server: %s", serverErr)
509
+ }
510
+
511
+ conn, dialErr := net.Dial("tcp", listen)
512
+ if dialErr != nil {
513
+ t.Fatalf("Error dialing server: %s", dialErr)
514
+ }
515
+
516
+ spdyConn, spdyErr := NewConnection(conn, false)
517
+ if spdyErr != nil {
518
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
519
+ }
520
+ go spdyConn.Serve(NoOpStreamHandler)
521
+
522
+ spdyConn.SetIdleTimeout(10 * time.Millisecond)
523
+ <-spdyConn.CloseChan()
524
+
525
+ closeErr := server.Close()
526
+ if closeErr != nil {
527
+ t.Fatalf("Error shutting down server: %s", closeErr)
528
+ }
529
+ wg.Wait()
530
+}
531
+
532
+func TestIdleWithData(t *testing.T) {
533
+ var wg sync.WaitGroup
534
+ server, listen, serverErr := runServer(&wg)
535
+ if serverErr != nil {
536
+ t.Fatalf("Error initializing server: %s", serverErr)
537
+ }
538
+
539
+ conn, dialErr := net.Dial("tcp", listen)
540
+ if dialErr != nil {
541
+ t.Fatalf("Error dialing server: %s", dialErr)
542
+ }
543
+
544
+ spdyConn, spdyErr := NewConnection(conn, false)
545
+ if spdyErr != nil {
546
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
547
+ }
548
+ go spdyConn.Serve(NoOpStreamHandler)
549
+
550
+ spdyConn.SetIdleTimeout(25 * time.Millisecond)
551
+
552
+ authenticated = true
553
+ stream, err := spdyConn.CreateStream(http.Header{}, nil, false)
554
+ if err != nil {
555
+ t.Fatalf("Error creating stream: %v", err)
556
+ }
557
+
558
+ writeCh := make(chan struct{})
559
+
560
+ go func() {
561
+ b := []byte{1, 2, 3, 4, 5}
562
+ for i := 0; i < 10; i++ {
563
+ _, err = stream.Write(b)
564
+ if err != nil {
565
+ t.Fatalf("Error writing to stream: %v", err)
566
+ }
567
+ time.Sleep(10 * time.Millisecond)
568
+ }
569
+ close(writeCh)
570
+ }()
571
+
572
+ writesFinished := false
573
+
574
+Loop:
575
+ for {
576
+ select {
577
+ case <-writeCh:
578
+ writesFinished = true
579
+ case <-spdyConn.CloseChan():
580
+ if !writesFinished {
581
+ t.Fatal("Connection closed before all writes finished")
582
+ }
583
+ break Loop
584
+ }
585
+ }
586
+
587
+ closeErr := server.Close()
588
+ if closeErr != nil {
589
+ t.Fatalf("Error shutting down server: %s", closeErr)
590
+ }
591
+ wg.Wait()
592
+}
593
+
594
+func TestIdleRace(t *testing.T) {
595
+ var wg sync.WaitGroup
596
+ server, listen, serverErr := runServer(&wg)
597
+ if serverErr != nil {
598
+ t.Fatalf("Error initializing server: %s", serverErr)
599
+ }
600
+
601
+ conn, dialErr := net.Dial("tcp", listen)
602
+ if dialErr != nil {
603
+ t.Fatalf("Error dialing server: %s", dialErr)
604
+ }
605
+
606
+ spdyConn, spdyErr := NewConnection(conn, false)
607
+ if spdyErr != nil {
608
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
609
+ }
610
+ go spdyConn.Serve(NoOpStreamHandler)
611
+
612
+ spdyConn.SetIdleTimeout(10 * time.Millisecond)
613
+
614
+ authenticated = true
615
+
616
+ for i := 0; i < 10; i++ {
617
+ _, err := spdyConn.CreateStream(http.Header{}, nil, false)
618
+ if err != nil {
619
+ t.Fatalf("Error creating stream: %v", err)
620
+ }
621
+ }
622
+
623
+ <-spdyConn.CloseChan()
624
+
625
+ closeErr := server.Close()
626
+ if closeErr != nil {
627
+ t.Fatalf("Error shutting down server: %s", closeErr)
628
+ }
629
+ wg.Wait()
630
+}
631
+
632
+func TestHalfClosedIdleTimeout(t *testing.T) {
633
+ listener, listenErr := net.Listen("tcp", "localhost:0")
634
+ if listenErr != nil {
635
+ t.Fatalf("Error listening: %v", listenErr)
636
+ }
637
+ listen := listener.Addr().String()
638
+
639
+ go func() {
640
+ serverConn, err := listener.Accept()
641
+ if err != nil {
642
+ t.Fatalf("Error accepting: %v", err)
643
+ }
644
+
645
+ serverSpdyConn, err := NewConnection(serverConn, true)
646
+ if err != nil {
647
+ t.Fatalf("Error creating server connection: %v", err)
648
+ }
649
+ go serverSpdyConn.Serve(func(s *Stream) {
650
+ s.SendReply(http.Header{}, true)
651
+ })
652
+ serverSpdyConn.SetIdleTimeout(10 * time.Millisecond)
653
+ }()
654
+
655
+ conn, dialErr := net.Dial("tcp", listen)
656
+ if dialErr != nil {
657
+ t.Fatalf("Error dialing server: %s", dialErr)
658
+ }
659
+
660
+ spdyConn, spdyErr := NewConnection(conn, false)
661
+ if spdyErr != nil {
662
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
663
+ }
664
+ go spdyConn.Serve(NoOpStreamHandler)
665
+
666
+ stream, err := spdyConn.CreateStream(http.Header{}, nil, false)
667
+ if err != nil {
668
+ t.Fatalf("Error creating stream: %v", err)
669
+ }
670
+
671
+ time.Sleep(20 * time.Millisecond)
672
+
673
+ stream.Reset()
674
+
675
+ err = spdyConn.Close()
676
+ if err != nil {
677
+ t.Fatalf("Error closing client spdy conn: %v", err)
678
+ }
679
+}
680
+
681
+func TestStreamReset(t *testing.T) {
682
+ var wg sync.WaitGroup
683
+ server, listen, serverErr := runServer(&wg)
684
+ if serverErr != nil {
685
+ t.Fatalf("Error initializing server: %s", serverErr)
686
+ }
687
+
688
+ conn, dialErr := net.Dial("tcp", listen)
689
+ if dialErr != nil {
690
+ t.Fatalf("Error dialing server: %s", dialErr)
691
+ }
692
+
693
+ spdyConn, spdyErr := NewConnection(conn, false)
694
+ if spdyErr != nil {
695
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
696
+ }
697
+ go spdyConn.Serve(NoOpStreamHandler)
698
+
699
+ authenticated = true
700
+ stream, streamErr := spdyConn.CreateStream(http.Header{}, nil, false)
701
+ if streamErr != nil {
702
+ t.Fatalf("Error creating stream: %s", streamErr)
703
+ }
704
+
705
+ buf := []byte("dskjahfkdusahfkdsahfkdsafdkas")
706
+ for i := 0; i < 10; i++ {
707
+ if _, err := stream.Write(buf); err != nil {
708
+ t.Fatalf("Error writing to stream: %s", err)
709
+ }
710
+ }
711
+ for i := 0; i < 10; i++ {
712
+ if _, err := stream.Read(buf); err != nil {
713
+ t.Fatalf("Error reading from stream: %s", err)
714
+ }
715
+ }
716
+
717
+ // fmt.Printf("Resetting...\n")
718
+ if err := stream.Reset(); err != nil {
719
+ t.Fatalf("Error reseting stream: %s", err)
720
+ }
721
+
722
+ closeErr := server.Close()
723
+ if closeErr != nil {
724
+ t.Fatalf("Error shutting down server: %s", closeErr)
725
+ }
726
+ wg.Wait()
727
+}
728
+
729
+func TestStreamResetWithDataRemaining(t *testing.T) {
730
+ var wg sync.WaitGroup
731
+ server, listen, serverErr := runServer(&wg)
732
+ if serverErr != nil {
733
+ t.Fatalf("Error initializing server: %s", serverErr)
734
+ }
735
+
736
+ conn, dialErr := net.Dial("tcp", listen)
737
+ if dialErr != nil {
738
+ t.Fatalf("Error dialing server: %s", dialErr)
739
+ }
740
+
741
+ spdyConn, spdyErr := NewConnection(conn, false)
742
+ if spdyErr != nil {
743
+ t.Fatalf("Error creating spdy connection: %s", spdyErr)
744
+ }
745
+ go spdyConn.Serve(NoOpStreamHandler)
746
+
747
+ authenticated = true
748
+ stream, streamErr := spdyConn.CreateStream(http.Header{}, nil, false)
749
+ if streamErr != nil {
750
+ t.Fatalf("Error creating stream: %s", streamErr)
751
+ }
752
+
753
+ buf := []byte("dskjahfkdusahfkdsahfkdsafdkas")
754
+ for i := 0; i < 10; i++ {
755
+ if _, err := stream.Write(buf); err != nil {
756
+ t.Fatalf("Error writing to stream: %s", err)
757
+ }
758
+ }
759
+
760
+ // read a bit to make sure a goroutine gets to <-dataChan
761
+ if _, err := stream.Read(buf); err != nil {
762
+ t.Fatalf("Error reading from stream: %s", err)
763
+ }
764
+
765
+ // fmt.Printf("Resetting...\n")
766
+ if err := stream.Reset(); err != nil {
767
+ t.Fatalf("Error reseting stream: %s", err)
768
+ }
769
+
770
+ closeErr := server.Close()
771
+ if closeErr != nil {
772
+ t.Fatalf("Error shutting down server: %s", closeErr)
773
+ }
774
+ wg.Wait()
775
+}
776
+
777
+type roundTripper struct {
778
+ conn net.Conn
779
+}
780
+
781
+func (s *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
782
+ r := *req
783
+ req = &r
784
+
785
+ conn, err := net.Dial("tcp", req.URL.Host)
786
+ if err != nil {
787
+ return nil, err
788
+ }
789
+
790
+ err = req.Write(conn)
791
+ if err != nil {
792
+ return nil, err
793
+ }
794
+
795
+ resp, err := http.ReadResponse(bufio.NewReader(conn), req)
796
+ if err != nil {
797
+ return nil, err
798
+ }
799
+
800
+ s.conn = conn
801
+
802
+ return resp, nil
803
+}
804
+
805
+// see https://github.com/GoogleCloudPlatform/kubernetes/issues/4882
806
+func TestFramingAfterRemoteConnectionClosed(t *testing.T) {
807
+ server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
808
+ streamCh := make(chan *Stream)
809
+
810
+ w.WriteHeader(http.StatusSwitchingProtocols)
811
+
812
+ netconn, _, _ := w.(http.Hijacker).Hijack()
813
+ conn, _ := NewConnection(netconn, true)
814
+ go conn.Serve(func(s *Stream) {
815
+ s.SendReply(http.Header{}, false)
816
+ streamCh <- s
817
+ })
818
+
819
+ stream := <-streamCh
820
+ io.Copy(stream, stream)
821
+
822
+ closeChan := make(chan struct{})
823
+ go func() {
824
+ stream.Reset()
825
+ conn.Close()
826
+ close(closeChan)
827
+ }()
828
+
829
+ <-closeChan
830
+ }))
831
+
832
+ server.Start()
833
+ defer server.Close()
834
+
835
+ req, err := http.NewRequest("GET", server.URL, nil)
836
+ if err != nil {
837
+ t.Fatalf("Error creating request: %s", err)
838
+ }
839
+
840
+ rt := &roundTripper{}
841
+ client := &http.Client{Transport: rt}
842
+
843
+ _, err = client.Do(req)
844
+ if err != nil {
845
+ t.Fatalf("unexpected error from client.Do: %s", err)
846
+ }
847
+
848
+ conn, err := NewConnection(rt.conn, false)
849
+ go conn.Serve(NoOpStreamHandler)
850
+
851
+ stream, err := conn.CreateStream(http.Header{}, nil, false)
852
+ if err != nil {
853
+ t.Fatalf("error creating client stream: %s", err)
854
+ }
855
+
856
+ n, err := stream.Write([]byte("hello"))
857
+ if err != nil {
858
+ t.Fatalf("error writing to stream: %s", err)
859
+ }
860
+ if n != 5 {
861
+ t.Fatalf("Expected to write 5 bytes, but actually wrote %d", n)
862
+ }
863
+
864
+ b := make([]byte, 5)
865
+ n, err = stream.Read(b)
866
+ if err != nil {
867
+ t.Fatalf("error reading from stream: %s", err)
868
+ }
869
+ if n != 5 {
870
+ t.Fatalf("Expected to read 5 bytes, but actually read %d", n)
871
+ }
872
+ if e, a := "hello", string(b[0:n]); e != a {
873
+ t.Fatalf("expected '%s', got '%s'", e, a)
874
+ }
875
+
876
+ stream.Reset()
877
+ conn.Close()
878
+}
879
+
880
+var authenticated bool
881
+
882
+func authStreamHandler(stream *Stream) {
883
+ if !authenticated {
884
+ stream.Refuse()
885
+ }
886
+ MirrorStreamHandler(stream)
887
+}
888
+
889
+func runServer(wg *sync.WaitGroup) (io.Closer, string, error) {
890
+ listener, listenErr := net.Listen("tcp", "localhost:0")
891
+ if listenErr != nil {
892
+ return nil, "", listenErr
893
+ }
894
+ wg.Add(1)
895
+ go func() {
896
+ for {
897
+ conn, connErr := listener.Accept()
898
+ if connErr != nil {
899
+ break
900
+ }
901
+
902
+ spdyConn, _ := NewConnection(conn, true)
903
+ go spdyConn.Serve(authStreamHandler)
904
+
905
+ }
906
+ wg.Done()
907
+ }()
908
+ return listener, listener.Addr().String(), nil
909
+}
Godeps/_workspace/src/github.com/docker/spdystream/stream.go
new
+327
@@ -0,0 +1,327 @@
1
+package spdystream
2
+
3
+import (
4
+ "errors"
5
+ "fmt"
6
+ "io"
7
+ "net"
8
+ "net/http"
9
+ "sync"
10
+ "time"
11
+
12
+ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/docker/spdystream/spdy"
13
+)
14
+
15
+var (
16
+ ErrUnreadPartialData = errors.New("unread partial data")
17
+)
18
+
19
+type Stream struct {
20
+ streamId spdy.StreamId
21
+ parent *Stream
22
+ conn *Connection
23
+ startChan chan error
24
+
25
+ dataLock sync.RWMutex
26
+ dataChan chan []byte
27
+ unread []byte
28
+
29
+ priority uint8
30
+ headers http.Header
31
+ headerChan chan http.Header
32
+ finishLock sync.Mutex
33
+ finished bool
34
+ replyCond *sync.Cond
35
+ replied bool
36
+ closeLock sync.Mutex
37
+ closeChan chan bool
38
+}
39
+
40
+// WriteData writes data to stream, sending a dataframe per call
41
+func (s *Stream) WriteData(data []byte, fin bool) error {
42
+ s.waitWriteReply()
43
+ var flags spdy.DataFlags
44
+
45
+ if fin {
46
+ flags = spdy.DataFlagFin
47
+ s.finishLock.Lock()
48
+ if s.finished {
49
+ s.finishLock.Unlock()
50
+ return ErrWriteClosedStream
51
+ }
52
+ s.finished = true
53
+ s.finishLock.Unlock()
54
+ }
55
+
56
+ dataFrame := &spdy.DataFrame{
57
+ StreamId: s.streamId,
58
+ Flags: flags,
59
+ Data: data,
60
+ }
61
+
62
+ debugMessage("(%p) (%d) Writing data frame", s, s.streamId)
63
+ return s.conn.framer.WriteFrame(dataFrame)
64
+}
65
+
66
+// Write writes bytes to a stream, calling write data for each call.
67
+func (s *Stream) Write(data []byte) (n int, err error) {
68
+ err = s.WriteData(data, false)
69
+ if err == nil {
70
+ n = len(data)
71
+ }
72
+ return
73
+}
74
+
75
+// Read reads bytes from a stream, a single read will never get more
76
+// than what is sent on a single data frame, but a multiple calls to
77
+// read may get data from the same data frame.
78
+func (s *Stream) Read(p []byte) (n int, err error) {
79
+ if s.unread == nil {
80
+ select {
81
+ case <-s.closeChan:
82
+ return 0, io.EOF
83
+ case read, ok := <-s.dataChan:
84
+ if !ok {
85
+ return 0, io.EOF
86
+ }
87
+ s.unread = read
88
+ }
89
+ }
90
+ n = copy(p, s.unread)
91
+ if n < len(s.unread) {
92
+ s.unread = s.unread[n:]
93
+ } else {
94
+ s.unread = nil
95
+ }
96
+ return
97
+}
98
+
99
+// ReadData reads an entire data frame and returns the byte array
100
+// from the data frame. If there is unread data from the result
101
+// of a Read call, this function will return an ErrUnreadPartialData.
102
+func (s *Stream) ReadData() ([]byte, error) {
103
+ debugMessage("(%p) Reading data from %d", s, s.streamId)
104
+ if s.unread != nil {
105
+ return nil, ErrUnreadPartialData
106
+ }
107
+ select {
108
+ case <-s.closeChan:
109
+ return nil, io.EOF
110
+ case read, ok := <-s.dataChan:
111
+ if !ok {
112
+ return nil, io.EOF
113
+ }
114
+ return read, nil
115
+ }
116
+}
117
+
118
+func (s *Stream) waitWriteReply() {
119
+ if s.replyCond != nil {
120
+ s.replyCond.L.Lock()
121
+ for !s.replied {
122
+ s.replyCond.Wait()
123
+ }
124
+ s.replyCond.L.Unlock()
125
+ }
126
+}
127
+
128
+// Wait waits for the stream to receive a reply.
129
+func (s *Stream) Wait() error {
130
+ return s.WaitTimeout(time.Duration(0))
131
+}
132
+
133
+// WaitTimeout waits for the stream to receive a reply or for timeout.
134
+// When the timeout is reached, ErrTimeout will be returned.
135
+func (s *Stream) WaitTimeout(timeout time.Duration) error {
136
+ var timeoutChan <-chan time.Time
137
+ if timeout > time.Duration(0) {
138
+ timeoutChan = time.After(timeout)
139
+ }
140
+
141
+ select {
142
+ case err := <-s.startChan:
143
+ if err != nil {
144
+ return err
145
+ }
146
+ break
147
+ case <-timeoutChan:
148
+ return ErrTimeout
149
+ }
150
+ return nil
151
+}
152
+
153
+// Close closes the stream by sending an empty data frame with the
154
+// finish flag set, indicating this side is finished with the stream.
155
+func (s *Stream) Close() error {
156
+ select {
157
+ case <-s.closeChan:
158
+ // Stream is now fully closed
159
+ s.conn.removeStream(s)
160
+ default:
161
+ break
162
+ }
163
+ return s.WriteData([]byte{}, true)
164
+}
165
+
166
+// Reset sends a reset frame, putting the stream into the fully closed state.
167
+func (s *Stream) Reset() error {
168
+ s.conn.removeStream(s)
169
+ return s.resetStream()
170
+}
171
+
172
+func (s *Stream) resetStream() error {
173
+ s.finishLock.Lock()
174
+ if s.finished {
175
+ s.finishLock.Unlock()
176
+ return nil
177
+ }
178
+ s.finished = true
179
+ s.finishLock.Unlock()
180
+
181
+ s.closeRemoteChannels()
182
+
183
+ resetFrame := &spdy.RstStreamFrame{
184
+ StreamId: s.streamId,
185
+ Status: spdy.Cancel,
186
+ }
187
+ return s.conn.framer.WriteFrame(resetFrame)
188
+}
189
+
190
+// CreateSubStream creates a stream using the current as the parent
191
+func (s *Stream) CreateSubStream(headers http.Header, fin bool) (*Stream, error) {
192
+ return s.conn.CreateStream(headers, s, fin)
193
+}
194
+
195
+// SetPriority sets the stream priority, does not affect the
196
+// remote priority of this stream after Open has been called.
197
+// Valid values are 0 through 7, 0 being the highest priority
198
+// and 7 the lowest.
199
+func (s *Stream) SetPriority(priority uint8) {
200
+ s.priority = priority
201
+}
202
+
203
+// SendHeader sends a header frame across the stream
204
+func (s *Stream) SendHeader(headers http.Header, fin bool) error {
205
+ return s.conn.sendHeaders(headers, s, fin)
206
+}
207
+
208
+// SendReply sends a reply on a stream, only valid to be called once
209
+// when handling a new stream
210
+func (s *Stream) SendReply(headers http.Header, fin bool) error {
211
+ if s.replyCond == nil {
212
+ return errors.New("cannot reply on initiated stream")
213
+ }
214
+ s.replyCond.L.Lock()
215
+ defer s.replyCond.L.Unlock()
216
+ if s.replied {
217
+ return nil
218
+ }
219
+
220
+ err := s.conn.sendReply(headers, s, fin)
221
+ if err != nil {
222
+ return err
223
+ }
224
+
225
+ s.replied = true
226
+ s.replyCond.Broadcast()
227
+ return nil
228
+}
229
+
230
+// Refuse sends a reset frame with the status refuse, only
231
+// valid to be called once when handling a new stream. This
232
+// may be used to indicate that a stream is not allowed
233
+// when http status codes are not being used.
234
+func (s *Stream) Refuse() error {
235
+ if s.replied {
236
+ return nil
237
+ }
238
+ s.replied = true
239
+ return s.conn.sendReset(spdy.RefusedStream, s)
240
+}
241
+
242
+// Cancel sends a reset frame with the status canceled. This
243
+// can be used at any time by the creator of the Stream to
244
+// indicate the stream is no longer needed.
245
+func (s *Stream) Cancel() error {
246
+ return s.conn.sendReset(spdy.Cancel, s)
247
+}
248
+
249
+// ReceiveHeader receives a header sent on the other side
250
+// of the stream. This function will block until a header
251
+// is received or stream is closed.
252
+func (s *Stream) ReceiveHeader() (http.Header, error) {
253
+ select {
254
+ case <-s.closeChan:
255
+ break
256
+ case header, ok := <-s.headerChan:
257
+ if !ok {
258
+ return nil, fmt.Errorf("header chan closed")
259
+ }
260
+ return header, nil
261
+ }
262
+ return nil, fmt.Errorf("stream closed")
263
+}
264
+
265
+// Parent returns the parent stream
266
+func (s *Stream) Parent() *Stream {
267
+ return s.parent
268
+}
269
+
270
+// Headers returns the headers used to create the stream
271
+func (s *Stream) Headers() http.Header {
272
+ return s.headers
273
+}
274
+
275
+// String returns the string version of stream using the
276
+// streamId to uniquely identify the stream
277
+func (s *Stream) String() string {
278
+ return fmt.Sprintf("stream:%d", s.streamId)
279
+}
280
+
281
+// Identifier returns a 32 bit identifier for the stream
282
+func (s *Stream) Identifier() uint32 {
283
+ return uint32(s.streamId)
284
+}
285
+
286
+// IsFinished returns whether the stream has finished
287
+// sending data
288
+func (s *Stream) IsFinished() bool {
289
+ return s.finished
290
+}
291
+
292
+// Implement net.Conn interface
293
+
294
+func (s *Stream) LocalAddr() net.Addr {
295
+ return s.conn.conn.LocalAddr()
296
+}
297
+
298
+func (s *Stream) RemoteAddr() net.Addr {
299
+ return s.conn.conn.RemoteAddr()
300
+}
301
+
302
+// TODO set per stream values instead of connection-wide
303
+
304
+func (s *Stream) SetDeadline(t time.Time) error {
305
+ return s.conn.conn.SetDeadline(t)
306
+}
307
+
308
+func (s *Stream) SetReadDeadline(t time.Time) error {
309
+ return s.conn.conn.SetReadDeadline(t)
310
+}
311
+
312
+func (s *Stream) SetWriteDeadline(t time.Time) error {
313
+ return s.conn.conn.SetWriteDeadline(t)
314
+}
315
+
316
+func (s *Stream) closeRemoteChannels() {
317
+ s.closeLock.Lock()
318
+ defer s.closeLock.Unlock()
319
+ select {
320
+ case <-s.closeChan:
321
+ default:
322
+ close(s.closeChan)
323
+ s.dataLock.Lock()
324
+ defer s.dataLock.Unlock()
325
+ close(s.dataChan)
326
+ }
327
+}
Godeps/_workspace/src/github.com/docker/spdystream/utils.go
new
+16
@@ -0,0 +1,16 @@
1
+package spdystream
2
+
3
+import (
4
+ "log"
5
+ "os"
6
+)
7
+
8
+var (
9
+ DEBUG = os.Getenv("DEBUG")
10
+)
11
+
12
+func debugMessage(fmt string, args ...interface{}) {
13
+ if DEBUG != "" {
14
+ log.Printf(fmt, args...)
15
+ }
16
+}
Godeps/_workspace/src/github.com/docker/spdystream/ws/connection.go
new
+65
@@ -0,0 +1,65 @@
1
+package ws
2
+
3
+import (
4
+ "github.com/gorilla/websocket"
5
+ "io"
6
+ "log"
7
+ "time"
8
+)
9
+
10
+// Wrap an HTTP2 connection over WebSockets and
11
+// use the underlying WebSocket framing for proxy
12
+// compatibility.
13
+type Conn struct {
14
+ *websocket.Conn
15
+ reader io.Reader
16
+}
17
+
18
+func NewConnection(w *websocket.Conn) *Conn {
19
+ return &Conn{Conn: w}
20
+}
21
+
22
+func (c Conn) Write(b []byte) (int, error) {
23
+ err := c.WriteMessage(websocket.BinaryMessage, b)
24
+ if err != nil {
25
+ return 0, err
26
+ }
27
+ return len(b), nil
28
+}
29
+
30
+func (c Conn) Read(b []byte) (int, error) {
31
+ if c.reader == nil {
32
+ t, r, err := c.NextReader()
33
+ if err != nil {
34
+ return 0, err
35
+ }
36
+ if t != websocket.BinaryMessage {
37
+ log.Printf("ws: ignored non-binary message in stream")
38
+ return 0, nil
39
+ }
40
+ c.reader = r
41
+ }
42
+ n, err := c.reader.Read(b)
43
+ if err != nil {
44
+ if err == io.EOF {
45
+ c.reader = nil
46
+ }
47
+ return n, err
48
+ }
49
+ return n, nil
50
+}
51
+
52
+func (c Conn) SetDeadline(t time.Time) error {
53
+ if err := c.Conn.SetReadDeadline(t); err != nil {
54
+ return err
55
+ }
56
+ if err := c.Conn.SetWriteDeadline(t); err != nil {
57
+ return err
58
+ }
59
+ return nil
60
+}
61
+
62
+func (c Conn) Close() error {
63
+ err := c.Conn.Close()
64
+ return err
65
+}
Godeps/_workspace/src/github.com/docker/spdystream/ws/ws_test.go
new
+175
@@ -0,0 +1,175 @@
1
+package ws
2
+
3
+import (
4
+ "bytes"
5
+ "github.com/gorilla/websocket"
6
+ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/docker/spdystream"
7
+ "io"
8
+ "log"
9
+ "net/http"
10
+ "net/http/httptest"
11
+ "strings"
12
+ "testing"
13
+)
14
+
15
+var upgrader = websocket.Upgrader{
16
+ ReadBufferSize: 1024,
17
+ WriteBufferSize: 1024,
18
+}
19
+
20
+var serverSpdyConn *spdystream.Connection
21
+
22
+// Connect to the Websocket endpoint at ws://localhost
23
+// using SPDY over Websockets framing.
24
+func ExampleConn() {
25
+ wsconn, _, _ := websocket.DefaultDialer.Dial("ws://localhost/", http.Header{"Origin": {"http://localhost/"}})
26
+ conn, _ := spdystream.NewConnection(NewConnection(wsconn), false)
27
+ go conn.Serve(spdystream.NoOpStreamHandler, spdystream.NoAuthHandler)
28
+ stream, _ := conn.CreateStream(http.Header{}, nil, false)
29
+ stream.Wait()
30
+}
31
+
32
+func serveWs(w http.ResponseWriter, r *http.Request) {
33
+ if r.Method != "GET" {
34
+ http.Error(w, "Method not allowed", 405)
35
+ return
36
+ }
37
+
38
+ ws, err := upgrader.Upgrade(w, r, nil)
39
+ if err != nil {
40
+ if _, ok := err.(websocket.HandshakeError); !ok {
41
+ log.Println(err)
42
+ }
43
+ return
44
+ }
45
+
46
+ wrap := NewConnection(ws)
47
+ spdyConn, err := spdystream.NewConnection(wrap, true)
48
+ if err != nil {
49
+ log.Fatal(err)
50
+ return
51
+ }
52
+ serverSpdyConn = spdyConn
53
+ go spdyConn.Serve(spdystream.MirrorStreamHandler, authStreamHandler)
54
+}
55
+
56
+func TestSpdyStreamOverWs(t *testing.T) {
57
+ server := httptest.NewServer(http.HandlerFunc(serveWs))
58
+ defer server.Close()
59
+ defer func() {
60
+ if serverSpdyConn != nil {
61
+ serverSpdyConn.Close()
62
+ }
63
+ }()
64
+
65
+ wsconn, _, err := websocket.DefaultDialer.Dial(strings.Replace(server.URL, "http://", "ws://", 1), http.Header{"Origin": {server.URL}})
66
+ if err != nil {
67
+ t.Fatal(err)
68
+ }
69
+
70
+ wrap := NewConnection(wsconn)
71
+ spdyConn, err := spdystream.NewConnection(wrap, false)
72
+ if err != nil {
73
+ defer wsconn.Close()
74
+ t.Fatal(err)
75
+ }
76
+ defer spdyConn.Close()
77
+ authenticated = true
78
+ go spdyConn.Serve(spdystream.NoOpStreamHandler, spdystream.RejectAuthHandler)
79
+
80
+ stream, streamErr := spdyConn.CreateStream(http.Header{}, nil, false)
81
+ if streamErr != nil {
82
+ t.Fatalf("Error creating stream: %s", streamErr)
83
+ }
84
+
85
+ waitErr := stream.Wait()
86
+ if waitErr != nil {
87
+ t.Fatalf("Error waiting for stream: %s", waitErr)
88
+ }
89
+
90
+ message := []byte("hello")
91
+ writeErr := stream.WriteData(message, false)
92
+ if writeErr != nil {
93
+ t.Fatalf("Error writing data")
94
+ }
95
+
96
+ buf := make([]byte, 10)
97
+ n, readErr := stream.Read(buf)
98
+ if readErr != nil {
99
+ t.Fatalf("Error reading data from stream: %s", readErr)
100
+ }
101
+ if n != 5 {
102
+ t.Fatalf("Unexpected number of bytes read:\nActual: %d\nExpected: 5", n)
103
+ }
104
+ if bytes.Compare(buf[:n], message) != 0 {
105
+ t.Fatalf("Did not receive expected message:\nActual: %s\nExpectd: %s", buf, message)
106
+ }
107
+
108
+ writeErr = stream.WriteData(message, true)
109
+ if writeErr != nil {
110
+ t.Fatalf("Error writing data")
111
+ }
112
+
113
+ smallBuf := make([]byte, 3)
114
+ n, readErr = stream.Read(smallBuf)
115
+ if readErr != nil {
116
+ t.Fatalf("Error reading data from stream: %s", readErr)
117
+ }
118
+ if n != 3 {
119
+ t.Fatalf("Unexpected number of bytes read:\nActual: %d\nExpected: 3", n)
120
+ }
121
+ if bytes.Compare(smallBuf[:n], []byte("hel")) != 0 {
122
+ t.Fatalf("Did not receive expected message:\nActual: %s\nExpectd: %s", smallBuf[:n], message)
123
+ }
124
+ n, readErr = stream.Read(smallBuf)
125
+ if readErr != nil {
126
+ t.Fatalf("Error reading data from stream: %s", readErr)
127
+ }
128
+ if n != 2 {
129
+ t.Fatalf("Unexpected number of bytes read:\nActual: %d\nExpected: 2", n)
130
+ }
131
+ if bytes.Compare(smallBuf[:n], []byte("lo")) != 0 {
132
+ t.Fatalf("Did not receive expected message:\nActual: %s\nExpected: lo", smallBuf[:n])
133
+ }
134
+
135
+ n, readErr = stream.Read(buf)
136
+ if readErr != io.EOF {
137
+ t.Fatalf("Expected EOF reading from finished stream, read %d bytes", n)
138
+ }
139
+
140
+ streamCloseErr := stream.Close()
141
+ if streamCloseErr != nil {
142
+ t.Fatalf("Error closing stream: %s", streamCloseErr)
143
+ }
144
+
145
+ // Closing again should return nil
146
+ streamCloseErr = stream.Close()
147
+ if streamCloseErr != nil {
148
+ t.Fatalf("Error closing stream: %s", streamCloseErr)
149
+ }
150
+
151
+ authenticated = false
152
+ badStream, badStreamErr := spdyConn.CreateStream(http.Header{}, nil, false)
153
+ if badStreamErr != nil {
154
+ t.Fatalf("Error creating stream: %s", badStreamErr)
155
+ }
156
+
157
+ waitErr = badStream.Wait()
158
+ if waitErr == nil {
159
+ t.Fatalf("Did not receive error creating stream")
160
+ }
161
+ if waitErr != spdystream.ErrReset {
162
+ t.Fatalf("Unexpected error creating stream: %s", waitErr)
163
+ }
164
+
165
+ spdyCloseErr := spdyConn.Close()
166
+ if spdyCloseErr != nil {
167
+ t.Fatalf("Error closing spdy connection: %s", spdyCloseErr)
168
+ }
169
+}
170
+
171
+var authenticated bool
172
+
173
+func authStreamHandler(header http.Header, slot uint8, parent uint32) bool {
174
+ return authenticated
175
+}
Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/Godeps/Godeps.json
+2
-2
@@ -19,11 +19,11 @@
19
},
20
{
21
"ImportPath": "github.com/whyrusleeping/go-multiplex",
22
- "Rev": "ce5baa716247510379cb7640a14da857afd3b622"
22
+ "Rev": "474b9aebeb391746f304ddf7c764a5da12319857"
23
},
24
{
25
"ImportPath": "github.com/whyrusleeping/go-multistream",
26
- "Rev": "08e8f9c9f5665ed0c63ffde4fa5ef1d5fb3d516d"
26
+ "Rev": "31bb014803a6eba2261bda5593e42c016a5f33bb"
27
}
28
]
29
}
Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multiplex/multiplex.go
+9
-5
@@ -5,7 +5,7 @@ import (
5
"net"
6
7
smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer"
8
- mp "github.com/whyrusleeping/go-multiplex" // Conn is a connection to a remote peer.
8
+ mp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex" // Conn is a connection to a remote peer.
9
)
10
11
var ErrUseServe = errors.New("not implemented, use Serve")
@@ -29,15 +29,19 @@ func (c *conn) OpenStream() (smux.Stream, error) {
29
30
// AcceptStream accepts a stream opened by the other side.
31
func (c *conn) AcceptStream() (smux.Stream, error) {
32
- return nil, ErrUseServe
32
+ return c.Multiplex.Accept()
33
}
34
35
// Serve starts listening for incoming requests and handles them
36
// using given StreamHandler
37
func (c *conn) Serve(handler smux.StreamHandler) {
38
- c.Multiplex.Serve(func(s *mp.Stream) {
39
- handler(s)
40
- })
38
+ for {
39
+ s, err := c.AcceptStream()
40
+ if err != nil {
41
+ return
42
+ }
43
+ go handler(s)
44
+ }
45
}
46
47
// Transport is a go-peerstream transport that constructs
Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multistream/multistream.go
+1
-1
@@ -5,7 +5,7 @@ package multistream
5
import (
6
"net"
7
8
- mss "github.com/whyrusleeping/go-multistream"
8
+ mss "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream"
9
10
smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer"
11
multiplex "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multiplex"
Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/spdystream/spdystream.go
+1
-1
@@ -5,7 +5,7 @@ import (
5
"net"
6
"net/http"
7
8
- ss "github.com/docker/spdystream"
8
+ ss "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/docker/spdystream"
9
smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer"
10
)
11
Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/README.md
new
+43
@@ -0,0 +1,43 @@
1
+#Multistream-select router
2
+This package implements a simple stream router for the multistream-select protocol.
3
+The protocol is defined [here](https://github.com/jbenet/multistream).
4
+
5
+
6
+Usage:
7
+
8
+```go
9
+package main
10
+
11
+import (
12
+ "fmt"
13
+ ms "github.com/whyrusleeping/go-multistream"
14
+ "io"
15
+ "net"
16
+)
17
+
18
+func main() {
19
+ mux := ms.NewMultistreamMuxer()
20
+ mux.AddHandler("/cats", func(rwc io.ReadWriteCloser) error {
21
+ fmt.Fprintln(rwc, "HELLO I LIKE CATS")
22
+ return rwc.Close()
23
+ })
24
+ mux.AddHandler("/dogs", func(rwc io.ReadWriteCloser) error {
25
+ fmt.Fprintln(rwc, "HELLO I LIKE DOGS")
26
+ return rwc.Close()
27
+ })
28
+
29
+ list, err := net.Listen("tcp", ":8765")
30
+ if err != nil {
31
+ panic(err)
32
+ }
33
+
34
+ for {
35
+ con, err := list.Accept()
36
+ if err != nil {
37
+ panic(err)
38
+ }
39
+
40
+ go mux.Handle(con)
41
+ }
42
+}
43
+```
Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/client.go
new
+75
@@ -0,0 +1,75 @@
1
+package multistream
2
+
3
+import (
4
+ "errors"
5
+ "io"
6
+)
7
+
8
+var ErrNotSupported = errors.New("protocol not supported")
9
+
10
+func SelectProtoOrFail(proto string, rwc io.ReadWriteCloser) error {
11
+ err := handshake(rwc)
12
+ if err != nil {
13
+ return err
14
+ }
15
+
16
+ return trySelect(proto, rwc)
17
+}
18
+
19
+func SelectOneOf(protos []string, rwc io.ReadWriteCloser) (string, error) {
20
+ err := handshake(rwc)
21
+ if err != nil {
22
+ return "", err
23
+ }
24
+
25
+ for _, p := range protos {
26
+ err := trySelect(p, rwc)
27
+ switch err {
28
+ case nil:
29
+ return p, nil
30
+ case ErrNotSupported:
31
+ default:
32
+ return "", err
33
+ }
34
+ }
35
+ return "", ErrNotSupported
36
+}
37
+
38
+func handshake(rwc io.ReadWriteCloser) error {
39
+ tok, err := ReadNextToken(rwc)
40
+ if err != nil {
41
+ return err
42
+ }
43
+
44
+ if tok != ProtocolID {
45
+ return errors.New("received mismatch in protocol id")
46
+ }
47
+
48
+ err = delimWrite(rwc, []byte(ProtocolID))
49
+ if err != nil {
50
+ return err
51
+ }
52
+
53
+ return nil
54
+}
55
+
56
+func trySelect(proto string, rwc io.ReadWriteCloser) error {
57
+ err := delimWrite(rwc, []byte(proto))
58
+ if err != nil {
59
+ return err
60
+ }
61
+
62
+ tok, err := ReadNextToken(rwc)
63
+ if err != nil {
64
+ return err
65
+ }
66
+
67
+ switch tok {
68
+ case proto:
69
+ return nil
70
+ case "na":
71
+ return ErrNotSupported
72
+ default:
73
+ return errors.New("unrecognized response: " + tok)
74
+ }
75
+}
Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/multistream.go
new
+193
@@ -0,0 +1,193 @@
1
+package multistream
2
+
3
+import (
4
+ "bytes"
5
+ "encoding/binary"
6
+ "errors"
7
+ "io"
8
+ "sync"
9
+)
10
+
11
+var ErrTooLarge = errors.New("incoming message was too large")
12
+
13
+const ProtocolID = "/multistream/1.0.0"
14
+
15
+type HandlerFunc func(io.ReadWriteCloser) error
16
+
17
+type MultistreamMuxer struct {
18
+ handlerlock sync.Mutex
19
+ handlers map[string]HandlerFunc
20
+}
21
+
22
+func NewMultistreamMuxer() *MultistreamMuxer {
23
+ return &MultistreamMuxer{handlers: make(map[string]HandlerFunc)}
24
+}
25
+
26
+func writeUvarint(w io.Writer, i uint64) error {
27
+ varintbuf := make([]byte, 32)
28
+ n := binary.PutUvarint(varintbuf, i)
29
+ _, err := w.Write(varintbuf[:n])
30
+ if err != nil {
31
+ return err
32
+ }
33
+ return nil
34
+}
35
+
36
+func delimWrite(w io.Writer, mes []byte) error {
37
+ err := writeUvarint(w, uint64(len(mes)+1))
38
+ if err != nil {
39
+ return err
40
+ }
41
+
42
+ _, err = w.Write(mes)
43
+ if err != nil {
44
+ return err
45
+ }
46
+
47
+ _, err = w.Write([]byte{'\n'})
48
+ if err != nil {
49
+ return err
50
+ }
51
+ return nil
52
+}
53
+
54
+func (msm *MultistreamMuxer) AddHandler(protocol string, handler HandlerFunc) {
55
+ msm.handlerlock.Lock()
56
+ msm.handlers[protocol] = handler
57
+ msm.handlerlock.Unlock()
58
+}
59
+
60
+func (msm *MultistreamMuxer) RemoveHandler(protocol string) {
61
+ msm.handlerlock.Lock()
62
+ delete(msm.handlers, protocol)
63
+ msm.handlerlock.Unlock()
64
+}
65
+
66
+func (msm *MultistreamMuxer) Protocols() []string {
67
+ var out []string
68
+ msm.handlerlock.Lock()
69
+ for k, _ := range msm.handlers {
70
+ out = append(out, k)
71
+ }
72
+ msm.handlerlock.Unlock()
73
+ return out
74
+}
75
+
76
+func (msm *MultistreamMuxer) Negotiate(rwc io.ReadWriteCloser) (string, HandlerFunc, error) {
77
+ // Send our protocol ID
78
+ err := delimWrite(rwc, []byte(ProtocolID))
79
+ if err != nil {
80
+ return "", nil, err
81
+ }
82
+
83
+ line, err := ReadNextToken(rwc)
84
+ if err != nil {
85
+ return "", nil, err
86
+ }
87
+
88
+ if line != ProtocolID {
89
+ rwc.Close()
90
+ return "", nil, errors.New("client connected with incorrect version")
91
+ }
92
+
93
+loop:
94
+ for {
95
+ // Now read and respond to commands until they send a valid protocol id
96
+ tok, err := ReadNextToken(rwc)
97
+ if err != nil {
98
+ return "", nil, err
99
+ }
100
+
101
+ switch tok {
102
+ case "ls":
103
+ buf := new(bytes.Buffer)
104
+ msm.handlerlock.Lock()
105
+ for proto, _ := range msm.handlers {
106
+ err := delimWrite(buf, []byte(proto))
107
+ if err != nil {
108
+ msm.handlerlock.Unlock()
109
+ return "", nil, err
110
+ }
111
+ }
112
+ msm.handlerlock.Unlock()
113
+ err := delimWrite(rwc, buf.Bytes())
114
+ if err != nil {
115
+ return "", nil, err
116
+ }
117
+ default:
118
+ msm.handlerlock.Lock()
119
+ h, ok := msm.handlers[tok]
120
+ msm.handlerlock.Unlock()
121
+ if !ok {
122
+ err := delimWrite(rwc, []byte("na"))
123
+ if err != nil {
124
+ return "", nil, err
125
+ }
126
+ continue loop
127
+ }
128
+
129
+ err := delimWrite(rwc, []byte(tok))
130
+ if err != nil {
131
+ return "", nil, err
132
+ }
133
+
134
+ // hand off processing to the sub-protocol handler
135
+ return tok, h, nil
136
+ }
137
+ }
138
+
139
+}
140
+
141
+func (msm *MultistreamMuxer) Handle(rwc io.ReadWriteCloser) error {
142
+ _, h, err := msm.Negotiate(rwc)
143
+ if err != nil {
144
+ return err
145
+ }
146
+ return h(rwc)
147
+}
148
+
149
+func ReadNextToken(rw io.ReadWriter) (string, error) {
150
+ br := &byteReader{rw}
151
+ length, err := binary.ReadUvarint(br)
152
+ if err != nil {
153
+ return "", err
154
+ }
155
+
156
+ if length > 64*1024 {
157
+ err := delimWrite(rw, []byte("messages over 64k are not allowed"))
158
+ if err != nil {
159
+ return "", err
160
+ }
161
+ return "", ErrTooLarge
162
+ }
163
+
164
+ buf := make([]byte, length)
165
+ _, err = io.ReadFull(rw, buf)
166
+ if err != nil {
167
+ return "", err
168
+ }
169
+
170
+ if len(buf) == 0 || buf[length-1] != '\n' {
171
+ return "", errors.New("message did not have trailing newline")
172
+ }
173
+
174
+ // slice off the trailing newline
175
+ buf = buf[:length-1]
176
+
177
+ return string(buf), nil
178
+}
179
+
180
+// byteReader implements the ByteReader interface that ReadUVarint requires
181
+type byteReader struct {
182
+ io.Reader
183
+}
184
+
185
+func (br *byteReader) ReadByte() (byte, error) {
186
+ var b [1]byte
187
+ _, err := br.Read(b[:])
188
+
189
+ if err != nil {
190
+ return 0, err
191
+ }
192
+ return b[0], nil
193
+}
Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/multistream_test.go
new
+153
@@ -0,0 +1,153 @@
1
+package multistream
2
+
3
+import (
4
+ "crypto/rand"
5
+ "io"
6
+ "net"
7
+ "testing"
8
+ "time"
9
+)
10
+
11
+func TestProtocolNegotiation(t *testing.T) {
12
+ a, b := net.Pipe()
13
+
14
+ mux := NewMultistreamMuxer()
15
+ mux.AddHandler("/a", nil)
16
+ mux.AddHandler("/b", nil)
17
+ mux.AddHandler("/c", nil)
18
+
19
+ done := make(chan struct{})
20
+ go func() {
21
+ selected, _, err := mux.Negotiate(a)
22
+ if err != nil {
23
+ t.Fatal(err)
24
+ }
25
+ if selected != "/a" {
26
+ t.Fatal("incorrect protocol selected")
27
+ }
28
+ close(done)
29
+ }()
30
+
31
+ err := SelectProtoOrFail("/a", b)
32
+ if err != nil {
33
+ t.Fatal(err)
34
+ }
35
+
36
+ select {
37
+ case <-time.After(time.Second):
38
+ t.Fatal("protocol negotiation didnt complete")
39
+ case <-done:
40
+ }
41
+
42
+ verifyPipe(t, a, b)
43
+}
44
+
45
+func TestSelectOne(t *testing.T) {
46
+ a, b := net.Pipe()
47
+
48
+ mux := NewMultistreamMuxer()
49
+ mux.AddHandler("/a", nil)
50
+ mux.AddHandler("/b", nil)
51
+ mux.AddHandler("/c", nil)
52
+
53
+ done := make(chan struct{})
54
+ go func() {
55
+ selected, _, err := mux.Negotiate(a)
56
+ if err != nil {
57
+ t.Fatal(err)
58
+ }
59
+ if selected != "/c" {
60
+ t.Fatal("incorrect protocol selected")
61
+ }
62
+ close(done)
63
+ }()
64
+
65
+ sel, err := SelectOneOf([]string{"/d", "/e", "/c"}, b)
66
+ if err != nil {
67
+ t.Fatal(err)
68
+ }
69
+
70
+ if sel != "/c" {
71
+ t.Fatal("selected wrong protocol")
72
+ }
73
+
74
+ select {
75
+ case <-time.After(time.Second):
76
+ t.Fatal("protocol negotiation didnt complete")
77
+ case <-done:
78
+ }
79
+
80
+ verifyPipe(t, a, b)
81
+}
82
+
83
+func TestSelectOneAndWrite(t *testing.T) {
84
+ a, b := net.Pipe()
85
+
86
+ mux := NewMultistreamMuxer()
87
+ mux.AddHandler("/a", nil)
88
+ mux.AddHandler("/b", nil)
89
+ mux.AddHandler("/c", nil)
90
+
91
+ done := make(chan struct{})
92
+ go func() {
93
+ selected, _, err := mux.Negotiate(a)
94
+ if err != nil {
95
+ t.Fatal(err)
96
+ }
97
+ if selected != "/c" {
98
+ t.Fatal("incorrect protocol selected")
99
+ }
100
+ close(done)
101
+ }()
102
+
103
+ sel, err := SelectOneOf([]string{"/d", "/e", "/c"}, b)
104
+ if err != nil {
105
+ t.Fatal(err)
106
+ }
107
+
108
+ if sel != "/c" {
109
+ t.Fatal("selected wrong protocol")
110
+ }
111
+
112
+ select {
113
+ case <-time.After(time.Second):
114
+ t.Fatal("protocol negotiation didnt complete")
115
+ case <-done:
116
+ }
117
+
118
+ verifyPipe(t, a, b)
119
+}
120
+
121
+func verifyPipe(t *testing.T, a, b io.ReadWriter) {
122
+ mes := make([]byte, 1024)
123
+ rand.Read(mes)
124
+ go func() {
125
+ b.Write(mes)
126
+ a.Write(mes)
127
+ }()
128
+
129
+ buf := make([]byte, len(mes))
130
+ n, err := a.Read(buf)
131
+ if err != nil {
132
+ t.Fatal(err)
133
+ }
134
+ if n != len(buf) {
135
+ t.Fatal("failed to read enough")
136
+ }
137
+
138
+ if string(buf) != string(mes) {
139
+ t.Fatal("somehow read wrong message")
140
+ }
141
+
142
+ n, err = b.Read(buf)
143
+ if err != nil {
144
+ t.Fatal(err)
145
+ }
146
+ if n != len(buf) {
147
+ t.Fatal("failed to read enough")
148
+ }
149
+
150
+ if string(buf) != string(mes) {
151
+ t.Fatal("somehow read wrong message")
152
+ }
153
+}
p2p/host/basic/basic_host.go
+19
-9
@@ -15,6 +15,8 @@ import (
15
protocol "github.com/ipfs/go-ipfs/p2p/protocol"
16
identify "github.com/ipfs/go-ipfs/p2p/protocol/identify"
17
relay "github.com/ipfs/go-ipfs/p2p/protocol/relay"
18
+
19
+ msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream"
20
)
21
22
var log = logging.Logger("p2p/host/basic")
@@ -39,7 +41,7 @@ const (
41
// * uses a nat service to establish NAT port mappings
42
type BasicHost struct {
43
network inet.Network
42
- mux *protocol.Mux
44
+ mux *msmux.MultistreamMuxer
45
ids *identify.IDService
46
relay *relay.RelayService
47
natmgr *natManager
@@ -53,7 +55,7 @@ type BasicHost struct {
55
func New(net inet.Network, opts ...interface{}) *BasicHost {
56
h := &BasicHost{
57
network: net,
56
- mux: protocol.NewMux(),
58
+ mux: msmux.NewMultistreamMuxer(),
59
bwc: metrics.NewBandwidthCounter(),
60
}
61
@@ -67,7 +69,12 @@ func New(net inet.Network, opts ...interface{}) *BasicHost {
69
70
// setup host services
71
h.ids = identify.NewIDService(h)
70
- h.relay = relay.NewRelayService(h, h.Mux().HandleSync)
72
+
73
+ muxh := h.Mux().Handle
74
+ handle := func(s inet.Stream) {
75
+ muxh(s)
76
+ }
77
+ h.relay = relay.NewRelayService(h, handle)
78
79
for _, o := range opts {
80
switch o := o.(type) {
@@ -95,7 +102,7 @@ func (h *BasicHost) newConnHandler(c inet.Conn) {
102
// newStreamHandler is the remote-opened stream handler for inet.Network
103
// TODO: this feels a bit wonky
104
func (h *BasicHost) newStreamHandler(s inet.Stream) {
98
- protoID, handle, err := h.Mux().ReadHeader(s)
105
+ protoID, handle, err := h.Mux().Negotiate(s)
106
if err != nil {
107
if err == io.EOF {
108
log.Debugf("protocol EOF: %s", s.Conn().RemotePeer())
@@ -105,7 +112,7 @@ func (h *BasicHost) newStreamHandler(s inet.Stream) {
112
return
113
}
114
108
- logStream := mstream.WrapStream(s, protoID, h.bwc)
115
+ logStream := mstream.WrapStream(s, protocol.ID(protoID), h.bwc)
116
117
go handle(logStream)
118
}
@@ -126,7 +133,7 @@ func (h *BasicHost) Network() inet.Network {
133
}
134
135
// Mux returns the Mux multiplexing incoming streams to protocol handlers
129
-func (h *BasicHost) Mux() *protocol.Mux {
136
+func (h *BasicHost) Mux() *msmux.MultistreamMuxer {
137
return h.mux
138
}
139
@@ -140,12 +147,15 @@ func (h *BasicHost) IDService() *identify.IDService {
147
// host.Mux().SetHandler(proto, handler)
148
// (Threadsafe)
149
func (h *BasicHost) SetStreamHandler(pid protocol.ID, handler inet.StreamHandler) {
143
- h.Mux().SetHandler(pid, handler)
150
+ h.Mux().AddHandler(string(pid), func(rwc io.ReadWriteCloser) error {
151
+ handler(rwc.(inet.Stream))
152
+ return nil
153
+ })
154
}
155
156
// RemoveStreamHandler returns ..
157
func (h *BasicHost) RemoveStreamHandler(pid protocol.ID) {
148
- h.Mux().RemoveHandler(pid)
158
+ h.Mux().RemoveHandler(string(pid))
159
}
160
161
// NewStream opens a new stream to given peer p, and writes a p2p/protocol
@@ -160,7 +170,7 @@ func (h *BasicHost) NewStream(pid protocol.ID, p peer.ID) (inet.Stream, error) {
170
171
logStream := mstream.WrapStream(s, pid, h.bwc)
172
163
- if err := protocol.WriteHeader(logStream, pid); err != nil {
173
+ if err := msmux.SelectProtoOrFail(string(pid), logStream); err != nil {
174
logStream.Close()
175
return nil, err
176
}
p2p/host/host.go
+3
-1
@@ -8,6 +8,8 @@ import (
8
peer "github.com/ipfs/go-ipfs/p2p/peer"
9
protocol "github.com/ipfs/go-ipfs/p2p/protocol"
10
logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
11
+
12
+ msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream"
13
)
14
15
var log = logging.Logger("p2p/host")
@@ -31,7 +33,7 @@ type Host interface {
33
Network() inet.Network
34
35
// Mux returns the Mux multiplexing incoming streams to protocol handlers
34
- Mux() *protocol.Mux
36
+ Mux() *msmux.MultistreamMuxer
37
38
// Connect ensures there is a connection between this host and the peer with
39
// given peer.ID. Connect will absorb the addresses in pi into its internal
p2p/host/routed/routed.go
+3
-1
@@ -15,6 +15,8 @@ import (
15
peer "github.com/ipfs/go-ipfs/p2p/peer"
16
protocol "github.com/ipfs/go-ipfs/p2p/protocol"
17
routing "github.com/ipfs/go-ipfs/routing"
18
+
19
+ msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream"
20
)
21
22
var log = logging.Logger("p2p/host/routed")
@@ -97,7 +99,7 @@ func (rh *RoutedHost) Network() inet.Network {
99
return rh.host.Network()
100
}
101
100
-func (rh *RoutedHost) Mux() *protocol.Mux {
102
+func (rh *RoutedHost) Mux() *msmux.MultistreamMuxer {
103
return rh.host.Mux()
104
}
105
p2p/net/swarm/swarm.go
+2
-4
@@ -20,7 +20,7 @@ import (
20
ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
21
ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream"
22
pst "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer"
23
- psy "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/yamux"
23
+ psmss "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multistream"
24
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
25
goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
26
prom "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus"
@@ -40,9 +40,7 @@ var peersTotal = prom.NewGaugeVec(prom.GaugeOpts{
40
}, []string{"peer_id"})
41
42
func init() {
43
- tpt := *psy.DefaultTransport
44
- tpt.MaxStreamWindowSize = 512 * 1024
45
- PSTransport = &tpt
43
+ PSTransport = psmss.NewTransport()
44
}
45
46
// Swarm is a connection muxer, allowing connections to other peers to
p2p/net/swarm/swarm_test.go
+9
@@ -237,6 +237,15 @@ func TestSwarm(t *testing.T) {
237
SubtestSwarm(t, swarms, msgs)
238
}
239
240
+func TestBasicSwarm(t *testing.T) {
241
+ // t.Skip("skipping for another test")
242
+ t.Parallel()
243
+
244
+ msgs := 1
245
+ swarms := 2
246
+ SubtestSwarm(t, swarms, msgs)
247
+}
248
+
249
func TestConnHandler(t *testing.T) {
250
// t.Skip("skipping for another test")
251
t.Parallel()
p2p/protocol/identify/id.go
+5
-5
@@ -7,13 +7,13 @@ import (
7
semver "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
8
ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io"
9
ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10
+ msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream"
11
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
12
13
mstream "github.com/ipfs/go-ipfs/metrics/stream"
14
host "github.com/ipfs/go-ipfs/p2p/host"
15
inet "github.com/ipfs/go-ipfs/p2p/net"
16
peer "github.com/ipfs/go-ipfs/p2p/peer"
16
- protocol "github.com/ipfs/go-ipfs/p2p/protocol"
17
pb "github.com/ipfs/go-ipfs/p2p/protocol/identify/pb"
18
config "github.com/ipfs/go-ipfs/repo/config"
19
lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
@@ -23,7 +23,7 @@ import (
23
var log = logging.Logger("net/identify")
24
25
// ID is the protocol.ID of the Identify Service.
26
-const ID protocol.ID = "/ipfs/identify"
26
+const ID = "/ipfs/identify"
27
28
// IpfsVersion holds the current protocol version for a client running this code
29
// TODO(jbenet): fix the versioning mess.
@@ -87,14 +87,14 @@ func (ids *IDService) IdentifyConn(c inet.Conn) {
87
s = mstream.WrapStream(s, ID, bwc)
88
89
// ok give the response to our handler.
90
- if err := protocol.WriteHeader(s, ID); err != nil {
90
+ if err := msmux.SelectProtoOrFail(ID, s); err != nil {
91
log.Debugf("error writing stream header for %s", ID)
92
log.Event(context.TODO(), "IdentifyOpenFailed", c.RemotePeer())
93
s.Close()
94
- c.Close()
94
return
95
+ } else {
96
+ ids.ResponseHandler(s)
97
}
97
- ids.ResponseHandler(s)
98
}
99
100
ids.currmu.Lock()
p2p/protocol/mux.go
deleted
-142
@@ -1,142 +0,0 @@
1
-package protocol
2
-
3
-import (
4
- "fmt"
5
- "io"
6
- "sync"
7
-
8
- context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9
- inet "github.com/ipfs/go-ipfs/p2p/net"
10
- lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
11
- logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
12
-)
13
-
14
-var log = logging.Logger("net/mux")
15
-
16
-type streamHandlerMap map[ID]inet.StreamHandler
17
-
18
-// Mux provides simple stream multixplexing.
19
-// It helps you precisely when:
20
-// * You have many streams
21
-// * You have function handlers
22
-//
23
-// It contains the handlers for each protocol accepted.
24
-// It dispatches handlers for streams opened by remote peers.
25
-type Mux struct {
26
- lock sync.RWMutex
27
- handlers streamHandlerMap
28
- defaultHandler inet.StreamHandler
29
-}
30
-
31
-func NewMux() *Mux {
32
- return &Mux{
33
- handlers: streamHandlerMap{},
34
- }
35
-}
36
-
37
-// Protocols returns the list of protocols this muxer has handlers for
38
-func (m *Mux) Protocols() []ID {
39
- m.lock.RLock()
40
- l := make([]ID, 0, len(m.handlers))
41
- for p := range m.handlers {
42
- l = append(l, p)
43
- }
44
- m.lock.RUnlock()
45
- return l
46
-}
47
-
48
-// ReadHeader reads the stream and returns the next Handler function
49
-// according to the muxer encoding.
50
-func (m *Mux) ReadHeader(s io.Reader) (ID, inet.StreamHandler, error) {
51
- p, err := ReadHeader(s)
52
- if err != nil {
53
- return "", nil, err
54
- }
55
-
56
- m.lock.RLock()
57
- defer m.lock.RUnlock()
58
- h, found := m.handlers[p]
59
-
60
- switch {
61
- case !found && m.defaultHandler != nil:
62
- return p, m.defaultHandler, nil
63
- case !found && m.defaultHandler == nil:
64
- return p, nil, fmt.Errorf("%s no handler with name: %s (%d)", m, p, len(p))
65
- default:
66
- return p, h, nil
67
- }
68
-}
69
-
70
-// String returns the muxer's printing representation
71
-func (m *Mux) String() string {
72
- m.lock.RLock()
73
- defer m.lock.RUnlock()
74
- return fmt.Sprintf("<Muxer %p %d>", m, len(m.handlers))
75
-}
76
-
77
-func (m *Mux) SetDefaultHandler(h inet.StreamHandler) {
78
- m.lock.Lock()
79
- m.defaultHandler = h
80
- m.lock.Unlock()
81
-}
82
-
83
-// SetHandler sets the protocol handler on the Network's Muxer.
84
-// This operation is threadsafe.
85
-func (m *Mux) SetHandler(p ID, h inet.StreamHandler) {
86
- log.Debugf("%s setting handler for protocol: %s (%d)", m, p, len(p))
87
- m.lock.Lock()
88
- m.handlers[p] = h
89
- m.lock.Unlock()
90
-}
91
-
92
-// RemoveHandler removes the protocol handler on the Network's Muxer.
93
-// This operation is threadsafe.
94
-func (m *Mux) RemoveHandler(p ID) {
95
- log.Debugf("%s removing handler for protocol: %s (%d)", m, p, len(p))
96
- m.lock.Lock()
97
- delete(m.handlers, p)
98
- m.lock.Unlock()
99
-}
100
-
101
-// Handle reads the next name off the Stream, and calls a handler function
102
-// This is done in its own goroutine, to avoid blocking the caller.
103
-func (m *Mux) Handle(s inet.Stream) {
104
- go m.HandleSync(s)
105
-}
106
-
107
-// HandleSync reads the next name off the Stream, and calls a handler function
108
-// This is done synchronously. The handler function will return before
109
-// HandleSync returns.
110
-func (m *Mux) HandleSync(s inet.Stream) {
111
- ctx := context.Background()
112
-
113
- name, handler, err := m.ReadHeader(s)
114
- if err != nil {
115
- err = fmt.Errorf("protocol mux error: %s", err)
116
- log.Event(ctx, "muxError", lgbl.Error(err))
117
- s.Close()
118
- return
119
- }
120
-
121
- log.Debugf("muxer handle protocol %s: %s", s.Conn().RemotePeer(), name)
122
- handler(s)
123
-}
124
-
125
-// ReadLengthPrefix reads the name from Reader with a length-byte-prefix.
126
-func ReadLengthPrefix(r io.Reader) (string, error) {
127
- // c-string identifier
128
- // the first byte is our length
129
- l := make([]byte, 1)
130
- if _, err := io.ReadFull(r, l); err != nil {
131
- return "", err
132
- }
133
- length := int(l[0])
134
-
135
- // the next are our identifier
136
- name := make([]byte, length)
137
- if _, err := io.ReadFull(r, name); err != nil {
138
- return "", err
139
- }
140
-
141
- return string(name), nil
142
-}
p2p/protocol/mux_test.go
deleted
-67
@@ -1,67 +0,0 @@
1
-package protocol
2
-
3
-import (
4
- "bytes"
5
- "testing"
6
-
7
- inet "github.com/ipfs/go-ipfs/p2p/net"
8
-)
9
-
10
-var testCases = map[string]string{
11
- "/bitswap": "\u0009/bitswap\n",
12
- "/dht": "\u0005/dht\n",
13
- "/ipfs": "\u0006/ipfs\n",
14
- "/ipfs/dksnafkasnfkdajfkdajfdsjadosiaaodj": ")/ipfs/dksnafkasnfkdajfkdajfdsjadosiaaodj\n",
15
-}
16
-
17
-func TestWrite(t *testing.T) {
18
- for k, v := range testCases {
19
- buf := new(bytes.Buffer)
20
- if err := WriteHeader(buf, ID(k)); err != nil {
21
- t.Fatal(err)
22
- }
23
-
24
- v2 := buf.Bytes()
25
- if !bytes.Equal(v2, []byte(v)) {
26
- t.Errorf("failed: %s - %v != %v", k, []byte(v), v2)
27
- }
28
- }
29
-}
30
-
31
-func TestHandler(t *testing.T) {
32
-
33
- outs := make(chan string, 10)
34
-
35
- h := func(n string) func(s inet.Stream) {
36
- return func(s inet.Stream) {
37
- outs <- n
38
- }
39
- }
40
-
41
- m := NewMux()
42
- m.SetDefaultHandler(h("default"))
43
- m.SetHandler("/dht", h("bitswap"))
44
- // m.Handlers["/ipfs"] = h("bitswap") // default!
45
- m.SetHandler("/bitswap", h("bitswap"))
46
- m.SetHandler("/ipfs/dksnafkasnfkdajfkdajfdsjadosiaaodj", h("bitswap"))
47
-
48
- for k, v := range testCases {
49
- buf := new(bytes.Buffer)
50
- if _, err := buf.Write([]byte(v)); err != nil {
51
- t.Error(err)
52
- continue
53
- }
54
-
55
- name, err := ReadHeader(buf)
56
- if err != nil {
57
- t.Error(err)
58
- continue
59
- }
60
-
61
- if name != ID(k) {
62
- t.Errorf("name mismatch: %s != %s", k, name)
63
- continue
64
- }
65
- }
66
-
67
-}
p2p/protocol/protocol.go
-31
@@ -1,11 +1,5 @@
1
package protocol
2
3
-import (
4
- "io"
5
-
6
- msgio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
7
-)
8
-
3
// ID is an identifier used to write protocol headers in streams.
4
type ID string
5
@@ -13,28 +7,3 @@ type ID string
7
const (
8
TestingID ID = "/p2p/_testing"
9
)
16
-
17
-// WriteHeader writes a protocol.ID header to an io.Writer. This is so
18
-// multiple protocols can be multiplexed on top of the same transport.
19
-//
20
-// We use go-msgio varint encoding:
21
-// <varint length><string name>\n
22
-// (the varint includes the \n)
23
-func WriteHeader(w io.Writer, id ID) error {
24
- vw := msgio.NewVarintWriter(w)
25
- s := string(id) + "\n" // add \n
26
- return vw.WriteMsg([]byte(s))
27
-}
28
-
29
-// ReadHeader reads a protocol.ID header from an io.Reader. This is so
30
-// multiple protocols can be multiplexed on top of the same transport.
31
-// See WriteHeader.
32
-func ReadHeader(r io.Reader) (ID, error) {
33
- vr := msgio.NewVarintReader(r)
34
- msg, err := vr.ReadMsg()
35
- if err != nil {
36
- return ID(""), err
37
- }
38
- msg = msg[:len(msg)-1] // remove \n
39
- return ID(msg), nil
40
-}
p2p/protocol/relay/relay_test.go
+6
-5
@@ -10,6 +10,7 @@ import (
10
testutil "github.com/ipfs/go-ipfs/p2p/test/util"
11
logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
12
13
+ msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream"
14
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
15
)
16
@@ -62,7 +63,7 @@ func TestRelaySimple(t *testing.T) {
63
64
// ok now the header's there, we can write the next protocol header.
65
log.Debug("write testing header")
65
- if err := protocol.WriteHeader(s, protocol.TestingID); err != nil {
66
+ if err := msmux.SelectProtoOrFail(string(protocol.TestingID), s); err != nil {
67
t.Fatal(err)
68
}
69
@@ -155,7 +156,7 @@ func TestRelayAcrossFour(t *testing.T) {
156
}
157
158
log.Debugf("write relay header n1->n4 (%s -> %s)", n1p, n4p)
158
- if err := protocol.WriteHeader(s, relay.ID); err != nil {
159
+ if err := msmux.SelectProtoOrFail(string(relay.ID), s); err != nil {
160
t.Fatal(err)
161
}
162
if err := relay.WriteHeader(s, n1p, n4p); err != nil {
@@ -163,7 +164,7 @@ func TestRelayAcrossFour(t *testing.T) {
164
}
165
166
log.Debugf("write relay header n1->n5 (%s -> %s)", n1p, n5p)
166
- if err := protocol.WriteHeader(s, relay.ID); err != nil {
167
+ if err := msmux.SelectProtoOrFail(string(relay.ID), s); err != nil {
168
t.Fatal(err)
169
}
170
if err := relay.WriteHeader(s, n1p, n5p); err != nil {
@@ -172,7 +173,7 @@ func TestRelayAcrossFour(t *testing.T) {
173
174
// ok now the header's there, we can write the next protocol header.
175
log.Debug("write testing header")
175
- if err := protocol.WriteHeader(s, protocol.TestingID); err != nil {
176
+ if err := msmux.SelectProtoOrFail(string(protocol.TestingID), s); err != nil {
177
t.Fatal(err)
178
}
179
@@ -257,7 +258,7 @@ func TestRelayStress(t *testing.T) {
258
259
// ok now the header's there, we can write the next protocol header.
260
log.Debug("write testing header")
260
- if err := protocol.WriteHeader(s, protocol.TestingID); err != nil {
261
+ if err := msmux.SelectProtoOrFail(string(protocol.TestingID), s); err != nil {
262
t.Fatal(err)
263
}
264
pin/pin.go
+4
-1
@@ -5,6 +5,7 @@ package pin
5
import (
6
"fmt"
7
"sync"
8
+ "time"
9
10
ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
11
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
@@ -242,7 +243,9 @@ func LoadPinner(d ds.ThreadSafeDatastore, dserv mdag.DAGService) (Pinner, error)
243
244
rootKey := key.Key(rootKeyBytes)
245
245
- ctx := context.TODO()
246
+ ctx, cancel := context.WithTimeout(context.TODO(), time.Second*5)
247
+ defer cancel()
248
+
249
root, err := dserv.Get(ctx, rootKey)
250
if err != nil {
251
return nil, fmt.Errorf("cannot find pinning root object: %v", err)
pin/set_test.go
+1
-1
@@ -6,12 +6,12 @@ import (
6
7
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
8
dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
9
+ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10
"github.com/ipfs/go-ipfs/blocks/blockstore"
11
"github.com/ipfs/go-ipfs/blocks/key"
12
"github.com/ipfs/go-ipfs/blockservice"
13
"github.com/ipfs/go-ipfs/exchange/offline"
14
"github.com/ipfs/go-ipfs/merkledag"
14
- "golang.org/x/net/context"
15
)
16
17
func ignoreKeys(key.Key) {}
test/sharness/t0060-daemon.sh
+1
-1
@@ -105,7 +105,7 @@ test_expect_success "nc is available" '
105
test_expect_success "transport should be encrypted" '
106
nc -w 5 localhost 4001 >swarmnc &&
107
grep -q "AES-256,AES-128" swarmnc &&
108
- test_must_fail grep -q "/ipfs/identify" swarmnc ||
108
+ test_must_fail grep -q "/multistream/1.0.0" swarmnc ||
109
test_fsh cat swarmnc
110
'
111
test/sharness/t0061-daemon-opts.sh
+1
-1
@@ -29,7 +29,7 @@ test_expect_success 'api gateway should be unrestricted' '
29
test_expect_success 'transport should be unencrypted' '
30
go-sleep 0.5s | nc localhost "$PORT_SWARM" >swarmnc &&
31
test_must_fail grep -q "AES-256,AES-128" swarmnc &&
32
- grep -q "/ipfs/identify" swarmnc ||
32
+ grep -q "/multistream/1.0.0" swarmnc ||
33
test_fsh cat swarmnc
34
'
35