rack-contrib 1.0.0 → 1.0.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.

Potentially problematic release.


This version of rack-contrib might be problematic. Click here for more details.

@@ -3,7 +3,7 @@ require 'rack'
3
3
  module Rack
4
4
  module Contrib
5
5
  def self.release
6
- "0.9.1"
6
+ "1.0.1"
7
7
  end
8
8
  end
9
9
 
@@ -13,7 +13,6 @@ module Rack
13
13
  autoload :Cookies, "rack/contrib/cookies"
14
14
  autoload :CSSHTTPRequest, "rack/contrib/csshttprequest"
15
15
  autoload :Deflect, "rack/contrib/deflect"
16
- autoload :ETag, "rack/contrib/etag"
17
16
  autoload :ExpectationCascade, "rack/contrib/expectation_cascade"
18
17
  autoload :GarbageCollector, "rack/contrib/garbagecollector"
19
18
  autoload :JSONP, "rack/contrib/jsonp"
@@ -36,5 +35,5 @@ module Rack
36
35
  autoload :NotFound, "rack/contrib/not_found"
37
36
  autoload :ResponseCache, "rack/contrib/response_cache"
38
37
  autoload :RelativeRedirect, "rack/contrib/relative_redirect"
39
- autoload :StaticCache, "rack/contrib/static_cache"
38
+ autoload :StaticCache, "rack/contrib/static_cache"
40
39
  end
@@ -70,7 +70,7 @@ module Rack
70
70
  end
71
71
 
72
72
  def forbidden!
73
- [403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, '']
73
+ [403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, []]
74
74
  end
75
75
 
76
76
  def ip_authorized?(ipmasks)
@@ -63,7 +63,7 @@ module Rack
63
63
  end
64
64
 
65
65
  def deflect!
66
- [403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, '']
66
+ [403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, []]
67
67
  end
68
68
 
69
69
  def deflect? env
@@ -5,36 +5,59 @@ module Rack
5
5
  # Full credit to Flinn Mueller (http://actsasflinn.com/) for this contribution.
6
6
  #
7
7
  class JSONP
8
+ include Rack::Utils
8
9
 
9
10
  def initialize(app)
10
11
  @app = app
11
12
  end
12
13
 
13
14
  # Proxies the request to the application, stripping out the JSON-P callback
14
- # method and padding the response with the appropriate callback format.
15
+ # method and padding the response with the appropriate callback format if
16
+ # the returned body is application/json
15
17
  #
16
18
  # Changes nothing if no <tt>callback</tt> param is specified.
17
19
  #
18
20
  def call(env)
19
21
  status, headers, response = @app.call(env)
22
+
23
+ headers = HeaderHash.new(headers)
20
24
  request = Rack::Request.new(env)
21
- if request.params.include?('callback')
25
+
26
+ if is_json?(headers) && has_callback?(request)
22
27
  response = pad(request.params.delete('callback'), response)
23
- headers['Content-Length'] = response.length.to_s
28
+
29
+ # No longer json, its javascript!
30
+ headers['Content-Type'].gsub!('json', 'javascript')
31
+
32
+ # Set new Content-Length, if it was set before we mutated the response body
33
+ if headers['Content-Length']
34
+ length = response.to_ary.inject(0) { |len, part| len + bytesize(part) }
35
+ headers['Content-Length'] = length.to_s
36
+ end
24
37
  end
25
38
  [status, headers, response]
26
39
  end
40
+
41
+ private
42
+
43
+ def is_json?(headers)
44
+ headers['Content-Type'].include?('application/json')
45
+ end
46
+
47
+ def has_callback?(request)
48
+ request.params.include?('callback')
49
+ end
27
50
 
28
51
  # Pads the response with the appropriate callback format according to the
29
52
  # JSON-P spec/requirements.
30
53
  #
31
- # The Rack response spec indicates that it should be enumerable. The method
32
- # of combining all of the data into a single string makes sense since JSON
33
- # is returned as a full string.
54
+ # The Rack response spec indicates that it should be enumerable. The
55
+ # method of combining all of the data into a single string makes sense
56
+ # since JSON is returned as a full string.
34
57
  #
