mongrel2 0.24.0 → 0.25.0.pre.285
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/ChangeLog +53 -1
- data/History.rdoc +14 -0
- data/examples/Procfile +1 -1
- data/examples/async-upload.rb +4 -1
- data/examples/config.rb +4 -3
- data/examples/request-dumper.rb +1 -0
- data/examples/request-dumper.tmpl +6 -5
- data/examples/ws-echo.rb +3 -3
- data/lib/mongrel2.rb +2 -2
- data/lib/mongrel2/connection.rb +4 -2
- data/lib/mongrel2/constants.rb +7 -0
- data/lib/mongrel2/httprequest.rb +0 -42
- data/lib/mongrel2/httpresponse.rb +20 -22
- data/lib/mongrel2/request.rb +97 -3
- data/lib/mongrel2/response.rb +34 -6
- data/lib/mongrel2/testing.rb +2 -4
- data/lib/mongrel2/websocket.rb +104 -45
- data/spec/mongrel2/httprequest_spec.rb +0 -40
- data/spec/mongrel2/httpresponse_spec.rb +6 -12
- data/spec/mongrel2/request_spec.rb +112 -3
- data/spec/mongrel2/response_spec.rb +22 -7
- data/spec/mongrel2/websocket_spec.rb +32 -13
- metadata +2 -2
- metadata.gz.sig +0 -0
@@ -12,6 +12,8 @@ BEGIN {
|
|
12
12
|
|
13
13
|
require 'rspec'
|
14
14
|
require 'tnetstring'
|
15
|
+
require 'tmpdir'
|
16
|
+
require 'tempfile'
|
15
17
|
|
16
18
|
require 'spec/lib/helpers'
|
17
19
|
|
@@ -27,6 +29,7 @@ describe Mongrel2::Request do
|
|
27
29
|
|
28
30
|
before( :all ) do
|
29
31
|
setup_logging( :fatal )
|
32
|
+
@factory = Mongrel2::RequestFactory.new( route: '/form' )
|
30
33
|
end
|
31
34
|
|
32
35
|
after( :all ) do
|
@@ -79,9 +82,7 @@ describe Mongrel2::Request do
|
|
79
82
|
"don't look like HTTP ones" do
|
80
83
|
|
81
84
|
message = make_request( :headers => {'METHOD' => '!DIVULGE'} )
|
82
|
-
expect {
|
83
|
-
Mongrel2::Request.parse( message )
|
84
|
-
}.to raise_error( Mongrel2::UnhandledMethodError, /!DIVULGE/ )
|
85
|
+
expect { Mongrel2::Request.parse(message) }.to raise_error( Mongrel2::UnhandledMethodError, /!DIVULGE/ )
|
85
86
|
end
|
86
87
|
|
87
88
|
it "knows what kind of response it should return" do
|
@@ -110,6 +111,31 @@ describe Mongrel2::Request do
|
|
110
111
|
end
|
111
112
|
|
112
113
|
|
114
|
+
describe "content-type charset support" do
|
115
|
+
|
116
|
+
it "uses the charset in the content-type header, if present" do
|
117
|
+
body = "some data".encode( 'binary' )
|
118
|
+
req = @factory.post( '/form', body, content_type: 'text/plain; charset=iso-8859-1' )
|
119
|
+
|
120
|
+
req.body.string.encoding.should be( Encoding::ISO_8859_1 )
|
121
|
+
end
|
122
|
+
|
123
|
+
it "keeps the data as ascii-8bit if no charset is in the content-type header" do
|
124
|
+
body = "some data".encode( 'binary' )
|
125
|
+
req = @factory.post( '/form', body, content_type: 'application/octet-stream' )
|
126
|
+
|
127
|
+
req.body.string.encoding.should be( Encoding::ASCII_8BIT )
|
128
|
+
end
|
129
|
+
|
130
|
+
it "keeps the data as ascii-8bit if there is no content-type header" do
|
131
|
+
body = "some data".encode( 'binary' )
|
132
|
+
req = @factory.post( '/form', body )
|
133
|
+
|
134
|
+
req.body.string.encoding.should be( Encoding::ASCII_8BIT )
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
113
139
|
describe "framework support" do
|
114
140
|
|
115
141
|
before( :all ) do
|
@@ -161,5 +187,88 @@ describe Mongrel2::Request do
|
|
161
187
|
|
162
188
|
end
|
163
189
|
|
190
|
+
|
191
|
+
describe "async upload support" do
|
192
|
+
|
193
|
+
before( :all ) do
|
194
|
+
setup_config_db()
|
195
|
+
Mongrel2::Config::Server.create(
|
196
|
+
uuid: Mongrel2::RequestFactory::DEFAULT_TEST_UUID,
|
197
|
+
access_log: 'access.log',
|
198
|
+
error_log: 'error.log',
|
199
|
+
pid_file: '/var/run/mongrel2.pid',
|
200
|
+
default_host: 'localhost',
|
201
|
+
port: 663,
|
202
|
+
chroot: Dir.tmpdir
|
203
|
+
)
|
204
|
+
end
|
205
|
+
|
206
|
+
before( :each ) do
|
207
|
+
@spoolfile = Tempfile.new( 'mongrel2.upload', Dir.tmpdir )
|
208
|
+
@spoolfile.print( File.read(__FILE__) )
|
209
|
+
@spoolpath = @spoolfile.path.slice( Dir.tmpdir.length + 1..-1 )
|
210
|
+
end
|
211
|
+
|
212
|
+
it "knows if it's an 'async upload started' notification" do
|
213
|
+
req = @factory.post( '/form', '', x_mongrel2_upload_start: @spoolpath )
|
214
|
+
|
215
|
+
req.should be_upload_started()
|
216
|
+
req.should_not be_upload_done()
|
217
|
+
end
|
218
|
+
|
219
|
+
it "knows if it's an 'async upload done' notification" do
|
220
|
+
req = @factory.post( '/form', '',
|
221
|
+
x_mongrel2_upload_start: @spoolpath,
|
222
|
+
x_mongrel2_upload_done: @spoolpath )
|
223
|
+
|
224
|
+
req.should_not be_upload_started()
|
225
|
+
req.should be_upload_done()
|
226
|
+
req.should be_valid_upload()
|
227
|
+
end
|
228
|
+
|
229
|
+
it "knows if it's not a valid 'async upload done' notification" do
|
230
|
+
req = @factory.post( '/form', '',
|
231
|
+
x_mongrel2_upload_start: @spoolpath,
|
232
|
+
x_mongrel2_upload_done: '/etc/passwd' )
|
233
|
+
|
234
|
+
req.should_not be_upload_started()
|
235
|
+
req.should be_upload_done()
|
236
|
+
req.should_not be_valid_upload()
|
237
|
+
end
|
238
|
+
|
239
|
+
it "raises an exception if the uploaded file fetched with mismatched headers" do
|
240
|
+
req = @factory.post( '/form', '',
|
241
|
+
x_mongrel2_upload_start: @spoolpath,
|
242
|
+
x_mongrel2_upload_done: '/etc/passwd' )
|
243
|
+
|
244
|
+
expect {
|
245
|
+
req.uploaded_file
|
246
|
+
}.to raise_error( Mongrel2::UploadError, /upload headers/i )
|
247
|
+
end
|
248
|
+
|
249
|
+
it "can return a Pathname object for the uploaded file if it's valid" do
|
250
|
+
req = @factory.post( '/form', '',
|
251
|
+
x_mongrel2_upload_start: @spoolpath,
|
252
|
+
x_mongrel2_upload_done: @spoolpath )
|
253
|
+
|
254
|
+
req.should be_valid_upload()
|
255
|
+
|
256
|
+
req.uploaded_file.should be_a( Pathname )
|
257
|
+
req.uploaded_file.to_s.should == @spoolfile.path
|
258
|
+
end
|
259
|
+
|
260
|
+
it "sets the body of the request to the uploaded File if it's valid" do
|
261
|
+
req = @factory.post( '/form', '',
|
262
|
+
x_mongrel2_upload_start: @spoolpath,
|
263
|
+
x_mongrel2_upload_done: @spoolpath )
|
264
|
+
|
265
|
+
req.should be_valid_upload()
|
266
|
+
|
267
|
+
req.body.should be_a( File )
|
268
|
+
req.body.path.should == @spoolfile.path
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
|
164
273
|
end
|
165
274
|
|
@@ -48,7 +48,7 @@ describe Mongrel2::Response do
|
|
48
48
|
|
49
49
|
it "can be created with a body" do
|
50
50
|
response = Mongrel2::Response.new( TEST_UUID, 8, 'the body' )
|
51
|
-
response.body.should == 'the body'
|
51
|
+
response.body.read.should == 'the body'
|
52
52
|
end
|
53
53
|
|
54
54
|
it "stringifies to its body contents" do
|
@@ -56,24 +56,39 @@ describe Mongrel2::Response do
|
|
56
56
|
response.to_s.should == 'the body'
|
57
57
|
end
|
58
58
|
|
59
|
+
it "can be streamed in chunks" do
|
60
|
+
response = Mongrel2::Response.new( TEST_UUID, 8, 'the body' )
|
61
|
+
expect {|b| response.each_chunk(&b) }.to yield_with_args( 'the body' )
|
62
|
+
end
|
63
|
+
|
64
|
+
it "wraps non-IO bodies set via the #body= accessor in a StringIO" do
|
65
|
+
response = Mongrel2::Response.new( TEST_UUID, 8 )
|
66
|
+
response.body = 'a stringioed body'
|
67
|
+
response.body.should be_a( StringIO )
|
68
|
+
response.body.string.should == 'a stringioed body'
|
69
|
+
end
|
70
|
+
|
59
71
|
context "an instance with default values" do
|
60
72
|
|
61
73
|
before( :each ) do
|
62
74
|
@response = Mongrel2::Response.new( TEST_UUID, 8 )
|
63
75
|
end
|
64
76
|
|
65
|
-
it "has an empty-
|
66
|
-
@response.body.
|
77
|
+
it "has an empty-IO body" do
|
78
|
+
@response.body.rewind
|
79
|
+
@response.body.read.should == ''
|
67
80
|
end
|
68
81
|
|
69
|
-
it "supports the append operator to append objects to the body" do
|
82
|
+
it "supports the append operator to append objects to the body IO" do
|
70
83
|
@response << 'some body stuff' << ' and some more body stuff'
|
71
|
-
@response.body.
|
84
|
+
@response.body.rewind
|
85
|
+
@response.body.read.should == 'some body stuff and some more body stuff'
|
72
86
|
end
|
73
87
|
|
74
|
-
it "supports #puts for appending objects separated by EOL" do
|
88
|
+
it "supports #puts for appending objects to the body IO separated by EOL" do
|
75
89
|
@response.puts( "some body stuff\n", " and some more body stuff\n\n", :and_a_symbol )
|
76
|
-
@response.body.
|
90
|
+
@response.body.rewind
|
91
|
+
@response.body.read.should == "some body stuff\n and some more body stuff\n\nand_a_symbol\n"
|
77
92
|
end
|
78
93
|
|
79
94
|
end
|
@@ -144,7 +144,8 @@ describe Mongrel2::WebSocket do
|
|
144
144
|
result.conn_id.should == frame.conn_id
|
145
145
|
result.opcode.should == :text
|
146
146
|
|
147
|
-
result.payload.
|
147
|
+
result.payload.rewind
|
148
|
+
result.payload.read.should == ''
|
148
149
|
end
|
149
150
|
|
150
151
|
it "creates PONG responses with the same payload for PING frames" do
|
@@ -157,7 +158,8 @@ describe Mongrel2::WebSocket do
|
|
157
158
|
result.conn_id.should == frame.conn_id
|
158
159
|
result.opcode.should == :pong
|
159
160
|
|
160
|
-
result.payload.
|
161
|
+
result.payload.rewind
|
162
|
+
result.payload.read.should == 'WOO'
|
161
163
|
end
|
162
164
|
|
163
165
|
it "allows header flags and/or opcode to be specified when creating a response" do
|
@@ -171,7 +173,19 @@ describe Mongrel2::WebSocket do
|
|
171
173
|
result.opcode.should == :close
|
172
174
|
result.should be_fin()
|
173
175
|
|
174
|
-
result.payload.
|
176
|
+
result.payload.rewind
|
177
|
+
result.payload.read.should == ''
|
178
|
+
end
|
179
|
+
|
180
|
+
it "can be streamed in chunks instead of read all at once" do
|
181
|
+
data = BINARY_DATA * 256
|
182
|
+
binary = @factory.binary( '/websock', data, :fin )
|
183
|
+
|
184
|
+
binary.chunksize = 16
|
185
|
+
binary.each_chunk.to_a[0,2].should == [
|
186
|
+
"\x82\x7F\x00\x00\x00\x00\x00\x01\x00\x00\a\xBD\xB3\xFE\x87\xEB".force_encoding('binary'),
|
187
|
+
"\xA9\x0En2q\xCE\x85\xAF)\x88w_d\xD6M\x9E".force_encoding('binary'),
|
188
|
+
]
|
175
189
|
end
|
176
190
|
|
177
191
|
end
|
@@ -180,14 +194,15 @@ describe Mongrel2::WebSocket do
|
|
180
194
|
describe "a WebSocket text frame" do
|
181
195
|
|
182
196
|
before( :each ) do
|
183
|
-
@frame = @factory.text( '/websock', '
|
197
|
+
@frame = @factory.text( '/websock', '', :fin )
|
184
198
|
end
|
185
199
|
|
186
200
|
it "automatically transcodes its payload to UTF8" do
|
187
201
|
text = "Стрелке!".encode( Encoding::KOI8_U )
|
188
|
-
@frame
|
202
|
+
@frame << text
|
189
203
|
|
190
|
-
|
204
|
+
# 2-byte header
|
205
|
+
@frame.bytes.to_a[ 2..-1 ].should ==
|
191
206
|
[0xD0, 0xA1, 0xD1, 0x82, 0xD1, 0x80, 0xD0, 0xB5, 0xD0, 0xBB, 0xD0,
|
192
207
|
0xBA, 0xD0, 0xB5, 0x21]
|
193
208
|
end
|
@@ -201,7 +216,10 @@ describe Mongrel2::WebSocket do
|
|
201
216
|
end
|
202
217
|
|
203
218
|
it "doesn't try to transcode non-UTF8 data" do
|
204
|
-
|
219
|
+
# 4-byte header
|
220
|
+
@frame.bytes.to_a[ 4, 16 ].should ==
|
221
|
+
[ 0x07, 0xbd, 0xb3, 0xfe, 0x87, 0xeb, 0xa9, 0x0e, 0x6e, 0x32, 0x71,
|
222
|
+
0xce, 0x85, 0xaf, 0x29, 0x88 ]
|
205
223
|
end
|
206
224
|
end
|
207
225
|
|
@@ -213,7 +231,8 @@ describe Mongrel2::WebSocket do
|
|
213
231
|
|
214
232
|
it "has convenience methods for setting its payload via integer status code" do
|
215
233
|
@frame.set_status( CLOSE_BAD_DATA )
|
216
|
-
@frame.
|
234
|
+
@frame.payload.rewind
|
235
|
+
@frame.payload.read.should == "%d %s\n" %
|
217
236
|
[ CLOSE_BAD_DATA, CLOSING_STATUS_DESC[CLOSE_BAD_DATA] ]
|
218
237
|
end
|
219
238
|
|
@@ -227,16 +246,16 @@ describe Mongrel2::WebSocket do
|
|
227
246
|
|
228
247
|
|
229
248
|
it "raises an exception if its payload is bigger than 125 bytes" do
|
230
|
-
@frame.body
|
249
|
+
@frame.body << "x" * 126
|
231
250
|
expect {
|
232
|
-
@frame.
|
251
|
+
@frame.validate
|
233
252
|
}.to raise_error( Mongrel2::WebSocket::FrameError, /cannot exceed 125 bytes/i )
|
234
253
|
end
|
235
254
|
|
236
255
|
it "raises an exception if it's fragmented" do
|
237
256
|
@frame.fin = false
|
238
257
|
expect {
|
239
|
-
@frame.
|
258
|
+
@frame.validate
|
240
259
|
}.to raise_error( Mongrel2::WebSocket::FrameError, /fragmented/i )
|
241
260
|
end
|
242
261
|
|
@@ -274,7 +293,7 @@ describe Mongrel2::WebSocket do
|
|
274
293
|
binary = @factory.binary( '/websock', BINARY_DATA, :fin )
|
275
294
|
|
276
295
|
# 1 + 1 + 2
|
277
|
-
binary.
|
296
|
+
binary.bytes.to_a[0,4].should == [ 0x82, 0x7E, 0x01, 0x00 ]
|
278
297
|
binary.to_s[4..-1].should == BINARY_DATA
|
279
298
|
end
|
280
299
|
|
@@ -284,7 +303,7 @@ describe Mongrel2::WebSocket do
|
|
284
303
|
binary = @factory.binary( '/websock', data, :fin )
|
285
304
|
|
286
305
|
# 1 + 1 + 8
|
287
|
-
binary.
|
306
|
+
binary.bytes.to_a[0,10].should ==
|
288
307
|
[ 0x82, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 ]
|
289
308
|
binary.to_s[10..-1].should == data
|
290
309
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongrel2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.25.0.pre.285
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -36,7 +36,7 @@ cert_chain:
|
|
36
36
|
YUhDS0xaZFNLai9SSHVUT3QrZ2JsUmV4OEZBaDhOZUEKY21saFhlNDZwWk5K
|
37
37
|
Z1dLYnhaYWg4NWpJang5NWhSOHZPSStOQU01aUg5a09xSzEzRHJ4YWNUS1Bo
|
38
38
|
cWo1UGp3RgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
39
|
-
date: 2012-
|
39
|
+
date: 2012-06-20 00:00:00.000000000 Z
|
40
40
|
dependencies:
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: nokogiri
|
metadata.gz.sig
CHANGED
Binary file
|