serverside 0.4.1 → 0.4.3

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.
@@ -0,0 +1,287 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ include ServerSide::HTTP
4
+
5
+ context "Response.new" do
6
+ specify "should use a default status of 200 OK" do
7
+ @res = Response.new
8
+ @res.status.should == '200 OK'
9
+ end
10
+
11
+ specify "should extract status from options" do
12
+ @res = Response.new(:status => 'aok')
13
+ @res.status.should == 'aok'
14
+ end
15
+
16
+ specify "should extract body from options" do
17
+ @res = Response.new(:status => 200, :body => 'hello!')
18
+ @res.body.should == 'hello!'
19
+ end
20
+
21
+ specify "should extract headers from options" do
22
+ @res = Response.new(:status => 200, :content_type => 'text/html')
23
+ @res.status.should == 200
24
+ @res.headers.size.should == 1
25
+ @res.headers[0].should == "Content-Type: text/html\r\n"
26
+ end
27
+
28
+ specify "should default body to empty string" do
29
+ @res = Response.new
30
+ @res.body.should == ''
31
+
32
+ @res = Response.new(:body => nil)
33
+ @res.body.should be_nil
34
+ end
35
+ end
36
+
37
+ context "Response.redirect" do
38
+ setup do
39
+ @res = Response.redirect('foobar.html')
40
+ end
41
+
42
+ specify "should default to temporary redirect" do
43
+ @res.status.should == STATUS_FOUND
44
+ end
45
+
46
+ specify "should support custom status" do
47
+ @res = Response.redirect('foobar.html', 'BBQ')
48
+ @res.status.should == 'BBQ'
49
+ end
50
+
51
+ specify "should include a location header with the redirect url" do
52
+ @res.headers.should == ["Location: foobar.html\r\n"]
53
+ end
54
+ end
55
+
56
+ context "Response.static" do
57
+ setup do
58
+ @t = Time.now
59
+ @res = Response.static(__FILE__)
60
+ end
61
+
62
+ specify "should have the file content as the body" do
63
+ @res.body.should == IO.read(__FILE__)
64
+ end
65
+
66
+ specify "should raise not found error for an unknown file" do
67
+ proc {Response.static('xxx_yyy_zzz')}.should raise_error(NotFoundError)
68
+ end
69
+
70
+ specify "should set cache headers correctly" do
71
+ s = @res.to_s
72
+ s.should =~ /\r\nETag: "#{Regexp.quote(File.etag(__FILE__))}"\r\n/
73
+ s.should =~ /\r\nLast-Modified: #{File.mtime(__FILE__).httpdate}\r\n/
74
+ s.should =~ /\r\nExpires: #{(@t + 86400).httpdate}\r\n/
75
+ end
76
+
77
+ specify "should validate the client's cache" do
78
+ 1.should == 1
79
+ end
80
+
81
+ specify "should be able to serve directories" do
82
+ proc {Response.static('.')}.should_not raise_error
83
+ end
84
+ end
85
+
86
+ context "Response.to_s" do
87
+ specify "should render the status correctly" do
88
+ r = Response.new
89
+ s = r.to_s
90
+ s.should =~ /^HTTP\/1.1 200 OK\r\n/
91
+
92
+ r = Response.new(:status => '400 Bad Request')
93
+ s = r.to_s
94
+ s.should =~ /^HTTP\/1.1 400 Bad Request\r\n/
95
+ end
96
+
97
+ specify "should include a Date header" do
98
+ r = Response.new
99
+ s = r.to_s
100
+ s.should =~ /^HTTP\/1.1 200 OK\r\nDate: (.+)\r\n/
101
+
102
+ # extract stamp
103
+ s =~ /^HTTP\/1.1 200 OK\r\nDate: (.+)\r\n/
104
+ proc {Time.parse($1)}.should_not raise_error
105
+ end
106
+
107
+ specify "should include blank line before the body" do
108
+ r = Response.new
109
+ s = r.to_s
110
+ s.should =~ /(.+)\r\n\r\n$/
111
+
112
+ r = Response.new(:body => 'test')
113
+ s = r.to_s
114
+ s.should =~ /(.+)\r\n\r\ntest$/
115
+ end
116
+
117
+ specify "should include a content_length unless body is nil" do
118
+ b = 'a' * (rand(30) + 30)
119
+ r = Response.new(:body => b)
120
+ s = r.to_s
121
+ s.should =~ /Content-Length: #{b.size}\r\n\r\n#{b}$/
122
+
123
+ r = Response.new(:body => nil)
124
+ s = r.to_s
125
+ s.should_not =~ /Content-Length/
126
+ end
127
+
128
+ specify "should not include a content_length if streaming" do
129
+ r = Response.new(:body => 'test')
130
+ r.stream(1) {}
131
+ s = r.to_s
132
+ s.should_not =~ /Content-Length/
133
+ s.should =~ /\r\n\r\ntest$/
134
+ end
135
+
136
+ specify "should include all headers in the response" do
137
+ r = Response.new(:body => nil)
138
+ r.add_header('ABC', 123)
139
+ r.add_header('DEF', 456)
140
+ s = r.to_s
141
+
142
+ s.should =~ /\r\nABC: 123\r\nDEF: 456\r\n\r\n$/
143
+ end
144
+ end
145
+
146
+ context "Response.add_header" do
147
+ setup do
148
+ @res = Response.new
149
+ end
150
+
151
+ specify "should a header to the response's headers" do
152
+ @res.add_header('ABC', '123')
153
+ @res.headers.should == ["ABC: 123\r\n"]
154
+
155
+ @res.add_header('DEF', '456')
156
+ @res.headers.should == ["ABC: 123\r\n", "DEF: 456\r\n"]
157
+ end
158
+
159
+ specify "should be always additive" do
160
+ @res.add_header('ABC', '123')
161
+ @res.add_header('ABC', '456')
162
+ @res.headers.should == ["ABC: 123\r\n", "ABC: 456\r\n"]
163
+ end
164
+ end
165
+
166
+ context "Response.set_cookie" do
167
+ setup do
168
+ @res = Response.new
169
+ end
170
+
171
+ specify "should add a cookie header" do
172
+ t = Time.now + 1000
173
+ @res.set_cookie(:abc, '2 3 4', :expires => t)
174
+ @res.headers.should == ["Set-Cookie: abc=2+3+4; path=/; expires=#{t.httpdate}\r\n"]
175
+ end
176
+
177
+ specify "should accept a path option" do
178
+ t = Time.now + 1000
179
+ @res.set_cookie(:abc, '2 3 4', :path => '/def', :expires => t)
180
+ @res.headers.should == ["Set-Cookie: abc=2+3+4; path=/def; expires=#{t.httpdate}\r\n"]
181
+ end
182
+
183
+ specify "should accept a domain option" do
184
+ t = Time.now + 1000
185
+ @res.set_cookie(:abc, '2 3 4', :domain => 'test.net', :expires => t)
186
+ @res.headers.should == ["Set-Cookie: abc=2+3+4; path=/; expires=#{t.httpdate}; domain=test.net\r\n"]
187
+ end
188
+
189
+ specify "should accept a ttl option" do
190
+ t = Time.now + 1000
191
+ @res.set_cookie(:abc, '2 3 4', :ttl => 1000)
192
+ @res.headers.should == ["Set-Cookie: abc=2+3+4; path=/; expires=#{t.httpdate}\r\n"]
193
+ end
194
+ end
195
+
196
+ context "Response.cache" do
197
+ setup do
198
+ @res = Response.new
199
+ end
200
+
201
+ specify "should support a :cache_control option" do
202
+ @res.cache(:cache_control => 'public')
203
+ @res.headers.should == ["Cache-Control: public\r\n"]
204
+ end
205
+
206
+ specify "should support an :expires option" do
207
+ t = Time.now + 1000
208
+ @res.cache(:expires => t)
209
+ @res.headers.should == ["Expires: #{t.httpdate}\r\n"]
210
+ end
211
+
212
+ specify "should support a :ttl option" do
213
+ t = Time.now + 1000
214
+ @res.cache(:ttl => 1000)
215
+ @res.headers.should == ["Expires: #{t.httpdate}\r\n"]
216
+ end
217
+
218
+ specify "should remove the cache-control header if present" do
219
+ @res.add_header('Cache-Control', 'max-age=300')
220
+ @res.headers.should == ["Cache-Control: max-age=300\r\n"]
221
+ t = Time.now + 1000
222
+ @res.cache(:expires => t)
223
+ @res.headers.should == ["Expires: #{t.httpdate}\r\n"]
224
+ end
225
+ end
226
+
227
+ context "Response.validate_cache" do
228
+ setup do
229
+ @req = Request.new(nil)
230
+ @last_modified = Time.now - 300
231
+ @req.headers['If-None-Match'] = '"abcde"'
232
+ @req.headers['If-Modified-Since'] = @last_modified.httpdate
233
+
234
+ @res = Response.new(:request => @req)
235
+ end
236
+
237
+ specify "should validate against an etag validator" do
238
+ @res.validate_cache(:etag => 'abcde')
239
+ @res.status.should == '304 Not Modified'
240
+ end
241
+
242
+ specify "should validate against a last-modified validator" do
243
+ @res.validate_cache(:last_modified => @last_modified)
244
+ @res.status.should == '304 Not Modified'
245
+ end
246
+
247
+ specify "should yield to the supplied block if the cache is not validated" do
248
+ @res.validate_cache(:etag => 'defgh') do |r|
249
+ r.status = '204'
250
+ r.body = 'hey there hey'
251
+ end
252
+
253
+ @res.status.should == '204'
254
+ @res.body.should == 'hey there hey'
255
+ end
256
+
257
+ specify "should set cache-related headers" do
258
+ t = Time.now + 1000
259
+ @res.validate_cache(:etag => 'defgh', :expires => t) do |r|
260
+ r.status = '204'
261
+ r.body = 'hey there hey'
262
+ end
263
+ s = @res.to_s
264
+ s.should =~ /\r\nETag: "defgh"\r\n/
265
+ s.should =~ /\r\nExpires: #{t.httpdate}\r\n/
266
+
267
+ @res = Response.new(:request => @req)
268
+ t = Time.now + 1000
269
+ @res.validate_cache(:etag => 'defgh', :ttl => 1000) do |r|
270
+ r.status = '204'
271
+ r.body = 'hey there hey'
272
+ end
273
+ s = @res.to_s
274
+ s.should =~ /\r\nETag: "defgh"\r\n/
275
+ s.should =~ /\r\nExpires: #{t.httpdate}\r\n/
276
+
277
+ @res = Response.new(:request => @req)
278
+ t = Time.now
279
+ @res.validate_cache(:last_modified => t, :cache_control => 'private') do |r|
280
+ r.status = '204'
281
+ r.body = 'hey there hey'
282
+ end
283
+ s = @res.to_s
284
+ s.should =~ /\r\nLast-Modified: #{t.httpdate}\r\n/
285
+ s.should =~ /\r\nCache-Control: private\r\n/
286
+ end
287
+ end
@@ -0,0 +1,39 @@
1
+ require File.join(File.dirname(__FILE__), '../lib/serverside')
2
+
3
+ include ServerSide::HTTP
4
+
5
+ class Request
6
+ attr_writer :persistent
7
+ end
8
+
9
+ class SpecHTTPServer
10
+ include Server
11
+
12
+ attr_accessor :in, :state
13
+
14
+ def initialize
15
+ reset
16
+ end
17
+
18
+ def reset
19
+ post_init
20
+ @response = ''
21
+ @response_headers = []
22
+ @closed = false
23
+ end
24
+
25
+ attr_accessor :response, :closed
26
+
27
+ def send_data(data)
28
+ @response << data
29
+ end
30
+
31
+ def close_connection_after_writing
32
+ @closed = true
33
+ end
34
+
35
+ def handle_error(e)
36
+ raise e
37
+ end
38
+ end
39
+
@@ -1,6 +1,4 @@
1
- __END__
2
-
3
- require File.join(File.dirname(__FILE__), '../lib/serverside')
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
4
2
  require 'stringio'
