serverside 0.2.9 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +56 -0
- data/Rakefile +12 -52
- data/bin/serverside +1 -1
- data/lib/serverside/application.rb +2 -1
- data/lib/serverside/caching.rb +62 -50
- data/lib/serverside/controllers.rb +91 -0
- data/lib/serverside/core_ext.rb +6 -0
- data/lib/serverside/daemon.rb +25 -5
- data/lib/serverside/request.rb +17 -11
- data/lib/serverside/routing.rb +11 -10
- data/lib/serverside/server.rb +14 -6
- data/lib/serverside/static.rb +7 -18
- data/lib/serverside/template.rb +20 -12
- data/spec/caching_spec.rb +318 -0
- data/spec/cluster_spec.rb +140 -0
- data/{test/spec → spec}/connection_spec.rb +4 -4
- data/{test/spec/controller_spec.rb → spec/controllers_spec.rb} +15 -12
- data/{test/spec → spec}/core_ext_spec.rb +23 -18
- data/spec/daemon_spec.rb +99 -0
- data/{test/spec → spec}/request_spec.rb +45 -45
- data/spec/routing_spec.rb +240 -0
- data/spec/server_spec.rb +40 -0
- data/spec/static_spec.rb +279 -0
- data/spec/template_spec.rb +129 -0
- metadata +21 -35
- data/lib/serverside/controller.rb +0 -67
- data/test/functional/primitive_static_server_test.rb +0 -61
- data/test/functional/request_body_test.rb +0 -93
- data/test/functional/routing_server.rb +0 -14
- data/test/functional/routing_server_test.rb +0 -41
- data/test/functional/static_profile.rb +0 -17
- data/test/functional/static_rfuzz.rb +0 -31
- data/test/functional/static_server.rb +0 -7
- data/test/functional/static_server_test.rb +0 -31
- data/test/spec/caching_spec.rb +0 -139
- data/test/test_helper.rb +0 -2
- data/test/unit/cluster_test.rb +0 -129
- data/test/unit/connection_test.rb +0 -48
- data/test/unit/core_ext_test.rb +0 -46
- data/test/unit/daemon_test.rb +0 -75
- data/test/unit/request_test.rb +0 -278
- data/test/unit/routing_test.rb +0 -171
- data/test/unit/server_test.rb +0 -28
- data/test/unit/static_test.rb +0 -171
- data/test/unit/template_test.rb +0 -78
data/spec/server_spec.rb
ADDED
@@ -0,0 +1,40 @@
|
|
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
|
data/spec/static_spec.rb
ADDED
@@ -0,0 +1,279 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../lib/serverside')
|
2
|
+
require 'stringio'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
class Dummy < ServerSide::HTTP::Request
|
6
|
+
def self.mime_types
|
7
|
+
@@mime_types
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :path, :socket, :headers
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
super(nil)
|
14
|
+
@headers = {}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
include ServerSide
|
19
|
+
|
20
|
+
context "Static.mime_types" do
|
21
|
+
specify "should be a hash" do
|
22
|
+
Dummy.mime_types.should_be_a_kind_of Hash
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "should return text/plain as the default mime type" do
|
26
|
+
Dummy.mime_types['.rb'].should == 'text/plain'
|
27
|
+
Dummy.mime_types['.invalid'].should == 'text/plain'
|
28
|
+
end
|
29
|
+
|
30
|
+
specify "should return the correct mime type for common files" do
|
31
|
+
Dummy.mime_types['.html'].should == 'text/html'
|
32
|
+
Dummy.mime_types['.css'].should == 'text/css'
|
33
|
+
Dummy.mime_types['.js'].should == 'text/javascript'
|
34
|
+
Dummy.mime_types['.gif'].should == 'image/gif'
|
35
|
+
Dummy.mime_types['.jpg'].should == 'image/jpeg'
|
36
|
+
Dummy.mime_types['.jpeg'].should == 'image/jpeg'
|
37
|
+
Dummy.mime_types['.png'].should == 'image/png'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "Static.serve_file" do
|
42
|
+
specify "should render correctly with file content, etag and size" do
|
43
|
+
c = Dummy.new
|
44
|
+
c.socket = StringIO.new
|
45
|
+
c.serve_file(__FILE__)
|
46
|
+
c.socket.rewind
|
47
|
+
resp = c.socket.read
|
48
|
+
|
49
|
+
resp.should_match /HTTP\/1.1\s200(.*)\r\n/
|
50
|
+
fc = IO.read(__FILE__)
|
51
|
+
stat = File.stat(__FILE__)
|
52
|
+
etag = (ServerSide::Static::ETAG_FORMAT %
|
53
|
+
[stat.mtime.to_i, stat.size, stat.ino])
|
54
|
+
resp.should_match /ETag:\s"#{etag}"\r\n/
|
55
|
+
resp.should_match /Content-Length:\s#{stat.size.to_s}\r\n/
|
56
|
+
end
|
57
|
+
|
58
|
+
specify "should send a not modified response only if a correct etag is specified in the request" do
|
59
|
+
stat = File.stat(__FILE__)
|
60
|
+
etag = (ServerSide::Static::ETAG_FORMAT %
|
61
|
+
[stat.mtime.to_i, stat.size, stat.ino])
|
62
|
+
|
63
|
+
# normal response
|
64
|
+
c = Dummy.new
|
65
|
+
c.socket = StringIO.new
|
66
|
+
c.serve_file(__FILE__)
|
67
|
+
c.socket.rewind
|
68
|
+
resp = c.socket.read
|
69
|
+
|
70
|
+
resp.should_match /HTTP\/1.1\s200(.*)\r\n/
|
71
|
+
resp.should_match /ETag:\s"#{etag}"\r\n/
|
72
|
+
resp.should_match /Content-Length:\s#{stat.size.to_s}\r\n/
|
73
|
+
|
74
|
+
# normal response (invalid etag)
|
75
|
+
c = Dummy.new
|
76
|
+
c.socket = StringIO.new
|
77
|
+
c.headers['If-None-Match'] = "\"xxx-yyy\""
|
78
|
+
c.serve_file(__FILE__)
|
79
|
+
c.socket.rewind
|
80
|
+
resp = c.socket.read
|
81
|
+
|
82
|
+
resp.should_match /HTTP\/1.1\s200(.*)\r\n/
|
83
|
+
resp.should_match /ETag:\s"#{etag}"\r\n/
|
84
|
+
resp.should_match /Content-Length:\s#{stat.size.to_s}\r\n/
|
85
|
+
|
86
|
+
# not modified (etag specified)
|
87
|
+
c.socket = StringIO.new
|
88
|
+
c.headers['If-None-Match'] = "\"#{etag}\""
|
89
|
+
c.valid_etag?(etag).should_be true
|
90
|
+
c.serve_file(__FILE__)
|
91
|
+
c.socket.rewind
|
92
|
+
resp = c.socket.read
|
93
|
+
|
94
|
+
resp.should_match /HTTP\/1.1\s304(.*)\r\n/
|
95
|
+
|
96
|
+
# modified response (file stamp changed)
|
97
|
+
FileUtils.touch(__FILE__)
|
98
|
+
c.socket = StringIO.new
|
99
|
+
c.headers['If-None-Match'] = etag
|
100
|
+
c.serve_file(__FILE__)
|
101
|
+
c.socket.rewind
|
102
|
+
resp = c.socket.read
|
103
|
+
|
104
|
+
resp.should_match /HTTP\/1.1\s200(.*)\r\n/
|
105
|
+
stat = File.stat(__FILE__)
|
106
|
+
etag = (ServerSide::Static::ETAG_FORMAT %
|
107
|
+
[stat.mtime.to_i, stat.size, stat.ino])
|
108
|
+
resp.should_match /ETag:\s"#{etag}"\r\n/
|
109
|
+
resp.should_match /Content-Length:\s#{stat.size.to_s}\r\n/
|
110
|
+
end
|
111
|
+
|
112
|
+
specify "should serve a 404 response for invalid files" do
|
113
|
+
c = Dummy.new
|
114
|
+
c.socket = StringIO.new
|
115
|
+
c.serve_file('invalid_file.html')
|
116
|
+
c.socket.rewind
|
117
|
+
resp = c.socket.read
|
118
|
+
|
119
|
+
resp.should_match /HTTP\/1.1\s404(.*)\r\n/
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class IO
|
124
|
+
def self.write(fn, content)
|
125
|
+
File.open(fn, 'w') {|f| f << content}
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class ServerSide::Template
|
130
|
+
def self.reset
|
131
|
+
@@templates = {}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
context "Static.serve_template" do
|
137
|
+
specify "should render .rhtml file as template" do
|
138
|
+
IO.write('tmp.rhtml', '<%= @t %>')
|
139
|
+
@t = Time.now.to_f
|
140
|
+
c = Dummy.new
|
141
|
+
c.socket = StringIO.new
|
142
|
+
c.serve_template('tmp.rhtml', binding)
|
143
|
+
c.socket.rewind
|
144
|
+
resp = c.socket.read
|
145
|
+
resp.should.match /\r\n\r\n#{@t}$/
|
146
|
+
FileUtils.rm('tmp.rhtml')
|
147
|
+
end
|
148
|
+
|
149
|
+
specify "should use its own binding when none is specified" do
|
150
|
+
Template.reset
|
151
|
+
IO.write('tmp.rhtml', '<%= @path %>')
|
152
|
+
|
153
|
+
c = Dummy.new
|
154
|
+
c.socket = StringIO.new
|
155
|
+
c.path = '/test/hey'
|
156
|
+
c.serve_template('tmp.rhtml')
|
157
|
+
c.socket.rewind
|
158
|
+
resp = c.socket.read
|
159
|
+
resp.should.match /\r\n\r\n\/test\/hey$/
|
160
|
+
FileUtils.rm('tmp.rhtml')
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context "Static.serve_dir" do
|
165
|
+
specify "should render a directory with all its entries" do
|
166
|
+
dir = File.dirname(__FILE__)
|
167
|
+
|
168
|
+
c = Dummy.new
|
169
|
+
c.socket = StringIO.new
|
170
|
+
c.path = dir
|
171
|
+
c.serve_dir(dir)
|
172
|
+
c.socket.rewind
|
173
|
+
resp = c.socket.read
|
174
|
+
|
175
|
+
Dir.entries(dir).each do |fn|
|
176
|
+
next if fn =~ /^\./
|
177
|
+
resp.should_match /<a href="#{dir/fn}">(#{fn})<\/a>/
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
context "Static.serve_static" do
|
183
|
+
specify "should serve directories" do
|
184
|
+
dir = File.dirname(__FILE__)
|
185
|
+
|
186
|
+
c = Dummy.new
|
187
|
+
c.socket = StringIO.new
|
188
|
+
c.path = dir
|
189
|
+
c.serve_static(dir)
|
190
|
+
c.socket.rewind
|
191
|
+
resp = c.socket.read
|
192
|
+
|
193
|
+
Dir.entries(dir).each do |fn|
|
194
|
+
next if fn =~ /^\./
|
195
|
+
resp.should_match /<a href="#{dir/fn}">(#{fn})<\/a>/
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
specify "should serve files" do
|
200
|
+
c = Dummy.new
|
201
|
+
c.socket = StringIO.new
|
202
|
+
c.serve_static(__FILE__)
|
203
|
+
c.socket.rewind
|
204
|
+
resp = c.socket.read
|
205
|
+
|
206
|
+
# normal response
|
207
|
+
resp.should_match /HTTP\/1.1\s200(.*)\r\n/
|
208
|
+
stat = File.stat(__FILE__)
|
209
|
+
etag = (ServerSide::Static::ETAG_FORMAT %
|
210
|
+
[stat.mtime.to_i, stat.size, stat.ino])
|
211
|
+
resp.should_match /ETag:\s"#{etag}"\r\n/
|
212
|
+
resp.should_match /Content-Length:\s#{stat.size.to_s}\r\n/
|
213
|
+
end
|
214
|
+
|
215
|
+
specify "should serve templates" do
|
216
|
+
Template.reset
|
217
|
+
IO.write('tmp.rhtml', '<%= 1 + 1%>')
|
218
|
+
|
219
|
+
c = Dummy.new
|
220
|
+
c.socket = StringIO.new
|
221
|
+
c.serve_static('tmp.rhtml')
|
222
|
+
c.socket.rewind
|
223
|
+
resp = c.socket.read
|
224
|
+
|
225
|
+
resp.should_match /HTTP\/1.1\s200(.*)\r\n/
|
226
|
+
resp.should_match /\r\n\r\n2$/
|
227
|
+
|
228
|
+
FileUtils.rm('tmp.rhtml')
|
229
|
+
end
|
230
|
+
|
231
|
+
specify "should serve index.html if exists in directory path" do
|
232
|
+
dir = File.dirname(__FILE__)/:tmp_dir
|
233
|
+
FileUtils.mkdir(dir) rescue nil
|
234
|
+
begin
|
235
|
+
IO.write(dir/'index.html', '<h1>HI</h1>')
|
236
|
+
c = Dummy.new
|
237
|
+
c.socket = StringIO.new
|
238
|
+
c.serve_static(dir)
|
239
|
+
c.socket.rewind
|
240
|
+
resp = c.socket.read
|
241
|
+
|
242
|
+
resp.should_match /HTTP\/1.1\s200(.*)\r\n/
|
243
|
+
resp.should_match /\r\n\r\n<h1>HI<\/h1>$/
|
244
|
+
resp.should_match /Content-Type: text\/html/
|
245
|
+
ensure
|
246
|
+
FileUtils.rmtree(dir) rescue nil
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
specify "should serve index.rhtml if exists in directory path" do
|
251
|
+
dir = File.dirname(__FILE__)/:tmp_dir
|
252
|
+
FileUtils.mkdir(dir) rescue puts "dir already exists"
|
253
|
+
begin
|
254
|
+
IO.write(dir/'index.rhtml', '<h1><%= @path %></h1>')
|
255
|
+
c = Dummy.new
|
256
|
+
c.socket = StringIO.new
|
257
|
+
c.path = dir
|
258
|
+
c.serve_static(dir)
|
259
|
+
c.socket.rewind
|
260
|
+
resp = c.socket.read
|
261
|
+
|
262
|
+
resp.should_match /HTTP\/1.1\s200(.*)\r\n/
|
263
|
+
resp.should_match /\r\n\r\n<h1>#{dir}<\/h1>$/
|
264
|
+
resp.should_match /Content-Type: text\/html/
|
265
|
+
ensure
|
266
|
+
FileUtils.rmtree(dir) rescue nil
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
specify "should serve a 404 response for invalid files" do
|
271
|
+
c = Dummy.new
|
272
|
+
c.socket = StringIO.new
|
273
|
+
c.serve_static('invalid_file.html')
|
274
|
+
c.socket.rewind
|
275
|
+
resp = c.socket.read
|
276
|
+
|
277
|
+
resp.should_match /HTTP\/1.1\s404(.*)\r\n/
|
278
|
+
end
|
279
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../lib/serverside')
|
2
|
+
require 'stringio'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
class ServerSide::Template
|
6
|
+
def self.templates
|
7
|
+
@@templates
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.reset
|
11
|
+
@@templates = {}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class IO
|
16
|
+
def self.write(fn, content)
|
17
|
+
File.open(fn, 'w') {|f| f << content}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
include ServerSide
|
22
|
+
|
23
|
+
context "ServerSide::Template.set" do
|
24
|
+
specify "should add an consisting of stamp and template to the templates hash" do
|
25
|
+
Template.reset
|
26
|
+
Template.templates.should_be_empty
|
27
|
+
t = Time.now
|
28
|
+
Template.set('test', 'hello', t)
|
29
|
+
Template.templates.include?('test').should_be true
|
30
|
+
a = Template.templates['test']
|
31
|
+
a.should_be_a_kind_of Array
|
32
|
+
a.size.should == 2
|
33
|
+
a.first.should_be t
|
34
|
+
a.last.should_be_a_kind_of ERB
|
35
|
+
end
|
36
|
+
|
37
|
+
specify "should set stamp to nil by default" do
|
38
|
+
Template.set('test', 'hello')
|
39
|
+
Template.templates['test'].first.should_be_nil
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "should construct a new ERB instance with the body" do
|
43
|
+
Template.set('test', 'yo')
|
44
|
+
Template.templates['test'].last.result(binding).should == 'yo'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "ServerSide::Template.validate" do
|
49
|
+
specify "should return nil for a non-existant template" do
|
50
|
+
Template.reset
|
51
|
+
Template.validate('test').should_be_nil
|
52
|
+
Template.validate('invalid_file_ref').should_be_nil
|
53
|
+
end
|
54
|
+
|
55
|
+
specify "should load a file as template if the name references a file" do
|
56
|
+
Template.reset
|
57
|
+
t = Template.validate(__FILE__)
|
58
|
+
t.should_be_a_kind_of ERB
|
59
|
+
t.result(binding).should == IO.read(__FILE__)
|
60
|
+
Template.templates.size.should == 1
|
61
|
+
t = Template.templates[__FILE__]
|
62
|
+
t.first.should == File.mtime(__FILE__)
|
63
|
+
t.last.should_be_a_kind_of ERB
|
64
|
+
end
|
65
|
+
|
66
|
+
specify "should return the ERB instance for an existing template" do
|
67
|
+
Template.reset
|
68
|
+
t = Template.validate(__FILE__)
|
69
|
+
t.should_be_a_kind_of ERB
|
70
|
+
t.result(binding).should == IO.read(__FILE__)
|
71
|
+
end
|
72
|
+
|
73
|
+
specify "should reload a file if its stamp changed" do
|
74
|
+
Template.reset
|
75
|
+
IO.write('tmp', '1')
|
76
|
+
Template.validate('tmp').result(binding).should == '1'
|
77
|
+
Template.templates['tmp'].first.should == File.mtime('tmp')
|
78
|
+
sleep 1.5
|
79
|
+
IO.write('tmp', '2')
|
80
|
+
Template.validate('tmp').result(binding).should == '2'
|
81
|
+
Template.templates['tmp'].first.should == File.mtime('tmp')
|
82
|
+
FileUtils.rm('tmp')
|
83
|
+
end
|
84
|
+
|
85
|
+
specify "should return nil and clear the cache if a cached file has been deleted" do
|
86
|
+
Template.reset
|
87
|
+
IO.write('tmp', '1')
|
88
|
+
Template.validate('tmp').result(binding).should == '1'
|
89
|
+
Template.templates['tmp'].first.should == File.mtime('tmp')
|
90
|
+
FileUtils.rm('tmp')
|
91
|
+
Template.validate('tmp').should_be_nil
|
92
|
+
Template.templates['tmp'].should_be_nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "ServerSide::Template.render" do
|
97
|
+
specify "should raise a RuntimeError for an invalid template" do
|
98
|
+
Template.reset
|
99
|
+
proc {Template.render('invalid', binding)}.should_raise RuntimeError
|
100
|
+
end
|
101
|
+
|
102
|
+
specify "should render an existing ad-hoc template" do
|
103
|
+
Template.reset
|
104
|
+
Template.set('test', 'hello there')
|
105
|
+
Template.render('test', binding).should == 'hello there'
|
106
|
+
end
|
107
|
+
|
108
|
+
specify "should render a file-based template" do
|
109
|
+
Template.reset
|
110
|
+
Template.render(__FILE__, binding).should == IO.read(__FILE__)
|
111
|
+
end
|
112
|
+
|
113
|
+
specify "should validate a file-based template by checking its stamp" do
|
114
|
+
Template.reset
|
115
|
+
IO.write('tmp', '1')
|
116
|
+
Template.render('tmp', binding).should == '1'
|
117
|
+
sleep 1.5
|
118
|
+
IO.write('tmp', '2')
|
119
|
+
Template.render('tmp', binding).should == '2'
|
120
|
+
FileUtils.rm('tmp')
|
121
|
+
end
|
122
|
+
|
123
|
+
specify "should pass the binding to the ERB instance for processing" do
|
124
|
+
@x = 23
|
125
|
+
Template.reset
|
126
|
+
Template.set('test', '<' + '%= @x %' + '>')
|
127
|
+
Template.render('test', binding).should == '23'
|
128
|
+
end
|
129
|
+
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: serverside
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2006-
|
6
|
+
version: 0.3.0
|
7
|
+
date: 2006-11-27 00:00:00 +02:00
|
8
8
|
summary: Performance-oriented web framework.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -33,46 +33,32 @@ files:
|
|
33
33
|
- README
|
34
34
|
- Rakefile
|
35
35
|
- bin/serverside
|
36
|
-
-
|
37
|
-
-
|
38
|
-
-
|
39
|
-
-
|
40
|
-
-
|
41
|
-
-
|
42
|
-
-
|
43
|
-
-
|
44
|
-
-
|
45
|
-
-
|
46
|
-
-
|
47
|
-
-
|
48
|
-
- test/unit/template_test.rb
|
49
|
-
- test/functional/routing_server.rb
|
50
|
-
- test/functional/static_server.rb
|
51
|
-
- test/functional/primitive_static_server_test.rb
|
52
|
-
- test/functional/request_body_test.rb
|
53
|
-
- test/functional/static_profile.rb
|
54
|
-
- test/functional/static_rfuzz.rb
|
55
|
-
- test/functional/static_server_test.rb
|
56
|
-
- test/functional/routing_server_test.rb
|
57
|
-
- test/spec/controller_spec.rb
|
58
|
-
- test/spec/core_ext_spec.rb
|
59
|
-
- test/spec/request_spec.rb
|
60
|
-
- test/spec/caching_spec.rb
|
61
|
-
- test/spec/connection_spec.rb
|
62
|
-
- lib/serverside
|
36
|
+
- doc/rdoc
|
37
|
+
- spec/core_ext_spec.rb
|
38
|
+
- spec/connection_spec.rb
|
39
|
+
- spec/caching_spec.rb
|
40
|
+
- spec/request_spec.rb
|
41
|
+
- spec/template_spec.rb
|
42
|
+
- spec/static_spec.rb
|
43
|
+
- spec/server_spec.rb
|
44
|
+
- spec/routing_spec.rb
|
45
|
+
- spec/controllers_spec.rb
|
46
|
+
- spec/daemon_spec.rb
|
47
|
+
- spec/cluster_spec.rb
|
63
48
|
- lib/serverside.rb
|
64
|
-
- lib/serverside
|
65
|
-
- lib/serverside/
|
49
|
+
- lib/serverside
|
50
|
+
- lib/serverside/server.rb
|
66
51
|
- lib/serverside/daemon.rb
|
67
52
|
- lib/serverside/application.rb
|
68
|
-
- lib/serverside/
|
69
|
-
- lib/serverside/
|
53
|
+
- lib/serverside/core_ext.rb
|
54
|
+
- lib/serverside/connection.rb
|
55
|
+
- lib/serverside/cluster.rb
|
70
56
|
- lib/serverside/static.rb
|
71
57
|
- lib/serverside/routing.rb
|
72
|
-
- lib/serverside/core_ext.rb
|
73
|
-
- lib/serverside/request.rb
|
74
58
|
- lib/serverside/template.rb
|
59
|
+
- lib/serverside/request.rb
|
75
60
|
- lib/serverside/caching.rb
|
61
|
+
- lib/serverside/controllers.rb
|
76
62
|
- CHANGELOG
|
77
63
|
test_files: []
|
78
64
|
|
@@ -1,67 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'routing')
|
2
|
-
|
3
|
-
module ServerSide
|
4
|
-
class Controller
|
5
|
-
def self.mount(rule = nil, &block)
|
6
|
-
rule ||= block
|
7
|
-
raise ArgumentError, "No routing rule specified." if rule.nil?
|
8
|
-
c = Class.new(self) {}
|
9
|
-
ServerSide::Router.route(rule) {c.new(self)}
|
10
|
-
c
|
11
|
-
end
|
12
|
-
|
13
|
-
def initialize(request)
|
14
|
-
@request = request
|
15
|
-
@path = request.path
|
16
|
-
@parameters = request.parameters
|
17
|
-
process
|
18
|
-
render_default if not @rendered
|
19
|
-
end
|
20
|
-
|
21
|
-
def process
|
22
|
-
end
|
23
|
-
|
24
|
-
def render_default
|
25
|
-
@request.send_response(200, 'text/plain', 'no response.')
|
26
|
-
end
|
27
|
-
|
28
|
-
def render(body, content_type)
|
29
|
-
@request.send_response(200, content_type, body)
|
30
|
-
@rendered = true
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
__END__
|
36
|
-
|
37
|
-
require 'rubygems'
|
38
|
-
require 'active_support/inflector'
|
39
|
-
require 'metaid'
|
40
|
-
|
41
|
-
class ActionController
|
42
|
-
def self.default_routing_rule
|
43
|
-
if name.split('::').last =~ /(.+)Controller$/
|
44
|
-
controller = Inflector.underscore($1)
|
45
|
-
{:path => ["/#{controller}/:action", "/#{controller}/:action/:id"]}
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.inherited(c)
|
50
|
-
routing_rule = c.respond_to?(:routing_rule) ?
|
51
|
-
c.routing_rule : c.default_routing_rule
|
52
|
-
if routing_rule
|
53
|
-
ServerSide::Router.route(routing_rule) {c.new(self)}
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.route(arg = nil, &block)
|
58
|
-
rule = arg || block
|
59
|
-
meta_def(:get_route) {rule}
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
class MyController < ActionController
|
64
|
-
route "hello"
|
65
|
-
end
|
66
|
-
|
67
|
-
p MyController.get_route
|
@@ -1,61 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
-
require 'net/http'
|
3
|
-
|
4
|
-
class StaticServerTest < Test::Unit::TestCase
|
5
|
-
|
6
|
-
class StaticRequest < ServerSide::HTTP::Request
|
7
|
-
def respond
|
8
|
-
begin
|
9
|
-
# set_cookie(:hello, 'world', Time.now + 30) if @cookies[:test] == 'hello'
|
10
|
-
rescue => e
|
11
|
-
puts e.message
|
12
|
-
end
|
13
|
-
status = 200
|
14
|
-
body = IO.read('.'/@path)
|
15
|
-
rescue => e
|
16
|
-
status = 404
|
17
|
-
body = "Couldn't open file #{@path}."
|
18
|
-
ensure
|
19
|
-
send_response(status, 'text', body)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_basic
|
24
|
-
@t = Thread.new {ServerSide::HTTP::Server.new('0.0.0.0', 17654, StaticRequest)}
|
25
|
-
sleep 0.1
|
26
|
-
|
27
|
-
h = Net::HTTP.new('localhost', 17654)
|
28
|
-
resp, data = h.get('/qqq', nil)
|
29
|
-
assert_equal 404, resp.code.to_i
|
30
|
-
assert_equal "Couldn't open file /qqq.", data
|
31
|
-
|
32
|
-
h = Net::HTTP.new('localhost', 17654)
|
33
|
-
resp, data = h.get("/#{__FILE__}", nil)
|
34
|
-
assert_equal 200, resp.code.to_i
|
35
|
-
assert_equal IO.read(__FILE__), data
|
36
|
-
assert_equal 'text', resp['Content-Type']
|
37
|
-
# Net::HTTP includes this header in the request, so our server returns
|
38
|
-
# likewise.
|
39
|
-
assert_equal 'close', resp['Connection']
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_cookies
|
43
|
-
@t = Thread.new {ServerSide::HTTP::Server.new('0.0.0.0', 17655, StaticRequest)}
|
44
|
-
sleep 0.1
|
45
|
-
|
46
|
-
h = Net::HTTP.new('localhost', 17655)
|
47
|
-
resp, data = h.get('/qqq', nil)
|
48
|
-
assert_equal 404, resp.code.to_i
|
49
|
-
assert_nil resp['Set-Cookie']
|
50
|
-
|
51
|
-
h = Net::HTTP.new('localhost', 17655)
|
52
|
-
resp, data = h.get('/qqq', {'Cookie' => 'test=hello'})
|
53
|
-
assert_equal 404, resp.code.to_i
|
54
|
-
assert_not_nil resp['Set-Cookie'] =~ /hello=world/
|
55
|
-
|
56
|
-
h = Net::HTTP.new('localhost', 17655)
|
57
|
-
resp, data = h.get('/qqq', nil)
|
58
|
-
assert_equal 404, resp.code.to_i
|
59
|
-
assert_nil resp['Set-Cookie']
|
60
|
-
end
|
61
|
-
end
|