mongrel2 0.52.1 → 0.52.2

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.
@@ -31,12 +31,9 @@ describe Mongrel2::Connection do
31
31
  response_sock = double( "response socket", options: OpenStruct.new )
32
32
 
33
33
  expect( CZTop::Socket::PULL ).to receive( :new ).and_return( request_sock )
34
- expect( request_sock.options ).to receive( :linger= ).with( 0 )
35
34
  expect( request_sock ).to receive( :connect ).with( TEST_SEND_SPEC )
36
35
 
37
36
  expect( CZTop::Socket::PUB ).to receive( :new ).and_return( response_sock )
38
- expect( response_sock.options ).to receive( :linger= ).with( 0 )
39
- expect( response_sock.options ).to_not receive( :identity= )
40
37
  expect( response_sock ).to receive( :connect ).with( TEST_RECV_SPEC )
41
38
 
42
39
  expect( @conn.request_sock ).to eq( request_sock )
@@ -13,9 +13,6 @@ require 'mongrel2/control'
13
13
 
14
14
  describe Mongrel2::Control do
15
15
 
16
- before( :all ) do
17
- end
18
-
19
16
  before( :each ) do
20
17
  @ctx = double( "ZMQ::Context" )
21
18
  @socket = double( "ZMQ REQ socket", :connect => nil, :options => OpenStruct.new )
@@ -34,6 +31,7 @@ describe Mongrel2::Control do
34
31
  expect( @control.stop ).to eq( [{ :msg => "signal sent to server" }] )
35
32
  end
36
33
 
34
+
37
35
  it "sends a 'reload' command to the control port when #reload is called" do
38
36
  expect( @socket ).to receive( :<< ).with( "12:6:reload,0:}]" )
39
37
  expect( @socket ).to receive( :receive ).
@@ -41,6 +39,7 @@ describe Mongrel2::Control do
41
39
  expect( @control.reload ).to eq( [{ :msg => "signal sent to server" }] )
42
40
  end
43
41
 
42
+
44
43
  it "sends a 'terminate' command to the control port when #terminate is called" do
45
44
  expect( @socket ).to receive( :<< ).with( "15:9:terminate,0:}]" )
46
45
  expect( @socket ).to receive( :receive ).
@@ -48,6 +47,7 @@ describe Mongrel2::Control do
48
47
  expect( @control.terminate ).to eq( [{ :msg => "signal sent to server" }] )
49
48
  end
50
49
 
50
+
51
51
  it "sends a 'help' command to the control port when #help is called" do
52
52
  expect( @socket ).to receive( :<< ).with( "10:4:help,0:}]" )
53
53
  expect( @socket ).to receive( :receive ).and_return(
@@ -75,6 +75,7 @@ describe Mongrel2::Control do
75
75
  ])
76
76
  end
77
77
 
78
+
78
79
  it "sends a 'uuid' command to the control port when #uuid is called" do
79
80
  expect( @socket ).to receive( :<< ).with( "10:4:uuid,0:}]" )
80
81
  expect( @socket ).to receive( :receive ).and_return(
@@ -84,6 +85,7 @@ describe Mongrel2::Control do
84
85
  expect( @control.uuid ).to eq( [{ :uuid => '34D8E57C-3E91-4F24-9BBE-0B53C1827CB4' }] )
85
86
  end
86
87
 
88
+
87
89
  it "sends an 'info' command to the control port when #info is called" do
88
90
  expect( @socket ).to receive( :<< ).with( "10:4:info,0:}]" )
89
91
  expect( @socket ).to receive( :receive ).and_return(
@@ -106,6 +108,7 @@ describe Mongrel2::Control do
106
108
  }])
107
109
  end
108
110
 
111
+
109
112
  it "sends a 'status' command with a 'what' option set to 'tasks' to the control port " +
110
113
  "when #tasklist is called" do
111
114
 
@@ -129,6 +132,7 @@ describe Mongrel2::Control do
129
132
  ])
130
133
  end
131
134
 
135
+
132
136
  it "sends an 'status' command with a 'what' option set to 'net' to the control port " +
