serverside 0.3.1 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +15 -11
- data/Rakefile +18 -18
- data/bin/serverside +20 -16
- data/lib/serverside/cluster.rb +4 -33
- data/lib/serverside/core_ext.rb +56 -7
- data/lib/serverside/daemon.rb +10 -17
- data/lib/serverside/http/caching.rb +79 -0
- data/lib/serverside/http/const.rb +69 -0
- data/lib/serverside/http/error.rb +24 -0
- data/lib/serverside/http/parsing.rb +175 -0
- data/lib/serverside/http/response.rb +91 -0
- data/lib/serverside/http/server.rb +194 -0
- data/lib/serverside/http/static.rb +72 -0
- data/lib/serverside/http.rb +14 -0
- data/lib/serverside/js.rb +173 -0
- data/lib/serverside/log.rb +79 -0
- data/lib/serverside/template.rb +5 -4
- data/lib/serverside/xml.rb +84 -0
- data/lib/serverside.rb +11 -2
- data/spec/core_ext_spec.rb +13 -58
- data/spec/daemon_spec.rb +61 -28
- data/spec/http_spec.rb +259 -0
- data/spec/template_spec.rb +9 -7
- metadata +42 -28
- data/CHANGELOG +0 -261
- data/lib/serverside/application.rb +0 -26
- data/lib/serverside/caching.rb +0 -91
- data/lib/serverside/connection.rb +0 -34
- data/lib/serverside/controllers.rb +0 -91
- data/lib/serverside/request.rb +0 -210
- data/lib/serverside/routing.rb +0 -133
- data/lib/serverside/server.rb +0 -27
- data/lib/serverside/static.rb +0 -82
- data/spec/caching_spec.rb +0 -318
- data/spec/cluster_spec.rb +0 -140
- data/spec/connection_spec.rb +0 -59
- data/spec/controllers_spec.rb +0 -142
- data/spec/request_spec.rb +0 -288
- data/spec/routing_spec.rb +0 -240
- data/spec/server_spec.rb +0 -40
- data/spec/static_spec.rb +0 -279
data/spec/request_spec.rb
DELETED
@@ -1,288 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '../lib/serverside')
|
2
|
-
require 'stringio'
|
3
|
-
|
4
|
-
class DummyRequest2 < ServerSide::HTTP::Request
|
5
|
-
attr_accessor :calls, :parse_result, :persistent
|
6
|
-
|
7
|
-
def parse
|
8
|
-
@calls ||= []
|
9
|
-
@calls << :parse
|
10
|
-
@parse_result
|
11
|
-
end
|
12
|
-
|
13
|
-
def respond
|
14
|
-
@calls ||= []
|
15
|
-
@calls << :respond
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
context "HTTP::Request.process" do
|
20
|
-
specify "should call parse and and short-circuit if the result is nil" do
|
21
|
-
r = DummyRequest2.new(nil)
|
22
|
-
r.process.should_be_nil
|
23
|
-
r.calls.should == [:parse]
|
24
|
-
|
25
|
-
r.calls = []
|
26
|
-
r.parse_result = false
|
27
|
-
r.process.should_be false
|
28
|
-
r.calls.should == [:parse]
|
29
|
-
end
|
30
|
-
|
31
|
-
specify "should follow parse with respond and return @persistent" do
|
32
|
-
r = DummyRequest2.new(nil)
|
33
|
-
r.parse_result = true
|
34
|
-
r.process.should_be_nil
|
35
|
-
r.calls.should == [:parse, :respond]
|
36
|
-
|
37
|
-
r.calls = []
|
38
|
-
r.persistent = 'mau'
|
39
|
-
r.process.should == 'mau'
|
40
|
-
r.calls.should == [:parse, :respond]
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class ServerSide::HTTP::Request
|
45
|
-
attr_writer :socket, :persistent, :response_headers
|
46
|
-
end
|
47
|
-
|
48
|
-
context "HTTP::Request.parse" do
|
49
|
-
specify "should return nil for invalid requests" do
|
50
|
-
r = ServerSide::HTTP::Request.new(nil)
|
51
|
-
r.socket = StringIO.new('POST /test')
|
52
|
-
r.parse.should_be_nil
|
53
|
-
r.socket = StringIO.new('invalid string')
|
54
|
-
r.parse.should_be_nil
|
55
|
-
r.socket = StringIO.new('GET HTTP/1.1')
|
56
|
-
r.parse.should_be_nil
|
57
|
-
r.socket = StringIO.new('GET /test http')
|
58
|
-
r.parse.should_be_nil
|
59
|
-
r.socket = StringIO.new('GET /test HTTP')
|
60
|
-
r.parse.should_be_nil
|
61
|
-
r.socket = StringIO.new('GET /test HTTP/')
|
62
|
-
r.parse.should_be_nil
|
63
|
-
r.socket = StringIO.new('POST /test HTTP/1.1')
|
64
|
-
r.parse.should_be_nil
|
65
|
-
end
|
66
|
-
|
67
|
-
specify "should parse valid requests and return request headers" do
|
68
|
-
r = ServerSide::HTTP::Request.new(nil)
|
69
|
-
r.socket = StringIO.new(
|
70
|
-
"POST /test HTTP/1.1\r\nContent-Type: text/html\r\n\r\n")
|
71
|
-
r.parse.should_be r.headers
|
72
|
-
r.method.should == :post
|
73
|
-
r.path.should == '/test'
|
74
|
-
r.query.should_be_nil
|
75
|
-
r.version.should == '1.1'
|
76
|
-
r.parameters.should == {}
|
77
|
-
r.headers.should == {'Content-Type' => 'text/html'}
|
78
|
-
r.cookies.should == {}
|
79
|
-
r.response_cookies.should_be_nil
|
80
|
-
r.persistent.should == true
|
81
|
-
end
|
82
|
-
|
83
|
-
specify "should correctly handle trailing slash in path" do
|
84
|
-
r = ServerSide::HTTP::Request.new(nil)
|
85
|
-
r.socket = StringIO.new("POST /test/asdf/qw/ HTTP/1.1\r\n\r\n")
|
86
|
-
r.parse.should_not_be_nil
|
87
|
-
r.path.should == '/test/asdf/qw'
|
88
|
-
|
89
|
-
r.socket = StringIO.new(
|
90
|
-
"POST /test/asdf/qw/?time=24%20hours HTTP/1.1\r\n\r\n")
|
91
|
-
r.parse.should_not_be_nil
|
92
|
-
r.path.should == '/test/asdf/qw'
|
93
|
-
end
|
94
|
-
|
95
|
-
specify "should parse URL-encoded parameters" do
|
96
|
-
r = ServerSide::HTTP::Request.new(nil)
|
97
|
-
r.socket = StringIO.new(
|
98
|
-
"POST /test?q=node_history&time=24%20hours HTTP/1.1\r\n\r\n")
|
99
|
-
r.parse.should_not_be_nil
|
100
|
-
r.parameters.size.should == 2
|
101
|
-
r.parameters[:time].should == '24 hours'
|
102
|
-
r.parameters[:q].should == 'node_history'
|
103
|
-
end
|
104
|
-
|
105
|
-
specify "should correctly parse the HTTP version" do
|
106
|
-
r = ServerSide::HTTP::Request.new(nil)
|
107
|
-
r.socket = StringIO.new(
|
108
|
-
"POST / HTTP/1.0\r\n\r\n")
|
109
|
-
r.parse.should_not_be_nil
|
110
|
-
r.version.should == '1.0'
|
111
|
-
r.socket = StringIO.new(
|
112
|
-
"POST / HTTP/3.2\r\n\r\n")
|
113
|
-
r.parse.should_not_be_nil
|
114
|
-
r.version.should == '3.2'
|
115
|
-
end
|
116
|
-
|
117
|
-
specify "should set @persistent correctly" do
|
118
|
-
r = ServerSide::HTTP::Request.new(nil)
|
119
|
-
r.socket = StringIO.new("POST / HTTP/1.0\r\n\r\n")
|
120
|
-
r.parse.should_not_be_nil
|
121
|
-
r.persistent.should == false
|
122
|
-
r.socket = StringIO.new("POST / HTTP/1.1\r\n\r\n")
|
123
|
-
r.parse.should_not_be_nil
|
124
|
-
r.persistent.should == true
|
125
|
-
r.socket = StringIO.new("POST / HTTP/0.6\r\n\r\n")
|
126
|
-
r.parse.should_not_be_nil
|
127
|
-
r.persistent.should == false
|
128
|
-
r.socket = StringIO.new("POST / HTTP/1.1\r\nConnection: close\r\n\r\n")
|
129
|
-
r.parse.should_not_be_nil
|
130
|
-
r.persistent.should == false
|
131
|
-
r.socket = StringIO.new("POST / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n")
|
132
|
-
r.parse.should_not_be_nil
|
133
|
-
r.persistent.should == true
|
134
|
-
end
|
135
|
-
|
136
|
-
specify "should parse cookies" do
|
137
|
-
r = ServerSide::HTTP::Request.new(nil)
|
138
|
-
r.socket = StringIO.new(
|
139
|
-
"POST / HTTP/1.0\r\nCookie: abc=1342; def=7%2f4\r\n\r\n")
|
140
|
-
r.parse.should_not_be_nil
|
141
|
-
r.headers['Cookie'].should == 'abc=1342; def=7%2f4'
|
142
|
-
r.cookies.size.should == 2
|
143
|
-
r.cookies[:abc].should == '1342'
|
144
|
-
r.cookies[:def].should == '7/4'
|
145
|
-
end
|
146
|
-
|
147
|
-
specify "should parse the post body" do
|
148
|
-
r = ServerSide::HTTP::Request.new(nil)
|
149
|
-
r.socket = StringIO.new(
|
150
|
-
"POST /?q=node_history HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 15\r\n\r\ntime=24%20hours")
|
151
|
-
r.parse.should_not_be_nil
|
152
|
-
r.parameters.size.should == 2
|
153
|
-
r.parameters[:q].should == 'node_history'
|
154
|
-
r.parameters[:time].should == '24 hours'
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
context "HTTP::Request.send_response" do
|
159
|
-
specify "should format a response with status and body" do
|
160
|
-
r = ServerSide::HTTP::Request.new(nil)
|
161
|
-
r.socket = StringIO.new
|
162
|
-
r.send_response(200, 'text', 'Hello there!')
|
163
|
-
r.socket.rewind
|
164
|
-
r.socket.read.should == "HTTP/1.1 200\r\nDate: #{Time.now.httpdate}\r\nConnection: close\r\nContent-Type: text\r\nContent-Length: 12\r\n\r\nHello there!"
|
165
|
-
end
|
166
|
-
|
167
|
-
specify "should format a response without connect-close when persistent" do
|
168
|
-
r = ServerSide::HTTP::Request.new(nil)
|
169
|
-
r.socket = StringIO.new
|
170
|
-
r.persistent = true
|
171
|
-
r.send_response(200, 'text', 'Hello there!')
|
172
|
-
r.socket.rewind
|
173
|
-
r.socket.read.should == "HTTP/1.1 200\r\nDate: #{Time.now.httpdate}\r\nContent-Type: text\r\nContent-Length: 12\r\n\r\nHello there!"
|
174
|
-
end
|
175
|
-
|
176
|
-
specify "should format a response without content-length for streaming response" do
|
177
|
-
r = ServerSide::HTTP::Request.new(nil)
|
178
|
-
r.socket = StringIO.new
|
179
|
-
r.persistent = true
|
180
|
-
r.send_response(200, 'text')
|
181
|
-
r.socket.rewind
|
182
|
-
r.socket.read.should == "HTTP/1.1 200\r\nDate: #{Time.now.httpdate}\r\nConnection: close\r\nContent-Type: text\r\n\r\n"
|
183
|
-
r.stream('hey there')
|
184
|
-
r.socket.rewind
|
185
|
-
r.socket.read.should == "HTTP/1.1 200\r\nDate: #{Time.now.httpdate}\r\nConnection: close\r\nContent-Type: text\r\n\r\nhey there"
|
186
|
-
end
|
187
|
-
|
188
|
-
specify "should include response_headers and headers in the response" do
|
189
|
-
r = ServerSide::HTTP::Request.new(nil)
|
190
|
-
r.socket = StringIO.new
|
191
|
-
r.persistent = true
|
192
|
-
r.response_headers['XXX'] = 'Test'
|
193
|
-
r.send_response(200, 'text')
|
194
|
-
r.socket.rewind
|
195
|
-
r.socket.read.should == "HTTP/1.1 200\r\nDate: #{Time.now.httpdate}\r\nConnection: close\r\nContent-Type: text\r\nXXX: Test\r\n\r\n"
|
196
|
-
|
197
|
-
r = ServerSide::HTTP::Request.new(nil)
|
198
|
-
r.socket = StringIO.new
|
199
|
-
r.persistent = true
|
200
|
-
r.send_response(200, 'text', nil, nil, {'YYY' => 'TTT'})
|
201
|
-
r.socket.rewind
|
202
|
-
r.socket.read.should == "HTTP/1.1 200\r\nDate: #{Time.now.httpdate}\r\nConnection: close\r\nContent-Type: text\r\nYYY: TTT\r\n\r\n"
|
203
|
-
end
|
204
|
-
|
205
|
-
specify "should set persistent to false if exception is raised" do
|
206
|
-
r = ServerSide::HTTP::Request.new(nil)
|
207
|
-
r.persistent = true
|
208
|
-
proc {r.send_response(200, 'text', 'Hello there!')}.should_not_raise
|
209
|
-
r.persistent.should == false
|
210
|
-
end
|
211
|
-
|
212
|
-
specify "should include cookies in the response" do
|
213
|
-
r = ServerSide::HTTP::Request.new(nil)
|
214
|
-
r.socket = StringIO.new
|
215
|
-
t = Time.now + 360
|
216
|
-
r.set_cookie(:session, "ABCDEFG", t)
|
217
|
-
r.response_cookies.should == "Set-Cookie: session=ABCDEFG; path=/; expires=#{t.rfc2822}\r\n"
|
218
|
-
r.send_response(200, 'text', 'Hi!')
|
219
|
-
r.socket.rewind
|
220
|
-
r.socket.read.should == "HTTP/1.1 200\r\nDate: #{Time.now.httpdate}\r\nConnection: close\r\nContent-Type: text\r\nSet-Cookie: session=ABCDEFG; path=/; expires=#{t.rfc2822}\r\nContent-Length: 3\r\n\r\nHi!"
|
221
|
-
|
222
|
-
r = ServerSide::HTTP::Request.new(nil)
|
223
|
-
r.socket = StringIO.new
|
224
|
-
r.delete_cookie(:session)
|
225
|
-
r.response_cookies.should == "Set-Cookie: session=; path=/; expires=#{Time.at(0).rfc2822}\r\n"
|
226
|
-
r.send_response(200, 'text', 'Hi!')
|
227
|
-
r.socket.rewind
|
228
|
-
r.socket.read.should == "HTTP/1.1 200\r\nDate: #{Time.now.httpdate}\r\nConnection: close\r\nContent-Type: text\r\nSet-Cookie: session=; path=/; expires=#{Time.at(0).rfc2822}\r\nContent-Length: 3\r\n\r\nHi!"
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
context "HTTP::Request.send_file" do
|
233
|
-
specify "should include a disposition header in the response" do
|
234
|
-
socket = StringIO.new
|
235
|
-
r = ServerSide::HTTP::Request.new(socket)
|
236
|
-
r.send_file('text', 'text/plain', :attachment)
|
237
|
-
socket.rewind
|
238
|
-
socket.read.should_match /Content-Disposition: attachment\r\n/
|
239
|
-
end
|
240
|
-
|
241
|
-
specify "should use :inline as default disposition" do
|
242
|
-
socket = StringIO.new
|
243
|
-
r = ServerSide::HTTP::Request.new(socket)
|
244
|
-
r.send_file('text', 'text/plain')
|
245
|
-
socket.rewind
|
246
|
-
socket.read.should_match /Content-Disposition: inline\r\n/
|
247
|
-
end
|
248
|
-
|
249
|
-
specify "should include filename parameter if specified" do
|
250
|
-
socket = StringIO.new
|
251
|
-
r = ServerSide::HTTP::Request.new(socket)
|
252
|
-
r.send_file('text', 'text/plain', :attachment, 'text.txt')
|
253
|
-
socket.rewind
|
254
|
-
socket.read.should_match /Content-Disposition: attachment; filename=text.txt\r\n/
|
255
|
-
end
|
256
|
-
|
257
|
-
specify "should include a description header if specified" do
|
258
|
-
socket = StringIO.new
|
259
|
-
r = ServerSide::HTTP::Request.new(socket)
|
260
|
-
r.send_file('text', 'text/plain', :attachment, 'text.txt')
|
261
|
-
socket.rewind
|
262
|
-
socket.read.should_not_match /Content-Description:\s/
|
263
|
-
|
264
|
-
socket = StringIO.new
|
265
|
-
r = ServerSide::HTTP::Request.new(socket)
|
266
|
-
r.send_file('text', 'text/plain', :attachment, 'text.txt', 'this is text.')
|
267
|
-
socket.rewind
|
268
|
-
socket.read.should_match /Content-Description:\sthis is text\./
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
context "HTTP::Request.redirect" do
|
273
|
-
specify "should send a 302 response for temporary redirect" do
|
274
|
-
r = ServerSide::HTTP::Request.new(nil)
|
275
|
-
r.socket = StringIO.new
|
276
|
-
r.redirect('http://mau.com/132')
|
277
|
-
r.socket.rewind
|
278
|
-
r.socket.read.should == "HTTP/1.1 302\r\nDate: #{Time.now.httpdate}\r\nConnection: close\r\nLocation: http://mau.com/132\r\n\r\n"
|
279
|
-
end
|
280
|
-
|
281
|
-
specify "should send a 301 response for permanent redirect" do
|
282
|
-
r = ServerSide::HTTP::Request.new(nil)
|
283
|
-
r.socket = StringIO.new
|
284
|
-
r.redirect('http://mau.com/132', true)
|
285
|
-
r.socket.rewind
|
286
|
-
r.socket.read.should == "HTTP/1.1 301\r\nDate: #{Time.now.httpdate}\r\nConnection: close\r\nLocation: http://mau.com/132\r\n\r\n"
|
287
|
-
end
|
288
|
-
end
|
data/spec/routing_spec.rb
DELETED
@@ -1,240 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '../lib/serverside')
|
2
|
-
require 'stringio'
|
3
|
-
|
4
|
-
class ServerSide::Router
|
5
|
-
attr_accessor :t, :parameters, :path
|
6
|
-
|
7
|
-
def self.rules
|
8
|
-
@@rules
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.reset
|
12
|
-
@@rules = []
|
13
|
-
@@default_route = nil
|
14
|
-
define_method(:respond) {nil}
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
R = ServerSide::Router
|
19
|
-
|
20
|
-
context "Router.routes_defined?" do
|
21
|
-
specify "should return nil if no routes were defined" do
|
22
|
-
R.reset
|
23
|
-
R.routes_defined?.should_be_nil
|
24
|
-
end
|
25
|
-
|
26
|
-
specify "should return true if routes were defined" do
|
27
|
-
R.reset
|
28
|
-
R.route('/controller') {}
|
29
|
-
R.routes_defined?.should_be true
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context "Router.route" do
|
34
|
-
specify "should add the rule to @@rules" do
|
35
|
-
l = proc {1 + 1}
|
36
|
-
R.reset
|
37
|
-
R.route(:path => '/t', &l)
|
38
|
-
R.rules.size.should == 1
|
39
|
-
R.rules[0][0].should == {:path => '/t'}
|
40
|
-
R.rules[0][1].should == l
|
41
|
-
end
|
42
|
-
|
43
|
-
specify "should convert a string argument to a path rule" do
|
44
|
-
R.reset
|
45
|
-
R.route('/test') {}
|
46
|
-
R.rules[0][0].should == {:path => '/test'}
|
47
|
-
end
|
48
|
-
|
49
|
-
specify "should convert a regexp argument to a path rule" do
|
50
|
-
R.reset
|
51
|
-
R.route(/abc/) {}
|
52
|
-
R.rules[0][0].should == {:path => /abc/}
|
53
|
-
end
|
54
|
-
|
55
|
-
specify "should convert an array argument into a multiple path rule" do
|
56
|
-
R.reset
|
57
|
-
R.route(['/a', '/b', '/c']) {}
|
58
|
-
R.rules[0][0].should == {:path => ['/a', '/b', '/c']}
|
59
|
-
end
|
60
|
-
|
61
|
-
specify "should store a hash argument as the rule" do
|
62
|
-
R.reset
|
63
|
-
R.route(:a => 'abc', :b => 'def') {}
|
64
|
-
R.rules[0][0].should_be_a_kind_of Hash
|
65
|
-
R.rules[0][0].size.should == 2
|
66
|
-
R.rules[0][0][:a].should == 'abc'
|
67
|
-
R.rules[0][0][:b].should == 'def'
|
68
|
-
end
|
69
|
-
|
70
|
-
specify "should unshift new rules into the rules array" do
|
71
|
-
R.reset
|
72
|
-
R.route('abc') {}
|
73
|
-
R.route('def') {}
|
74
|
-
R.route('ghi') {}
|
75
|
-
R.rules.size.should == 3
|
76
|
-
R.rules[0][0][:path].should == 'ghi'
|
77
|
-
R.rules[1][0][:path].should == 'def'
|
78
|
-
R.rules[2][0][:path].should == 'abc'
|
79
|
-
end
|
80
|
-
|
81
|
-
specify "should accept a proc as a rule" do
|
82
|
-
R.reset
|
83
|
-
l1 = proc {}
|
84
|
-
l2 = proc {}
|
85
|
-
R.route(l1, &l2)
|
86
|
-
R.rules.size.should == 1
|
87
|
-
R.rules[0][0].should_be l1
|
88
|
-
R.rules[0][1].should_be l2
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
context "Router.compile_rules" do
|
93
|
-
specify "should compile a respond method for routing requests" do
|
94
|
-
R.reset
|
95
|
-
R.new(StringIO.new).respond.should_be_nil
|
96
|
-
R.rules << [{:t => 'abc'}, proc{:abc}]
|
97
|
-
R.rules << [{:t => 'def'}, proc{:def}]
|
98
|
-
R.default_route {:default}
|
99
|
-
# R.compile_rules - already called by default_route
|
100
|
-
r = R.new(StringIO.new)
|
101
|
-
r.t = 'abc'
|
102
|
-
r.respond.should == :abc
|
103
|
-
r.t = 'def'
|
104
|
-
r.respond.should == :def
|
105
|
-
r.t = ''
|
106
|
-
r.respond.should == :default
|
107
|
-
end
|
108
|
-
|
109
|
-
specify "should allow handlers to give up on a request, and then pass it on." do
|
110
|
-
R.reset
|
111
|
-
R.default_route {:default}
|
112
|
-
R.new(StringIO.new).respond.should == :default
|
113
|
-
R.route('.*') {@path == '/first' ? :first : nil}
|
114
|
-
R.route('.*') {@path == '/second' ? :second : nil}
|
115
|
-
r = R.new(StringIO.new)
|
116
|
-
r.path = '/second'
|
117
|
-
r.respond.should == :second
|
118
|
-
r.path = '/first'
|
119
|
-
r.respond.should == :first
|
120
|
-
r.path = '/other'
|
121
|
-
r.respond.should == :default
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
context "Router.rule_to_statement" do
|
126
|
-
specify "should define procs as methods and construct a test expression" do
|
127
|
-
l1 = proc {}
|
128
|
-
l2 = proc {}
|
129
|
-
R.rule_to_statement(l1, l2).should == "if #{l1.proc_tag} && (r = #{l2.proc_tag}); return r; end\n"
|
130
|
-
r = R.new(StringIO.new)
|
131
|
-
r.should_respond_to l1.proc_tag
|
132
|
-
r.should_respond_to l2.proc_tag
|
133
|
-
end
|
134
|
-
|
135
|
-
specify "should convert hash rule with single key-value to a test expression" do
|
136
|
-
l3 = proc {}
|
137
|
-
s = R.rule_to_statement({:path => '/.*'}, l3)
|
138
|
-
s =~ /^if \(@path =~ ([^\(]*)\)/
|
139
|
-
eval("R::#{$1}").should == /\/.*/
|
140
|
-
r = R.new(StringIO.new)
|
141
|
-
r.should_respond_to l3.proc_tag
|
142
|
-
end
|
143
|
-
|
144
|
-
specify "should convert hash with multiple key-values to an OR test expression" do
|
145
|
-
l4 = proc {}
|
146
|
-
|
147
|
-
s = R.rule_to_statement({:path => '/controller', :host => 'static'}, l4)
|
148
|
-
s.should_match /\(@path\s=~\s([^\)]+)\)/
|
149
|
-
s =~ /\(@path\s=~\s([^\)]+)\)/
|
150
|
-
eval("R::#{$1}").should == /\/controller/
|
151
|
-
s.should_match /\(@host\s=~\s([^\)]+)\)/
|
152
|
-
s =~ /\(@host\s=~\s([^\)]+)\)/
|
153
|
-
eval("R::#{$1}").should == /static/
|
154
|
-
r = R.new(StringIO.new)
|
155
|
-
r.should_respond_to l4.proc_tag
|
156
|
-
end
|
157
|
-
|
158
|
-
specify "should convert hash with Array value to a test expression" do
|
159
|
-
l5 = proc {}
|
160
|
-
s = R.rule_to_statement({:path => ['/x', '/y']}, l5)
|
161
|
-
s =~ /^if\s\(\(@path\s=~\s([^\)]*)\)\|\|\(@path\s=~\s([^\)]*)\)\)/
|
162
|
-
eval("R::#{$1}").should == /\/x/
|
163
|
-
eval("R::#{$2}").should == /\/y/
|
164
|
-
r = R.new(StringIO.new)
|
165
|
-
r.should_respond_to l5.proc_tag
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
context "Router.condition part" do
|
170
|
-
specify "should compile a condition expression with key and value" do
|
171
|
-
s = R.condition_part(:path, 'abc')
|
172
|
-
s.should_match /\(@path\s=~\s(.*)\)$/
|
173
|
-
s =~ /\(@path\s=~\s(.*)\)$/
|
174
|
-
eval("R::#{$1}").should == /abc/
|
175
|
-
end
|
176
|
-
|
177
|
-
specify "should parse parametrized value and compile it into a lambda" do
|
178
|
-
s = R.condition_part(:t, ':action/:id')
|
179
|
-
(s =~ /^\((.*)\)$/).should_not_be_nil
|
180
|
-
tag = $1
|
181
|
-
r = R.new(StringIO.new)
|
182
|
-
r.should_respond_to tag
|
183
|
-
r.parameters = {}
|
184
|
-
r.t = 'abc'
|
185
|
-
r.send(tag).should_be false
|
186
|
-
r.t = 'show/16'
|
187
|
-
r.send(tag).should_be true
|
188
|
-
r.parameters[:action].should == 'show'
|
189
|
-
r.parameters[:id].should == '16'
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
context "Router.define_proc" do
|
194
|
-
specify "should convert a lambda into an instance method" do
|
195
|
-
l1 = proc {1 + 1}
|
196
|
-
tag = R.define_proc(&l1)
|
197
|
-
tag.should_be_a_kind_of Symbol
|
198
|
-
tag.should == l1.proc_tag.to_sym
|
199
|
-
r = R.new(StringIO.new)
|
200
|
-
r.should_respond_to(tag)
|
201
|
-
r.send(tag).should == 2
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
context "Router.cache_constant" do
|
206
|
-
specify "should cache a value as a constant inside the Router namespace" do
|
207
|
-
c = rand(100000)
|
208
|
-
tag = R.cache_constant(c)
|
209
|
-
tag.should_be_a_kind_of String
|
210
|
-
tag.should == c.const_tag
|
211
|
-
eval("R::#{tag}").should == c
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
context "Router.default_route" do
|
216
|
-
specify "should set the default route" do
|
217
|
-
R.default_route {'mau m'}
|
218
|
-
R.new(StringIO.new).default_handler.should == 'mau m'
|
219
|
-
|
220
|
-
R.default_route {654321}
|
221
|
-
R.new(StringIO.new).default_handler.should == 654321
|
222
|
-
end
|
223
|
-
|
224
|
-
specify "should affect the result of routes_defined?" do
|
225
|
-
R.reset
|
226
|
-
R.routes_defined?.should_be_nil
|
227
|
-
R.default_route {654321}
|
228
|
-
R.routes_defined?.should_not_be_nil
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
context "Router.unhandled" do
|
233
|
-
specify "should send a 403 response" do
|
234
|
-
r = R.new(StringIO.new)
|
235
|
-
r.unhandled
|
236
|
-
r.socket.rewind
|
237
|
-
resp = r.socket.read
|
238
|
-
resp.should_match /HTTP\/1.1\s403(.*)\r\n/
|
239
|
-
end
|
240
|
-
end
|
data/spec/server_spec.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '../lib/serverside')
|
2
|
-
require 'stringio'
|
3
|
-
require 'fileutils'
|
4
|
-
|
5
|
-
include ServerSide::HTTP
|
6
|
-
|
7
|
-
$http_connection_created = false
|
8
|
-
|
9
|
-
class Connection
|
10
|
-
alias_method :orig_initialize, :initialize
|
11
|
-
def initialize(socket, request_class)
|
12
|
-
orig_initialize(socket, request_class)
|
13
|
-
if (request_class == ServerSide::HTTP::Request) && socket.is_a?(TCPSocket)
|
14
|
-
$http_connection_created = true
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
context "HTTP::Server" do
|
20
|
-
specify "should open TCP port for listening" do
|
21
|
-
server = Server.new('0.0.0.0', 17863, Request)
|
22
|
-
t = Thread.new {server.start}
|
23
|
-
proc {TCPServer.new('0.0.0.0', 17863)}.should_raise Errno::EADDRINUSE
|
24
|
-
t.exit
|
25
|
-
t.alive?.should_be false
|
26
|
-
server.listener.close
|
27
|
-
end
|
28
|
-
|
29
|
-
specify "should loop indefinitely, accepting connections" do
|
30
|
-
$http_connection_created = false
|
31
|
-
server = Server.new('0.0.0.0', 17863, Request)
|
32
|
-
t = Thread.new {server.start}
|
33
|
-
sleep 0.2
|
34
|
-
s = nil
|
35
|
-
proc {s = TCPSocket.new('localhost', 17863)}.should_not_raise
|
36
|
-
sleep 0.2
|
37
|
-
$http_connection_created.should == true
|
38
|
-
server.listener.close
|
39
|
-
end
|
40
|
-
end
|