mongrel2 0.24.0 → 0.25.0.pre.285
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|