133
137
  "when #conn_status is called" do
134
138
 
@@ -144,6 +148,7 @@ describe Mongrel2::Control do
144
148
  ])
145
149
  end
146
150
 
151
+
147
152
  it "sends a 'time' command to the control port when #time is called" do
148
153
  expect( @socket ).to receive( :<< ).with( "10:4:time,0:}]" )
149
154
  expect( @socket ).to receive( :receive ).
@@ -151,6 +156,7 @@ describe Mongrel2::Control do
151
156
  expect( @control.time ).to eq( Time.at( 1315532674 ) )
152
157
  end
153
158
 
159
+
154
160
  it "sends a 'kill' command with an ID equal to the argument to the control port when #kill " +
155
161
  "is called" do
156
162
  expect( @socket ).to receive( :<< ).with( "19:4:kill,9:2:id,1:0#}]" )
@@ -159,6 +165,7 @@ describe Mongrel2::Control do
159
165
  expect( @control.kill( 0 ) ).to eq( [{ :status => "OK" }] )
160
166
  end
161
167
 
168
+
162
169
  it "sends a 'control_stop' command to the control port when #info is called" do
163
170
  expect( @socket ).to receive( :<< ).with( "19:12:control_stop,0:}]" )
164
171
  expect( @socket ).to receive( :receive ).
@@ -85,6 +85,7 @@ describe Mongrel2::Handler, :db do
85
85
  Mongrel2::Config::Handler.dataset.truncate
86
86
  end
87
87
 
88
+
88
89
  it "raises an exception if no handler with its appid exists in the config DB" do
89
90
  Mongrel2::Config::Handler.dataset.truncate
90
91
  expect {
@@ -95,6 +96,7 @@ describe Mongrel2::Handler, :db do
95
96
  end
96
97
 
97
98
 
99
+
98
100
  it "responds to HTTP requests with a 204 No Content response by default" do
99
101
  request = make_request_object()
100
102
  handler = TestingHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
@@ -268,6 +270,7 @@ describe Mongrel2::Handler, :db do
268
270
  handler = TestingHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
269
271
  original_conn = handler.conn
270
272
 
273
+ handler.reactor = instance_double( CZTop::Reactor )
271
274
  expect( handler.reactor ).to receive( :unregister ).with( original_conn.request_sock )
272
275
  expect( handler.reactor ).to receive( :register ) do |request_sock, mode, &callback|
273
276
  expect( request_sock ).to be_a( CZTop::Socket )
@@ -300,5 +303,6 @@ describe Mongrel2::Handler, :db do
300
303
  expect( request.body ).to be_closed
301
304
  expect( spoolfile ).to_not exist
302
305
  end
306
+
303
307
  end
304
308
 
@@ -32,6 +32,7 @@ describe Mongrel2::HTTPRequest do
32
32
  expect( result.conn_id ).to eq( @req.conn_id )
33
33
  end
34
34
 
35
+
35
36
  it "remembers its corresponding HTTPResponse if it's created it already" do
36
37
  result = @req.response
37
38
  expect( result ).to be_a( Mongrel2::HTTPResponse )
@@ -39,17 +40,20 @@ describe Mongrel2::HTTPRequest do
39
40
  expect( result.conn_id ).to eq( @req.conn_id )
40
41
  end
41
42
 
43
+
42
44
  it "knows that its connection isn't persistent if it's an HTTP/1.0 request" do
43
45
  @req.headers.version = 'HTTP/1.0'
44
46
  expect( @req ).to_not be_keepalive()
45
47
  end
46
48
 
49
+
47
50
  it "knows that its connection isn't persistent if has a 'close' token in its Connection header" do
48
51
  @req.headers.version = 'HTTP/1.1'
49
52
  @req.headers[ :connection ] = 'violent, close'
50
53
  expect( @req ).to_not be_keepalive()
51
54
  end
52
55
 
56
+
53
57
  it "knows that its connection could be persistent if doesn't have a Connection header, " +
54
58
  "and it's an HTTP/1.1 request" do
55
59
  @req.headers.version = 'HTTP/1.1'
@@ -57,6 +61,7 @@ describe Mongrel2::HTTPRequest do
57
61
  expect( @req ).to be_keepalive()
58
62
  end
59
63
 
64
+
60
65
  it "knows that its connection is persistent if has a Connection header without a 'close' " +
61
66
  "token and it's an HTTP/1.1 request" do
62
67
  @req.headers.version = 'HTTP/1.1'
@@ -64,20 +69,24 @@ describe Mongrel2::HTTPRequest do
64
69
  expect( @req ).to be_keepalive()
65
70
  end
66
71
 
72
+
67
73
  it "knows what its URL scheme was" do
68
74
  expect( @req.scheme ).to eq( 'http' )
69
75
  end
70
76
 
77
+
71
78
  it "falls back to 'http' if the url_scheme isn't provided (mongrel2 <= 1.8.0)" do
72
79
  @req.headers.url_scheme = nil
73
80
  expect( @req.scheme ).to eq( 'http' )
74
81
  end
75
82
 
83
+
76
84
  it "knows that it was an SSL-encrypted request if its scheme was 'https'" do
77
85
  @req.headers.url_scheme = 'https'
78
86
  expect( @req ).to be_secure()
79
87
  end
80
88
 
89
+
81
90
  it "doesn't error when inspecting a bodiless instance" do
82
91
  # I don't remember what circumstances this is guarding against, so this is a bit
83
92
  # artificial
@@ -96,33 +105,40 @@ describe Mongrel2::HTTPRequest do
96
105
  )