35
58
  def pad(callback, response, body = "")
36
59
  response.each{ |s| body << s.to_s }
37
- "#{callback}(#{body})"
60
+ ["#{callback}(#{body})"]
38
61
  end
39
62
 
40
63
  end
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
3
3
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
4
 
5
5
  s.name = 'rack-contrib'
6
- s.version = '1.0.0'
7
- s.date = '2010-06-07'
6
+ s.version = '1.0.1'
7
+ s.date = '2010-06-09'
8
8
 
9
9
  s.description = "Contributed Rack Middleware and Utilities"
10
10
  s.summary = "Contributed Rack Middleware and Utilities"
@@ -5,7 +5,7 @@ require 'rack/contrib/access'
5
5
  context "Rack::Access" do
6
6
 
7
7
  setup do
8
- @app = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, 'hello'] }
8
+ @app = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, ['hello']] }
9
9
  @mock_addr_1 = '111.111.111.111'
10
10
  @mock_addr_2 = '192.168.1.222'
11
11
  @mock_addr_localhost = '127.0.0.1'
@@ -24,42 +24,42 @@ context "Rack::Access" do
24
24
  app = middleware
25
25
  status, headers, body = app.call(mock_env(@mock_addr_1))
26
26
  status.should.equal 403
27
- body.should.equal ''
27
+ body.should.equal []
28
28
  end
29
29
 
30
30
  specify "default configuration should allow requests from 127.0.0.1" do
31
31
  app = middleware
32
32
  status, headers, body = app.call(mock_env(@mock_addr_localhost))
33
33
  status.should.equal 200
34
- body.should.equal 'hello'
34
+ body.should.equal ['hello']
35
35
  end
36
36
 
37
37
  specify "should allow remote addresses in allow_ipmasking" do
38
38
  app = middleware('/' => [@mock_addr_1])
39
39
  status, headers, body = app.call(mock_env(@mock_addr_1))
40
40
  status.should.equal 200
41
- body.should.equal 'hello'
41
+ body.should.equal ['hello']
42
42
  end
43
43
 
44
44
  specify "should deny remote addresses not in allow_ipmasks" do
45
45
  app = middleware('/' => [@mock_addr_1])
46
46
  status, headers, body = app.call(mock_env(@mock_addr_2))
47
47
  status.should.equal 403
48
- body.should.equal ''
48
+ body.should.equal []
49
49
  end
50
50
 
51
51
  specify "should allow remote addresses in allow_ipmasks range" do
52
52
  app = middleware('/' => [@mock_addr_range])
53
53
  status, headers, body = app.call(mock_env(@mock_addr_2))
54
54
  status.should.equal 200
55
- body.should.equal 'hello'
55
+ body.should.equal ['hello']
56
56
  end
57
57
 
58
58
  specify "should deny remote addresses not in allow_ipmasks range" do
59
59
  app = middleware('/' => [@mock_addr_range])
60
60
  status, headers, body = app.call(mock_env(@mock_addr_1))
61
61
  status.should.equal 403
62
- body.should.equal ''
62
+ body.should.equal []
63
63
  end
64
64
 
65
65
  specify "should allow remote addresses in one of allow_ipmasking" do
@@ -67,18 +67,18 @@ context "Rack::Access" do
67
67
 
68
68
  status, headers, body = app.call(mock_env(@mock_addr_2))
69
69
  status.should.equal 200
70
- body.should.equal 'hello'
70
+ body.should.equal ['hello']
71
71
 
72
72
  status, headers, body = app.call(mock_env(@mock_addr_localhost))
73
73
  status.should.equal 200
74
- body.should.equal 'hello'
74
+ body.should.equal ['hello']
75
75
  end
76
76
 
77
77
  specify "should deny remote addresses not in one of allow_ipmasks" do