5
3
  require 'fileutils'
6
4
 
@@ -25,20 +23,20 @@ include ServerSide
25
23
  context "ServerSide::Template.set" do
26
24
  specify "should add an consisting of stamp and template to the templates hash" do
27
25
  Template.reset
28
- Template.templates.should_be_empty
26
+ Template.templates.should be_empty
29
27
  t = Time.now
30
28
  Template.set('test', 'hello', t)
31
- Template.templates.include?('test').should_be true
29
+ Template.templates.include?('test').should be_true
32
30
  a = Template.templates['test']
33
- a.should_be_a_kind_of Array
31
+ a.should be_a_kind_of(Array)
34
32
  a.size.should == 2
35
- a.first.should_be t
36
- a.last.should_be_a_kind_of Erubis::Eruby
33
+ a.first.should be(t)
34
+ a.last.should be_a_kind_of(Erubis::Eruby)
37
35
  end
38
36
 
39
37
  specify "should set stamp to nil by default" do
40
38
  Template.set('test', 'hello')
41
- Template.templates['test'].first.should_be_nil
39
+ Template.templates['test'].first.should be_nil
42
40
  end
43
41
 
44
42
  specify "should construct a new Erubis::Eruby instance with the body" do
@@ -50,25 +48,25 @@ end
50
48
  context "ServerSide::Template.validate" do
