@cryptotaxi247 / kubo / commits / 1f59e18d3

whoops deps

Juan Batiz-Benet committed Dec 16, 2014 at 15:10 UTC 1f59e18d36319f2dde51b5e4988531d3a4ad4e6a
35 files changed +5780
Godeps/_workspace/src/code.google.com/p/go.net/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/code.google.com/p/go.net/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/code.google.com/p/go.net/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/code.google.com/p/go.net/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/code.google.com/p/go.net/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/code.google.com/p/gogoprotobuf/io/full.go new
+96
@@ -0,0 +1,96 @@
1 +// Extensions for Protocol Buffers to create more go like structures.
2 +//
3 +// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
4 +// http://code.google.com/p/gogoprotobuf/gogoproto
5 +//
6 +// Redistribution and use in source and binary forms, with or without
7 +// modification, are permitted provided that the following conditions are
8 +// met:
9 +//
10 +// * Redistributions of source code must retain the above copyright
11 +// notice, this list of conditions and the following disclaimer.
12 +// * Redistributions in binary form must reproduce the above
13 +// copyright notice, this list of conditions and the following disclaimer
14 +// in the documentation and/or other materials provided with the
15 +// distribution.
16 +//
17 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 +
29 +package io
30 +
31 +import (
32 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/proto"
33 + "io"
34 +)
35 +
36 +func NewFullWriter(w io.Writer) WriteCloser {
37 + return &fullWriter{w, nil}
38 +}
39 +
40 +type fullWriter struct {
41 + w io.Writer
42 + buffer []byte
43 +}
44 +
45 +func (this *fullWriter) WriteMsg(msg proto.Message) (err error) {
46 + var data []byte
47 + if m, ok := msg.(marshaler); ok {
48 + n := m.Size()
49 + if n >= len(this.buffer) {
50 + this.buffer = make([]byte, n)
51 + }
52 + _, err = m.MarshalTo(this.buffer)
53 + if err != nil {
54 + return err
55 + }
56 + data = this.buffer[:n]
57 + } else {
58 + data, err = proto.Marshal(msg)
59 + if err != nil {
60 + return err
61 + }
62 + }
63 + _, err = this.w.Write(data)
64 + return err
65 +}
66 +
67 +func (this *fullWriter) Close() error {
68 + if closer, ok := this.w.(io.Closer); ok {
69 + return closer.Close()
70 + }
71 + return nil
72 +}
73 +
74 +type fullReader struct {
75 + r io.Reader
76 + buf []byte
77 +}
78 +
79 +func NewFullReader(r io.Reader, maxSize int) ReadCloser {
80 + return &fullReader{r, make([]byte, maxSize)}
81 +}
82 +
83 +func (this *fullReader) ReadMsg(msg proto.Message) error {
84 + length, err := this.r.Read(this.buf)
85 + if err != nil {
86 + return err
87 + }
88 + return proto.Unmarshal(this.buf[:length], msg)
89 +}
90 +
91 +func (this *fullReader) Close() error {
92 + if closer, ok := this.r.(io.Closer); ok {
93 + return closer.Close()
94 + }
95 + return nil
96 +}
Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io/io.go new
+57
@@ -0,0 +1,57 @@
1 +// Extensions for Protocol Buffers to create more go like structures.
2 +//
3 +// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
4 +// http://code.google.com/p/gogoprotobuf/gogoproto
5 +//
6 +// Redistribution and use in source and binary forms, with or without
7 +// modification, are permitted provided that the following conditions are
8 +// met:
9 +//
10 +// * Redistributions of source code must retain the above copyright
11 +// notice, this list of conditions and the following disclaimer.
12 +// * Redistributions in binary form must reproduce the above
13 +// copyright notice, this list of conditions and the following disclaimer
14 +// in the documentation and/or other materials provided with the
15 +// distribution.
16 +//
17 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 +
29 +package io
30 +
31 +import (
32 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/proto"
33 + "io"
34 +)
35 +
36 +type Writer interface {
37 + WriteMsg(proto.Message) error
38 +}
39 +
40 +type WriteCloser interface {
41 + Writer
42 + io.Closer
43 +}
44 +
45 +type Reader interface {
46 + ReadMsg(msg proto.Message) error
47 +}
48 +
49 +type ReadCloser interface {
50 + Reader
51 + io.Closer
52 +}
53 +
54 +type marshaler interface {
55 + MarshalTo(data []byte) (n int, err error)
56 + Size() (n int)
57 +}
Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io/io_test.go new
+137
@@ -0,0 +1,137 @@
1 +// Extensions for Protocol Buffers to create more go like structures.
2 +//
3 +// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
4 +// http://code.google.com/p/gogoprotobuf/gogoproto
5 +//
6 +// Redistribution and use in source and binary forms, with or without
7 +// modification, are permitted provided that the following conditions are
8 +// met:
9 +//
10 +// * Redistributions of source code must retain the above copyright
11 +// notice, this list of conditions and the following disclaimer.
12 +// * Redistributions in binary form must reproduce the above
13 +// copyright notice, this list of conditions and the following disclaimer
14 +// in the documentation and/or other materials provided with the
15 +// distribution.
16 +//
17 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 +
29 +package io_test
30 +
31 +import (
32 + "bytes"
33 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io"
34 + "code.google.com/p/gogoprotobuf/test"
35 + "encoding/binary"
36 + goio "io"
37 + "math/rand"
38 + "testing"
39 + "time"
40 +)
41 +
42 +func iotest(writer io.WriteCloser, reader io.ReadCloser) {
43 + size := 1000
44 + msgs := make([]*test.NinOptNative, size)
45 + r := rand.New(rand.NewSource(time.Now().UnixNano()))
46 + for i := range msgs {
47 + msgs[i] = test.NewPopulatedNinOptNative(r, true)
48 + err := writer.WriteMsg(msgs[i])
49 + if err != nil {
50 + panic(err)
51 + }
52 + }
53 + if err := writer.Close(); err != nil {
54 + panic(err)
55 + }
56 + i := 0
57 + for {
58 + msg := &test.NinOptNative{}
59 + if err := reader.ReadMsg(msg); err != nil {
60 + if err == goio.EOF {
61 + break
62 + }
63 + panic(err)
64 + }
65 + if err := msg.VerboseEqual(msgs[i]); err != nil {
66 + panic(err)
67 + }
68 + i++
69 + }
70 + if i != size {
71 + panic("not enough messages read")
72 + }
73 + if err := reader.Close(); err != nil {
74 + panic(err)
75 + }
76 +}
77 +
78 +func TestBigUint32(t *testing.T) {
79 + buf := bytes.NewBuffer(nil)
80 + writer := io.NewUint32DelimitedWriter(buf, binary.BigEndian)
81 + reader := io.NewUint32DelimitedReader(buf, binary.BigEndian, 1024*1024)
82 + iotest(writer, reader)
83 +}
84 +
85 +func TestLittleUint32(t *testing.T) {
86 + buf := bytes.NewBuffer(nil)
87 + writer := io.NewUint32DelimitedWriter(buf, binary.LittleEndian)
88 + reader := io.NewUint32DelimitedReader(buf, binary.LittleEndian, 1024*1024)
89 + iotest(writer, reader)
90 +}
91 +
92 +func TestVarint(t *testing.T) {
93 + buf := bytes.NewBuffer(nil)
94 + writer := io.NewDelimitedWriter(buf)
95 + reader := io.NewDelimitedReader(buf, 1024*1024)
96 + iotest(writer, reader)
97 +}
98 +
99 +func TestVarintError(t *testing.T) {
100 + buf := bytes.NewBuffer(nil)
101 + buf.Write([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f})
102 + reader := io.NewDelimitedReader(buf, 1024*1024)
103 + msg := &test.NinOptNative{}
104 + err := reader.ReadMsg(msg)
105 + if err == nil {
106 + t.Fatalf("Expected error")
107 + }
108 +}
109 +
110 +func TestFull(t *testing.T) {
111 + buf := bytes.NewBuffer(nil)
112 + writer := io.NewFullWriter(buf)
113 + reader := io.NewFullReader(buf, 1024*1024)
114 + r := rand.New(rand.NewSource(time.Now().UnixNano()))
115 + msgIn := test.NewPopulatedNinOptNative(r, true)
116 + if err := writer.WriteMsg(msgIn); err != nil {
117 + panic(err)
118 + }
119 + if err := writer.Close(); err != nil {
120 + panic(err)
121 + }
122 + msgOut := &test.NinOptNative{}
123 + if err := reader.ReadMsg(msgOut); err != nil {
124 + panic(err)
125 + }
126 + if err := msgIn.VerboseEqual(msgOut); err != nil {
127 + panic(err)
128 + }
129 + if err := reader.ReadMsg(msgOut); err != nil {
130 + if err != goio.EOF {
131 + panic(err)
132 + }
133 + }
134 + if err := reader.Close(); err != nil {
135 + panic(err)
136 + }
137 +}
Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io/uint32.go new
+116
@@ -0,0 +1,116 @@
1 +// Extensions for Protocol Buffers to create more go like structures.
2 +//
3 +// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
4 +// http://code.google.com/p/gogoprotobuf/gogoproto
5 +//
6 +// Redistribution and use in source and binary forms, with or without
7 +// modification, are permitted provided that the following conditions are
8 +// met:
9 +//
10 +// * Redistributions of source code must retain the above copyright
11 +// notice, this list of conditions and the following disclaimer.
12 +// * Redistributions in binary form must reproduce the above
13 +// copyright notice, this list of conditions and the following disclaimer
14 +// in the documentation and/or other materials provided with the
15 +// distribution.
16 +//
17 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 +
29 +package io
30 +
31 +import (
32 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/proto"
33 + "encoding/binary"
34 + "io"
35 +)
36 +
37 +func NewUint32DelimitedWriter(w io.Writer, byteOrder binary.ByteOrder) WriteCloser {
38 + return &uint32Writer{w, byteOrder, nil}
39 +}
40 +
41 +type uint32Writer struct {
42 + w io.Writer
43 + byteOrder binary.ByteOrder
44 + buffer []byte
45 +}
46 +
47 +func (this *uint32Writer) WriteMsg(msg proto.Message) (err error) {
48 + var data []byte
49 + if m, ok := msg.(marshaler); ok {
50 + n := m.Size()
51 + if n >= len(this.buffer) {
52 + this.buffer = make([]byte, n)
53 + }
54 + _, err = m.MarshalTo(this.buffer)
55 + if err != nil {
56 + return err
57 + }
58 + data = this.buffer[:n]
59 + } else {
60 + data, err = proto.Marshal(msg)
61 + if err != nil {
62 + return err
63 + }
64 + }
65 + length := uint32(len(data))
66 + if err := binary.Write(this.w, this.byteOrder, &length); err != nil {
67 + return err
68 + }
69 + _, err = this.w.Write(data)
70 + return err
71 +}
72 +
73 +func (this *uint32Writer) Close() error {
74 + if closer, ok := this.w.(io.Closer); ok {
75 + return closer.Close()
76 + }
77 + return nil
78 +}
79 +
80 +type uint32Reader struct {
81 + r io.Reader
82 + byteOrder binary.ByteOrder
83 + lenBuf []byte
84 + buf []byte
85 + maxSize int
86 +}
87 +
88 +func NewUint32DelimitedReader(r io.Reader, byteOrder binary.ByteOrder, maxSize int) ReadCloser {
89 + return &uint32Reader{r, byteOrder, make([]byte, 4), nil, maxSize}
90 +}
91 +
92 +func (this *uint32Reader) ReadMsg(msg proto.Message) error {
93 + if _, err := io.ReadFull(this.r, this.lenBuf); err != nil {
94 + return err
95 + }
96 + length32 := this.byteOrder.Uint32(this.lenBuf)
97 + length := int(length32)
98 + if length < 0 || length > this.maxSize {
99 + return io.ErrShortBuffer
100 + }
101 + if length >= len(this.buf) {
102 + this.buf = make([]byte, length)
103 + }
104 + _, err := io.ReadFull(this.r, this.buf[:length])
105 + if err != nil {
106 + return err
107 + }
108 + return proto.Unmarshal(this.buf[:length], msg)
109 +}
110 +
111 +func (this *uint32Reader) Close() error {
112 + if closer, ok := this.r.(io.Closer); ok {
113 + return closer.Close()
114 + }
115 + return nil
116 +}
Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io/varint.go new
+127
@@ -0,0 +1,127 @@
1 +// Extensions for Protocol Buffers to create more go like structures.
2 +//
3 +// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
4 +// http://code.google.com/p/gogoprotobuf/gogoproto
5 +//
6 +// Redistribution and use in source and binary forms, with or without
7 +// modification, are permitted provided that the following conditions are
8 +// met:
9 +//
10 +// * Redistributions of source code must retain the above copyright
11 +// notice, this list of conditions and the following disclaimer.
12 +// * Redistributions in binary form must reproduce the above
13 +// copyright notice, this list of conditions and the following disclaimer
14 +// in the documentation and/or other materials provided with the
15 +// distribution.
16 +//
17 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 +
29 +package io
30 +
31 +import (
32 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/proto"
33 + "encoding/binary"
34 + "errors"
35 + "io"
36 +)
37 +
38 +var (
39 + errSmallBuffer = errors.New("Buffer Too Small")
40 + errLargeValue = errors.New("Value is Larger than 64 bits")
41 +)
42 +
43 +func NewDelimitedWriter(w io.Writer) WriteCloser {
44 + return &varintWriter{w, make([]byte, 10), nil}
45 +}
46 +
47 +type varintWriter struct {
48 + w io.Writer
49 + lenBuf []byte
50 + buffer []byte
51 +}
52 +
53 +func (this *varintWriter) WriteMsg(msg proto.Message) (err error) {
54 + var data []byte
55 + if m, ok := msg.(marshaler); ok {
56 + n := m.Size()
57 + if n >= len(this.buffer) {
58 + this.buffer = make([]byte, n)
59 + }
60 + _, err = m.MarshalTo(this.buffer)
61 + if err != nil {
62 + return err
63 + }
64 + data = this.buffer[:n]
65 + } else {
66 + data, err = proto.Marshal(msg)
67 + if err != nil {
68 + return err
69 + }
70 + }
71 + length := uint64(len(data))
72 + n := binary.PutUvarint(this.lenBuf, length)
73 + _, err = this.w.Write(this.lenBuf[:n])
74 + if err != nil {
75 + return err
76 + }
77 + _, err = this.w.Write(data)
78 + return err
79 +}
80 +
81 +func (this *varintWriter) Close() error {
82 + if closer, ok := this.w.(io.Closer); ok {
83 + return closer.Close()
84 + }
85 + return nil
86 +}
87 +
88 +func NewDelimitedReader(r io.Reader, maxSize int) ReadCloser {
89 + return &varintReader{r, make([]byte, 10), nil, maxSize}
90 +}
91 +
92 +type varintReader struct {
93 + r io.Reader
94 + lenBuf []byte
95 + buf []byte
96 + maxSize int
97 +}
98 +
99 +func (this *varintReader) ReadMsg(msg proto.Message) error {
100 + firstLen, err := this.r.Read(this.lenBuf)
101 + if err != nil {
102 + return err
103 + }
104 + length64, lenLen := binary.Uvarint(this.lenBuf)
105 + if lenLen <= 0 {
106 + if lenLen == 0 {
107 + return errSmallBuffer
108 + }
109 + return errLargeValue
110 + }
111 + msgLen := int(length64)
112 + if len(this.buf) < msgLen {
113 + this.buf = make([]byte, msgLen)
114 + }
115 + prefixN := copy(this.buf, this.lenBuf[lenLen:firstLen])
116 + if _, err := io.ReadFull(this.r, this.buf[prefixN:msgLen]); err != nil {
117 + return err
118 + }
119 + return proto.Unmarshal(this.buf[:msgLen], msg)
120 +}
121 +
122 +func (this *varintReader) Close() error {
123 + if closer, ok := this.r.(io.Closer); ok {
124 + return closer.Close()
125 + }
126 + return nil
127 +}
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
+798
@@ -0,0 +1,798 @@
1 +package spdystream
2 +
3 +import (
4 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/spdy"
5 + "errors"
6 + "fmt"
7 + "io"
8 + "net"
9 + "net/http"
10 + "sync"
11 + "time"
12 +)
13 +
14 +var (
15 + ErrInvalidStreamId = errors.New("Invalid stream id")
16 + ErrTimeout = errors.New("Timeout occured")
17 + ErrReset = errors.New("Stream reset")
18 + ErrWriteClosedStream = errors.New("Write on closed stream")
19 +)
20 +
21 +const (
22 + FRAME_WORKERS = 5
23 + QUEUE_SIZE = 50
24 +)
25 +
26 +type StreamHandler func(stream *Stream)
27 +
28 +type AuthHandler func(header http.Header, slot uint8, parent uint32) bool
29 +
30 +type Connection struct {
31 + conn net.Conn
32 + framer *spdy.Framer
33 + writeLock sync.Mutex
34 +
35 + closeChan chan bool
36 + goneAway bool
37 + lastStreamChan chan<- *Stream
38 + goAwayTimeout time.Duration
39 + closeTimeout time.Duration
40 +
41 + streamLock *sync.RWMutex
42 + streamCond *sync.Cond
43 + streams map[spdy.StreamId]*Stream
44 +
45 + nextIdLock sync.Mutex
46 + receiveIdLock sync.Mutex
47 + nextStreamId spdy.StreamId
48 + receivedStreamId spdy.StreamId
49 +
50 + pingIdLock sync.Mutex
51 + pingId uint32
52 + pingChans map[uint32]chan error
53 +
54 + shutdownLock sync.Mutex
55 + shutdownChan chan error
56 + hasShutdown bool
57 +}
58 +
59 +// NewConnection creates a new spdy connection from an existing
60 +// network connection.
61 +func NewConnection(conn net.Conn, server bool) (*Connection, error) {
62 + framer, framerErr := spdy.NewFramer(conn, conn)
63 + if framerErr != nil {
64 + return nil, framerErr
65 + }
66 + var sid spdy.StreamId
67 + var rid spdy.StreamId
68 + var pid uint32
69 + if server {
70 + sid = 2
71 + rid = 1
72 + pid = 2
73 + } else {
74 + sid = 1
75 + rid = 2
76 + pid = 1
77 + }
78 +
79 + streamLock := new(sync.RWMutex)
80 + streamCond := sync.NewCond(streamLock)
81 +
82 + session := &Connection{
83 + conn: conn,
84 + framer: framer,
85 +
86 + closeChan: make(chan bool),
87 + goAwayTimeout: time.Duration(0),
88 + closeTimeout: time.Duration(0),
89 +
90 + streamLock: streamLock,
91 + streamCond: streamCond,
92 + streams: make(map[spdy.StreamId]*Stream),
93 + nextStreamId: sid,
94 + receivedStreamId: rid,
95 +
96 + pingId: pid,
97 + pingChans: make(map[uint32]chan error),
98 +
99 + shutdownChan: make(chan error),
100 + }
101 +
102 + return session, nil
103 +}
104 +
105 +// Ping sends a ping frame across the connection and
106 +// returns the response time
107 +func (s *Connection) Ping() (time.Duration, error) {
108 + pid := s.pingId
109 + s.pingIdLock.Lock()
110 + if s.pingId > 0x7ffffffe {
111 + s.pingId = s.pingId - 0x7ffffffe
112 + } else {
113 + s.pingId = s.pingId + 2
114 + }
115 + s.pingIdLock.Unlock()
116 + pingChan := make(chan error)
117 + s.pingChans[pid] = pingChan
118 + defer delete(s.pingChans, pid)
119 +
120 + frame := &spdy.PingFrame{Id: pid}
121 + startTime := time.Now()
122 + s.writeLock.Lock()
123 + writeErr := s.framer.WriteFrame(frame)
124 + s.writeLock.Unlock()
125 + if writeErr != nil {
126 + return time.Duration(0), writeErr
127 + }
128 + select {
129 + case <-s.closeChan:
130 + return time.Duration(0), errors.New("connection closed")
131 + case err, ok := <-pingChan:
132 + if ok && err != nil {
133 + return time.Duration(0), err
134 + }
135 + break
136 + }
137 + return time.Now().Sub(startTime), nil
138 +}
139 +
140 +// Serve handles frames sent from the server, including reply frames
141 +// which are needed to fully initiate connections. Both clients and servers
142 +// should call Serve in a separate goroutine before creating streams.
143 +func (s *Connection) Serve(newHandler StreamHandler) {
144 + // Parition queues to ensure stream frames are handled
145 + // by the same worker, ensuring order is maintained
146 + frameQueues := make([]*PriorityFrameQueue, FRAME_WORKERS)
147 + for i := 0; i < FRAME_WORKERS; i++ {
148 + frameQueues[i] = NewPriorityFrameQueue(QUEUE_SIZE)
149 + // Ensure frame queue is drained when connection is closed
150 + go func(frameQueue *PriorityFrameQueue) {
151 + <-s.closeChan
152 + frameQueue.Drain()
153 + }(frameQueues[i])
154 +
155 + go s.frameHandler(frameQueues[i], newHandler)
156 + }
157 +
158 + var partitionRoundRobin int
159 + for {
160 + readFrame, err := s.framer.ReadFrame()
161 + if err != nil {
162 + if err != io.EOF {
163 + fmt.Errorf("frame read error: %s", err)
164 + } else {
165 + debugMessage("EOF received")
166 + }
167 + break
168 + }
169 + var priority uint8
170 + var partition int
171 + switch frame := readFrame.(type) {
172 + case *spdy.SynStreamFrame:
173 + if s.checkStreamFrame(frame) {
174 + priority = frame.Priority
175 + partition = int(frame.StreamId % FRAME_WORKERS)
176 + debugMessage("(%p) Add stream frame: %d ", s, frame.StreamId)
177 + s.addStreamFrame(frame)
178 + } else {
179 + debugMessage("(%p) Rejected stream frame: %d ", s, frame.StreamId)
180 + continue
181 + }
182 + case *spdy.SynReplyFrame:
183 + priority = s.getStreamPriority(frame.StreamId)
184 + partition = int(frame.StreamId % FRAME_WORKERS)
185 + case *spdy.DataFrame:
186 + priority = s.getStreamPriority(frame.StreamId)
187 + partition = int(frame.StreamId % FRAME_WORKERS)
188 + case *spdy.RstStreamFrame:
189 + priority = s.getStreamPriority(frame.StreamId)
190 + partition = int(frame.StreamId % FRAME_WORKERS)
191 + case *spdy.HeadersFrame:
192 + priority = s.getStreamPriority(frame.StreamId)
193 + partition = int(frame.StreamId % FRAME_WORKERS)
194 + case *spdy.PingFrame:
195 + priority = 0
196 + partition = partitionRoundRobin
197 + partitionRoundRobin = (partitionRoundRobin + 1) % FRAME_WORKERS
198 + case *spdy.GoAwayFrame:
199 + priority = 0
200 + partition = partitionRoundRobin
201 + partitionRoundRobin = (partitionRoundRobin + 1) % FRAME_WORKERS
202 + default:
203 + priority = 7
204 + partition = partitionRoundRobin
205 + partitionRoundRobin = (partitionRoundRobin + 1) % FRAME_WORKERS
206 + }
207 + frameQueues[partition].Push(readFrame, priority)
208 + }
209 + close(s.closeChan)
210 +
211 + s.streamCond.L.Lock()
212 + s.streams = make(map[spdy.StreamId]*Stream)
213 + s.streamCond.Broadcast()
214 + s.streamCond.L.Unlock()
215 +}
216 +
217 +func (s *Connection) frameHandler(frameQueue *PriorityFrameQueue, newHandler StreamHandler) {
218 + for {
219 + popFrame := frameQueue.Pop()
220 + if popFrame == nil {
221 + return
222 + }
223 +
224 + var frameErr error
225 + switch frame := popFrame.(type) {
226 + case *spdy.SynStreamFrame:
227 + frameErr = s.handleStreamFrame(frame, newHandler)
228 + case *spdy.SynReplyFrame:
229 + frameErr = s.handleReplyFrame(frame)
230 + case *spdy.DataFrame:
231 + frameErr = s.handleDataFrame(frame)
232 + case *spdy.RstStreamFrame:
233 + frameErr = s.handleResetFrame(frame)
234 + case *spdy.HeadersFrame:
235 + frameErr = s.handleHeaderFrame(frame)
236 + case *spdy.PingFrame:
237 + frameErr = s.handlePingFrame(frame)
238 + case *spdy.GoAwayFrame:
239 + frameErr = s.handleGoAwayFrame(frame)
240 + default:
241 + frameErr = fmt.Errorf("unhandled frame type: %T", frame)
242 + }
243 +
244 + if frameErr != nil {
245 + fmt.Errorf("frame handling error: %s", frameErr)
246 + }
247 + }
248 +}
249 +
250 +func (s *Connection) getStreamPriority(streamId spdy.StreamId) uint8 {
251 + stream, streamOk := s.getStream(streamId)
252 + if !streamOk {
253 + return 7
254 + }
255 + return stream.priority
256 +}
257 +
258 +func (s *Connection) addStreamFrame(frame *spdy.SynStreamFrame) {
259 + var parent *Stream
260 + if frame.AssociatedToStreamId != spdy.StreamId(0) {
261 + parent, _ = s.getStream(frame.AssociatedToStreamId)
262 + }
263 +
264 + stream := &Stream{
265 + streamId: frame.StreamId,
266 + parent: parent,
267 + conn: s,
268 + startChan: make(chan error),
269 + headers: frame.Headers,
270 + finished: (frame.CFHeader.Flags & spdy.ControlFlagUnidirectional) != 0x00,
271 + replyCond: sync.NewCond(new(sync.Mutex)),
272 + dataChan: make(chan []byte),
273 + headerChan: make(chan http.Header),
274 + closeChan: make(chan bool),
275 + }
276 + if frame.CFHeader.Flags&spdy.ControlFlagFin != 0x00 {
277 + close(stream.dataChan)
278 + close(stream.closeChan)
279 + }
280 +
281 + s.addStream(stream)
282 +}
283 +
284 +// checkStreamFrame checks to see if a stream frame is allowed.
285 +// If the stream is invalid, then a reset frame with protocol error
286 +// will be returned.
287 +func (s *Connection) checkStreamFrame(frame *spdy.SynStreamFrame) bool {
288 + s.receiveIdLock.Lock()
289 + defer s.receiveIdLock.Unlock()
290 + if s.goneAway {
291 + return false
292 + }
293 + validationErr := s.validateStreamId(frame.StreamId)
294 + if validationErr != nil {
295 + go func() {
296 + resetErr := s.sendResetFrame(spdy.ProtocolError, frame.StreamId)
297 + if resetErr != nil {
298 + fmt.Errorf("reset error: %s", resetErr)
299 + }
300 + }()
301 + return false
302 + }
303 + return true
304 +}
305 +
306 +func (s *Connection) handleStreamFrame(frame *spdy.SynStreamFrame, newHandler StreamHandler) error {
307 + stream, ok := s.getStream(frame.StreamId)
308 + if !ok {
309 + return fmt.Errorf("Missing stream: %d", frame.StreamId)
310 + }
311 +
312 + newHandler(stream)
313 +
314 + return nil
315 +}
316 +
317 +func (s *Connection) handleReplyFrame(frame *spdy.SynReplyFrame) error {
318 + debugMessage("(%p) Reply frame received for %d", s, frame.StreamId)
319 + stream, streamOk := s.getStream(frame.StreamId)
320 + if !streamOk {
321 + debugMessage("Reply frame gone away for %d", frame.StreamId)
322 + // Stream has already gone away
323 + return nil
324 + }
325 + if stream.replied {
326 + // Stream has already received reply
327 + return nil
328 + }
329 + stream.replied = true
330 +
331 + // TODO Check for error
332 + if (frame.CFHeader.Flags & spdy.ControlFlagFin) != 0x00 {
333 + s.remoteStreamFinish(stream)
334 + }
335 +
336 + close(stream.startChan)
337 +
338 + return nil
339 +}
340 +
341 +func (s *Connection) handleResetFrame(frame *spdy.RstStreamFrame) error {
342 + stream, streamOk := s.getStream(frame.StreamId)
343 + if !streamOk {
344 + // Stream has already been removed
345 + return nil
346 + }
347 + s.removeStream(stream)
348 + stream.dataLock.Lock()
349 + select {
350 + case <-stream.closeChan:
351 + break
352 + default:
353 + close(stream.dataChan)
354 + close(stream.closeChan)
355 + }
356 + stream.dataLock.Unlock()
357 +
358 + if !stream.replied {
359 + stream.replied = true
360 + stream.startChan <- ErrReset
361 + close(stream.startChan)
362 + }
363 +
364 + stream.finishLock.Lock()
365 + stream.finished = true
366 + stream.finishLock.Unlock()
367 +
368 + return nil
369 +}
370 +
371 +func (s *Connection) handleHeaderFrame(frame *spdy.HeadersFrame) error {
372 + stream, streamOk := s.getStream(frame.StreamId)
373 + if !streamOk {
374 + // Stream has already gone away
375 + return nil
376 + }
377 + if !stream.replied {
378 + // No reply received...Protocol error?
379 + return nil
380 + }
381 +
382 + // TODO limit headers while not blocking (use buffered chan or goroutine?)
383 + select {
384 + case <-stream.closeChan:
385 + return nil
386 + case stream.headerChan <- frame.Headers:
387 + }
388 +
389 + if (frame.CFHeader.Flags & spdy.ControlFlagFin) != 0x00 {
390 + s.remoteStreamFinish(stream)
391 + }
392 +
393 + return nil
394 +}
395 +
396 +func (s *Connection) handleDataFrame(frame *spdy.DataFrame) error {
397 + debugMessage("(%p) Data frame received for %d", s, frame.StreamId)
398 + stream, streamOk := s.getStream(frame.StreamId)
399 + if !streamOk {
400 + debugMessage("Data frame gone away for %d", frame.StreamId)
401 + // Stream has already gone away
402 + return nil
403 + }
404 + if !stream.replied {
405 + debugMessage("Data frame not replied %d", frame.StreamId)
406 + // No reply received...Protocol error?
407 + return nil
408 + }
409 +
410 + debugMessage("(%p) (%d) Data frame handling", stream, stream.streamId)
411 + if len(frame.Data) > 0 {
412 + stream.dataLock.RLock()
413 + select {
414 + case <-stream.closeChan:
415 + break
416 + default:
417 + debugMessage("(%p) (%d) Data frame send chan", stream, stream.streamId)
418 + stream.dataChan <- frame.Data
419 + debugMessage("(%p) (%d) Data frame sent", stream, stream.streamId)
420 + }
421 + stream.dataLock.RUnlock()
422 + }
423 + if (frame.Flags & spdy.DataFlagFin) != 0x00 {
424 + s.remoteStreamFinish(stream)
425 + }
426 + return nil
427 +}
428 +
429 +func (s *Connection) handlePingFrame(frame *spdy.PingFrame) error {
430 + if s.pingId&0x01 != frame.Id&0x01 {
431 + s.writeLock.Lock()
432 + defer s.writeLock.Unlock()
433 + return s.framer.WriteFrame(frame)
434 + }
435 + pingChan, pingOk := s.pingChans[frame.Id]
436 + if pingOk {
437 + close(pingChan)
438 + }
439 + return nil
440 +}
441 +
442 +func (s *Connection) handleGoAwayFrame(frame *spdy.GoAwayFrame) error {
443 + debugMessage("(%p) Go away received", s)
444 + s.receiveIdLock.Lock()
445 + if s.goneAway {
446 + s.receiveIdLock.Unlock()
447 + return nil
448 + }
449 + s.goneAway = true
450 + s.receiveIdLock.Unlock()
451 +
452 + if s.lastStreamChan != nil {
453 + stream, _ := s.getStream(frame.LastGoodStreamId)
454 + go func() {
455 + s.lastStreamChan <- stream
456 + }()
457 + }
458 +
459 + // Do not block frame handler waiting for closure
460 + go s.shutdown(s.goAwayTimeout)
461 +
462 + return nil
463 +}
464 +
465 +func (s *Connection) remoteStreamFinish(stream *Stream) {
466 + // synchronize closing channel
467 + stream.dataLock.Lock()
468 + select {
469 + case <-stream.closeChan:
470 + break
471 + default:
472 + close(stream.dataChan)
473 + close(stream.closeChan)
474 + }
475 + stream.dataLock.Unlock()
476 +
477 + stream.finishLock.Lock()
478 + if stream.finished {
479 + // Stream is fully closed, cleanup
480 + s.removeStream(stream)
481 + }
482 + stream.finishLock.Unlock()
483 +}
484 +
485 +// CreateStream creates a new spdy stream using the parameters for
486 +// creating the stream frame. The stream frame will be sent upon
487 +// calling this function, however this function does not wait for
488 +// the reply frame. If waiting for the reply is desired, use
489 +// the stream Wait or WaitTimeout function on the stream returned
490 +// by this function.
491 +func (s *Connection) CreateStream(headers http.Header, parent *Stream, fin bool) (*Stream, error) {
492 + streamId := s.getNextStreamId()
493 + if streamId == 0 {
494 + return nil, fmt.Errorf("Unable to get new stream id")
495 + }
496 +
497 + stream := &Stream{
498 + streamId: streamId,
499 + parent: parent,
500 + conn: s,
501 + startChan: make(chan error),
502 + headers: headers,
503 + dataChan: make(chan []byte),
504 + headerChan: make(chan http.Header),
505 + closeChan: make(chan bool),
506 + }
507 +
508 + debugMessage("(%p) (%p) Create stream", s, stream)
509 +
510 + s.addStream(stream)
511 +
512 + return stream, s.sendStream(stream, fin)
513 +}
514 +
515 +func (s *Connection) shutdown(closeTimeout time.Duration) {
516 + // TODO Ensure this isn't called multiple times
517 + s.shutdownLock.Lock()
518 + if s.hasShutdown {
519 + s.shutdownLock.Unlock()
520 + return
521 + }
522 + s.hasShutdown = true
523 + s.shutdownLock.Unlock()
524 +
525 + var timeout <-chan time.Time
526 + if closeTimeout > time.Duration(0) {
527 + timeout = time.After(closeTimeout)
528 + }
529 + streamsClosed := make(chan bool)
530 +
531 + go func() {
532 + s.streamCond.L.Lock()
533 + for len(s.streams) > 0 {
534 + debugMessage("Streams opened: %d, %#v", len(s.streams), s.streams)
535 + s.streamCond.Wait()
536 + }
537 + s.streamCond.L.Unlock()
538 + close(streamsClosed)
539 + }()
540 +
541 + var err error
542 + select {
543 + case <-streamsClosed:
544 + // No active streams, close should be safe
545 + err = s.conn.Close()
546 + case <-timeout:
547 + // Force ungraceful close
548 + err = s.conn.Close()
549 + // Wait for cleanup to clear active streams
550 + <-streamsClosed
551 + }
552 +
553 + if err != nil {
554 + duration := 10 * time.Minute
555 + time.AfterFunc(duration, func() {
556 + select {
557 + case err, ok := <-s.shutdownChan:
558 + if ok {
559 + fmt.Errorf("Unhandled close error after %s: %s", duration, err)
560 + }
561 + default:
562 + }
563 + })
564 + s.shutdownChan <- err
565 + }
566 + close(s.shutdownChan)
567 +
568 + return
569 +}
570 +
571 +// Closes spdy connection by sending GoAway frame and initiating shutdown
572 +func (s *Connection) Close() error {
573 + s.receiveIdLock.Lock()
574 + if s.goneAway {
575 + s.receiveIdLock.Unlock()
576 + return nil
577 + }
578 + s.goneAway = true
579 + s.receiveIdLock.Unlock()
580 +
581 + var lastStreamId spdy.StreamId
582 + if s.receivedStreamId > 2 {
583 + lastStreamId = s.receivedStreamId - 2
584 + }
585 +
586 + goAwayFrame := &spdy.GoAwayFrame{
587 + LastGoodStreamId: lastStreamId,
588 + Status: spdy.GoAwayOK,
589 + }
590 +
591 + s.writeLock.Lock()
592 + err := s.framer.WriteFrame(goAwayFrame)
593 + s.writeLock.Unlock()
594 + if err != nil {
595 + return err
596 + }
597 +
598 + go s.shutdown(s.closeTimeout)
599 +
600 + return nil
601 +}
602 +
603 +// CloseWait closes the connection and waits for shutdown
604 +// to finish. Note the underlying network Connection
605 +// is not closed until the end of shutdown.
606 +func (s *Connection) CloseWait() error {
607 + closeErr := s.Close()
608 + if closeErr != nil {
609 + return closeErr
610 + }
611 + shutdownErr, ok := <-s.shutdownChan
612 + if ok {
613 + return shutdownErr
614 + }
615 + return nil
616 +}
617 +
618 +// Wait waits for the connection to finish shutdown or for
619 +// the wait timeout duration to expire. This needs to be
620 +// called either after Close has been called or the GOAWAYFRAME
621 +// has been received. If the wait timeout is 0, this function
622 +// will block until shutdown finishes. If wait is never called
623 +// and a shutdown error occurs, that error will be logged as an
624 +// unhandled error.
625 +func (s *Connection) Wait(waitTimeout time.Duration) error {
626 + var timeout <-chan time.Time
627 + if waitTimeout > time.Duration(0) {
628 + timeout = time.After(waitTimeout)
629 + }
630 +
631 + select {
632 + case err, ok := <-s.shutdownChan:
633 + if ok {
634 + return err
635 + }
636 + case <-timeout:
637 + return ErrTimeout
638 + }
639 + return nil
640 +}
641 +
642 +// NotifyClose registers a channel to be called when the remote
643 +// peer inidicates connection closure. The last stream to be
644 +// received by the remote will be sent on the channel. The notify
645 +// timeout will determine the duration between go away received
646 +// and the connection being closed.
647 +func (s *Connection) NotifyClose(c chan<- *Stream, timeout time.Duration) {
648 + s.goAwayTimeout = timeout
649 + s.lastStreamChan = c
650 +}
651 +
652 +// SetCloseTimeout sets the amount of time close will wait for
653 +// streams to finish before terminating the underlying network
654 +// connection. Setting the timeout to 0 will cause close to
655 +// wait forever, which is the default.
656 +func (s *Connection) SetCloseTimeout(timeout time.Duration) {
657 + s.closeTimeout = timeout
658 +}
659 +
660 +func (s *Connection) sendHeaders(headers http.Header, stream *Stream, fin bool) error {
661 + var flags spdy.ControlFlags
662 + if fin {
663 + flags = spdy.ControlFlagFin
664 + }
665 +
666 + headerFrame := &spdy.HeadersFrame{
667 + StreamId: stream.streamId,
668 + Headers: headers,
669 + CFHeader: spdy.ControlFrameHeader{Flags: flags},
670 + }
671 +
672 + s.writeLock.Lock()
673 + defer s.writeLock.Unlock()
674 + return s.framer.WriteFrame(headerFrame)
675 +}
676 +
677 +func (s *Connection) sendReply(headers http.Header, stream *Stream, fin bool) error {
678 + var flags spdy.ControlFlags
679 + if fin {
680 + flags = spdy.ControlFlagFin
681 + }
682 +
683 + replyFrame := &spdy.SynReplyFrame{
684 + StreamId: stream.streamId,
685 + Headers: headers,
686 + CFHeader: spdy.ControlFrameHeader{Flags: flags},
687 + }
688 +
689 + s.writeLock.Lock()
690 + defer s.writeLock.Unlock()
691 + return s.framer.WriteFrame(replyFrame)
692 +}
693 +
694 +func (s *Connection) sendResetFrame(status spdy.RstStreamStatus, streamId spdy.StreamId) error {
695 + resetFrame := &spdy.RstStreamFrame{
696 + StreamId: streamId,
697 + Status: status,
698 + }
699 +
700 + s.writeLock.Lock()
701 + defer s.writeLock.Unlock()
702 + return s.framer.WriteFrame(resetFrame)
703 +}
704 +
705 +func (s *Connection) sendReset(status spdy.RstStreamStatus, stream *Stream) error {
706 + return s.sendResetFrame(status, stream.streamId)
707 +}
708 +
709 +func (s *Connection) sendStream(stream *Stream, fin bool) error {
710 + var flags spdy.ControlFlags
711 + if fin {
712 + flags = spdy.ControlFlagFin
713 + stream.finished = true
714 + }
715 +
716 + var parentId spdy.StreamId
717 + if stream.parent != nil {
718 + parentId = stream.parent.streamId
719 + }
720 +
721 + streamFrame := &spdy.SynStreamFrame{
722 + StreamId: spdy.StreamId(stream.streamId),
723 + AssociatedToStreamId: spdy.StreamId(parentId),
724 + Headers: stream.headers,
725 + CFHeader: spdy.ControlFrameHeader{Flags: flags},
726 + }
727 +
728 + s.writeLock.Lock()
729 + defer s.writeLock.Unlock()
730 + return s.framer.WriteFrame(streamFrame)
731 +}
732 +
733 +// getNextStreamId returns the next sequential id
734 +// every call should produce a unique value or an error
735 +func (s *Connection) getNextStreamId() spdy.StreamId {
736 + s.nextIdLock.Lock()
737 + defer s.nextIdLock.Unlock()
738 + sid := s.nextStreamId
739 + if sid > 0x7fffffff {
740 + return 0
741 + }
742 + s.nextStreamId = s.nextStreamId + 2
743 + return sid
744 +}
745 +
746 +// PeekNextStreamId returns the next sequential id and keeps the next id untouched
747 +func (s *Connection) PeekNextStreamId() spdy.StreamId {
748 + sid := s.nextStreamId
749 + return sid
750 +}
751 +
752 +func (s *Connection) validateStreamId(rid spdy.StreamId) error {
753 + if rid > 0x7fffffff || rid < s.receivedStreamId {
754 + return ErrInvalidStreamId
755 + }
756 + s.receivedStreamId = rid + 2
757 + return nil
758 +}
759 +
760 +func (s *Connection) addStream(stream *Stream) {
761 + s.streamCond.L.Lock()
762 + s.streams[stream.streamId] = stream
763 + debugMessage("(%p) (%p) Stream added, broadcasting: %d", s, stream, stream.streamId)
764 + s.streamCond.Broadcast()
765 + s.streamCond.L.Unlock()
766 +}
767 +
768 +func (s *Connection) removeStream(stream *Stream) {
769 + s.streamCond.L.Lock()
770 + delete(s.streams, stream.streamId)
771 + debugMessage("Stream removed, broadcasting: %d", stream.streamId)
772 + s.streamCond.Broadcast()
773 + s.streamCond.L.Unlock()
774 +}
775 +
776 +func (s *Connection) getStream(streamId spdy.StreamId) (stream *Stream, ok bool) {
777 + s.streamLock.RLock()
778 + stream, ok = s.streams[streamId]
779 + s.streamLock.RUnlock()
780 + return
781 +}
782 +
783 +// FindStream looks up the given stream id and either waits for the
784 +// stream to be found or returns nil if the stream id is no longer
785 +// valid.
786 +func (s *Connection) FindStream(streamId uint32) *Stream {
787 + var stream *Stream
788 + var ok bool
789 + s.streamCond.L.Lock()
790 + stream, ok = s.streams[spdy.StreamId(streamId)]
791 + debugMessage("(%p) Found stream %d? %t", s, spdy.StreamId(streamId), ok)
792 + for !ok && streamId >= uint32(s.receivedStreamId) {
793 + s.streamCond.Wait()
794 + stream, ok = s.streams[spdy.StreamId(streamId)]
795 + }
796 + s.streamCond.L.Unlock()
797 + return stream
798 +}
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
+97
@@ -0,0 +1,97 @@
1 +package spdystream
2 +
3 +import (
4 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/spdy"
5 + "container/heap"
6 + "sync"
7 +)
8 +
9 +type prioritizedFrame struct {
10 + frame spdy.Frame
11 + priority uint8
12 + insertId uint64
13 +}
14 +
15 +type frameQueue []*prioritizedFrame
16 +
17 +func (fq frameQueue) Len() int {
18 + return len(fq)
19 +}
20 +
21 +func (fq frameQueue) Less(i, j int) bool {
22 + if fq[i].priority == fq[j].priority {
23 + return fq[i].insertId < fq[j].insertId
24 + }
25 + return fq[i].priority < fq[j].priority
26 +}
27 +
28 +func (fq frameQueue) Swap(i, j int) {
29 + fq[i], fq[j] = fq[j], fq[i]
30 +}
31 +
32 +func (fq *frameQueue) Push(x interface{}) {
33 + *fq = append(*fq, x.(*prioritizedFrame))
34 +}
35 +
36 +func (fq *frameQueue) Pop() interface{} {
37 + old := *fq
38 + n := len(old)
39 + *fq = old[0 : n-1]
40 + return old[n-1]
41 +}
42 +
43 +type PriorityFrameQueue struct {
44 + queue *frameQueue
45 + c *sync.Cond
46 + size int
47 + nextInsertId uint64
48 + drain bool
49 +}
50 +
51 +func NewPriorityFrameQueue(size int) *PriorityFrameQueue {
52 + queue := make(frameQueue, 0, size)
53 + heap.Init(&queue)
54 +
55 + return &PriorityFrameQueue{
56 + queue: &queue,
57 + size: size,
58 + c: sync.NewCond(&sync.Mutex{}),
59 + }
60 +}
61 +
62 +func (q *PriorityFrameQueue) Push(frame spdy.Frame, priority uint8) {
63 + q.c.L.Lock()
64 + defer q.c.L.Unlock()
65 + for q.queue.Len() >= q.size {
66 + q.c.Wait()
67 + }
68 + pFrame := &prioritizedFrame{
69 + frame: frame,
70 + priority: priority,
71 + insertId: q.nextInsertId,
72 + }
73 + q.nextInsertId = q.nextInsertId + 1
74 + heap.Push(q.queue, pFrame)
75 + q.c.Signal()
76 +}
77 +
78 +func (q *PriorityFrameQueue) Pop() spdy.Frame {
79 + q.c.L.Lock()
80 + defer q.c.L.Unlock()
81 + for q.queue.Len() == 0 {
82 + if q.drain {
83 + return nil
84 + }
85 + q.c.Wait()
86 + }
87 + frame := heap.Pop(q.queue).(*prioritizedFrame).frame
88 + q.c.Signal()
89 + return frame
90 +}
91 +
92 +func (q *PriorityFrameQueue) Drain() {
93 + q.c.L.Lock()
94 + defer q.c.L.Unlock()
95 + q.drain = true
96 + q.c.Broadcast()
97 +}
Godeps/_workspace/src/github.com/docker/spdystream/priority_test.go new
+107
@@ -0,0 +1,107 @@
1 +package spdystream
2 +
3 +import (
4 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/spdy"
5 + "sync"
6 + "testing"
7 + "time"
8 +)
9 +
10 +func TestPriorityQueueOrdering(t *testing.T) {
11 + queue := NewPriorityFrameQueue(150)
12 + data1 := &spdy.DataFrame{}
13 + data2 := &spdy.DataFrame{}
14 + data3 := &spdy.DataFrame{}
15 + data4 := &spdy.DataFrame{}
16 + queue.Push(data1, 2)
17 + queue.Push(data2, 1)
18 + queue.Push(data3, 1)
19 + queue.Push(data4, 0)
20 +
21 + if queue.Pop() != data4 {
22 + t.Fatalf("Wrong order, expected data4 first")
23 + }
24 + if queue.Pop() != data2 {
25 + t.Fatalf("Wrong order, expected data2 second")
26 + }
27 + if queue.Pop() != data3 {
28 + t.Fatalf("Wrong order, expected data3 third")
29 + }
30 + if queue.Pop() != data1 {
31 + t.Fatalf("Wrong order, expected data1 fourth")
32 + }
33 +
34 + // Insert 50 Medium priority frames
35 + for i := spdy.StreamId(50); i < 100; i++ {
36 + queue.Push(&spdy.DataFrame{StreamId: i}, 1)
37 + }
38 + // Insert 50 low priority frames
39 + for i := spdy.StreamId(100); i < 150; i++ {
40 + queue.Push(&spdy.DataFrame{StreamId: i}, 2)
41 + }
42 + // Insert 50 high priority frames
43 + for i := spdy.StreamId(0); i < 50; i++ {
44 + queue.Push(&spdy.DataFrame{StreamId: i}, 0)
45 + }
46 +
47 + for i := spdy.StreamId(0); i < 150; i++ {
48 + frame := queue.Pop()
49 + if frame.(*spdy.DataFrame).StreamId != i {
50 + t.Fatalf("Wrong frame\nActual: %d\nExpecting: %d", frame.(*spdy.DataFrame).StreamId, i)
51 + }
52 + }
53 +}
54 +
55 +func TestPriorityQueueSync(t *testing.T) {
56 + queue := NewPriorityFrameQueue(150)
57 + var wg sync.WaitGroup
58 + insertRange := func(start, stop spdy.StreamId, priority uint8) {
59 + for i := start; i < stop; i++ {
60 + queue.Push(&spdy.DataFrame{StreamId: i}, priority)
61 + }
62 + wg.Done()
63 + }
64 + wg.Add(3)
65 + go insertRange(spdy.StreamId(100), spdy.StreamId(150), 2)
66 + go insertRange(spdy.StreamId(0), spdy.StreamId(50), 0)
67 + go insertRange(spdy.StreamId(50), spdy.StreamId(100), 1)
68 +
69 + wg.Wait()
70 + for i := spdy.StreamId(0); i < 150; i++ {
71 + frame := queue.Pop()
72 + if frame.(*spdy.DataFrame).StreamId != i {
73 + t.Fatalf("Wrong frame\nActual: %d\nExpecting: %d", frame.(*spdy.DataFrame).StreamId, i)
74 + }
75 + }
76 +}
77 +
78 +func TestPriorityQueueBlocking(t *testing.T) {
79 + queue := NewPriorityFrameQueue(15)
80 + for i := 0; i < 15; i++ {
81 + queue.Push(&spdy.DataFrame{}, 2)
82 + }
83 + doneChan := make(chan bool)
84 + go func() {
85 + queue.Push(&spdy.DataFrame{}, 2)
86 + close(doneChan)
87 + }()
88 + select {
89 + case <-doneChan:
90 + t.Fatalf("Push succeeded, expected to block")
91 + case <-time.After(time.Millisecond):
92 + break
93 + }
94 +
95 + queue.Pop()
96 +
97 + select {
98 + case <-doneChan:
99 + break
100 + case <-time.After(time.Millisecond):
101 + t.Fatalf("Push should have succeeded, but timeout reached")
102 + }
103 +
104 + for i := 0; i < 15; i++ {
105 + queue.Pop()
106 + }
107 +}
Godeps/_workspace/src/github.com/docker/spdystream/spdy_bench_test.go new
+117
@@ -0,0 +1,117 @@
1 +package spdystream
2 +
3 +import (
4 + "fmt"
5 + "io"
6 + "net"
7 + "net/http"
8 + "sync"
9 + "testing"
10 +)
11 +
12 +const (
13 + LISTEN_ADDRESS = "127.0.0.1:7777"
14 +)
15 +
16 +func configureServer() (io.Closer, *sync.WaitGroup) {
17 + authenticated = true
18 + wg := &sync.WaitGroup{}
19 + server, serverErr := runServer(LISTEN_ADDRESS, wg)
20 +
21 + if serverErr != nil {
22 + panic(serverErr)
23 + }
24 +
25 + return server, wg
26 +}
27 +
28 +func BenchmarkDial10000(b *testing.B) {
29 + server, wg := configureServer()
30 +
31 + defer func() {
32 + server.Close()
33 + wg.Wait()
34 + }()
35 +
36 + for i := 0; i < b.N; i++ {
37 + conn, dialErr := net.Dial("tcp", LISTEN_ADDRESS)
38 + if dialErr != nil {
39 + panic(fmt.Sprintf("Error dialing server: %s", dialErr))
40 + }
41 + conn.Close()
42 + }
43 +}
44 +
45 +func BenchmarkDialWithSPDYStream10000(b *testing.B) {
46 + server, wg := configureServer()
47 +
48 + defer func() {
49 + server.Close()
50 + wg.Wait()
51 + }()
52 +
53 + for i := 0; i < b.N; i++ {
54 + conn, dialErr := net.Dial("tcp", LISTEN_ADDRESS)
55 + if dialErr != nil {
56 + b.Fatalf("Error dialing server: %s", dialErr)
57 + }
58 +
59 + spdyConn, spdyErr := NewConnection(conn, false)
60 + if spdyErr != nil {
61 + b.Fatalf("Error creating spdy connection: %s", spdyErr)
62 + }
63 + go spdyConn.Serve(NoOpStreamHandler)
64 +
65 + closeErr := spdyConn.Close()
66 + if closeErr != nil {
67 + b.Fatalf("Error closing connection: %s, closeErr")
68 + }
69 + }
70 +}
71 +
72 +func benchmarkStreamWithDataAndSize(size uint64, b *testing.B) {
73 + server, wg := configureServer()
74 +
75 + defer func() {
76 + server.Close()
77 + wg.Wait()
78 + }()
79 +
80 + for i := 0; i < b.N; i++ {
81 + conn, dialErr := net.Dial("tcp", LISTEN_ADDRESS)
82 + if dialErr != nil {
83 + b.Fatalf("Error dialing server: %s", dialErr)
84 + }
85 +
86 + spdyConn, spdyErr := NewConnection(conn, false)
87 + if spdyErr != nil {
88 + b.Fatalf("Error creating spdy connection: %s", spdyErr)
89 + }
90 +
91 + go spdyConn.Serve(MirrorStreamHandler)
92 +
93 + stream, err := spdyConn.CreateStream(http.Header{}, nil, false)
94 +
95 + writer := make([]byte, size)
96 +
97 + stream.Write(writer)
98 +
99 + if err != nil {
100 + panic(err)
101 + }
102 +
103 + reader := make([]byte, size)
104 + stream.Read(reader)
105 +
106 + stream.Close()
107 +
108 + closeErr := spdyConn.Close()
109 + if closeErr != nil {
110 + b.Fatalf("Error closing connection: %s, closeErr")
111 + }
112 + }
113 +}
114 +
115 +func BenchmarkStreamWith1Byte10000(b *testing.B) { benchmarkStreamWithDataAndSize(1, b) }
116 +func BenchmarkStreamWith1KiloByte10000(b *testing.B) { benchmarkStreamWithDataAndSize(1024, b) }
117 +func BenchmarkStreamWith1Megabyte10000(b *testing.B) { benchmarkStreamWithDataAndSize(1024*1024, b) }
Godeps/_workspace/src/github.com/docker/spdystream/spdy_test.go new
+284
@@ -0,0 +1,284 @@
1 +package spdystream
2 +
3 +import (
4 + "bytes"
5 + "io"
6 + "net"
7 + "net/http"
8 + "sync"
9 + "testing"
10 + "time"
11 +)
12 +
13 +func TestSpdyStreams(t *testing.T) {
14 + var wg sync.WaitGroup
15 + listen := "localhost:7443"
16 + server, serverErr := runServer(listen, &wg)
17 + if serverErr != nil {
18 + t.Fatalf("Error initializing server: %s", serverErr)
19 + }
20 +
21 + conn, dialErr := net.Dial("tcp", listen)
22 + if dialErr != nil {
23 + t.Fatalf("Error dialing server: %s", dialErr)
24 + }
25 +
26 + spdyConn, spdyErr := NewConnection(conn, false)
27 + if spdyErr != nil {
28 + t.Fatalf("Error creating spdy connection: %s", spdyErr)
29 + }
30 + go spdyConn.Serve(NoOpStreamHandler)
31 +
32 + authenticated = true
33 + stream, streamErr := spdyConn.CreateStream(http.Header{}, nil, false)
34 + if streamErr != nil {
35 + t.Fatalf("Error creating stream: %s", streamErr)
36 + }
37 +
38 + waitErr := stream.Wait()
39 + if waitErr != nil {
40 + t.Fatalf("Error waiting for stream: %s", waitErr)
41 + }
42 +
43 + message := []byte("hello")
44 + writeErr := stream.WriteData(message, false)
45 + if writeErr != nil {
46 + t.Fatalf("Error writing data")
47 + }
48 +
49 + buf := make([]byte, 10)
50 + n, readErr := stream.Read(buf)
51 + if readErr != nil {
52 + t.Fatalf("Error reading data from stream: %s", readErr)
53 + }
54 + if n != 5 {
55 + t.Fatalf("Unexpected number of bytes read:\nActual: %d\nExpected: 5", n)
56 + }
57 + if bytes.Compare(buf[:n], message) != 0 {
58 + t.Fatalf("Did not receive expected message:\nActual: %s\nExpectd: %s", buf, message)
59 + }
60 +
61 + headers := http.Header{
62 + "TestKey": []string{"TestVal"},
63 + }
64 + sendErr := stream.SendHeader(headers, false)
65 + if sendErr != nil {
66 + t.Fatalf("Error sending headers: %s", sendErr)
67 + }
68 + receiveHeaders, receiveErr := stream.ReceiveHeader()
69 + if receiveErr != nil {
70 + t.Fatalf("Error receiving headers: %s", receiveErr)
71 + }
72 + if len(receiveHeaders) != 1 {
73 + t.Fatalf("Unexpected number of headers:\nActual: %d\nExpecting:%d", len(receiveHeaders), 1)
74 + }
75 + testVal := receiveHeaders.Get("TestKey")
76 + if testVal != "TestVal" {
77 + t.Fatalf("Wrong test value:\nActual: %q\nExpecting: %q", testVal, "TestVal")
78 + }
79 +
80 + writeErr = stream.WriteData(message, true)
81 + if writeErr != nil {
82 + t.Fatalf("Error writing data")
83 + }
84 +
85 + smallBuf := make([]byte, 3)
86 + n, readErr = stream.Read(smallBuf)
87 + if readErr != nil {
88 + t.Fatalf("Error reading data from stream: %s", readErr)
89 + }
90 + if n != 3 {
91 + t.Fatalf("Unexpected number of bytes read:\nActual: %d\nExpected: 3", n)
92 + }
93 + if bytes.Compare(smallBuf[:n], []byte("hel")) != 0 {
94 + t.Fatalf("Did not receive expected message:\nActual: %s\nExpectd: %s", smallBuf[:n], message)
95 + }
96 + n, readErr = stream.Read(smallBuf)
97 + if readErr != nil {
98 + t.Fatalf("Error reading data from stream: %s", readErr)
99 + }
100 + if n != 2 {
101 + t.Fatalf("Unexpected number of bytes read:\nActual: %d\nExpected: 2", n)
102 + }
103 + if bytes.Compare(smallBuf[:n], []byte("lo")) != 0 {
104 + t.Fatalf("Did not receive expected message:\nActual: %s\nExpected: lo", smallBuf[:n])
105 + }
106 +
107 + n, readErr = stream.Read(buf)
108 + if readErr != io.EOF {
109 + t.Fatalf("Expected EOF reading from finished stream, read %d bytes", n)
110 + }
111 +
112 + // Closing again should return error since stream is already closed
113 + streamCloseErr := stream.Close()
114 + if streamCloseErr == nil {
115 + t.Fatalf("No error closing finished stream")
116 + }
117 + if streamCloseErr != ErrWriteClosedStream {
118 + t.Fatalf("Unexpected error closing stream: %s", streamCloseErr)
119 + }
120 +
121 + streamResetErr := stream.Reset()
122 + if streamResetErr != nil {
123 + t.Fatalf("Error reseting stream: %s", streamResetErr)
124 + }
125 +
126 + authenticated = false
127 + badStream, badStreamErr := spdyConn.CreateStream(http.Header{}, nil, false)
128 + if badStreamErr != nil {
129 + t.Fatalf("Error creating stream: %s", badStreamErr)
130 + }
131 +
132 + waitErr = badStream.Wait()
133 + if waitErr == nil {
134 + t.Fatalf("Did not receive error creating stream")
135 + }
136 + if waitErr != ErrReset {
137 + t.Fatalf("Unexpected error creating stream: %s", waitErr)
138 + }
139 + streamCloseErr = badStream.Close()
140 + if streamCloseErr == nil {
141 + t.Fatalf("No error closing bad stream")
142 + }
143 +
144 + spdyCloseErr := spdyConn.Close()
145 + if spdyCloseErr != nil {
146 + t.Fatalf("Error closing spdy connection: %s", spdyCloseErr)
147 + }
148 +
149 + closeErr := server.Close()
150 + if closeErr != nil {
151 + t.Fatalf("Error shutting down server: %s", closeErr)
152 + }
153 + wg.Wait()
154 +}
155 +
156 +func TestPing(t *testing.T) {
157 + var wg sync.WaitGroup
158 + listen := "localhost:7543"
159 + server, serverErr := runServer(listen, &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 + listen := "localhost:7643"
193 + server, serverErr := runServer(listen, &wg)
194 + if serverErr != nil {
195 + t.Fatalf("Error initializing server: %s", serverErr)
196 + }
197 +
198 + conn, dialErr := net.Dial("tcp", listen)
199 + if dialErr != nil {
200 + t.Fatalf("Error dialing server: %s", dialErr)
201 + }
202 +
203 + spdyConn, spdyErr := NewConnection(conn, false)
204 + if spdyErr != nil {
205 + t.Fatalf("Error creating spdy connection: %s", spdyErr)
206 + }
207 + go spdyConn.Serve(NoOpStreamHandler)
208 +
209 + authenticated = true
210 + stream, streamErr := spdyConn.CreateStream(http.Header{}, nil, false)
211 + if streamErr != nil {
212 + t.Fatalf("Error creating stream: %s", streamErr)
213 + }
214 +
215 + waitErr := stream.Wait()
216 + if waitErr != nil {
217 + t.Fatalf("Error waiting for stream: %s", waitErr)
218 + }
219 +
220 + message := []byte("hello and will read after close")
221 + writeErr := stream.WriteData(message, false)
222 + if writeErr != nil {
223 + t.Fatalf("Error writing data")
224 + }
225 +
226 + streamCloseErr := stream.Close()
227 + if streamCloseErr != nil {
228 + t.Fatalf("Error closing stream: %s", streamCloseErr)
229 + }
230 +
231 + buf := make([]byte, 40)
232 + n, readErr := stream.Read(buf)
233 + if readErr != nil {
234 + t.Fatalf("Error reading data from stream: %s", readErr)
235 + }
236 + if n != 31 {
237 + t.Fatalf("Unexpected number of bytes read:\nActual: %d\nExpected: 5", n)
238 + }
239 + if bytes.Compare(buf[:n], message) != 0 {
240 + t.Fatalf("Did not receive expected message:\nActual: %s\nExpectd: %s", buf, message)
241 + }
242 +
243 + spdyCloseErr := spdyConn.Close()
244 + if spdyCloseErr != nil {
245 + t.Fatalf("Error closing spdy connection: %s", spdyCloseErr)
246 + }
247 +
248 + closeErr := server.Close()
249 + if closeErr != nil {
250 + t.Fatalf("Error shutting down server: %s", closeErr)
251 + }
252 + wg.Wait()
253 +}
254 +
255 +var authenticated bool
256 +
257 +func authStreamHandler(stream *Stream) {
258 + if !authenticated {
259 + stream.Refuse()
260 + }
261 + MirrorStreamHandler(stream)
262 +}
263 +
264 +func runServer(listen string, wg *sync.WaitGroup) (io.Closer, error) {
265 + listener, listenErr := net.Listen("tcp", listen)
266 + if listenErr != nil {
267 + return nil, listenErr
268 + }
269 + wg.Add(1)
270 + go func() {
271 + for {
272 + conn, connErr := listener.Accept()
273 + if connErr != nil {
274 + break
275 + }
276 +
277 + spdyConn, _ := NewConnection(conn, true)
278 + go spdyConn.Serve(authStreamHandler)
279 +
280 + }
281 + wg.Done()
282 + }()
283 + return listener, nil
284 +}
Godeps/_workspace/src/github.com/docker/spdystream/stream.go new
+321
@@ -0,0 +1,321 @@
1 +package spdystream
2 +
3 +import (
4 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/spdy"
5 + "errors"
6 + "fmt"
7 + "io"
8 + "net"
9 + "net/http"
10 + "sync"
11 + "time"
12 +)
13 +
14 +var (
15 + ErrUnreadPartialData = errors.New("unread partial data")
16 +)
17 +
18 +type Stream struct {
19 + streamId spdy.StreamId
20 + parent *Stream
21 + conn *Connection
22 + startChan chan error
23 +
24 + dataLock sync.RWMutex
25 + dataChan chan []byte
26 + unread []byte
27 +
28 + priority uint8
29 + headers http.Header
30 + headerChan chan http.Header
31 + finishLock sync.Mutex
32 + finished bool
33 + replyCond *sync.Cond
34 + replied bool
35 + closeChan chan bool
36 +}
37 +
38 +// WriteData writes data to stream, sending a dataframe per call
39 +func (s *Stream) WriteData(data []byte, fin bool) error {
40 + s.waitWriteReply()
41 + var flags spdy.DataFlags
42 +
43 + if fin {
44 + flags = spdy.DataFlagFin
45 + s.finishLock.Lock()
46 + if s.finished {
47 + s.finishLock.Unlock()
48 + return ErrWriteClosedStream
49 + }
50 + s.finished = true
51 + s.finishLock.Unlock()
52 + }
53 +
54 + dataFrame := &spdy.DataFrame{
55 + StreamId: s.streamId,
56 + Flags: flags,
57 + Data: data,
58 + }
59 +
60 + s.conn.writeLock.Lock()
61 + defer s.conn.writeLock.Unlock()
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 +
170 + s.finishLock.Lock()
171 + if s.finished {
172 + s.finishLock.Unlock()
173 + return nil
174 + }
175 + s.finished = true
176 + s.finishLock.Unlock()
177 +
178 + s.dataLock.Lock()
179 + select {
180 + case <-s.closeChan:
181 + break
182 + default:
183 + close(s.dataChan)
184 + close(s.closeChan)
185 + }
186 + s.dataLock.Unlock()
187 +
188 + resetFrame := &spdy.RstStreamFrame{
189 + StreamId: s.streamId,
190 + Status: spdy.Cancel,
191 + }
192 + s.conn.writeLock.Lock()
193 + defer s.conn.writeLock.Unlock()
194 + return s.conn.framer.WriteFrame(resetFrame)
195 +}
196 +
197 +// CreateSubStream creates a stream using the current as the parent
198 +func (s *Stream) CreateSubStream(headers http.Header, fin bool) (*Stream, error) {
199 + return s.conn.CreateStream(headers, s, fin)
200 +}
201 +
202 +// SetPriority sets the stream priority, does not affect the
203 +// remote priority of this stream after Open has been called.
204 +// Valid values are 0 through 7, 0 being the highest priority
205 +// and 7 the lowest.
206 +func (s *Stream) SetPriority(priority uint8) {
207 + s.priority = priority
208 +}
209 +
210 +// SendHeader sends a header frame across the stream
211 +func (s *Stream) SendHeader(headers http.Header, fin bool) error {
212 + return s.conn.sendHeaders(headers, s, fin)
213 +}
214 +
215 +// SendReply sends a reply on a stream, only valid to be called once
216 +// when handling a new stream
217 +func (s *Stream) SendReply(headers http.Header, fin bool) error {
218 + if s.replyCond == nil {
219 + return errors.New("cannot reply on initiated stream")
220 + }
221 + s.replyCond.L.Lock()
222 + defer s.replyCond.L.Unlock()
223 + if s.replied {
224 + return nil
225 + }
226 +
227 + err := s.conn.sendReply(headers, s, fin)
228 + if err != nil {
229 + return err
230 + }
231 +
232 + s.replied = true
233 + s.replyCond.Broadcast()
234 + return nil
235 +}
236 +
237 +// Refuse sends a reset frame with the status refuse, only
238 +// valid to be called once when handling a new stream. This
239 +// may be used to indicate that a stream is not allowed
240 +// when http status codes are not being used.
241 +func (s *Stream) Refuse() error {
242 + if s.replied {
243 + return nil
244 + }
245 + s.replied = true
246 + return s.conn.sendReset(spdy.RefusedStream, s)
247 +}
248 +
249 +// Cancel sends a reset frame with the status canceled. This
250 +// can be used at any time by the creator of the Stream to
251 +// indicate the stream is no longer needed.
252 +func (s *Stream) Cancel() error {
253 + return s.conn.sendReset(spdy.Cancel, s)
254 +}
255 +
256 +// ReceiveHeader receives a header sent on the other side
257 +// of the stream. This function will block until a header
258 +// is received or stream is closed.
259 +func (s *Stream) ReceiveHeader() (http.Header, error) {
260 + select {
261 + case <-s.closeChan:
262 + break
263 + case header, ok := <-s.headerChan:
264 + if !ok {
265 + return nil, fmt.Errorf("header chan closed")
266 + }
267 + return header, nil
268 + }
269 + return nil, fmt.Errorf("stream closed")
270 +}
271 +
272 +// Parent returns the parent stream
273 +func (s *Stream) Parent() *Stream {
274 + return s.parent
275 +}
276 +
277 +// Headers returns the headers used to create the stream
278 +func (s *Stream) Headers() http.Header {
279 + return s.headers
280 +}
281 +
282 +// String returns the string version of stream using the
283 +// streamId to uniquely identify the stream
284 +func (s *Stream) String() string {
285 + return fmt.Sprintf("stream:%d", s.streamId)
286 +}
287 +
288 +// Identifier returns a 32 bit identifier for the stream
289 +func (s *Stream) Identifier() uint32 {
290 + return uint32(s.streamId)
291 +}
292 +
293 +// IsFinished returns whether the stream has finished
294 +// sending data
295 +func (s *Stream) IsFinished() bool {
296 + return s.finished
297 +}
298 +
299 +// Implement net.Conn interface
300 +
301 +func (s *Stream) LocalAddr() net.Addr {
302 + return s.conn.conn.LocalAddr()
303 +}
304 +
305 +func (s *Stream) RemoteAddr() net.Addr {
306 + return s.conn.conn.RemoteAddr()
307 +}
308 +
309 +// TODO set per stream values instead of connection-wide
310 +
311 +func (s *Stream) SetDeadline(t time.Time) error {
312 + return s.conn.conn.SetDeadline(t)
313 +}
314 +
315 +func (s *Stream) SetReadDeadline(t time.Time) error {
316 + return s.conn.conn.SetReadDeadline(t)
317 +}
318 +
319 +func (s *Stream) SetWriteDeadline(t time.Time) error {
320 + return s.conn.conn.SetWriteDeadline(t)
321 +}
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/jbenet/go-ipfs/Godeps/_workspace/src/github.com/docker/spdystream"
6 + "github.com/gorilla/websocket"
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-peerstream/LICENSE new
+21
@@ -0,0 +1,21 @@
1 +The MIT License (MIT)
2 +
3 +Copyright (c) 2014 Juan Batiz-Benet
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in
13 +all copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 +THE SOFTWARE.
Godeps/_workspace/src/github.com/jbenet/go-peerstream/README.md new
+148
@@ -0,0 +1,148 @@
1 +# go-peerstream p2p multi-multixplexing
2 +
3 +Package peerstream is a peer-to-peer networking library that multiplexes
4 +connections to many hosts. It tried to simplify the complexity of:
5 +
6 +* accepting incoming connections over **multiple** listeners
7 +* dialing outgoing connections over **multiple** transports
8 +* multiplexing **multiple** connections per-peer
9 +* multiplexing **multiple** different servers or protocols
10 +* handling backpressure correctly
11 +* handling stream multiplexing (we use SPDY, but maybe QUIC some day)
12 +* providing a **simple** interface to the user
13 +
14 +### Godoc: https://godoc.org/github.com/jbenet/go-peerstream
15 +
16 +---
17 +
18 +See this working [example/example.go](example/example):
19 +
20 +```Go
21 +package main
22 +
23 +import (
24 + "fmt"
25 + "io"
26 + "net"
27 + "os"
28 +
29 + ps "github.com/jbenet/go-peerstream"
30 +)
31 +
32 +func main() {
33 + // create a new Swarm
34 + swarm := ps.NewSwarm()
35 + defer swarm.Close()
36 +
37 + // tell swarm what to do with a new incoming streams.
38 + // EchoHandler just echos back anything they write.
39 + swarm.SetStreamHandler(ps.EchoHandler)
40 +
41 + // Okay, let's try listening on some transports
42 + l1, err := net.Listen("tcp", "localhost:8001")
43 + if err != nil {
44 + panic(err)
45 + }
46 +
47 + l2, err := net.Listen("tcp", "localhost:8002")
48 + if err != nil {
49 + panic(err)
50 + }
51 +
52 + // tell swarm to accept incoming connections on these
53 + // listeners. Swarm will start accepting new connections.
54 + if err := swarm.AddListener(l1); err != nil {
55 + panic(err)
56 + }
57 + if err := swarm.AddListener(l2); err != nil {
58 + panic(err)
59 + }
60 +
61 + // ok, let's try some outgoing connections
62 + nc1, err := net.Dial("tcp", "localhost:8001")
63 + if err != nil {
64 + panic(err)
65 + }
66 +
67 + nc2, err := net.Dial("tcp", "localhost:8002")
68 + if err != nil {
69 + panic(err)
70 + }
71 +
72 + // add them to the swarm
73 + c1, err := swarm.AddConn(nc1)
74 + if err != nil {
75 + panic(err)
76 + }
77 + c2, err := swarm.AddConn(nc2)
78 + if err != nil {
79 + panic(err)
80 + }
81 +
82 + // Swarm treats listeners as sources of new connections and does
83 + // not distinguish between outgoing or incoming connections.
84 + // It provides the net.Conn to the StreamHandler so you can
85 + // distinguish between them however you wish.
86 +
87 + // now let's try opening some streams!
88 + // You can specify what connection you want to use
89 + s1, err := swarm.NewStreamWithConn(c1)
90 + if err != nil {
91 + panic(err)
92 + }
93 +
94 + // Or, you can specify a SelectConn function that picks between all
95 + // (it calls NewStreamWithConn underneath the hood)
96 + s2, err := swarm.NewStreamSelectConn(func(conns []*ps.Conn) *ps.Conn {
97 + if len(conns) > 0 {
98 + return conns[0]
99 + }
100 + return nil
101 + })
102 + if err != nil {
103 + panic(err)
104 + }
105 +
106 + // Or, you can bind connections to ConnGroup ids. You can bind a conn to
107 + // multiple groups. And, if conn wasn't in swarm, it calls swarm.AddConn.
108 + // You can use any Go `KeyType` as a group A `KeyType` as in maps...)
109 + swarm.AddConnToGroup(c2, 1)
110 +
111 + // And then use that group to select a connection. Swarm will use any
112 + // connection it finds in that group, using a SelectConn you can rebind:
113 + // swarm.SetGroupSelectConn(1, SelectConn)
114 + // swarm.SetDegaultGroupSelectConn(SelectConn)
115 + s3, err := swarm.NewStreamWithGroup(1)
116 + if err != nil {
117 + panic(err)
118 + }
119 +
120 + // Why groups? It's because with many connections, and many transports,
121 + // and many Servers (or Protocols), we can use the Swarm to associate
122 + // a different StreamHandlers per group, and to let us create NewStreams
123 + // on a given group.
124 +
125 + // Ok, we have streams. now what. Use them! Our Streams are basically
126 + // streams from github.com/docker/spdystream, so they work the same
127 + // way:
128 +
129 + for i, stream := range []ps.Stream{s1, s2, s3} {
130 + stream.Wait()
131 + str := "stream %d ready:"
132 + fmt.Fprintf(stream, str, i)
133 +
134 + buf := make([]byte, len(str))
135 + stream.Read(buf)
136 + fmt.Println(string(buf))
137 + }
138 +
139 + go io.Copy(os.Stdout, s1)
140 + go io.Copy(os.Stdout, s2)
141 + go io.Copy(os.Stdout, s3)
142 + io.Copy(io.MultiWriter(s1, s2, s3), os.Stdin)
143 +}
144 +
145 +func log(s string) {
146 + fmt.Fprintf(os.Stderr, s+"\n")
147 +}
148 +```
Godeps/_workspace/src/github.com/jbenet/go-peerstream/conn.go new
+249
@@ -0,0 +1,249 @@
1 +package peerstream
2 +
3 +import (
4 + "errors"
5 + "net"
6 + "net/http"
7 + "sync"
8 +
9 + ss "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/docker/spdystream"
10 +)
11 +
12 +// ConnHandler is a function which receives a Conn. It allows
13 +// clients to set a function to receive newly accepted
14 +// connections. It works like StreamHandler, but is usually
15 +// less useful than usual as most services will only use
16 +// Streams. It is safe to pass or store the *Conn elsewhere.
17 +// Note: the ConnHandler is called sequentially, so spawn
18 +// goroutines or pass the Conn. See EchoHandler.
19 +type ConnHandler func(s *Conn)
20 +
21 +// SelectConn selects a connection out of list. It allows
22 +// delegation of decision making to clients. Clients can
23 +// make SelectConn functons that check things connection
24 +// qualities -- like latency andbandwidth -- or pick from
25 +// a logical set of connections.
26 +type SelectConn func([]*Conn) *Conn
27 +
28 +// ErrInvalidConnSelected signals that a connection selected
29 +// with a SelectConn function is invalid. This may be due to
30 +// the Conn not being part of the original set given to the
31 +// function, or the value being nil.
32 +var ErrInvalidConnSelected = errors.New("invalid selected connection")
33 +
34 +// ErrNoConnections signals that no connections are available
35 +var ErrNoConnections = errors.New("no connections")
36 +
37 +// Conn is a Swarm-associated connection.
38 +type Conn struct {
39 + ssConn *ss.Connection
40 + netConn net.Conn // underlying connection
41 +
42 + swarm *Swarm
43 + groups groupSet
44 +
45 + streams map[*Stream]struct{}
46 + streamLock sync.RWMutex
47 +}
48 +
49 +func newConn(nconn net.Conn, sconn *ss.Connection, s *Swarm) *Conn {
50 + return &Conn{
51 + netConn: nconn,
52 + ssConn: sconn,
53 + swarm: s,
54 + groups: groupSet{m: make(map[Group]struct{})},
55 + streams: make(map[*Stream]struct{}),
56 + }
57 +}
58 +
59 +// Swarm returns the Swarm associated with this Conn
60 +func (c *Conn) Swarm() *Swarm {
61 + return c.swarm
62 +}
63 +
64 +// NetConn returns the underlying net.Conn
65 +func (c *Conn) NetConn() net.Conn {
66 + return c.netConn
67 +}
68 +
69 +// SPDYConn returns the spdystream.Connection we use
70 +// Warning: modifying this object is undefined.
71 +func (c *Conn) SPDYConn() *ss.Connection {
72 + return c.ssConn
73 +}
74 +
75 +// Groups returns the Groups this Conn belongs to
76 +func (c *Conn) Groups() []Group {
77 + return c.groups.Groups()
78 +}
79 +
80 +// InGroup returns whether this Conn belongs to a Group
81 +func (c *Conn) InGroup(g Group) bool {
82 + return c.groups.Has(g)
83 +}
84 +
85 +// AddGroup assigns given Group to Conn
86 +func (c *Conn) AddGroup(g Group) {
87 + c.groups.Add(g)
88 +}
89 +
90 +// Stream returns a stream associated with this Conn
91 +func (c *Conn) NewStream() (*Stream, error) {
92 + return c.swarm.NewStreamWithConn(c)
93 +}
94 +
95 +func (c *Conn) Streams() []*Stream {
96 + c.streamLock.RLock()
97 + defer c.streamLock.RUnlock()
98 +
99 + streams := make([]*Stream, 0, len(c.streams))
100 + for s := range c.streams {
101 + streams = append(streams, s)
102 + }
103 + return streams
104 +}
105 +
106 +// Close closes this connection
107 +func (c *Conn) Close() error {
108 + // close streams
109 + streams := c.Streams()
110 + for _, s := range streams {
111 + s.Close()
112 + }
113 +
114 + // close underlying connection
115 + c.netConn.Close()
116 + return c.swarm.removeConn(c)
117 +}
118 +
119 +// ConnsWithGroup narrows down a set of connections to those in a given group.
120 +func ConnsWithGroup(g Group, conns []*Conn) []*Conn {
121 + var out []*Conn
122 + for _, c := range conns {
123 + if c.InGroup(g) {
124 + out = append(out, c)
125 + }
126 + }
127 + return out
128 +}
129 +
130 +func ConnInConns(c1 *Conn, conns []*Conn) bool {
131 + for _, c2 := range conns {
132 + if c2 == c1 {
133 + return true
134 + }
135 + }
136 + return false
137 +}
138 +
139 +// ------------------------------------------------------------------
140 +// All the connection setup logic here, in one place.
141 +// these are mostly *Swarm methods, but i wanted a less-crowded place
142 +// for them.
143 +// ------------------------------------------------------------------
144 +
145 +// addConn is the internal version of AddConn. we need the server bool
146 +// as spdystream requires it.
147 +func (s *Swarm) addConn(netConn net.Conn, server bool) (*Conn, error) {
148 + if netConn == nil {
149 + return nil, errors.New("nil conn")
150 + }
151 +
152 + // this function is so we can defer our lock, which needs to be
153 + // unlocked **before** the Handler is called (which needs to be
154 + // sequential). This was the simplest thing :)
155 + setupConn := func() (*Conn, error) {
156 + s.connLock.Lock()
157 + defer s.connLock.Unlock()
158 +
159 + // first, check if we already have it...
160 + for c := range s.conns {
161 + if c.netConn == netConn {
162 + s.connLock.Unlock()
163 + return c, nil
164 + }
165 + }
166 +
167 + // create a new spdystream connection
168 + ssConn, err := ss.NewConnection(netConn, server)
169 + if err != nil {
170 + s.connLock.Unlock()
171 + return nil, err
172 + }
173 +
174 + // add the connection
175 + c := newConn(netConn, ssConn, s)
176 + s.conns[c] = struct{}{}
177 + return c, nil
178 + }
179 +
180 + c, err := setupConn()
181 + if err != nil {
182 + return nil, err
183 + }
184 +
185 + s.ConnHandler()(c)
186 +
187 + // go listen for incoming streams on this connection
188 + go c.ssConn.Serve(func(ssS *ss.Stream) {
189 + // log.Printf("accepted stream %d from %s\n", ssS.Identifier(), netConn.RemoteAddr())
190 + ssS.SendReply(http.Header{}, false)
191 + stream := s.setupSSStream(ssS, c)
192 + s.StreamHandler()(stream) // call our handler
193 + })
194 +
195 + return c, nil
196 +}
197 +
198 +// createStream is the internal function that creates a new stream. assumes
199 +// all validation has happened.
200 +func (s *Swarm) createStream(c *Conn) (*Stream, error) {
201 +
202 + // Create a new ss.Stream
203 + ssStream, err := c.ssConn.CreateStream(http.Header{}, nil, false)
204 + if err != nil {
205 + return nil, err
206 + }
207 +
208 + // create a new stream
209 + return s.setupSSStream(ssStream, c), nil
210 +}
211 +
212 +// newStream is the internal function that creates a new stream. assumes
213 +// all validation has happened.
214 +func (s *Swarm) setupSSStream(ssS *ss.Stream, c *Conn) *Stream {
215 + // create a new *Stream
216 + stream := newStream(ssS, c)
217 +
218 + // add it to our streams maps
219 +
220 + // add it to our map
221 + s.streamLock.Lock()
222 + c.streamLock.Lock()
223 + s.streams[stream] = struct{}{}
224 + c.streams[stream] = struct{}{}
225 + s.streamLock.Unlock()
226 + c.streamLock.Unlock()
227 + return stream
228 +}
229 +
230 +func (s *Swarm) removeStream(stream *Stream) error {
231 +
232 + // remove from our maps
233 + s.streamLock.Lock()
234 + stream.conn.streamLock.Lock()
235 + delete(s.streams, stream)
236 + delete(stream.conn.streams, stream)
237 + s.streamLock.Unlock()
238 + stream.conn.streamLock.Unlock()
239 +
240 + return stream.ssStream.Close()
241 +}
242 +
243 +func (s *Swarm) removeConn(conn *Conn) error {
244 + // remove from our maps
245 + s.connLock.Lock()
246 + delete(s.conns, conn)
247 + s.connLock.Unlock()
248 + return nil
249 +}
Godeps/_workspace/src/github.com/jbenet/go-peerstream/doc.go new
+12
@@ -0,0 +1,12 @@
1 +// Package peerstream is a peer-to-peer networking library that multiplexes
2 +// connections to many hosts. It tried to simplify the complexity of:
3 +//
4 +// * accepting incoming connections over **multiple** listeners
5 +// * dialing outgoing connections over **multiple** transports
6 +// * multiplexing **multiple** connections per-peer
7 +// * multiplexing **multiple** different servers or protocols
8 +// * handling backpressure correctly
9 +// * handling stream multiplexing (we use SPDY, but maybe QUIC some day)
10 +// * providing a **simple** interface to the user
11 +//
12 +package peerstream
Godeps/_workspace/src/github.com/jbenet/go-peerstream/example/example
Binary files /dev/null and b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/example/example differ
Godeps/_workspace/src/github.com/jbenet/go-peerstream/example/example.go new
+140
@@ -0,0 +1,140 @@
1 +package main
2 +
3 +import (
4 + "fmt"
5 + "io"
6 + "net"
7 + "os"
8 +
9 + ps "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream"
10 +)
11 +
12 +func main() {
13 + // create a new Swarm
14 + swarm := ps.NewSwarm()
15 + defer swarm.Close()
16 +
17 + // tell swarm what to do with a new incoming streams.
18 + // EchoHandler just echos back anything they write.
19 + swarm.SetStreamHandler(ps.EchoHandler)
20 +
21 + // Okay, let's try listening on some transports
22 + l1, err := net.Listen("tcp", "localhost:8001")
23 + if err != nil {
24 + panic(err)
25 + }
26 +
27 + l2, err := net.Listen("tcp", "localhost:8002")
28 + if err != nil {
29 + panic(err)
30 + }
31 +
32 + // tell swarm to accept incoming connections on these
33 + // listeners. Swarm will start accepting new connections.
34 + if _, err := swarm.AddListener(l1); err != nil {
35 + panic(err)
36 + }
37 + if _, err := swarm.AddListener(l2); err != nil {
38 + panic(err)
39 + }
40 +
41 + // ok, let's try some outgoing connections
42 + nc1, err := net.Dial("tcp", "localhost:8001")
43 + if err != nil {
44 + panic(err)
45 + }
46 +
47 + nc2, err := net.Dial("tcp", "localhost:8002")
48 + if err != nil {
49 + panic(err)
50 + }
51 +
52 + // add them to the swarm
53 + c1, err := swarm.AddConn(nc1)
54 + if err != nil {
55 + panic(err)
56 + }
57 + c2, err := swarm.AddConn(nc2)
58 + if err != nil {
59 + panic(err)
60 + }
61 +
62 + // Swarm treats listeners as sources of new connections and does
63 + // not distinguish between outgoing or incoming connections.
64 + // It provides the net.Conn to the StreamHandler so you can
65 + // distinguish between them however you wish.
66 +
67 + // now let's try opening some streams!
68 + // You can specify what connection you want to use
69 + s1, err := swarm.NewStreamWithConn(c1)
70 + if err != nil {
71 + panic(err)
72 + }
73 +
74 + // Or, you can specify a SelectConn function that picks between all
75 + // (it calls NewStreamWithConn underneath the hood)
76 + s2, err := swarm.NewStreamSelectConn(func(conns []*ps.Conn) *ps.Conn {
77 + if len(conns) > 0 {
78 + return conns[0]
79 + }
80 + return nil
81 + })
82 + if err != nil {
83 + panic(err)
84 + }
85 +
86 + // Or, you can bind connections to ConnGroup ids. You can bind a conn to
87 + // multiple groups. And, if conn wasn't in swarm, it calls swarm.AddConn.
88 + // You can use any Go `KeyType` as a group A `KeyType` as in maps...)
89 + swarm.AddConnToGroup(c2, 1)
90 +
91 + // And then use that group to select a connection. Swarm will use any
92 + // connection it finds in that group, using a SelectConn you can rebind:
93 + // swarm.SetGroupSelectConn(1, SelectConn)
94 + // swarm.SetDegaultGroupSelectConn(SelectConn)
95 + s3, err := swarm.NewStreamWithGroup(1)
96 + if err != nil {
97 + panic(err)
98 + }
99 +
100 + // Why groups? It's because with many connections, and many transports,
101 + // and many Servers (or Protocols), we can use the Swarm to associate
102 + // a different StreamHandlers per group, and to let us create NewStreams
103 + // on a given group.
104 +
105 + // Ok, we have streams. now what. Use them! Our Streams are basically
106 + // streams from github.com/docker/spdystream, so they work the same
107 + // way:
108 +
109 + for i, stream := range []*ps.Stream{s1, s2, s3} {
110 + stream.Wait()
111 + str := "stream %d ready:"
112 + fmt.Fprintf(stream, str, i)
113 +
114 + buf := make([]byte, len(str))
115 + stream.Read(buf)
116 + fmt.Println(string(buf))
117 + }
118 +
119 + go io.Copy(os.Stdout, s1)
120 + go io.Copy(os.Stdout, s2)
121 + go io.Copy(os.Stdout, s3)
122 + io.Copy(io.MultiWriter(s1, s2, s3), os.Stdin)
123 +
124 + // r := peerstream.ProtoRouter()
125 + // r.AddRoute("bitswap", BitswapHandler)
126 + // r.AddRoute("dht", DHTHandler)
127 + // r.AddRoute("id", IDHandler)
128 +
129 + // // The router's StreamHandler does this
130 + // swarm.SetStreamHandler(router.StreamHandler())
131 +
132 + // func (r *router) StreamHandler(s Stream) {
133 +
134 + // }
135 +
136 +}
137 +
138 +func log(s string) {
139 + fmt.Fprintf(os.Stderr, s+"\n")
140 +}
Godeps/_workspace/src/github.com/jbenet/go-peerstream/group.go new
+92
@@ -0,0 +1,92 @@
1 +package peerstream
2 +
3 +import (
4 + "errors"
5 + "sync"
6 + "unsafe"
7 +)
8 +
9 +// ErrGroupNotFound signals no such group exists
10 +var ErrGroupNotFound = errors.New("group not found")
11 +
12 +// Group is an object used to associate a group of
13 +// Streams, Connections, and Listeners. It can be anything,
14 +// it is meant to work like a KeyType in maps
15 +type Group interface{}
16 +
17 +// Groupable is an interface for a set of objects that can
18 +// be assigned groups: Streams, Connections, and Listeners.
19 +// Objects inherit groups (e.g. a Stream inherits the groups
20 +// of its parent Connection, and in turn that of its Listener).
21 +type Groupable interface {
22 + // Groups returns the groups this object belongs to
23 + Groups() []Group
24 +
25 + // InGroup returns whether this object belongs to a Group
26 + InGroup(g Group) bool
27 +
28 + // AddGroup adds this object to a group
29 + AddGroup(g Group)
30 +}
31 +
32 +// groupSet is a struct designed to be embedded and
33 +// give things group memebership
34 +type groupSet struct {
35 + m map[Group]struct{}
36 + sync.RWMutex
37 +}
38 +
39 +func (gs *groupSet) Add(g Group) {
40 + gs.Lock()
41 + defer gs.Unlock()
42 + gs.m[g] = struct{}{}
43 +}
44 +
45 +func (gs *groupSet) Remove(g Group) {
46 + gs.Lock()
47 + defer gs.Unlock()
48 + delete(gs.m, g)
49 +}
50 +
51 +func (gs *groupSet) Has(g Group) bool {
52 + gs.RLock()
53 + defer gs.RUnlock()
54 + _, ok := gs.m[g]
55 + return ok
56 +}
57 +
58 +func (gs *groupSet) Groups() []Group {
59 + gs.RLock()
60 + defer gs.RUnlock()
61 +
62 + out := make([]Group, 0, len(gs.m))
63 + for k := range gs.m {
64 + out = append(out, k)
65 + }
66 + return out
67 +}
68 +
69 +// AddSet adds all elements in another set.
70 +func (gs *groupSet) AddSet(gs2 *groupSet) {
71 + // acquire locks in order
72 + p1 := uintptr(unsafe.Pointer(gs))
73 + p2 := uintptr(unsafe.Pointer(gs2))
74 + switch {
75 + case p1 < p2:
76 + gs.Lock()
77 + gs2.RLock()
78 + defer gs.Unlock()
79 + defer gs2.RUnlock()
80 + case p1 > p2:
81 + gs2.Lock()
82 + gs.Lock()
83 + defer gs2.Unlock()
84 + defer gs.Unlock()
85 + default:
86 + return // they're the same!
87 + }
88 +
89 + for g := range gs2.m {
90 + gs.m[g] = struct{}{}
91 + }
92 +}
Godeps/_workspace/src/github.com/jbenet/go-peerstream/handlers.go new
+29
@@ -0,0 +1,29 @@
1 +package peerstream
2 +
3 +import (
4 + "io"
5 + "math/rand"
6 +)
7 +
8 +var SelectRandomConn = func(conns []*Conn) *Conn {
9 + if len(conns) == 0 {
10 + return nil
11 + }
12 +
13 + return conns[rand.Intn(len(conns))]
14 +}
15 +
16 +func EchoHandler(s *Stream) {
17 + go func() {
18 + io.Copy(s, s)
19 + s.Close()
20 + }()
21 +}
22 +
23 +func CloseHandler(s *Stream) {
24 + s.Close()
25 +}
26 +
27 +func NoOpStreamHandler(s *Stream) {}
28 +
29 +func NoOpConnHandler(c *Conn) {}
Godeps/_workspace/src/github.com/jbenet/go-peerstream/listener.go new
+149
@@ -0,0 +1,149 @@
1 +package peerstream
2 +
3 +import (
4 + "errors"
5 + "net"
6 + "time"
7 +)
8 +
9 +type Listener struct {
10 + netList net.Listener
11 + groups groupSet
12 + swarm *Swarm
13 +
14 + acceptErr chan error
15 +}
16 +
17 +func newListener(nl net.Listener, s *Swarm) *Listener {
18 + return &Listener{
19 + netList: nl,
20 + swarm: s,
21 + acceptErr: make(chan error, 10),
22 + }
23 +}
24 +
25 +// NetListener is the underlying net.Listener
26 +func (l *Listener) NetListener() net.Listener {
27 + return l.netList
28 +}
29 +
30 +// Groups returns the groups this Listener belongs to
31 +func (l *Listener) Groups() []Group {
32 + return l.groups.Groups()
33 +}
34 +
35 +// InGroup returns whether this Listener belongs to a Group
36 +func (l *Listener) InGroup(g Group) bool {
37 + return l.groups.Has(g)
38 +}
39 +
40 +// AddGroup assigns given Group to Listener
41 +func (l *Listener) AddGroup(g Group) {
42 + l.groups.Add(g)
43 +}
44 +
45 +// ListenersWithGroup narrows down a set of listeners to those in given group.
46 +func ListenersWithGroup(g Group, ls []*Listener) []*Listener {
47 + var out []*Listener
48 + for _, l := range ls {
49 + if l.InGroup(g) {
50 + out = append(out, l)
51 + }
52 + }
53 + return out
54 +}
55 +
56 +// accept continously accepts incoming connections and
57 +// adds them to the listener's Swarm. is is meant to be
58 +// run in a goroutine.
59 +// TODO: add rate limiting
60 +func (l *Listener) accept() {
61 + defer l.teardown()
62 +
63 + // catching the error here is odd. doing what net/http does:
64 + // http://golang.org/src/net/http/server.go?s=51504:51550#L1728
65 + var tempDelay time.Duration // how long to sleep on accept failure
66 +
67 + isTemporaryErr := func(e error) bool {
68 + if ne, ok := e.(net.Error); ok && ne.Temporary() {
69 + if tempDelay == 0 {
70 + tempDelay = 5 * time.Millisecond
71 + } else {
72 + tempDelay *= 2
73 + }
74 + if max := 1 * time.Second; tempDelay > max {
75 + tempDelay = max
76 + }
77 +
78 + time.Sleep(tempDelay)
79 + return true
80 + }
81 + return false
82 + }
83 +
84 + // loop forever accepting connections
85 + for {
86 + conn, err := l.netList.Accept()
87 + if err != nil {
88 + l.acceptErr <- err
89 + if isTemporaryErr(err) {
90 + continue
91 + }
92 + return // ok, problems. bail.
93 + }
94 + tempDelay = 0
95 +
96 + // add conn to swarm and listen for incoming streams
97 + // log.Printf("accepted conn %s\n", conn.RemoteAddr())
98 + conn2, err := l.swarm.addConn(conn, true)
99 + if err != nil {
100 + l.acceptErr <- err
101 + continue
102 + }
103 + conn2.groups.AddSet(&l.groups) // add out groups
104 + }
105 +}
106 +
107 +// AcceptError returns the error that we **might** on listener close
108 +func (l *Listener) AcceptErrors() <-chan error {
109 + return l.acceptErr
110 +}
111 +
112 +func (l *Listener) teardown() {
113 + // in case we exit from network errors (accept fails) but
114 + // (a) client doesn't call Close, and (b) listener remains open)
115 + l.netList.Close()
116 +
117 + close(l.acceptErr)
118 +
119 + // remove self from swarm
120 + l.swarm.listenerLock.Lock()
121 + delete(l.swarm.listeners, l)
122 + l.swarm.listenerLock.Unlock()
123 +}
124 +
125 +func (l *Listener) Close() error {
126 + return l.netList.Close()
127 +}
128 +
129 +// addListener is the internal version of AddListener.
130 +func (s *Swarm) addListener(nl net.Listener) (*Listener, error) {
131 + if nl == nil {
132 + return nil, errors.New("nil listener")
133 + }
134 +
135 + s.listenerLock.Lock()
136 + defer s.listenerLock.Unlock()
137 +
138 + // first, check if we already have it...
139 + for l := range s.listeners {
140 + if l.netList == nl {
141 + return l, nil
142 + }
143 + }
144 +
145 + l := newListener(nl, s)
146 + s.listeners[l] = struct{}{}
147 + go l.accept()
148 + return l, nil
149 +}
Godeps/_workspace/src/github.com/jbenet/go-peerstream/stream.go new
+90
@@ -0,0 +1,90 @@
1 +package peerstream
2 +
3 +import (
4 + ss "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/docker/spdystream"
5 +)
6 +
7 +// StreamHandler is a function which receives a Stream. It
8 +// allows clients to set a function to receive newly created
9 +// streams, and decide whether to continue adding them.
10 +// It works sort of like a http.HandleFunc.
11 +// Note: the StreamHandler is called sequentially, so spawn
12 +// goroutines or pass the Stream. See EchoHandler.
13 +type StreamHandler func(s *Stream)
14 +
15 +// Stream is an io.{Read,Write,Close}r to a remote counterpart.
16 +// It wraps a spdystream.Stream, and links it to a Conn and groups
17 +type Stream struct {
18 + ssStream *ss.Stream
19 +
20 + conn *Conn
21 + groups groupSet
22 +}
23 +
24 +func newStream(ssS *ss.Stream, c *Conn) *Stream {
25 + s := &Stream{
26 + conn: c,
27 + ssStream: ssS,
28 + groups: groupSet{m: make(map[Group]struct{})},
29 + }
30 + s.groups.AddSet(&c.groups) // inherit groups
31 + return s
32 +}
33 +
34 +// SPDYStream returns the underlying *spdystream.Stream
35 +func (s *Stream) SPDYStream() *ss.Stream {
36 + return s.ssStream
37 +}
38 +
39 +// Conn returns the Conn associated with this Stream
40 +func (s *Stream) Conn() *Conn {
41 + return s.conn
42 +}
43 +
44 +// Swarm returns the Swarm asociated with this Stream
45 +func (s *Stream) Swarm() *Swarm {
46 + return s.conn.swarm
47 +}
48 +
49 +// Groups returns the Groups this Stream belongs to
50 +func (s *Stream) Groups() []Group {
51 + return s.groups.Groups()
52 +}
53 +
54 +// InGroup returns whether this stream belongs to a Group
55 +func (s *Stream) InGroup(g Group) bool {
56 + return s.groups.Has(g)
57 +}
58 +
59 +// AddGroup assigns given Group to Stream
60 +func (s *Stream) AddGroup(g Group) {
61 + s.groups.Add(g)
62 +}
63 +
64 +// Write writes bytes to a stream, calling write data for each call.
65 +func (s *Stream) Wait() error {
66 + return s.ssStream.Wait()
67 +}
68 +
69 +func (s *Stream) Read(p []byte) (n int, err error) {
70 + return s.ssStream.Read(p)
71 +}
72 +
73 +func (s *Stream) Write(p []byte) (n int, err error) {
74 + return s.ssStream.Write(p)
75 +}
76 +
77 +func (s *Stream) Close() error {
78 + return s.conn.swarm.removeStream(s)
79 +}
80 +
81 +// StreamsWithGroup narrows down a set of streams to those in given group.
82 +func StreamsWithGroup(g Group, streams []*Stream) []*Stream {
83 + var out []*Stream
84 + for _, s := range streams {
85 + if s.InGroup(g) {
86 + out = append(out, s)
87 + }
88 + }
89 + return out
90 +}
Godeps/_workspace/src/github.com/jbenet/go-peerstream/swarm.go new
+244
@@ -0,0 +1,244 @@
1 +package peerstream
2 +
3 +import (
4 + "errors"
5 + "net"
6 + "sync"
7 +)
8 +
9 +// fd is a (file) descriptor, unix style
10 +type fd uint32
11 +
12 +type Swarm struct {
13 + // active streams.
14 + streams map[*Stream]struct{}
15 + streamLock sync.RWMutex
16 +
17 + // active connections. generate new Streams
18 + conns map[*Conn]struct{}
19 + connLock sync.RWMutex
20 +
21 + // active listeners. generate new Listeners
22 + listeners map[*Listener]struct{}
23 + listenerLock sync.RWMutex
24 +
25 + // these handlers should be accessed with their getter/setter
26 + // as this pointer may be changed at any time.
27 + handlerLock sync.RWMutex // protects the functions below
28 + connHandler ConnHandler // receives Conns intiated remotely
29 + streamHandler StreamHandler // receives Streams initiated remotely
30 + selectConn SelectConn // default SelectConn function
31 +}
32 +
33 +func NewSwarm() *Swarm {
34 + return &Swarm{
35 + streams: make(map[*Stream]struct{}),
36 + conns: make(map[*Conn]struct{}),
37 + listeners: make(map[*Listener]struct{}),
38 + selectConn: SelectRandomConn,
39 + streamHandler: NoOpStreamHandler,
40 + connHandler: NoOpConnHandler,
41 + }
42 +}
43 +
44 +// SetStreamHandler assigns the stream handler in the swarm.
45 +// The handler assumes responsibility for closing the stream.
46 +// This need not happen at the end of the handler, leaving the
47 +// stream open (to be used and closed later) is fine.
48 +// It is also fine to keep a pointer to the Stream.
49 +// This is a threadsafe (atomic) operation
50 +func (s *Swarm) SetStreamHandler(sh StreamHandler) {
51 + s.handlerLock.Lock()
52 + defer s.handlerLock.Unlock()
53 + s.streamHandler = sh
54 +}
55 +
56 +// StreamHandler returns the Swarm's current StreamHandler.
57 +// This is a threadsafe (atomic) operation
58 +func (s *Swarm) StreamHandler() StreamHandler {
59 + s.handlerLock.RLock()
60 + defer s.handlerLock.RUnlock()
61 + if s.streamHandler == nil {
62 + return NoOpStreamHandler
63 + }
64 + return s.streamHandler
65 +}
66 +
67 +// SetConnHandler assigns the conn handler in the swarm.
68 +// Unlike the StreamHandler, the ConnHandler has less respon-
69 +// ibility for the Connection. The Swarm is still its client.
70 +// This handler is only a notification.
71 +// This is a threadsafe (atomic) operation
72 +func (s *Swarm) SetConnHandler(ch ConnHandler) {
73 + s.handlerLock.Lock()
74 + defer s.handlerLock.Unlock()
75 + s.connHandler = ch
76 +}
77 +
78 +// ConnHandler returns the Swarm's current ConnHandler.
79 +// This is a threadsafe (atomic) operation
80 +func (s *Swarm) ConnHandler() ConnHandler {
81 + s.handlerLock.RLock()
82 + defer s.handlerLock.RUnlock()
83 + if s.connHandler == nil {
84 + return NoOpConnHandler
85 + }
86 + return s.connHandler
87 +}
88 +
89 +// SetConnSelect assigns the connection selector in the swarm.
90 +// If cs is nil, will use SelectRandomConn
91 +// This is a threadsafe (atomic) operation
92 +func (s *Swarm) SetSelectConn(cs SelectConn) {
93 + s.handlerLock.Lock()
94 + defer s.handlerLock.Unlock()
95 + s.selectConn = cs
96 +}
97 +
98 +// ConnSelect returns the Swarm's current connection selector.
99 +// ConnSelect is used in order to select the best of a set of
100 +// possible connections. The default chooses one at random.
101 +// This is a threadsafe (atomic) operation
102 +func (s *Swarm) SelectConn() SelectConn {
103 + s.handlerLock.RLock()
104 + defer s.handlerLock.RUnlock()
105 + if s.selectConn == nil {
106 + return SelectRandomConn
107 + }
108 + return s.selectConn
109 +}
110 +
111 +// Conns returns all the connections associated with this Swarm.
112 +func (s *Swarm) Conns() []*Conn {
113 + conns := make([]*Conn, 0, len(s.conns))
114 + for c := range s.conns {
115 + conns = append(conns, c)
116 + }
117 + return conns
118 +}
119 +
120 +// Listeners returns all the listeners associated with this Swarm.
121 +func (s *Swarm) Listeners() []*Listener {
122 + out := make([]*Listener, 0, len(s.listeners))
123 + for c := range s.listeners {
124 + out = append(out, c)
125 + }
126 + return out
127 +}
128 +
129 +// Streams returns all the streams associated with this Swarm.
130 +func (s *Swarm) Streams() []*Stream {
131 + out := make([]*Stream, 0, len(s.streams))
132 + for c := range s.streams {
133 + out = append(out, c)
134 + }
135 + return out
136 +}
137 +
138 +// AddListener adds net.Listener to the Swarm, and immediately begins
139 +// accepting incoming connections.
140 +func (s *Swarm) AddListener(l net.Listener) (*Listener, error) {
141 + return s.addListener(l)
142 +}
143 +
144 +// AddListenerWithRateLimit adds Listener to the Swarm, and immediately
145 +// begins accepting incoming connections. The rate of connection acceptance
146 +// depends on the RateLimit option
147 +// func (s *Swarm) AddListenerWithRateLimit(net.Listner, RateLimit) // TODO
148 +
149 +// AddConn gives the Swarm ownership of net.Conn. The Swarm will open a
150 +// SPDY session and begin listening for Streams.
151 +// Returns the resulting Swarm-associated peerstream.Conn.
152 +// Idempotent: if the Connection has already been added, this is a no-op.
153 +func (s *Swarm) AddConn(netConn net.Conn) (*Conn, error) {
154 + return s.addConn(netConn, false)
155 +}
156 +
157 +// NewStream opens a new Stream on the best available connection,
158 +// as selected by current swarm.SelectConn.
159 +func (s *Swarm) NewStream() (*Stream, error) {
160 + return s.NewStreamSelectConn(s.SelectConn())
161 +}
162 +
163 +func (s *Swarm) newStreamSelectConn(selConn SelectConn, conns []*Conn) (*Stream, error) {
164 + if selConn == nil {
165 + return nil, errors.New("nil SelectConn")
166 + }
167 +
168 + best := selConn(conns)
169 + if best == nil || !ConnInConns(best, conns) {
170 + return nil, ErrInvalidConnSelected
171 + }
172 + return s.NewStreamWithConn(best)
173 +}
174 +
175 +// NewStreamWithSelectConn opens a new Stream on a connection selected
176 +// by selConn.
177 +func (s *Swarm) NewStreamSelectConn(selConn SelectConn) (*Stream, error) {
178 + if selConn == nil {
179 + return nil, errors.New("nil SelectConn")
180 + }
181 +
182 + conns := s.Conns()
183 + if len(conns) == 0 {
184 + return nil, ErrNoConnections
185 + }
186 + return s.newStreamSelectConn(selConn, conns)
187 +}
188 +
189 +// NewStreamWithGroup opens a new Stream on an available connection in
190 +// the given group. Uses the current swarm.SelectConn to pick between
191 +// multiple connections.
192 +func (s *Swarm) NewStreamWithGroup(group Group) (*Stream, error) {
193 + conns := s.ConnsWithGroup(group)
194 + return s.newStreamSelectConn(s.SelectConn(), conns)
195 +}
196 +
197 +// NewStreamWithNetConn opens a new Stream on given net.Conn.
198 +// Calls s.AddConn(netConn).
199 +func (s *Swarm) NewStreamWithNetConn(netConn net.Conn) (*Stream, error) {
200 + c, err := s.AddConn(netConn)
201 + if err != nil {
202 + return nil, err
203 + }
204 + return s.NewStreamWithConn(c)
205 +}
206 +
207 +// NewStreamWithConnection opens a new Stream on given connection.
208 +func (s *Swarm) NewStreamWithConn(conn *Conn) (*Stream, error) {
209 + if conn == nil {
210 + return nil, errors.New("nil Conn")
211 + }
212 + if conn.Swarm() != s {
213 + return nil, errors.New("connection not associated with swarm")
214 + }
215 +
216 + s.connLock.RLock()
217 + if _, found := s.conns[conn]; !found {
218 + s.connLock.RUnlock()
219 + return nil, errors.New("connection not associated with swarm")
220 + }
221 + s.connLock.RUnlock()
222 + return s.createStream(conn)
223 +}
224 +
225 +// AddConnToGroup assigns given Group to conn
226 +func (s *Swarm) AddConnToGroup(conn *Conn, g Group) {
227 + conn.groups.Add(g)
228 +}
229 +
230 +// ConnsWithGroup returns all the connections with a given Group
231 +func (s *Swarm) ConnsWithGroup(g Group) []*Conn {
232 + return ConnsWithGroup(g, s.Conns())
233 +}
234 +
235 +// StreamsWithGroup returns all the streams with a given Group
236 +func (s *Swarm) StreamsWithGroup(g Group) []*Stream {
237 + return StreamsWithGroup(g, s.Streams())
238 +}
239 +
240 +// Close shuts down the Swarm, and it's listeners.
241 +func (s *Swarm) Close() error {
242 + // shut down TODO
243 + return nil
244 +}