78
78
  app = middleware('/' => [@mock_addr_range, @mock_addr_localhost])
79
79
  status, headers, body = app.call(mock_env(@mock_addr_1))
80
80
  status.should.equal 403
81
- body.should.equal ''
81
+ body.should.equal []
82
82
  end
83
83
 
84
84
  specify "handles paths correctly" do
@@ -90,65 +90,65 @@ context "Rack::Access" do
90
90
 
91
91
  status, headers, body = app.call(mock_env(@mock_addr_1, "/"))
92
92
  status.should.equal 200
93
- body.should.equal 'hello'
93
+ body.should.equal ['hello']
94
94
 
95
95
  status, headers, body = app.call(mock_env(@mock_addr_1, "/qux"))
96
96
  status.should.equal 200
97
- body.should.equal 'hello'
97
+ body.should.equal ['hello']
98
98
 
99
99
  status, headers, body = app.call(mock_env(@mock_addr_1, "/foo"))
100
100
  status.should.equal 403
101
- body.should.equal ''
101
+ body.should.equal []
102
102
  status, headers, body = app.call(mock_env(@mock_addr_localhost, "/foo"))
103
103
  status.should.equal 200
104
- body.should.equal 'hello'
104
+ body.should.equal ['hello']
105
105
 
106
106
  status, headers, body = app.call(mock_env(@mock_addr_1, "/foo/"))
107
107
  status.should.equal 403
108
- body.should.equal ''
108
+ body.should.equal []
109
109
  status, headers, body = app.call(mock_env(@mock_addr_localhost, "/foo/"))
110
110
  status.should.equal 200
111
- body.should.equal 'hello'
111
+ body.should.equal ['hello']
112
112
 
113
113
  status, headers, body = app.call(mock_env(@mock_addr_1, "/foo/bar"))
114
114
  status.should.equal 403
115
- body.should.equal ''
115
+ body.should.equal []
116
116
  status, headers, body = app.call(mock_env(@mock_addr_localhost, "/foo/bar"))
117
117
  status.should.equal 200
118
- body.should.equal 'hello'
118
+ body.should.equal ['hello']
119
119
  status, headers, body = app.call(mock_env(@mock_addr_2, "/foo/bar"))
120
120
  status.should.equal 200
121
- body.should.equal 'hello'
121
+ body.should.equal ['hello']
122
122
 
123
123
  status, headers, body = app.call(mock_env(@mock_addr_1, "/foo/bar/"))
124
124
  status.should.equal 403
125
- body.should.equal ''
125
+ body.should.equal []
126
126
  status, headers, body = app.call(mock_env(@mock_addr_localhost, "/foo/bar/"))
127
127
  status.should.equal 200
128
- body.should.equal 'hello'
128
+ body.should.equal ['hello']
129
129
 
130
130
  status, headers, body = app.call(mock_env(@mock_addr_1, "/foo///bar//quux"))
131
131
  status.should.equal 403
132
- body.should.equal ''
132
+ body.should.equal []
133
133
  status, headers, body = app.call(mock_env(@mock_addr_localhost, "/foo///bar//quux"))
134
134
  status.should.equal 200
135
- body.should.equal 'hello'
135
+ body.should.equal ['hello']
136
136
 
137
137
  status, headers, body = app.call(mock_env(@mock_addr_1, "/foo/quux"))
138
138
  status.should.equal 403
139
- body.should.equal ''
139
+ body.should.equal []
140
140
  status, headers, body = app.call(mock_env(@mock_addr_localhost, "/foo/quux"))
141
141
  status.should.equal 200
142
- body.should.equal 'hello'
142
+ body.should.equal ['hello']
143
143
 
144
144
  status, headers, body = app.call(mock_env(@mock_addr_1, "/bar"))
145
145
  status.should.equal 200
146
- body.should.equal 'hello'
146
+ body.should.equal ['hello']
147
147
  status, headers, body = app.call(mock_env(@mock_addr_1, "/bar").merge('HTTP_HOST' => 'foo.org'))