51
49
  specify "should return nil for a non-existant template" do
52
50
  Template.reset
53
- Template.validate('test').should_be_nil
54
- Template.validate('invalid_file_ref').should_be_nil
51
+ Template.validate('test').should be_nil
52
+ Template.validate('invalid_file_ref').should be_nil
55
53
  end
56
54
 
57
55
  specify "should load a file as template if the name references a file" do
58
56
  Template.reset
59
57
  t = Template.validate(__FILE__)
60
- t.should_be_a_kind_of Erubis::Eruby
58
+ t.should be_a_kind_of(Erubis::Eruby)
61
59
  t.result(binding).should == IO.read(__FILE__)
62
60
  Template.templates.size.should == 1
63
61
  t = Template.templates[__FILE__]
64
62
  t.first.should == File.mtime(__FILE__)
65
- t.last.should_be_a_kind_of Erubis::Eruby
63
+ t.last.should be_a_kind_of(Erubis::Eruby)
66
64
  end
67
65
 
68
66
  specify "should return the Erubis::Eruby instance for an existing template" do
69
67
  Template.reset
70
68
  t = Template.validate(__FILE__)
71
- t.should_be_a_kind_of Erubis::Eruby
69
+ t.should be_a_kind_of(Erubis::Eruby)
72
70
  t.result(binding).should == IO.read(__FILE__)