97
106
  end
98
107
 
108
+
99
109
  it "provides a convenience method for fetching the 'Content-type' header" do
100
110
  expect( @req.content_type ).to eq( 'application/x-pdf' )
101
111
  end
102
112
 
113
+
103
114
  it "provides a convenience method for resetting the 'Content-type' header" do
104
115
  @req.content_type = 'application/json'
105
116
  expect( @req.content_type ).to eq( 'application/json' )
106
117
  end
107
118
 
119
+
108
120
  it "provides a convenience method for fetching the 'Content-encoding' header" do
109
121
  expect( @req.content_encoding ).to eq( 'gzip' )
110
122
  end
111
123
 
124
+
112
125
  it "provides a convenience method for resetting the 'Content-encoding' header" do
113
126
  @req.content_encoding = 'identity'
114
127
  expect( @req.content_encoding ).to eq( 'identity' )
115
128
  end
116
129
 
130
+
117
131
  it "provides a convenience method for fetching the request's Content-length header" do
118
132
  expect( @req.content_length ).to eq( 28113 )
119
133
  end
120
134
 
135
+
121
136
  it "returns 0 as the content_length if the request doesn't have a Content-length header" do
122
137
  @req.headers.delete( :content_length )
123
138
  expect( @req.content_length ).to eq( 0 )
124
139
  end
125
140
 
141
+
126
142
  it "raises an exception if the Content-length header contains something other than an integer" do
127
143
  @req.headers.content_length = 'Lots'