148
148
  status.should.equal 403
149
- body.should.equal ''
149
+ body.should.equal []
150
150
  status, headers, body = app.call(mock_env(@mock_addr_localhost, "/bar").merge('HTTP_HOST' => 'foo.org'))
151
151
  status.should.equal 200
152
- body.should.equal 'hello'
152
+ body.should.equal ['hello']
153
153
  end
154
154
  end
@@ -5,7 +5,7 @@ require 'rack/contrib/deflect'
5
5
  context "Rack::Deflect" do
6
6
 
7
7
  setup do
8
- @app = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, 'cookies'] }
8
+ @app = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, ['cookies']] }
9
9
  @mock_addr_1 = '111.111.111.111'
10
10
  @mock_addr_2 = '222.222.222.222'
11
11
  @mock_addr_3 = '333.333.333.333'
@@ -23,7 +23,7 @@ context "Rack::Deflect" do
23
23
  app = mock_deflect
24
24
  status, headers, body = app.call mock_env(@mock_addr_1)
25
25
  status.should.equal 200
26
- body.should.equal 'cookies'
26
+ body.should.equal ['cookies']
27
27
  end
28
28
 
29
29
  specify "should deflect requests exceeding the request threshold" do
@@ -35,14 +35,14 @@ context "Rack::Deflect" do
35
35
  5.times do
36
36
  status, headers, body = app.call env
37
37
  status.should.equal 200
38
- body.should.equal 'cookies'
38
+ body.should.equal ['cookies']
39
39
  end
40
40
 
41
41
  # Remaining requests should fail for 10 seconds
42
42
  10.times do
43
43
  status, headers, body = app.call env
44
44
  status.should.equal 403
45
- body.should.equal ''
45
+ body.should.equal []
46
46
  end
47
47
 
48
48
  # Log should reflect that we have blocked an address
@@ -58,13 +58,13 @@ context "Rack::Deflect" do
58
58
  5.times do
59
59
  status, headers, body = app.call env
60
60
  status.should.equal 200
61
- body.should.equal 'cookies'
61
+ body.should.equal ['cookies']
62
62
  end
63
63
 
64
64
  # Exceeds request threshold
65
65
  status, headers, body = app.call env
66
66
  status.should.equal 403
67
- body.should.equal ''
67
+ body.should.equal []
68
68
 
69
69
  # Allow block to expire
70
70
  sleep 3
@@ -73,7 +73,7 @@ context "Rack::Deflect" do
73
73
  5.times do
74
74
  status, headers, body = app.call env
75
75
  status.should.equal 200
76
- body.should.equal 'cookies'
76
+ body.should.equal ['cookies']
77
77
  end
78
78
 
79
79
  # Log should reflect block and release
@@ -88,7 +88,7 @@ context "Rack::Deflect" do
88
88
  10.times do
89
89
  status, headers, body = app.call env
90
90
  status.should.equal 200
91
- body.should.equal 'cookies'
91
+ body.should.equal ['cookies']
92
92
  end
93
93
  end
94
94
 
@@ -97,11 +97,11 @@ context "Rack::Deflect" do
97
97
 
98
98
  status, headers, body = app.call mock_env(@mock_addr_1)
99
99
  status.should.equal 200
100
- body.should.equal 'cookies'
100
+ body.should.equal ['cookies']
101
101
 
102
102
  status, headers, body = app.call mock_env(@mock_addr_2)
103
103
  status.should.equal 403
104
- body.should.equal ''
104
+ body.should.equal []
105
105
  end
106
106
 
107
107
  end
@@ -5,30 +5,69 @@ require 'rack/contrib/jsonp'
5
5
  context "Rack::JSONP" do
6
6
 
7
7
  context "when a callback parameter is provided" do