73
71
  end
74
72
 
@@ -90,15 +88,15 @@ context "ServerSide::Template.validate" do
90
88
  Template.validate('tmp').result(binding).should == '1'
91
89
  Template.templates['tmp'].first.should == File.mtime('tmp')
92
90
  FileUtils.rm('tmp')
93
- Template.validate('tmp').should_be_nil
94
- Template.templates['tmp'].should_be_nil
91
+ Template.validate('tmp').should be_nil
92
+ Template.templates['tmp'].should be_nil
95
93
  end
96
94
  end
97
95
 
98
96
  context "ServerSide::Template.render" do
99
97
  specify "should raise a RuntimeError for an invalid template" do
100
98
  Template.reset
101
- proc {Template.render('invalid', binding)}.should_raise RuntimeError
99
+ proc {Template.render('invalid', binding)}.should raise_error(RuntimeError)
102
100
  end
103
101
 
104
102
  specify "should render an existing ad-hoc template" do
data/spec/xml_spec.rb ADDED
@@ -0,0 +1,75 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "A new XML representation" do
4
+ specify "should work with no arguments" do
5
+ xml = ServerSide::XML.new
6
+ xml.to_s.should == ''
7
+
8
+ xml.abc
9
+ xml.to_s.should == '<abc></abc>'
10
+ end
11
+
12
+ specify "should accept a tag name" do
13
+ xml = ServerSide::XML.new('def')
14
+ xml.to_s.should == '<def></def>'
15
+ end
16
+
17
+ specify "should accept attributes" do
18
+ xml = ServerSide::XML.new('a', :href => '/hello/dolly')
19
+ xml.to_s.should == '<a href="/hello/dolly"></a>'
20
+ end
21
+
22
+ specify "should accept a block and run it" do
23
+ xml = ServerSide::XML.new do |x|
24
+ x.abc do
25
+ x.def 123
26
+ end
27
+ end
28
+ xml.to_s.should == '<abc><def>123</def></abc>'
29
+ end
30
+ end
31
+
32
+ context "XML#instruct!" do
33
+ setup do
34
+ @xml = ServerSide::XML.new
35
+ end
36
+
37
+ specify "should add an XML instruction" do
38
+ @xml.instruct!
39
+ @xml.to_s.should =~ /^\<\?xml(.+)\?\>$/
40
+
41
+ @xml.to_s.should =~ /\s#{'version="1.0"'}/
42
+ @xml.to_s.should =~ /\s#{'encoding="UTF-8"'}/
43
+ end
44
+
45
+ specify "should accept attributes" do
46
+ @xml.instruct!(:something => 'XXX')
47
+ @xml.to_s.should == '<?xml something="XXX"?>'
48
+ end
49
+ end
50
+
51
+ context "XML instance methods" do
52
+ setup do
53
+ @xml = ServerSide::XML.new
54
+ end
55
+
56
+ specify "should escape values" do
57
+ @xml.x "&\"><"
58
+ @xml.to_s.should == "<x>&amp;&quot;&gt;&lt;</x>"
59
+ end
60
+
61
+ specify "should accept attributes" do
62
+ @xml.x({:z => '123'}, '')
63
+ @xml.to_s.should == '<x z="123"></x>'
64
+
65
+ @xml = ServerSide::XML.new
66
+ @xml.x({:z => '123'}, 'yyy')
67
+ @xml.to_s.should == '<x z="123">yyy</x>'
68
+ end
69
+
70
+ specify "should support subtags" do
71
+ h = {:name => 'abc', :category => 'def'}
72
+ @xml.item [:category, :name], h
73
+ @xml.to_s.should == '<item><category>def</category><name>abc</name></item>'
74
+ end
75
+ end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.2
2
+ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: serverside
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.4.1
7
- date: 2007-08-09 00:00:00 +03:00
6
+ version: 0.4.3
7
+ date: 2007-09-16 00:00:00 +03:00
8
8
  summary: Fast Ruby HTTP Server.