128
144
  expect {
@@ -23,15 +23,18 @@ describe Mongrel2::HTTPResponse do
23
23
  expect( @response.headers ).to be_a( Mongrel2::Table )
24
24
  end
25
25
 
26
+
26
27
  it "allows headers to be set when the response is created" do
27
28
  response = Mongrel2::HTTPResponse.new( TEST_UUID, 299, :content_type => 'image/jpeg' )
28
29
  expect( response.headers.content_type ).to eq( 'image/jpeg' )
29
30
  end
30
31
 
32
+
31
33
  it "is a No Content response if not set otherwise" do
32
34
  expect( @response.status_line ).to eq( 'HTTP/1.1 204 No Content' )
33
35
  end
34
36
 
37
+
35
38
  it "returns an empty response if its status is set to NO_CONTENT" do
36
39
  @response.puts "The response body"
37
40
  @response.status = HTTP::NO_CONTENT
@@ -40,6 +43,7 @@ describe Mongrel2::HTTPResponse do
40
43
  expect( @response.to_s ).to_not match( /The response body/i )
41
44
  end
42
45
 
46
+
43
47
  it "sets Date, Content-type, and Content-length headers automatically if they haven't been set" do
44
48
  @response << "Some stuff."
45
49
 
@@ -48,6 +52,7 @@ describe Mongrel2::HTTPResponse do
48
52
  expect( @response.header_data ).to match( /Date: #{HTTP_DATE}/i )
49
53
  end
50
54
 
55
+
51
56
  it "re-calculates the automatically-added headers when re-rendered" do
52
57
  expect( @response.header_data ).to match( /Content-length: 0\b/i )
53
58
  @response.status = HTTP::OK
@@ -55,18 +60,22 @@ describe Mongrel2::HTTPResponse do
55
60
  expect( @response.header_data ).to match( /Content-length: 10\b/i )
56
61
  end
57
62
 
63
+
58
64
  it "doesn't have a body" do
59
65
  expect( @response.body.size ).to eq( 0 )
60
66
  end
61
67
 
68
+
62
69
  it "stringifies to a valid RFC2616 response string" do
63
70
  expect( @response.to_s ).to match( HTTP_RESPONSE )
64
71
  end
65
72
 
73
+
66
74
  it "has some default headers" do
67
75
  expect( @response.headers['Server'] ).to eq( Mongrel2.version_string( true ) )
68
76
  end
69
77
 
78
+
70
79
  it "can be reset to a pristine state" do
71
80
  @response.body << "Some stuff we want to get rid of later"
72
81
  @response.headers['x-lunch-packed-by'] = 'Your Mom'
@@ -80,15 +89,18 @@ describe Mongrel2::HTTPResponse do
80
89
  expect( @response.headers.size ).to eq( 1 )
81
90
  end
82
91
 
92
+
83
93
  it "sets its status line to 200 OK if the body is set and the status hasn't yet been set" do
84
94
  @response << "Some stuff"
85
95
  expect( @response.status_line ).to eq( 'HTTP/1.1 200 OK' )
86
96
  end
87
97
 
98
+
88
99
  it "sets its status line to 204 No Content if the body is set and the status hasn't yet been set" do
89
100
  expect( @response.status_line ).to eq( 'HTTP/1.1 204 No Content' )
90
101
  end
91
102
 
103
+
92
104
  it "can find the length of its body if it's a String" do
93
105
  test_body = 'A string full of stuff'
94
106
  @response.body = test_body
@@ -96,6 +108,7 @@ describe Mongrel2::HTTPResponse do
96
108
  expect( @response.get_content_length ).to eq( test_body.length )
97
109
  end
98
110
 
111
+
99
112
  it "can find the length of its body if it's a String with multi-byte characters in it" do
100
113
  test_body = 'Хорошая собака, Стрелке! Очень хорошо.'
101
114
  @response << test_body
@@ -103,6 +116,7 @@ describe Mongrel2::HTTPResponse do
103
116
  expect( @response.get_content_length ).to eq( test_body.bytesize )
104
117
  end
105
118
 
119
+
106
120
  it "can find the length of its body if it's a seekable IO" do
107
121
  test_body = File.open( __FILE__, 'r' )
108
122
  test_body.seek( 0, IO::SEEK_END )
@@ -114,6 +128,7 @@ describe Mongrel2::HTTPResponse do
114
128
  expect( @response.get_content_length ).to eq( length )
115
129
  end
116
130
 
131
+
117
132
  it "can find the length of its body even if it's an IO that's been set to do a partial read" do
118
133
  test_body = File.open( __FILE__, 'r' )
119
134
  test_body.seek( 0, IO::SEEK_END )
@@ -125,12 +140,14 @@ describe Mongrel2::HTTPResponse do
125
140
  expect( @response.get_content_length ).to eq( length - 100 )
126
141
  end
127
142
 
143
+
128
144
  it "knows whether or not it has been handled" do
129
145
  expect( @response ).to_not be_handled()
130
146
  @response.status = HTTP::OK
131
147
  expect( @response ).to be_handled()
132
148
  end
133
149
 
150
+
134
151
  it "knows that it has been handled even if the status is set to NOT_FOUND" do
135
152
  @response.reset
136
153
  @response.status = HTTP::NOT_FOUND
@@ -271,6 +288,7 @@ describe Mongrel2::HTTPResponse do
271
288
  expect( @response ).to be_keepalive()
272
289
  end
273
290
 
291
+
274
292
  it "has a puts method for appending objects to the body" do
275
293
  @response.puts( :something_to_sable )
276
294
  @response.body.rewind
@@ -56,6 +56,7 @@ describe Mongrel2::Request, :db do
56
56
  expect( req.headers['Host'] ).to eq( TEST_HEADERS['host'] )
57
57
  end
58
58
 
59
+
59
60
  it "can parse a request message with TNetstring headers" do
60
61
 
61
62
  message = make_tn_request()
@@ -69,6 +70,7 @@ describe Mongrel2::Request, :db do
69
70
  expect( req.headers.host ).to eq( TEST_HEADERS['host'] )
70
71
  end
71
72
 
73
+
72
74
  it "can parse a request message with a JSON body" do
73
75
 
74
76
  message = make_json_request()
@@ -84,6 +86,7 @@ describe Mongrel2::Request, :db do
84
86
  expect( req.data ).to eq( TEST_JSON_BODY )
85
87
  end
86
88
 
89
+
87
90
  it "raises an UnhandledMethodError with the name of the method for METHOD verbs that " +
88
91
  "don't look like HTTP ones" do
89
92
 
@@ -91,6 +94,7 @@ describe Mongrel2::Request, :db do
91
94
  expect { Mongrel2::Request.parse(message) }.to raise_error( Mongrel2::UnhandledMethodError, /!DIVULGE/ )
92
95
  end
93
96
 
97
+
94
98
  it "knows what kind of response it should return" do
95
99
  expect( Mongrel2::Request.response_class ).to eq( Mongrel2::Response )
96
100
  end
@@ -103,6 +107,7 @@ describe Mongrel2::Request, :db do
103
107
  @req = Mongrel2::Request.parse( message )
104
108
  end
105
109
 
110
+
106
111
  it "can return an appropriate response instance for themselves" do
107
112
  result = @req.response
108
113
  expect( result ).to be_a( Mongrel2::Response )
@@ -110,22 +115,26 @@ describe Mongrel2::Request, :db do
110
115
  expect( result.conn_id ).to eq( @req.conn_id )
111
116
  end
112
117
 
118
+
113
119
  it "remembers its response if it's already made one" do
114
120
  expect( @req.response ).to equal( @req.response )
115
121
  end
116
122
 
123
+
117
124
  it "allows the entity body to be replaced by assigning a String" do
118
125
  @req.body = 'something else'
119
126
  expect( @req.body ).to be_a( StringIO )
120
127
  expect( @req.body.string ).to eq( 'something else' )
121
128
  end
122
129
 
130
+
123
131
  it "doesn't try to wrap non-stringish entity body replacements in a StringIO" do
124
132
  testobj = Object.new
125
133
  @req.body = testobj
126
134
  expect( @req.body ).to be( testobj )
127
135
  end
128
136
 
137
+
129
138
  it "provides a convenience method for fetching the requestor's IP address" do
130
139
  @req.headers.merge!(
131
140
  'X-Forwarded-For' => '127.0.0.1'
@@ -133,6 +142,7 @@ describe Mongrel2::Request, :db do
133
142
  expect( @req.remote_ip.to_s ).to eq( '127.0.0.1' )
134
143
  end
135
144
 
145
+
136
146
  it "fetching the requestor's IP address even when travelling via proxies" do
137
147
  @req.headers.merge!(
138
148
  'X-Forwarded-For' => [ '127.0.0.1', '8.8.8.8', '4.4.4.4' ]
@@ -140,6 +150,7 @@ describe Mongrel2::Request, :db do
140
150
  expect( @req.remote_ip.to_s ).to eq( '127.0.0.1' )
141
151
  end
142
152
 
153
+
143
154
  it "can look up the chroot directory of the server the request is from" do
144
155
  Mongrel2::Config::Server.first.update( chroot: '/usr/local/www' )
145
156
  expect( @req.server_chroot ).to be_a( Pathname )
@@ -165,6 +176,7 @@ describe Mongrel2::Request, :db do
165
176
  expect( req.body.string.encoding ).to be( Encoding::ISO_8859_1 )
166
177
  end
167
178
 
179
+
168
180
  it "keeps the data as ascii-8bit if no charset is in the content-type header" do
169
181
  body = "some data".encode( 'binary' )
170
182
  req = @factory.post( '/form', body, content_type: 'application/octet-stream' )
@@ -172,6 +184,7 @@ describe Mongrel2::Request, :db do
172
184
  expect( req.body.string.encoding ).to be( Encoding::ASCII_8BIT )
173
185
  end
174
186
 
187
+
175
188
  it "keeps the data as ascii-8bit if there is no content-type header" do
176
189
  body = "some data".encode( 'binary' )
177
190
  req = @factory.post( '/form', body )
@@ -210,6 +223,7 @@ describe Mongrel2::Request, :db do
210
223
  expect( Mongrel2::Request.subclass_for_method( 'JSON' ) ).to eq( subclass )
211
224
  end
212
225
 
226
+
213
227
  it "includes a mechanism for overriding the Request subclass for a particular request " +
214
228
  "method" do
215
229
  subclass = Class.new( Mongrel2::Request ) do
@@ -221,6 +235,7 @@ describe Mongrel2::Request, :db do
221
235
  expect( Mongrel2::Request.subclass_for_method( 'JSON' ) ).to_not eq( subclass )
222
236
  end
223
237
 
238
+
224
239
  it "clears any cached method -> subclass lookups when the default subclass changes" do
225
240
  Mongrel2::Request.subclass_for_method( 'OPTIONS' ) # cache OPTIONS -> Mongrel2::Request
226
241
 
@@ -242,6 +257,7 @@ describe Mongrel2::Request, :db do
242
257
  @spoolpath = @spoolfile.path.slice( Dir.tmpdir.length + 1..-1 )
243
258
  end
244
259
 
260
+
245
261
  it "knows if it's an 'async upload started' notification" do
246
262
  req = @factory.post( '/form', '', x_mongrel2_upload_start: @spoolpath )
247
263
 
@@ -249,6 +265,7 @@ describe Mongrel2::Request, :db do
249
265
  expect( req ).to_not be_upload_done()
250
266
  end
251
267
 
268
+
252
269
  it "knows if it's an 'async upload done' notification" do
253
270
  req = @factory.post( '/form', '',
254
271
  x_mongrel2_upload_start: @spoolpath,
@@ -259,6 +276,7 @@ describe Mongrel2::Request, :db do
259
276
  expect( req ).to be_valid_upload()
260
277
  end
261
278
 
279
+
262
280
  it "knows if it's not a valid 'async upload done' notification" do
263
281
  req = @factory.post( '/form', '',
264
282
  x_mongrel2_upload_start: @spoolpath,
@@ -269,6 +287,7 @@ describe Mongrel2::Request, :db do
269
287
  expect( req ).to_not be_valid_upload()
270
288
  end
271
289
 
290
+
272
291
  it "raises an exception if the uploaded file fetched with mismatched headers" do
273
292
  req = @factory.post( '/form', '',
274
293
  x_mongrel2_upload_start: @spoolpath,
@@ -279,6 +298,7 @@ describe Mongrel2::Request, :db do
279
298
  }.to raise_error( Mongrel2::UploadError, /upload headers/i )
280
299
  end
281
300
 
301
+
282
302
  it "can return a Pathname object for the uploaded file if it's valid" do
283
303
  req = @factory.post( '/form', '',
284
304
  x_mongrel2_upload_start: @spoolpath,
@@ -290,6 +310,7 @@ describe Mongrel2::Request, :db do
290
310
  expect( req.uploaded_file.to_s ).to eq( @spoolfile.path )
291
311
  end
292
312
 
313
+
293
314
  it "sets the body of the request to the uploaded File if it's valid" do
294
315
  req = @factory.post( '/form', '',
295
316
  x_mongrel2_upload_start: @spoolpath,