mongrel2 0.38.0 → 0.39.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/History.rdoc +6 -0
- data/Manifest.txt +5 -3
- data/Rakefile +2 -2
- data/data/mongrel2/config.sql +6 -1
- data/lib/mongrel2.rb +5 -2
- data/lib/mongrel2/config.rb +1 -0
- data/lib/mongrel2/config/server.rb +15 -0
- data/lib/mongrel2/config/xrequest.rb +45 -0
- data/lib/mongrel2/connection.rb +4 -5
- data/lib/mongrel2/control.rb +2 -2
- data/lib/mongrel2/handler.rb +1 -1
- data/spec/{lib/constants.rb → constants.rb} +0 -2
- data/spec/{lib/helpers.rb → helpers.rb} +9 -12
- data/spec/{lib/matchers.rb → matchers.rb} +2 -12
- data/spec/mongrel2/config/directory_spec.rb +16 -27
- data/spec/mongrel2/config/dsl_spec.rb +115 -98
- data/spec/mongrel2/config/filter_spec.rb +1 -12
- data/spec/mongrel2/config/handler_spec.rb +23 -33
- data/spec/mongrel2/config/host_spec.rb +1 -12
- data/spec/mongrel2/config/log_spec.rb +13 -24
- data/spec/mongrel2/config/proxy_spec.rb +1 -12
- data/spec/mongrel2/config/route_spec.rb +5 -15
- data/spec/mongrel2/config/server_spec.rb +23 -34
- data/spec/mongrel2/config/setting_spec.rb +1 -12
- data/spec/mongrel2/config/statistic_spec.rb +1 -12
- data/spec/mongrel2/config/xrequest_spec.rb +19 -0
- data/spec/mongrel2/config_spec.rb +17 -29
- data/spec/mongrel2/connection_spec.rb +41 -53
- data/spec/mongrel2/constants_spec.rb +2 -14
- data/spec/mongrel2/control_spec.rb +44 -56
- data/spec/mongrel2/handler_spec.rb +64 -76
- data/spec/mongrel2/httprequest_spec.rb +21 -31
- data/spec/mongrel2/httpresponse_spec.rb +55 -67
- data/spec/mongrel2/request_spec.rb +53 -62
- data/spec/mongrel2/response_spec.rb +15 -24
- data/spec/mongrel2/table_spec.rb +41 -53
- data/spec/mongrel2/websocket_spec.rb +95 -104
- data/spec/mongrel2_spec.rb +3 -12
- metadata +13 -11
- metadata.gz.sig +0 -0
@@ -1,18 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
require 'pathname'
|
5
|
-
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
6
|
-
|
7
|
-
libdir = basedir + "lib"
|
8
|
-
|
9
|
-
$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
|
10
|
-
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
11
|
-
}
|
12
|
-
|
13
|
-
require 'rspec'
|
14
|
-
|
15
|
-
require 'spec/lib/helpers'
|
3
|
+
require_relative '../helpers'
|
16
4
|
|
17
5
|
require 'mongrel2'
|
18
6
|
require 'mongrel2/config'
|
@@ -47,7 +35,7 @@ describe Mongrel2::Handler do
|
|
47
35
|
|
48
36
|
|
49
37
|
before( :all ) do
|
50
|
-
setup_logging(
|
38
|
+
setup_logging()
|
51
39
|
setup_config_db()
|
52
40
|
end
|
53
41
|
|
@@ -59,13 +47,13 @@ describe Mongrel2::Handler do
|
|
59
47
|
# Ensure 0MQ never actually gets called
|
60
48
|
before( :each ) do
|
61
49
|
@ctx = double( '0mq context', close: nil )
|
62
|
-
@request_sock = double( "request socket",
|
63
|
-
@response_sock = double( "response socket",
|
50
|
+
@request_sock = double( "request socket", :linger= => nil, :connect => nil, :close => nil )
|
51
|
+
@response_sock = double( "response socket", :linger= => nil, :connect => nil, :close => nil )
|
64
52
|
|
65
|
-
@ctx.
|
66
|
-
@ctx.
|
53
|
+
allow( @ctx ).to receive( :socket ).with( :PULL ).and_return( @request_sock )
|
54
|
+
allow( @ctx ).to receive( :socket ).with( :PUB ).and_return( @response_sock )
|
67
55
|
|
68
|
-
ZMQ.
|
56
|
+
allow( ZMQ ).to receive( :select ).and_return([ [@request_sock], [], [] ])
|
69
57
|
|
70
58
|
Mongrel2.instance_variable_set( :@zmq_ctx, @ctx )
|
71
59
|
end
|
@@ -98,25 +86,25 @@ describe Mongrel2::Handler do
|
|
98
86
|
"application ID" do
|
99
87
|
|
100
88
|
req = make_request()
|
101
|
-
@request_sock.
|
89
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
102
90
|
|
103
91
|
res = OneShotHandler.run( TEST_UUID )
|
104
92
|
|
105
93
|
# It should have pulled its connection info from the Handler entry in the database
|
106
|
-
res.conn.app_id.
|
107
|
-
res.conn.sub_addr.
|
108
|
-
res.conn.pub_addr.
|
94
|
+
expect( res.conn.app_id ).to eq( TEST_UUID )
|
95
|
+
expect( res.conn.sub_addr ).to eq( TEST_SEND_SPEC )
|
96
|
+
expect( res.conn.pub_addr ).to eq( TEST_RECV_SPEC )
|
109
97
|
end
|
110
98
|
|
111
99
|
it "knows what handler config corresponds to its" do
|
112
100
|
req = make_request()
|
113
|
-
@request_sock.
|
101
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
114
102
|
|
115
103
|
res = OneShotHandler.run( TEST_UUID )
|
116
104
|
|
117
|
-
res.handler_config.
|
118
|
-
res.handler_config.send_spec.
|
119
|
-
res.handler_config.recv_spec.
|
105
|
+
expect( res.handler_config ).to be_a( Mongrel2::Config::Handler )
|
106
|
+
expect( res.handler_config.send_spec ).to eq( TEST_SEND_SPEC )
|
107
|
+
expect( res.handler_config.recv_spec ).to eq( TEST_RECV_SPEC )
|
120
108
|
end
|
121
109
|
|
122
110
|
end
|
@@ -132,7 +120,7 @@ describe Mongrel2::Handler do
|
|
132
120
|
Mongrel2::Config::Handler.dataset.truncate
|
133
121
|
expect {
|
134
122
|
Mongrel2::Handler.connection_info_for( TEST_UUID )
|
135
|
-
}.
|
123
|
+
}.to raise_error()
|
136
124
|
end
|
137
125
|
|
138
126
|
end
|
@@ -140,27 +128,27 @@ describe Mongrel2::Handler do
|
|
140
128
|
|
141
129
|
it "dispatches HTTP requests to the #handle method" do
|
142
130
|
req = make_request()
|
143
|
-
@request_sock.
|
131
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
144
132
|
|
145
133
|
res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
|
146
134
|
|
147
|
-
res.transactions.
|
135
|
+
expect( res.transactions ).to have( 1 ).member
|
148
136
|
request, response = res.transactions.first
|
149
|
-
request.
|
150
|
-
response.
|
151
|
-
response.status.
|
137
|
+
expect( request ).to be_a( Mongrel2::HTTPRequest )
|
138
|
+
expect( response ).to be_a( Mongrel2::HTTPResponse )
|
139
|
+
expect( response.status ).to eq( 204 )
|
152
140
|
end
|
153
141
|
|
154
142
|
it "ignores JSON messages by default" do
|
155
143
|
req = make_json_request()
|
156
|
-
@request_sock.
|
144
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
157
145
|
|
158
146
|
res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
|
159
147
|
|
160
|
-
res.transactions.
|
148
|
+
expect( res.transactions ).to have( 1 ).member
|
161
149
|
request, response = res.transactions.first
|
162
|
-
request.
|
163
|
-
response.
|
150
|
+
expect( request ).to be_a( Mongrel2::JSONRequest )
|
151
|
+
expect( response ).to be_nil()
|
164
152
|
end
|
165
153
|
|
166
154
|
it "dispatches JSON message to the #handle_json method" do
|
@@ -171,26 +159,26 @@ describe Mongrel2::Handler do
|
|
171
159
|
end
|
172
160
|
|
173
161
|
req = make_json_request()
|
174
|
-
@request_sock.
|
162
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
175
163
|
|
176
164
|
res = json_handler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
|
177
165
|
|
178
|
-
res.transactions.
|
166
|
+
expect( res.transactions ).to have( 1 ).member
|
179
167
|
request, response = res.transactions.first
|
180
|
-
request.
|
181
|
-
response.
|
168
|
+
expect( request ).to be_a( Mongrel2::JSONRequest )
|
169
|
+
expect( response ).to be_a( Mongrel2::Response )
|
182
170
|
end
|
183
171
|
|
184
172
|
it "ignores XML messages by default" do
|
185
173
|
req = make_xml_request()
|
186
|
-
@request_sock.
|
174
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
187
175
|
|
188
176
|
res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
|
189
177
|
|
190
|
-
res.transactions.
|
178
|
+
expect( res.transactions ).to have( 1 ).member
|
191
179
|
request, response = res.transactions.first
|
192
|
-
request.
|
193
|
-
response.
|
180
|
+
expect( request ).to be_a( Mongrel2::XMLRequest )
|
181
|
+
expect( response ).to be_nil()
|
194
182
|
end
|
195
183
|
|
196
184
|
it "dispatches XML message to the #handle_xml method" do
|
@@ -201,14 +189,14 @@ describe Mongrel2::Handler do
|
|
201
189
|
end
|
202
190
|
|
203
191
|
req = make_xml_request()
|
204
|
-
@request_sock.
|
192
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
205
193
|
|
206
194
|
res = xml_handler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
|
207
195
|
|
208
|
-
res.transactions.
|
196
|
+
expect( res.transactions ).to have( 1 ).member
|
209
197
|
request, response = res.transactions.first
|
210
|
-
request.
|
211
|
-
response.
|
198
|
+
expect( request ).to be_a( Mongrel2::XMLRequest )
|
199
|
+
expect( response ).to be_a( Mongrel2::Response )
|
212
200
|
end
|
213
201
|
|
214
202
|
it "dispatches WebSocket opening handshakes to the #handle_websocket_handshake method" do
|
@@ -219,14 +207,14 @@ describe Mongrel2::Handler do
|
|
219
207
|
end
|
220
208
|
|
221
209
|
req = make_websocket_handshake()
|
222
|
-
@request_sock.
|
210
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
223
211
|
|
224
212
|
res = ws_handler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
|
225
213
|
|
226
|
-
res.transactions.
|
214
|
+
expect( res.transactions ).to have( 1 ).member
|
227
215
|
request, response = res.transactions.first
|
228
|
-
request.
|
229
|
-
response.
|
216
|
+
expect( request ).to be_a( Mongrel2::WebSocket::ClientHandshake )
|
217
|
+
expect( response ).to be_a( Mongrel2::WebSocket::ServerHandshake )
|
230
218
|
end
|
231
219
|
|
232
220
|
it "dispatches WebSocket protocol frames to the #handle_websocket method" do
|
@@ -237,41 +225,41 @@ describe Mongrel2::Handler do
|
|
237
225
|
end
|
238
226
|
|
239
227
|
req = make_websocket_frame()
|
240
|
-
@request_sock.
|
228
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
241
229
|
|
242
230
|
res = ws_handler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
|
243
231
|
|
244
|
-
res.transactions.
|
232
|
+
expect( res.transactions ).to have( 1 ).member
|
245
233
|
request, response = res.transactions.first
|
246
|
-
request.
|
247
|
-
response.
|
234
|
+
expect( request ).to be_a( Mongrel2::WebSocket::Frame )
|
235
|
+
expect( response ).to be_a( Mongrel2::WebSocket::Frame )
|
248
236
|
end
|
249
237
|
|
250
238
|
it "continues when a ZMQ::Error is received but the connection remains open" do
|
251
239
|
req = make_request()
|
252
240
|
|
253
|
-
@request_sock.
|
254
|
-
@request_sock.
|
241
|
+
expect( @request_sock ).to receive( :recv ).and_raise( ZMQ::Error.new("Interrupted system call.") )
|
242
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
255
243
|
|
256
244
|
res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
|
257
245
|
|
258
|
-
res.transactions.
|
246
|
+
expect( res.transactions ).to have( 1 ).member
|
259
247
|
request, response = res.transactions.first
|
260
|
-
request.
|
261
|
-
response.
|
262
|
-
response.status.
|
248
|
+
expect( request ).to be_a( Mongrel2::HTTPRequest )
|
249
|
+
expect( response ).to be_a( Mongrel2::HTTPResponse )
|
250
|
+
expect( response.status ).to eq( 204 )
|
263
251
|
end
|
264
252
|
|
265
253
|
it "ignores disconnect notices by default" do
|
266
254
|
req = make_json_request( :path => '@*', :body => {'type' => 'disconnect'} )
|
267
|
-
@request_sock.
|
255
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
268
256
|
|
269
257
|
res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
|
270
258
|
|
271
|
-
res.transactions.
|
259
|
+
expect( res.transactions ).to have( 1 ).member
|
272
260
|
request, response = res.transactions.first
|
273
|
-
request.
|
274
|
-
response.
|
261
|
+
expect( request ).to be_a( Mongrel2::JSONRequest )
|
262
|
+
expect( response ).to be_nil()
|
275
263
|
end
|
276
264
|
|
277
265
|
it "dispatches disconnect notices to the #handle_disconnect method" do
|
@@ -282,33 +270,33 @@ describe Mongrel2::Handler do
|
|
282
270
|
end
|
283
271
|
|
284
272
|
req = make_json_request( :path => '@*', :body => {'type' => 'disconnect'} )
|
285
|
-
@request_sock.
|
273
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
286
274
|
|
287
275
|
res = disconnect_handler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
|
288
276
|
|
289
|
-
res.transactions.
|
277
|
+
expect( res.transactions ).to have( 1 ).member
|
290
278
|
request, response = res.transactions.first
|
291
|
-
request.
|
292
|
-
response.
|
279
|
+
expect( request ).to be_a( Mongrel2::JSONRequest )
|
280
|
+
expect( response ).to be_nil()
|
293
281
|
end
|
294
282
|
|
295
283
|
it "cancels async upload notices by default" do
|
296
284
|
req = make_request( 'METHOD' => 'POST', :headers => {'x-mongrel2-upload-start' => 'uploadfile.XXX'} )
|
297
|
-
@request_sock.
|
298
|
-
@response_sock.
|
285
|
+
expect( @request_sock ).to receive( :recv ).and_return( req )
|
286
|
+
expect( @response_sock ).to receive( :send ).with( "#{TEST_UUID} 1:8, " )
|
299
287
|
|
300
288
|
res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
|
301
289
|
|
302
|
-
res.transactions.
|
290
|
+
expect( res.transactions ).to have( 1 ).member
|
303
291
|
request, response = res.transactions.first
|
304
|
-
response.
|
292
|
+
expect( response ).to be_nil()
|
305
293
|
end
|
306
294
|
|
307
295
|
it "re-establishes its connection when told to restart" do
|
308
296
|
res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
|
309
297
|
original_conn = res.conn
|
310
298
|
res.restart
|
311
|
-
res.conn.
|
299
|
+
expect( res.conn ).to_not equal( original_conn )
|
312
300
|
end
|
313
301
|
|
314
302
|
end
|
@@ -1,20 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
require 'pathname'
|
5
|
-
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
6
|
-
|
7
|
-
libdir = basedir + "lib"
|
8
|
-
|
9
|
-
$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
|
10
|
-
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
11
|
-
}
|
3
|
+
require_relative '../helpers'
|
12
4
|
|
13
5
|
require 'rspec'
|
14
6
|
require 'tnetstring'
|
15
7
|
|
16
|
-
require 'spec/lib/helpers'
|
17
|
-
|
18
8
|
require 'mongrel2'
|
19
9
|
require 'mongrel2/httprequest'
|
20
10
|
require 'mongrel2/httpresponse'
|
@@ -27,7 +17,7 @@ require 'mongrel2/httpresponse'
|
|
27
17
|
describe Mongrel2::HTTPRequest do
|
28
18
|
|
29
19
|
before( :all ) do
|
30
|
-
setup_logging(
|
20
|
+
setup_logging()
|
31
21
|
@factory = Mongrel2::RequestFactory.new( route: '/glamour' )
|
32
22
|
end
|
33
23
|
|
@@ -42,55 +32,55 @@ describe Mongrel2::HTTPRequest do
|
|
42
32
|
|
43
33
|
it "can create an HTTPResponse for itself" do
|
44
34
|
result = @req.response
|
45
|
-
result.
|
46
|
-
result.sender_id.
|
47
|
-
result.conn_id.
|
35
|
+
expect( result ).to be_a( Mongrel2::HTTPResponse )
|
36
|
+
expect( result.sender_id ).to eq( @req.sender_id )
|
37
|
+
expect( result.conn_id ).to eq( @req.conn_id )
|
48
38
|
end
|
49
39
|
|
50
40
|
it "remembers its corresponding HTTPResponse if it's created it already" do
|
51
41
|
result = @req.response
|
52
|
-
result.
|
53
|
-
result.sender_id.
|
54
|
-
result.conn_id.
|
42
|
+
expect( result ).to be_a( Mongrel2::HTTPResponse )
|
43
|
+
expect( result.sender_id ).to eq( @req.sender_id )
|
44
|
+
expect( result.conn_id ).to eq( @req.conn_id )
|
55
45
|
end
|
56
46
|
|
57
47
|
it "knows that its connection isn't persistent if it's an HTTP/1.0 request" do
|
58
48
|
@req.headers.version = 'HTTP/1.0'
|
59
|
-
@req.
|
49
|
+
expect( @req ).to_not be_keepalive()
|
60
50
|
end
|
61
51
|
|
62
52
|
it "knows that its connection isn't persistent if has a 'close' token in its Connection header" do
|
63
53
|
@req.headers.version = 'HTTP/1.1'
|
64
54
|
@req.headers[ :connection ] = 'violent, close'
|
65
|
-
@req.
|
55
|
+
expect( @req ).to_not be_keepalive()
|
66
56
|
end
|
67
57
|
|
68
58
|
it "knows that its connection could be persistent if doesn't have a Connection header, " +
|
69
59
|
"and it's an HTTP/1.1 request" do
|
70
60
|
@req.headers.version = 'HTTP/1.1'
|
71
61
|
@req.headers.delete( :connection )
|
72
|
-
@req.
|
62
|
+
expect( @req ).to be_keepalive()
|
73
63
|
end
|
74
64
|
|
75
65
|
it "knows that its connection is persistent if has a Connection header without a 'close' " +
|
76
66
|
"token and it's an HTTP/1.1 request" do
|
77
67
|
@req.headers.version = 'HTTP/1.1'
|
78
68
|
@req.headers.connection = 'keep-alive'
|
79
|
-
@req.
|
69
|
+
expect( @req ).to be_keepalive()
|
80
70
|
end
|
81
71
|
|
82
72
|
it "knows what its URL scheme was" do
|
83
|
-
@req.scheme.
|
73
|
+
expect( @req.scheme ).to eq( 'http' )
|
84
74
|
end
|
85
75
|
|
86
76
|
it "falls back to 'http' if the url_scheme isn't provided (mongrel2 <= 1.8.0)" do
|
87
77
|
@req.headers.url_scheme = nil
|
88
|
-
@req.scheme.
|
78
|
+
expect( @req.scheme ).to eq( 'http' )
|
89
79
|
end
|
90
80
|
|
91
81
|
it "knows that it was an SSL-encrypted request if its scheme was 'https'" do
|
92
82
|
@req.headers.url_scheme = 'https'
|
93
|
-
@req.
|
83
|
+
expect( @req ).to be_secure()
|
94
84
|
end
|
95
85
|
|
96
86
|
|
@@ -105,30 +95,30 @@ describe Mongrel2::HTTPRequest do
|
|
105
95
|
end
|
106
96
|
|
107
97
|
it "provides a convenience method for fetching the 'Content-type' header" do
|
108
|
-
@req.content_type.
|
98
|
+
expect( @req.content_type ).to eq( 'application/x-pdf' )
|
109
99
|
end
|
110
100
|
|
111
101
|
it "provides a convenience method for resetting the 'Content-type' header" do
|
112
102
|
@req.content_type = 'application/json'
|
113
|
-
@req.content_type.
|
103
|
+
expect( @req.content_type ).to eq( 'application/json' )
|
114
104
|
end
|
115
105
|
|
116
106
|
it "provides a convenience method for fetching the 'Content-encoding' header" do
|
117
|
-
@req.content_encoding.
|
107
|
+
expect( @req.content_encoding ).to eq( 'gzip' )
|
118
108
|
end
|
119
109
|
|
120
110
|
it "provides a convenience method for resetting the 'Content-encoding' header" do
|
121
111
|
@req.content_encoding = 'identity'
|
122
|
-
@req.content_encoding.
|
112
|
+
expect( @req.content_encoding ).to eq( 'identity' )
|
123
113
|
end
|
124
114
|
|
125
115
|
it "provides a convenience method for fetching the request's Content-length header" do
|
126
|
-
@req.content_length.
|
116
|
+
expect( @req.content_length ).to eq( 28113 )
|
127
117
|
end
|
128
118
|
|
129
119
|
it "returns 0 as the content_length if the request doesn't have a Content-length header" do
|
130
120
|
@req.headers.delete( :content_length )
|
131
|
-
@req.content_length.
|
121
|
+
expect( @req.content_length ).to eq( 0 )
|
132
122
|
end
|
133
123
|
|
134
124
|
it "raises an exception if the Content-length header contains something other than an integer" do
|
@@ -1,19 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#encoding: utf-8
|
3
3
|
|
4
|
-
|
5
|
-
require 'pathname'
|
6
|
-
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
7
|
-
|
8
|
-
libdir = basedir + "lib"
|
9
|
-
|
10
|
-
$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
|
11
|
-
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
12
|
-
}
|
13
|
-
|
14
|
-
require 'rspec'
|
15
|
-
|
16
|
-
require 'spec/lib/helpers'
|
4
|
+
require_relative '../helpers'
|
17
5
|
|
18
6
|
require 'mongrel2'
|
19
7
|
require 'mongrel2/httprequest'
|
@@ -27,7 +15,7 @@ require 'mongrel2/httpresponse'
|
|
27
15
|
describe Mongrel2::HTTPResponse do
|
28
16
|
|
29
17
|
before( :all ) do
|
30
|
-
setup_logging(
|
18
|
+
setup_logging()
|
31
19
|
end
|
32
20
|
|
33
21
|
before( :each ) do
|
@@ -40,51 +28,51 @@ describe Mongrel2::HTTPResponse do
|
|
40
28
|
|
41
29
|
|
42
30
|
it "has a headers table" do
|
43
|
-
@response.headers.
|
31
|
+
expect( @response.headers ).to be_a( Mongrel2::Table )
|
44
32
|
end
|
45
33
|
|
46
34
|
it "allows headers to be set when the response is created" do
|
47
35
|
response = Mongrel2::HTTPResponse.new( TEST_UUID, 299, :content_type => 'image/jpeg' )
|
48
|
-
response.headers.content_type.
|
36
|
+
expect( response.headers.content_type ).to eq( 'image/jpeg' )
|
49
37
|
end
|
50
38
|
|
51
39
|
it "is a No Content response if not set otherwise" do
|
52
|
-
@response.status_line.
|
40
|
+
expect( @response.status_line ).to eq( 'HTTP/1.1 204 No Content' )
|
53
41
|
end
|
54
42
|
|
55
43
|
it "returns an empty response if its status is set to NO_CONTENT" do
|
56
44
|
@response.puts "The response body"
|
57
45
|
@response.status = HTTP::NO_CONTENT
|
58
|
-
@response.header_data.
|
59
|
-
@response.header_data.
|
60
|
-
@response.to_s.
|
46
|
+
expect( @response.header_data ).to_not match( /Content-length/i )
|
47
|
+
expect( @response.header_data ).to_not match( /Content-type/i )
|
48
|
+
expect( @response.to_s ).to_not match( /The response body/i )
|
61
49
|
end
|
62
50
|
|
63
51
|
it "sets Date, Content-type, and Content-length headers automatically if they haven't been set" do
|
64
52
|
@response << "Some stuff."
|
65
53
|
|
66
|
-
@response.header_data.
|
67
|
-
@response.header_data.
|
68
|
-
@response.header_data.
|
54
|
+
expect( @response.header_data ).to match( %r{Content-type: #{Mongrel2::HTTPResponse::DEFAULT_CONTENT_TYPE}}i )
|
55
|
+
expect( @response.header_data ).to match( /Content-length: 11/i )
|
56
|
+
expect( @response.header_data ).to match( /Date: #{HTTP_DATE}/i )
|
69
57
|
end
|
70
58
|
|
71
59
|
it "re-calculates the automatically-added headers when re-rendered" do
|
72
|
-
@response.header_data.
|
60
|
+
expect( @response.header_data ).to match( /Content-length: 0\b/i )
|
73
61
|
@response.status = HTTP::OK
|
74
62
|
@response << "More data!"
|
75
|
-
@response.header_data.
|
63
|
+
expect( @response.header_data ).to match( /Content-length: 10\b/i )
|
76
64
|
end
|
77
65
|
|
78
66
|
it "doesn't have a body" do
|
79
|
-
@response.body.size.
|
67
|
+
expect( @response.body.size ).to eq( 0 )
|
80
68
|
end
|
81
69
|
|
82
70
|
it "stringifies to a valid RFC2616 response string" do
|
83
|
-
@response.to_s.
|
71
|
+
expect( @response.to_s ).to match( HTTP_RESPONSE )
|
84
72
|
end
|
85
73
|
|
86
74
|
it "has some default headers" do
|
87
|
-
@response.headers['Server'].
|
75
|
+
expect( @response.headers['Server'] ).to eq( Mongrel2.version_string( true ) )
|
88
76
|
end
|
89
77
|
|
90
78
|
it "can be reset to a pristine state" do
|
@@ -94,33 +82,33 @@ describe Mongrel2::HTTPResponse do
|
|
94
82
|
|
95
83
|
@response.reset
|
96
84
|
|
97
|
-
@response.
|
98
|
-
@response.body.
|
99
|
-
@response.body.size.
|
100
|
-
@response.headers.
|
85
|
+
expect( @response ).to_not be_handled()
|
86
|
+
expect( @response.body ).to be_a( StringIO )
|
87
|
+
expect( @response.body.size ).to eq( 0 )
|
88
|
+
expect( @response.headers ).to have(1).keys
|
101
89
|
end
|
102
90
|
|
103
91
|
it "sets its status line to 200 OK if the body is set and the status hasn't yet been set" do
|
104
92
|
@response << "Some stuff"
|
105
|
-
@response.status_line.
|
93
|
+
expect( @response.status_line ).to eq( 'HTTP/1.1 200 OK' )
|
106
94
|
end
|
107
95
|
|
108
96
|
it "sets its status line to 204 No Content if the body is set and the status hasn't yet been set" do
|
109
|
-
@response.status_line.
|
97
|
+
expect( @response.status_line ).to eq( 'HTTP/1.1 204 No Content' )
|
110
98
|
end
|
111
99
|
|
112
100
|
it "can find the length of its body if it's a String" do
|
113
101
|
test_body = 'A string full of stuff'
|
114
102
|
@response.body = test_body
|
115
103
|
|
116
|
-
@response.get_content_length.
|
104
|
+
expect( @response.get_content_length ).to eq( test_body.length )
|
117
105
|
end
|
118
106
|
|
119
107
|
it "can find the length of its body if it's a String with multi-byte characters in it" do
|
120
108
|
test_body = 'Хорошая собака, Стрелке! Очень хорошо.'
|
121
109
|
@response << test_body
|
122
110
|
|
123
|
-
@response.get_content_length.
|
111
|
+
expect( @response.get_content_length ).to eq( test_body.bytesize )
|
124
112
|
end
|
125
113
|
|
126
114
|
it "can find the length of its body if it's a seekable IO" do
|
@@ -131,7 +119,7 @@ describe Mongrel2::HTTPResponse do
|
|
131
119
|
|
132
120
|
@response.body = test_body
|
133
121
|
|
134
|
-
@response.get_content_length.
|
122
|
+
expect( @response.get_content_length ).to eq( length )
|
135
123
|
end
|
136
124
|
|
137
125
|
it "can find the length of its body even if it's an IO that's been set to do a partial read" do
|
@@ -142,94 +130,94 @@ describe Mongrel2::HTTPResponse do
|
|
142
130
|
|
143
131
|
@response.body = test_body
|
144
132
|
|
145
|
-
@response.get_content_length.
|
133
|
+
expect( @response.get_content_length ).to eq( length - 100 )
|
146
134
|
end
|
147
135
|
|
148
136
|
it "knows whether or not it has been handled" do
|
149
|
-
@response.
|
137
|
+
expect( @response ).to_not be_handled()
|
150
138
|
@response.status = HTTP::OK
|
151
|
-
@response.
|
139
|
+
expect( @response ).to be_handled()
|
152
140
|
end
|
153
141
|
|
154
142
|
it "knows that it has been handled even if the status is set to NOT_FOUND" do
|
155
143
|
@response.reset
|
156
144
|
@response.status = HTTP::NOT_FOUND
|
157
|
-
@response.
|
145
|
+
expect( @response ).to be_handled()
|
158
146
|
end
|
159
147
|
|
160
148
|
|
161
149
|
it "knows what category of response it is" do
|
162
150
|
@response.status = HTTP::CREATED
|
163
|
-
@response.status_category.
|
151
|
+
expect( @response.status_category ).to eq( 2 )
|
164
152
|
|
165
153
|
@response.status = HTTP::NOT_ACCEPTABLE
|
166
|
-
@response.status_category.
|
154
|
+
expect( @response.status_category ).to eq( 4 )
|
167
155
|
end
|
168
156
|
|
169
157
|
|
170
158
|
it "knows if its status indicates it is an informational response" do
|
171
159
|
@response.status = HTTP::PROCESSING
|
172
|
-
@response.status_category.
|
173
|
-
@response.status_is_informational
|
160
|
+
expect( @response.status_category ).to eq( 1 )
|
161
|
+
expect( @response.status_is_informational? ).to eq( true )
|
174
162
|
end
|
175
163
|
|
176
164
|
|
177
165
|
it "knows if its status indicates it is a successful response" do
|
178
166
|
@response.status = HTTP::ACCEPTED
|
179
|
-
@response.status_category.
|
180
|
-
@response.status_is_successful
|
167
|
+
expect( @response.status_category ).to eq( 2 )
|
168
|
+
expect( @response.status_is_successful? ).to eq( true )
|
181
169
|
end
|
182
170
|
|
183
171
|
|
184
172
|
it "knows if its status indicates it is a redirected response" do
|
185
173
|
@response.status = HTTP::SEE_OTHER
|
186
|
-
@response.status_category.
|
187
|
-
@response.status_is_redirect
|
174
|
+
expect( @response.status_category ).to eq( 3 )
|
175
|
+
expect( @response.status_is_redirect? ).to eq( true )
|
188
176
|
end
|
189
177
|
|
190
178
|
|
191
179
|
it "knows if its status indicates there was a client error" do
|
192
180
|
@response.status = HTTP::GONE
|
193
|
-
@response.status_category.
|
194
|
-
@response.status_is_clienterror
|
181
|
+
expect( @response.status_category ).to eq( 4 )
|
182
|
+
expect( @response.status_is_clienterror? ).to eq( true )
|
195
183
|
end
|
196
184
|
|
197
185
|
|
198
186
|
it "knows if its status indicates there was a server error" do
|
199
187
|
@response.status = HTTP::VERSION_NOT_SUPPORTED
|
200
|
-
@response.status_category.
|
201
|
-
@response.status_is_servererror
|
188
|
+
expect( @response.status_category ).to eq( 5 )
|
189
|
+
expect( @response.status_is_servererror? ).to eq( true )
|
202
190
|
end
|
203
191
|
|
204
192
|
|
205
193
|
it "knows that a 100 response shouldn't have a body" do
|
206
194
|
@response.status = HTTP::CONTINUE
|
207
|
-
@response.
|
195
|
+
expect( @response ).to be_bodiless()
|
208
196
|
end
|
209
197
|
|
210
198
|
|
211
199
|
it "knows that a 204 response shouldn't have a body" do
|
212
200
|
@response.status = HTTP::NO_CONTENT
|
213
|
-
@response.
|
201
|
+
expect( @response ).to be_bodiless()
|
214
202
|
end
|
215
203
|
|
216
204
|
|
217
205
|
it "knows that a response with a body explicitly set to nil is bodiless" do
|
218
206
|
@response.status = HTTP::CREATED
|
219
207
|
@response.body = nil
|
220
|
-
@response.
|
208
|
+
expect( @response ).to be_bodiless()
|
221
209
|
end
|
222
210
|
|
223
211
|
|
224
212
|
it "knows what the response content type is" do
|
225
213
|
@response.headers['Content-Type'] = 'text/erotica'
|
226
|
-
@response.content_type.
|
214
|
+
expect( @response.content_type ).to eq( 'text/erotica' )
|
227
215
|
end
|
228
216
|
|
229
217
|
|
230
218
|
it "can modify the response content type" do
|
231
219
|
@response.content_type = 'image/nude'
|
232
|
-
@response.headers['Content-Type'].
|
220
|
+
expect( @response.headers['Content-Type'] ).to eq( 'image/nude' )
|
233
221
|
end
|
234
222
|
|
235
223
|
|
@@ -238,21 +226,21 @@ describe Mongrel2::HTTPResponse do
|
|
238
226
|
test_body = StringIO.new( test_body_content )
|
239
227
|
@response.body = test_body
|
240
228
|
|
241
|
-
@response.get_content_length.
|
229
|
+
expect( @response.get_content_length ).to eq( test_body_content.length )
|
242
230
|
end
|
243
231
|
|
244
232
|
|
245
233
|
it "returns a body length of 0 if it's a bodiless status code" do
|
246
234
|
@response.puts "Some stuff"
|
247
235
|
@response.status = HTTP::NO_CONTENT
|
248
|
-
@response.get_content_length.
|
236
|
+
expect( @response.get_content_length ).to eq( 0 )
|
249
237
|
end
|
250
238
|
|
251
239
|
|
252
240
|
it "returns a body length of 0 if it has a nil body" do
|
253
241
|
@response.body = nil
|
254
242
|
@response.status = HTTP::CREATED
|
255
|
-
@response.get_content_length.
|
243
|
+
expect( @response.get_content_length ).to eq( 0 )
|
256
244
|
end
|
257
245
|
|
258
246
|
|
@@ -265,36 +253,36 @@ describe Mongrel2::HTTPResponse do
|
|
265
253
|
@response.header.content_length = 2048
|
266
254
|
@response.body = ''
|
267
255
|
|
268
|
-
@response.status_line.
|
256
|
+
expect( @response.status_line ).to match( /200 OK/i )
|
269
257
|
end
|
270
258
|
|
271
259
|
|
272
260
|
it "can build a valid HTTP status line for its status" do
|
273
261
|
@response.status = HTTP::SEE_OTHER
|
274
|
-
@response.status_line.
|
262
|
+
expect( @response.status_line ).to eq( "HTTP/1.1 303 See Other" )
|
275
263
|
end
|
276
264
|
|
277
265
|
|
278
266
|
it "has pipelining disabled by default" do
|
279
|
-
@response.
|
267
|
+
expect( @response ).to_not be_keepalive()
|
280
268
|
end
|
281
269
|
|
282
270
|
|
283
271
|
it "has pipelining disabled if it's explicitly disabled" do
|
284
272
|
@response.keepalive = false
|
285
|
-
@response.
|
273
|
+
expect( @response ).to_not be_keepalive()
|
286
274
|
end
|
287
275
|
|
288
276
|
|
289
277
|
it "can be set to allow pipelining" do
|
290
278
|
@response.keepalive = true
|
291
|
-
@response.
|
279
|
+
expect( @response ).to be_keepalive()
|
292
280
|
end
|
293
281
|
|
294
282
|
it "has a puts method for appending objects to the body" do
|
295
283
|
@response.puts( :something_to_sable )
|
296
284
|
@response.body.rewind
|
297
|
-
@response.body.read.
|
285
|
+
expect( @response.body.read ).to eq( "something_to_sable\n" )
|
298
286
|
end
|
299
287
|
|
300
288
|
end
|