9
9
  require_paths:
10
10
  - lib
@@ -33,29 +33,34 @@ files:
33
33
  - README
34
34
  - Rakefile
35
35
  - bin/serverside
36
- - doc/rdoc
37
- - spec/daemon_spec.rb
38
36
  - spec/core_ext_spec.rb
39
- - spec/template_spec.rb
37
+ - spec/daemon_spec.rb
40
38
  - spec/http_spec.rb
39
+ - spec/js_spec.rb
40
+ - spec/request_spec.rb
41
+ - spec/response_spec.rb
42
+ - spec/spec_helper.rb
43
+ - spec/template_spec.rb
44
+ - spec/xml_spec.rb
41
45
  - lib/serverside
46
+ - lib/serverside.rb
47
+ - lib/serverside/cluster.rb
48
+ - lib/serverside/core_ext.rb
49
+ - lib/serverside/daemon.rb
42
50
  - lib/serverside/http
51
+ - lib/serverside/http.rb
52
+ - lib/serverside/js.rb
53
+ - lib/serverside/log.rb
54
+ - lib/serverside/template.rb
55
+ - lib/serverside/xml.rb
43
56
  - lib/serverside/http/caching.rb
44
57
  - lib/serverside/http/const.rb
45
58
  - lib/serverside/http/error.rb
46
59
  - lib/serverside/http/parsing.rb
60
+ - lib/serverside/http/request.rb
47
61
  - lib/serverside/http/response.rb
48
62
  - lib/serverside/http/server.rb
49
63
  - lib/serverside/http/static.rb
50
- - lib/serverside/http.rb
51
- - lib/serverside/xml.rb
52
- - lib/serverside/cluster.rb
53
- - lib/serverside/log.rb
54
- - lib/serverside/daemon.rb
55
- - lib/serverside/core_ext.rb
56
- - lib/serverside/template.rb
57
- - lib/serverside/js.rb
58
- - lib/serverside.rb
59
64
  test_files: []
60
65
 
61
66
  rdoc_options: