rack-contrib 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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