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
+}