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