mongrel2 0.38.0 → 0.39.0
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.
- 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
|