@cryptotaxi247 / kubo / commits / de50b2156

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