8
- specify "should wrap the response body in the Javascript callback" do
8
+ specify "should wrap the response body in the Javascript callback if JSON" do
9
+ test_body = '{"bar":"foo"}'
10
+ callback = 'foo'
11
+ app = lambda { |env| [200, {'Content-Type' => 'application/json'}, [test_body]] }
12
+ request = Rack::MockRequest.env_for("/", :params => "foo=bar&callback=#{callback}")
13
+ body = Rack::JSONP.new(app).call(request).last
14
+ body.should.equal ["#{callback}(#{test_body})"]
15
+ end
16
+
17
+ specify "should not wrap the response body in a callback if body is not JSON" do
9
18
  test_body = '{"bar":"foo"}'
10
19
  callback = 'foo'
11
20
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, [test_body]] }
12
21
  request = Rack::MockRequest.env_for("/", :params => "foo=bar&callback=#{callback}")
13
22
  body = Rack::JSONP.new(app).call(request).last
14
- body.should.equal "#{callback}(#{test_body})"
23
+ body.should.equal ['{"bar":"foo"}']
15
24
  end
25
+
26
+ specify "should update content length if it was set" do
27
+ test_body = '{"bar":"foo"}'
28
+ callback = 'foo'
29
+ app = lambda { |env| [200, {'Content-Type' => 'application/json', 'Content-Length' => test_body.length}, [test_body]] }
30
+ request = Rack::MockRequest.env_for("/", :params => "foo=bar&callback=#{callback}")
16
31
 
17
- specify "should modify the content length to the correct value" do
32
+ headers = Rack::JSONP.new(app).call(request)[1]
33
+ expected_length = test_body.length + callback.length + "()".length
34
+ headers['Content-Length'].should.equal(expected_length.to_s)
35
+ end
36
+
37
+ specify "should not touch content length if not set" do
18
38
  test_body = '{"bar":"foo"}'
19
39
  callback = 'foo'
20
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, [test_body]] }
40
+ app = lambda { |env| [200, {'Content-Type' => 'application/json'}, [test_body]] }
21
41
  request = Rack::MockRequest.env_for("/", :params => "foo=bar&callback=#{callback}")
22
42
  headers = Rack::JSONP.new(app).call(request)[1]
23
- headers['Content-Length'].should.equal((test_body.length + callback.length + 2).to_s) # 2 parentheses
43
+ headers['Content-Length'].should.equal nil
24
44
  end
45
+
46
+ specify "should modify the content type to application/javascript" do
47
+ test_body = '{"bar":"foo"}'
48
+ callback = 'foo'
49
+ app = lambda { |env| [200, {'Content-Type' => 'application/json'}, [test_body]] }
50
+ request = Rack::MockRequest.env_for("/", :params => "foo=bar&callback=#{callback}")
51
+ headers = Rack::JSONP.new(app).call(request)[1]
52
+ headers['Content-Type'].should.equal('application/javascript')
53
+ end
54
+
25
55
  end
26
56
 
27
57
  specify "should not change anything if no callback param is provided" do
28
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['{"bar":"foo"}']] }
58
+ test_body = ['{"bar":"foo"}']
59
+ app = lambda { |env| [200, {'Content-Type' => 'application/json'}, test_body] }
29
60
  request = Rack::MockRequest.env_for("/", :params => "foo=bar")
30
61
  body = Rack::JSONP.new(app).call(request).last
31
- body.join.should.equal '{"bar":"foo"}'
62
+ body.should.equal test_body
63
+ end
64
+
65
+ specify "should not change anything if it's not a json response" do
66
+ test_body = '<html><body>404 Not Found</body></html>'
67
+ app = lambda { |env| [404, {'Content-Type' => 'text/html'}, [test_body]] }
68
+ request = Rack::MockRequest.env_for("/", :params => "callback=foo", 'HTTP_ACCEPT' => 'application/json')
69
+ body = Rack::JSONP.new(app).call(request).last
70
+ body.should.equal [test_body]
32
71
  end
33
72
 
34
- end
73
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 0
8
- - 0
9
- version: 1.0.0
8
+ - 1
9
+ version: 1.0.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - rack-devel
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-06-07 00:00:00 -07:00
17
+ date: 2010-06-09 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency