cuba-api 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,5 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'copyright-header', '~> 1.0', :platform => :mri
5
+ gem 'copyright-header', '~> 1.0', :platform => :mri, :group => :copyright
6
6
 
data/README.md CHANGED
@@ -3,7 +3,7 @@ cuba-api
3
3
 
4
4
  * [![Build Status](https://secure.travis-ci.org/mkristian/cuba-api.png)](http://travis-ci.org/mkristian/cuba-api)
5
5
  * [![Dependency Status](https://gemnasium.com/mkristian/cuba-api.png)](https://gemnasium.com/mkristian/cuba-api)
6
- * [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/mkristian/cuba-api)
6
+ * [![Code Climate](https://codeclimate.com/github/mkristian/cuba-api.png)](https://codeclimate.com/github/mkristian/cuba-api)
7
7
 
8
8
  these are just a handful for [cuba](https://github.com/soveran/cuba) to use cuba as API server.
9
9
 
@@ -12,7 +12,7 @@ security
12
12
 
13
13
  cuba-api installs the **safe_yaml** gem and will use it when you accept yaml input. installing **safe_yaml** is a bit invasiv, but better be on the safe side of things.
14
14
 
15
- cuba\_-api/config.rb
15
+ cuba\_api/config.rb
16
16
  ------------------
17
17
 
18
18
  this plugin adds configuration to cuba which inherits from its superclass. this is very similar to `Cuba.settings`.
@@ -52,6 +52,53 @@ some helper methods to manage a current_user n the session. needs a session-mana
52
52
  def from_session( session_data ) User.find_by_id( hash_data ); end
53
53
  end
54
54
 
55
+ cuba\_api/cors.rb
56
+ --------------------------
57
+
58
+ setup CORS for you cuba, i.e.
59
+
60
+ Cuba.plugin CubaApi::Config
61
+ Cuba.plugin CubaApi::Cors
62
+ # optinal
63
+ Cuba.cors_setup do |cors|
64
+ cors.max_age = 123 # default: 86400
65
+ cors.methods = :put # default: all methods
66
+ cors.headers = 'x-requested-with' # default: all headers
67
+ cors.origins = 'http://middleearth' # default: all origins
68
+ cors.expose = 'x-requested-with' # default: nil
69
+ end
70
+
71
+ that setup works fine with composition, i.e. each component has their own config and inherits from the parent component.
72
+
73
+ there a two variations of the "on" block one that takes an extra first argument for the method(s), i.e.
74
+
75
+ on_cors_method [:post, :get], 'office/:me' do |me|
76
+ on post do
77
+ res.write "#{me} posted"
78
+ end
79
+ end
80
+
81
+ on_cors_method :delete, 'something' do
82
+ res.write "delete something"
83
+ end
84
+
85
+ the method symbol get 'translated' into the checks for method like ```get```, ```post```, etc. when an CORS options request comes in the it will be answered with the respective 'Access-Control-' headers. especially the 'Access-Control-Allowed-Methods' is set appropriately.
86
+
87
+ the second "on" block is less fine controlled
88
+
89
+ on_cors 'path/to/:who' do |who|
90
+ on post do
91
+ res.write "post from #{who}"
92
+ end
93
+ end
94
+
95
+ on_cors do
96
+ on put do
97
+ res.write "put answered"
98
+ end
99
+ end
100
+
101
+ here the 'Access-Control-Allowed-Methods' is set with the default from the ```cors_setup```.
55
102
 
56
103
  cuba\_api/guard.rb
57
104
  --------------------------
@@ -69,7 +116,7 @@ simple authorization which assumes a user belongs to many groups and group has a
69
116
  Pending
70
117
  -------
71
118
 
72
- request payload needs to parse from json, yaml or xml into a hash.
119
+ improve guard
73
120
 
74
121
  Contributing
75
122
  ------------
@@ -0,0 +1,189 @@
1
+ class CORS
2
+
3
+ DEFAULT_METHODS = [ 'GET', 'HEAD', 'POST', 'PUT', 'DELETE' ]
4
+
5
+ def initialize( options, &block )
6
+ @options = options
7
+ # only for inspect
8
+ @config = options.config
9
+ # set default max_ago
10
+ self.max_age = 60 * 60 * 24 # one day
11
+ block.call self if block
12
+ end
13
+
14
+ def config
15
+ @config
16
+ end
17
+
18
+ def method_missing( method, *args )
19
+ m = method.to_s
20
+ if m.match /^_/
21
+ if m =~ /=$/
22
+ @options[ "cors_#{m[1..-2]}".to_sym ] = args.flatten
23
+ else
24
+ @options[ "cors_#{m[1..-1]}".to_sym ]
25
+ end
26
+ else
27
+ super
28
+ end
29
+ end
30
+
31
+ def max_age=( max )
32
+ @options[ :cors_max_age ] = max
33
+ end
34
+
35
+ def expose=( expose )
36
+ self._expose = expose
37
+ end
38
+
39
+ def origins=( *origins )
40
+ self._origins = [ origins ].flatten
41
+ end
42
+
43
+ def origins( domain )
44
+ origins = self._origins
45
+ if origins == [ '*' ] || origins.nil? || origins.member?( domain )
46
+ domain
47
+ end
48
+ end
49
+
50
+ def methods=( *methods )
51
+ self._methods = [ methods ].flatten.collect{ |h| h.to_s.upcase }
52
+ end
53
+
54
+ def methods( method, methods = nil )
55
+ methods = methods.collect { |m| m.to_s.upcase } if methods
56
+ if (methods || self._methods || DEFAULT_METHODS).member?( method.to_s.upcase )
57
+ methods || self._methods || DEFAULT_METHODS
58
+ end
59
+ end
60
+
61
+ def allowed?( methods )
62
+ if methods
63
+ methods = methods.collect { |m| m.to_s.upcase }
64
+ ( ( self._methods || DEFAULT_METHODS ) & methods ).size > 0
65
+ else
66
+ true
67
+ end
68
+ end
69
+
70
+ def headers=( *headers )
71
+ self._headers = [ headers ].flatten.collect{ |h| h.to_s.upcase }
72
+ end
73
+
74
+ def headers( headers )
75
+ # return headers as they come in when not configured
76
+ headers = headers.split( /,\s+/ ) if headers
77
+ if self._headers && headers
78
+ given = headers.collect{ |h| h.to_s.upcase }
79
+ # give back the allowed subset of the given headers
80
+ result = given & self._headers
81
+ result = nil if result.empty?
82
+ result
83
+ else
84
+ headers
85
+ end
86
+ end
87
+
88
+ def allow_origin( req, res )
89
+ if orig = origins( req[ 'HTTP_ORIGIN' ] )
90
+ res[ 'Access-Control-Allow-Origin' ] = orig
91
+ end
92
+ end
93
+
94
+ def process( req, res, methods )
95
+ allow_origin( req, res )
96
+ res[ 'Access-Control-Max-Age' ] = _max_age.to_s if _max_age
97
+ if m = methods( req[ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' ], methods )
98
+ res[ 'Access-Control-Allow-Methods' ] = m.join( ', ' )
99
+ end
100
+ if h = headers( req[ 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' ] )
101
+ res[ 'Access-Control-Allow-Headers' ] = h.join( ', ' )
102
+ end
103
+ unless _expose.nil? || _expose.empty?
104
+ res[ 'Access-Control-Expose-Headers' ] = _expose.join( ', ' )
105
+ end
106
+ res.status = 200
107
+ end
108
+ end
109
+
110
+ module CubaApi
111
+ module Cors
112
+ module ClassMethods
113
+
114
+ def cors_setup( &block )
115
+ self[ :cors ] = CORS.new( self, &block )
116
+ end
117
+
118
+ end
119
+
120
+ # # setup cors for in request coming here
121
+ # on_cors do
122
+ # on ...
123
+ # ...
124
+ # end
125
+ # end
126
+
127
+ # # all methods
128
+ # on_cors( 'my_path' ) do
129
+ # on get, 'something' do
130
+ # ...
131
+ # end
132
+ # end
133
+
134
+ # # only put method allowed
135
+ # on_cors_method( :put, 'my_path/change_something' ) do
136
+ # on ...
137
+ # ...
138
+ # end
139
+ # end
140
+
141
+ # # only put method allowed
142
+ # on_cors_method( [:post, :put], 'my_path/new' ) do
143
+ # on ...
144
+ # ...
145
+ # end
146
+ # end
147
+
148
+ def on_cors( *args )
149
+ _on_cors( nil, *args ) do |*vars|
150
+ yield( *vars )
151
+ end
152
+ end
153
+
154
+ def on_cors_method( methods, *args )
155
+ methods = [ methods ] unless methods.is_a? Array
156
+ _on_cors( methods, *args ) do |*vars|
157
+ yield( *vars )
158
+ end
159
+ end
160
+
161
+ private
162
+
163
+ def _on_cors( methods = nil, *args )
164
+ cors = ( self.class[ :cors ] ||= CORS.new( self.class ) )
165
+
166
+ if req.options? && cors.allowed?( methods )
167
+ # send the response on option headers
168
+ on *args do
169
+ cors.process( env, res, methods )
170
+ end
171
+ else
172
+ unless methods.nil?
173
+ allowed = methods.detect do |m|
174
+ send m.to_sym
175
+ end
176
+ args.insert( 0, allowed != nil )
177
+ end
178
+ if env[ 'HTTP_ORIGIN' ]
179
+ args.insert( 0, cors.origins( env[ 'HTTP_ORIGIN' ] ) != nil )
180
+ end
181
+ on *args do |*vars|
182
+ cors.allow_origin( env, res )
183
+ yield( *vars )
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
189
+
@@ -0,0 +1,162 @@
1
+ class CORS
2
+
3
+ DEFAULT_METHODS = [ 'GET', 'HEAD', 'POST', 'PUT', 'DELETE' ]
4
+
5
+ def initialize( options, &block )
6
+ @options = options
7
+ # only for inspect
8
+ @config = options.config
9
+ # set default max_ago
10
+ self.max_age = 60 * 60 * 24 # one day
11
+ block.call self if block
12
+ end
13
+
14
+ def config
15
+ @config
16
+ end
17
+
18
+ def method_missing( method, *args )
19
+ m = method.to_s
20
+ if m.match /^_/
21
+ if m =~ /=$/
22
+ @options[ "cors_#{m[1..-2]}".to_sym ] = args.flatten
23
+ else
24
+ @options[ "cors_#{m[1..-1]}".to_sym ]
25
+ end
26
+ else
27
+ super
28
+ end
29
+ end
30
+
31
+ def max_age=( max )
32
+ @options[ :cors_max_age ] = max
33
+ end
34
+
35
+ def exposed=( exposed )
36
+ self._exposed = exposed
37
+ end
38
+
39
+ def origins( domain )
40
+ origins = self._origins
41
+ if origins == [ '*' ] || origins.nil? || origins.member?( domain )
42
+ domain
43
+ end
44
+ end
45
+
46
+ def methods=( *methods )
47
+ self._methods = [ methods ].flatten.collect{ |h| h.to_s.upcase }
48
+ end
49
+
50
+ def methods( method, methods = nil )
51
+ if (methods || self._methods || DEFAULT_METHODS).member?( method.to_s.upcase )
52
+ methods || self._methods || DEFAULT_METHODS
53
+ end
54
+ end
55
+
56
+ def allowed?( methods )
57
+ methods = methods.nil? ? [] : methods.collect { |m| m.to_s.upcase }
58
+ ( ( self._methods || DEFAULT_METHODS ) & ( methods || [] ) ).size > 0
59
+ end
60
+
61
+ def headers=( *headers )
62
+ self._headers = [ headers ].flatten.collect{ |h| h.to_s.upcase }
63
+ end
64
+
65
+ def headers( headers )
66
+ # return headers as they come in when not configured
67
+ headers = headers.split( /,\s+/ ) if headers
68
+ if self._headers
69
+ given = [ headers ].flatten.collect{ |h| h.to_s.upcase }
70
+ # give back the allowed subset of the given headers
71
+ given & self._headers
72
+ else
73
+ headers
74
+ end
75
+ end
76
+
77
+ def allow_origin( req, res )
78
+ if orig = origins( req[ 'HTTP_ORIGIN' ] )
79
+ res[ 'Access-Control-Allow-Origin' ] = orig
80
+ end
81
+ end
82
+
83
+ def process( req, res, methods )
84
+ allow_origin( req, res )
85
+ res[ 'Access-Control-Max-Age' ] = _max_age.to_s if _max_age
86
+ if m = methods( req[ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' ], methods )
87
+ res[ 'Access-Control-Allow-Methods' ] = m.join( ', ' )
88
+ end
89
+ if h = headers( req[ 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' ] )
90
+ res[ 'Access-Control-Allow-Headers' ] = h.join( ', ' )
91
+ end
92
+ unless _expose.nil? || _expose.empty?
93
+ res[ 'Access-Control-Expose-Headers' ] = _expose.join( ', ' )
94
+ end
95
+ res.status = 200
96
+ end
97
+ end
98
+
99
+ module CubaApi
100
+ module Cors
101
+ module ClassMethods
102
+
103
+ def cors_setup( &block )
104
+ self[ :cors ] = CORS.new( self, &block )
105
+ end
106
+
107
+ end
108
+
109
+ # # setup cors for in request coming here
110
+ # on_cors do
111
+ # on ...
112
+ # ...
113
+ # end
114
+ # end
115
+
116
+ # # all methods
117
+ # on_cors( true, 'my_path' ) do
118
+ # on get, 'something' do
119
+ # ...
120
+ # end
121
+ # end
122
+
123
+ # # only put method allowed
124
+ # on_cors( :put, 'my_path/change_something' ) do
125
+ # on ...
126
+ # ...
127
+ # end
128
+ # end
129
+
130
+ def on_cors( methods = nil, *args )
131
+ cors = ( self.class[ :cors ] ||= CORS.new( self.class ) )
132
+ if methods == true || methods.nil?
133
+ methods = nil
134
+ else
135
+ methods = [ methods ] unless methods.is_a? Array
136
+ end
137
+
138
+ if req.options? && ( methods.nil? || cors.allowed?( methods ) )
139
+ # send the response on option headers
140
+ on *args do
141
+ cors.process( env, res, methods )
142
+ end
143
+ else
144
+ if methods.nil?
145
+ # allow all methods
146
+ elsif methods.size == 1
147
+ # restrict to given method
148
+ args.insert( 0, methods.first.to_sym )
149
+ else
150
+ # restrict to given methods
151
+ args.insert( 0, cors.allowed?( methods ) )
152
+ end
153
+
154
+ on *args do |*vars|
155
+ cors.allow_origin( env, res )
156
+ yield( *vars )
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+
@@ -0,0 +1,16 @@
1
+ module CubaApi
2
+ class NoSessionRack
3
+ def initialize( app, *not_pattern )
4
+ @app = app
5
+ @reg_exp = /^\/#{not_pattern.join( ',^\/' )}/
6
+ end
7
+
8
+ def call( env )
9
+ status, headers, resp = @app.call( env )
10
+ if not( env[ 'PATH_INFO' ] =~ @regexp )
11
+ headers.delete( 'Set-Cookie' )
12
+ end
13
+ [ status, headers, resp ]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module CubaApi
2
+ class NoSessionRack
3
+ def initialize( app, regexp )
4
+ @app = app
5
+ @regexp = regexp
6
+ end
7
+
8
+ def call( env )
9
+ status, headers, resp = @app.call( env )
10
+ if env[ 'PATH_INFO' ] =~ @regexp
11
+ headers.delete( 'Set-Cookie' )
12
+ end
13
+ [ status, headers, resp ]
14
+ end
15
+ end
16
+ end
@@ -5,6 +5,11 @@ module CubaApi
5
5
  if obj.respond_to?( :errors ) && obj.errors.size > 0
6
6
  res.status = 412 # Precondition Failed
7
7
  obj = obj.errors
8
+ if obj.respond_to? :to_hash
9
+ warn "[CubaApi::ResponseStatus] #{obj.to_hash.values.join( "\n" )}"
10
+ else
11
+ warn "[CubaApi::ResponseStatus] #{obj.inspect}"
12
+ end
8
13
  elsif req.post?
9
14
  res.status = 201 # Created
10
15
  if obj.respond_to?( :id ) && ! res[ 'Location' ]
@@ -34,7 +34,7 @@ module CubaApi
34
34
  if options[:serializer] == false || obj.is_a?( String )
35
35
  obj
36
36
  else
37
- s = self.class.serializer_factory.new_serializer( obj )
37
+ s = options[:serializer] ? options[:serializer].new( obj ) : self.class.serializer_factory.new_serializer( obj )
38
38
  s.use( options[ :use ] ) if options[ :use ]
39
39
  s
40
40
  end
@@ -6,6 +6,16 @@ module CubaApi
6
6
  Proc.new { env[ 'PATH_INFO' ].empty? }
7
7
  end
8
8
 
9
+ # matcher
10
+ def head
11
+ req.head?
12
+ end
13
+
14
+ def option
15
+ req.options?
16
+ end
17
+
18
+ # params
9
19
  def to_float( name, default = nil )
10
20
  v = req[ name ]
11
21
  if v
data/spec/cors_spec.rb ADDED
@@ -0,0 +1,118 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ),
2
+ 'spec_helper.rb' ) )
3
+ require 'cuba_api/config'
4
+ require 'cuba_api/cors'
5
+
6
+ describe CubaApi::Cors do
7
+
8
+ before do
9
+ Cuba.reset!
10
+ Cuba.plugin CubaApi::Config
11
+ Cuba.plugin CubaApi::Cors
12
+ Cuba.define do
13
+
14
+ on_cors 'path/to/:who' do |who|
15
+ on post do
16
+ res.write "post from #{who}"
17
+ end
18
+ end
19
+
20
+ on_cors_method [:post, :get], 'office/:me' do |me|
21
+ on post do
22
+ res.write "#{me} posted"
23
+ end
24
+ end
25
+
26
+ on_cors_method :delete, 'something' do
27
+ res.write "delete something"
28
+ end
29
+
30
+ on_cors_method :delete, 'home/:me' do |me|
31
+ res.write "delete #{me}"
32
+ end
33
+
34
+ on_cors do
35
+ on put do
36
+ res.write "put answered"
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+
43
+ let( :env ) do
44
+ { 'REQUEST_METHOD' => 'OPTIONS',
45
+ 'PATH_INFO' => '/account',
46
+ 'HTTP_ORIGIN' => 'http://middleearth',
47
+ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'PUT',
48
+ 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' => 'x-requested-with'
49
+ }
50
+ end
51
+
52
+ it 'should response with catch section' do
53
+ _, headers, _ = Cuba.call( env )
54
+
55
+ headers[ "Access-Control-Max-Age" ].must.eq "86400"
56
+ headers[ "Access-Control-Allow-Origin" ].must.eq "http://middleearth"
57
+ headers[ "Access-Control-Allow-Methods" ].must.eq "GET, HEAD, POST, PUT, DELETE"
58
+ headers[ "Access-Control-Allow-Headers" ].must.eq 'x-requested-with'
59
+ headers[ "Access-Control-Allow-Expose-Headers" ].must.eq nil
60
+
61
+ env[ 'REQUEST_METHOD' ] = 'PUT'
62
+ _, _, resp = Cuba.call( env )
63
+ resp.join.must.eq 'put answered'
64
+ end
65
+
66
+ it 'should with path/to/:me section' do
67
+ env[ 'PATH_INFO' ] = '/path/to/alf'
68
+ env[ 'SCRIPT_NAME' ] = '/path/to/alf'
69
+
70
+ _, headers, _ = Cuba.call( env )
71
+
72
+ headers[ "Access-Control-Max-Age" ].must.eq "86400"
73
+ headers[ "Access-Control-Allow-Origin" ].must.eq "http://middleearth"
74
+ headers[ "Access-Control-Allow-Methods" ].must.eq "GET, HEAD, POST, PUT, DELETE"
75
+ headers[ "Access-Control-Allow-Headers" ].must.eq 'x-requested-with'
76
+ headers[ "Access-Control-Allow-Expose-Headers" ].must.eq nil
77
+
78
+ env[ 'REQUEST_METHOD' ] = 'POST'
79
+ _, _, resp = Cuba.call( env )
80
+ resp.join.must.eq 'post from alf'
81
+ end
82
+
83
+ it 'should with home/:me section' do
84
+ env[ 'PATH_INFO' ] = '/home/gandalf'
85
+ env[ 'SCRIPT_NAME' ] = '/home/gandalf'
86
+ env[ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' ] = 'DELETE'
87
+
88
+ _, headers, _ = Cuba.call( env )
89
+
90
+ headers[ "Access-Control-Max-Age" ].must.eq "86400"
91
+ headers[ "Access-Control-Allow-Origin" ].must.eq "http://middleearth"
92
+ headers[ "Access-Control-Allow-Methods" ].must.eq "DELETE"
93
+ headers[ "Access-Control-Allow-Headers" ].must.eq 'x-requested-with'
94
+ headers[ "Access-Control-Allow-Expose-Headers" ].must.eq nil
95
+
96
+ env[ 'REQUEST_METHOD' ] = 'DELETE'
97
+ _, _, resp = Cuba.call( env )
98
+ resp.join.must.eq 'delete gandalf'
99
+ end
100
+
101
+ it 'should with office/:me section' do
102
+ env[ 'PATH_INFO' ] = '/office/frodo'
103
+ env[ 'SCRIPT_NAME' ] = '/home/frodo'
104
+ env[ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' ] = 'POST'
105
+
106
+ _, headers, _ = Cuba.call( env )
107
+
108
+ headers[ "Access-Control-Max-Age" ].must.eq "86400"
109
+ headers[ "Access-Control-Allow-Origin" ].must.eq "http://middleearth"
110
+ headers[ "Access-Control-Allow-Methods" ].must.eq "POST, GET"
111
+ headers[ "Access-Control-Allow-Headers" ].must.eq 'x-requested-with'
112
+ headers[ "Access-Control-Allow-Expose-Headers" ].must.eq nil
113
+
114
+ env[ 'REQUEST_METHOD' ] = 'POST'
115
+ _, _, resp = Cuba.call( env )
116
+ resp.join.must.eq 'frodo posted'
117
+ end
118
+ end
@@ -0,0 +1,119 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ),
2
+ 'spec_helper.rb' ) )
3
+ require 'cuba_api/config'
4
+ require 'cuba_api/cors'
5
+
6
+ describe CubaApi::Cors do
7
+
8
+ before do
9
+ Cuba.reset!
10
+ Cuba.plugin CubaApi::Config
11
+ Cuba.plugin CubaApi::Cors
12
+ Cuba.define do
13
+
14
+ on_cors 'path/to/:who' do |who|
15
+ on post do
16
+ res.write "post from #{who}"
17
+ end
18
+ end
19
+
20
+ on_cors_method [:post, :get], 'office/:me' do |me|
21
+ on post do
22
+ res.write "#{me} posted"
23
+ end
24
+ end
25
+
26
+ on_cors_method :delete, 'something' do
27
+ res.write "delete something"
28
+ end
29
+
30
+ on_cors_method :delete, 'home/:me' do |me|
31
+ res.write "delete #{me}"
32
+ end
33
+
34
+ on_cors do
35
+ on put do
36
+ res.write "put answered"
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+
43
+ let( :env ) do
44
+ { 'REQUEST_METHOD' => 'OPTIONS',
45
+ # 'SCRIPT_NAME' => '/account',
46
+ 'PATH_INFO' => '/account',
47
+ 'HTTP_ORIGIN' => 'http://middleearth',
48
+ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'PUT',
49
+ 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' => 'x-requested-with'
50
+ }
51
+ end
52
+
53
+ it 'should response with catch section' do
54
+ _, headers, _ = Cuba.call( env )
55
+
56
+ headers[ "Access-Control-Max-Age" ].must.eq "86400"
57
+ headers[ "Access-Control-Allow-Origin" ].must.eq "http://middleearth"
58
+ headers[ "Access-Control-Allow-Methods" ].must.eq "GET, HEAD, POST, PUT, DELETE"
59
+ headers[ "Access-Control-Allow-Headers" ].must.eq 'x-requested-with'
60
+ headers[ "Access-Control-Allow-Expose-Headers" ].must.eq nil
61
+
62
+ env[ 'REQUEST_METHOD' ] = 'PUT'
63
+ _, _, resp = Cuba.call( env )
64
+ resp.join.must.eq 'put answered'
65
+ end
66
+
67
+ it 'should with path/to/:me section' do
68
+ env[ 'PATH_INFO' ] = '/path/to/alf'
69
+ env[ 'SCRIPT_NAME' ] = '/path/to/alf'
70
+
71
+ _, headers, _ = Cuba.call( env )
72
+
73
+ headers[ "Access-Control-Max-Age" ].must.eq "86400"
74
+ headers[ "Access-Control-Allow-Origin" ].must.eq "http://middleearth"
75
+ headers[ "Access-Control-Allow-Methods" ].must.eq "GET, HEAD, POST, PUT, DELETE"
76
+ headers[ "Access-Control-Allow-Headers" ].must.eq 'x-requested-with'
77
+ headers[ "Access-Control-Allow-Expose-Headers" ].must.eq nil
78
+
79
+ env[ 'REQUEST_METHOD' ] = 'POST'
80
+ _, _, resp = Cuba.call( env )
81
+ resp.join.must.eq 'post from alf'
82
+ end
83
+
84
+ it 'should with home/:me section' do
85
+ env[ 'PATH_INFO' ] = '/home/gandalf'
86
+ env[ 'SCRIPT_NAME' ] = '/home/gandalf'
87
+ env[ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' ] = 'DELETE'
88
+
89
+ _, headers, _ = Cuba.call( env )
90
+
91
+ headers[ "Access-Control-Max-Age" ].must.eq "86400"
92
+ headers[ "Access-Control-Allow-Origin" ].must.eq "http://middleearth"
93
+ headers[ "Access-Control-Allow-Methods" ].must.eq "DELETE"
94
+ headers[ "Access-Control-Allow-Headers" ].must.eq 'x-requested-with'
95
+ headers[ "Access-Control-Allow-Expose-Headers" ].must.eq nil
96
+
97
+ env[ 'REQUEST_METHOD' ] = 'DELETE'
98
+ _, _, resp = Cuba.call( env )
99
+ resp.join.must.eq 'delete gandalf'
100
+ end
101
+
102
+ it 'should with office/:me section' do
103
+ env[ 'PATH_INFO' ] = '/office/frodo'
104
+ env[ 'SCRIPT_NAME' ] = '/home/frodo'
105
+ env[ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' ] = 'POST'
106
+
107
+ _, headers, _ = Cuba.call( env )
108
+
109
+ headers[ "Access-Control-Max-Age" ].must.eq "86400"
110
+ headers[ "Access-Control-Allow-Origin" ].must.eq "http://middleearth"
111
+ headers[ "Access-Control-Allow-Methods" ].must.eq "POST, GET"
112
+ headers[ "Access-Control-Allow-Headers" ].must.eq 'x-requested-with'
113
+ headers[ "Access-Control-Allow-Expose-Headers" ].must.eq nil
114
+
115
+ env[ 'REQUEST_METHOD' ] = 'POST'
116
+ _, _, resp = Cuba.call( env )
117
+ resp.join.must.eq 'frodo posted'
118
+ end
119
+ end
@@ -0,0 +1,77 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ),
2
+ 'spec_helper.rb' ) )
3
+ require 'cuba_api/config'
4
+ require 'cuba_api/cors'
5
+
6
+ describe CubaApi::Cors do
7
+
8
+ before do
9
+ Cuba.reset!
10
+ class ACuba < Cuba
11
+ plugin CubaApi::Config
12
+ plugin CubaApi::Cors
13
+ cors_setup do |cors|
14
+ cors.max_age = 123
15
+ cors.methods = :put
16
+ cors.headers = 'x-requested-with'
17
+ cors.origins = 'http://middleearth'
18
+ cors.expose = 'x-requested-with'
19
+ end
20
+ define do
21
+
22
+ on_cors do
23
+ on put do
24
+ res.write "put answered"
25
+ end
26
+
27
+ on do
28
+ res.status = 404
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+
36
+ let( :env ) do
37
+ { 'REQUEST_METHOD' => 'OPTIONS',
38
+ 'PATH_INFO' => '/account',
39
+ 'HTTP_ORIGIN' => 'http://middleearth',
40
+ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'PUT',
41
+ 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' => 'x-requested-with'
42
+ }
43
+ end
44
+
45
+ it 'should response OK' do
46
+ _, headers, _ = ACuba.call( env )
47
+
48
+ headers[ "Access-Control-Max-Age" ].must.eq "123"
49
+ headers[ "Access-Control-Allow-Origin" ].must.eq "http://middleearth"
50
+ headers[ "Access-Control-Allow-Methods" ].must.eq "PUT"
51
+ headers[ "Access-Control-Allow-Headers" ].must.eq 'X-REQUESTED-WITH'
52
+ headers[ "Access-Control-Expose-Headers" ].must.eq 'x-requested-with'
53
+
54
+ env[ 'REQUEST_METHOD' ] = 'PUT'
55
+ _, _, resp = ACuba.call( env )
56
+ resp.join.must.eq 'put answered'
57
+ end
58
+
59
+ it 'should response FAILED' do
60
+ env[ 'HTTP_ORIGIN' ] = 'http://localhost'
61
+ env[ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' ] = 'POST'
62
+ env[ 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' ] = 'x-timeout'
63
+
64
+ _, headers, _ = ACuba.call( env )
65
+
66
+ headers[ "Access-Control-Max-Age" ].must.eq "123"
67
+ headers[ "Access-Control-Allow-Origin" ].must.eq nil
68
+ headers[ "Access-Control-Allow-Methods" ].must.eq nil
69
+ headers[ "Access-Control-Allow-Headers" ].must.eq nil
70
+ headers[ "Access-Control-Expose-Headers" ].must.eq 'x-requested-with'
71
+
72
+ env[ 'REQUEST_METHOD' ] = 'PUT'
73
+ status, _, _ = ACuba.call( env )
74
+ status.must.eq 404
75
+ end
76
+
77
+ end
@@ -0,0 +1,77 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ),
2
+ 'spec_helper.rb' ) )
3
+ require 'cuba_api/config'
4
+ require 'cuba_api/cors'
5
+
6
+ describe CubaApi::Cors do
7
+
8
+ before do
9
+ Cuba.reset!
10
+ class ACuba < Cuba
11
+ plugin CubaApi::Config
12
+ plugin CubaApi::Cors
13
+ cors_setup do |cors|
14
+ cors.max_age = 123
15
+ cors.methods = :put
16
+ cors.headers = 'x-requested-with'
17
+ cors.origins = 'http://middleearth'
18
+ cors.expose = 'x-requested-with'
19
+ end
20
+ define do
21
+
22
+ on_cors do
23
+ on put do
24
+ res.write "put answered"
25
+ end
26
+
27
+ on do
28
+ res.status = 404
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+
36
+ let( :env ) do
37
+ { 'REQUEST_METHOD' => 'OPTIONS',
38
+ 'PATH_INFO' => '/account',
39
+ 'HTTP_ORIGIN' => 'http://middleearth',
40
+ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'PUT',
41
+ 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' => 'x-requested-with'
42
+ }
43
+ end
44
+
45
+ it 'should response OK' do
46
+ _, headers, _ = ACuba.call( env )
47
+
48
+ headers[ "Access-Control-Max-Age" ].must.eq "123"
49
+ headers[ "Access-Control-Allow-Origin" ].must.eq "http://middleearth"
50
+ headers[ "Access-Control-Allow-Methods" ].must.eq "PUT"
51
+ headers[ "Access-Control-Allow-Headers" ].must.eq 'X-REQUESTED-WITH'
52
+ headers[ "Access-Control-Expose-Headers" ].must.eq 'x-requested-with'
53
+
54
+ env[ 'REQUEST_METHOD' ] = 'PUT'
55
+ _, _, resp = ACuba.call( env )
56
+ resp.join.must.eq 'put answered'
57
+ end
58
+
59
+ it 'should response FAILED' do
60
+ env[ 'HTTP_ORIGIN' ] = 'http://localhost'
61
+ env[ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' ] = 'POST'
62
+ env[ 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' ] = 'x-timeout'
63
+
64
+ _, headers, _ = ACuba.call( env )
65
+
66
+ headers[ "Access-Control-Max-Age" ].must.eq "123"
67
+ headers[ "Access-Control-Allow-Origin" ].must.eq nil
68
+ headers[ "Access-Control-Allow-Methods" ].must.eq nil
69
+ headers[ "Access-Control-Allow-Headers" ].must.eq nil
70
+ headers[ "Access-Control-Expose-Headers" ].must.eq 'x-requested-with'
71
+
72
+ env[ 'REQUEST_METHOD' ] = 'PUT'
73
+ status, _, _ = ACuba.call( env )
74
+ status.must.eq 404
75
+ end
76
+
77
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,8 @@
1
+ # single spec setup
2
+ $LOAD_PATH.unshift File.join( File.dirname( File.expand_path( File.dirname( __FILE__ ) ) ),
3
+ 'lib' )
4
+ require 'minitest/autorun'
5
+
1
6
  require 'cuba'
2
7
  ENV["MT_NO_EXPECTATIONS"] = "true"
3
8
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cuba-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,19 +9,19 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-08 00:00:00.000000000 Z
12
+ date: 2013-09-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cuba
16
16
  version_requirements: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ~>
19
19
  - !ruby/object:Gem::Version
20
20
  version: '3.1'
21
21
  none: false
22
22
  requirement: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.1'
27
27
  none: false
@@ -31,13 +31,13 @@ dependencies:
31
31
  name: ixtlan-babel
32
32
  version_requirements: !ruby/object:Gem::Requirement
33
33
  requirements:
34
- - - "~>"
34
+ - - ~>
35
35
  - !ruby/object:Gem::Version
36
36
  version: '0.4'
37
37
  none: false
38
38
  requirement: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - "~>"
40
+ - - ~>
41
41
  - !ruby/object:Gem::Version
42
42
  version: '0.4'
43
43
  none: false
@@ -47,13 +47,13 @@ dependencies:
47
47
  name: safe_yaml
48
48
  version_requirements: !ruby/object:Gem::Requirement
49
49
  requirements:
50
- - - "~>"
50
+ - - ~>
51
51
  - !ruby/object:Gem::Version
52
52
  version: '0.8'
53
53
  none: false
54
54
  requirement: !ruby/object:Gem::Requirement
55
55
  requirements:
56
- - - "~>"
56
+ - - ~>
57
57
  - !ruby/object:Gem::Version
58
58
  version: '0.8'
59
59
  none: false
@@ -63,13 +63,13 @@ dependencies:
63
63
  name: multi_json
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.6'
69
69
  none: false
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - "~>"
72
+ - - ~>
73
73
  - !ruby/object:Gem::Version
74
74
  version: '1.6'
75
75
  none: false
@@ -79,13 +79,13 @@ dependencies:
79
79
  name: json
80
80
  version_requirements: !ruby/object:Gem::Requirement
81
81
  requirements:
82
- - - "~>"
82
+ - - ~>
83
83
  - !ruby/object:Gem::Version
84
84
  version: '1.6'
85
85
  none: false
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
- - - "~>"
88
+ - - ~>
89
89
  - !ruby/object:Gem::Version
90
90
  version: '1.6'
91
91
  none: false
@@ -95,13 +95,13 @@ dependencies:
95
95
  name: rake
96
96
  version_requirements: !ruby/object:Gem::Requirement
97
97
  requirements:
98
- - - "~>"
98
+ - - ~>
99
99
  - !ruby/object:Gem::Version
100
100
  version: '10.0'
101
101
  none: false
102
102
  requirement: !ruby/object:Gem::Requirement
103
103
  requirements:
104
- - - "~>"
104
+ - - ~>
105
105
  - !ruby/object:Gem::Version
106
106
  version: '10.0'
107
107
  none: false
@@ -111,13 +111,13 @@ dependencies:
111
111
  name: minitest
112
112
  version_requirements: !ruby/object:Gem::Requirement
113
113
  requirements:
114
- - - "~>"
114
+ - - ~>
115
115
  - !ruby/object:Gem::Version
116
116
  version: '4.0'
117
117
  none: false
118
118
  requirement: !ruby/object:Gem::Requirement
119
119
  requirements:
120
- - - "~>"
120
+ - - ~>
121
121
  - !ruby/object:Gem::Version
122
122
  version: '4.0'
123
123
  none: false
@@ -127,13 +127,13 @@ dependencies:
127
127
  name: mustard
128
128
  version_requirements: !ruby/object:Gem::Requirement
129
129
  requirements:
130
- - - "~>"
130
+ - - ~>
131
131
  - !ruby/object:Gem::Version
132
132
  version: '0.1'
133
133
  none: false
134
134
  requirement: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - "~>"
136
+ - - ~>
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0.1'
139
139
  none: false
@@ -143,13 +143,13 @@ dependencies:
143
143
  name: backports
144
144
  version_requirements: !ruby/object:Gem::Requirement
145
145
  requirements:
146
- - - "~>"
146
+ - - ~>
147
147
  - !ruby/object:Gem::Version
148
148
  version: '2.6'
149
149
  none: false
150
150
  requirement: !ruby/object:Gem::Requirement
151
151
  requirements:
152
- - - "~>"
152
+ - - ~>
153
153
  - !ruby/object:Gem::Version
154
154
  version: '2.6'
155
155
  none: false
@@ -164,48 +164,56 @@ extra_rdoc_files: []
164
164
  files:
165
165
  - MIT-LICENSE
166
166
  - README.md
167
- - lib/cuba_api.rb~
168
167
  - lib/cuba_api.rb
169
- - lib/cuba_api/ext2mime_rack.rb~
170
- - lib/cuba_api/guard.rb
171
- - lib/cuba_api/accept_content.rb
172
- - lib/cuba_api/ext2mime_rack.rb
173
- - lib/cuba_api/response_status.rb~
174
- - lib/cuba_api/accept_content.rb~
168
+ - lib/cuba_api.rb~
169
+ - lib/cuba_api/write_aspect.rb~
170
+ - lib/cuba_api/config.rb~
175
171
  - lib/cuba_api/reloader_rack.rb
172
+ - lib/cuba_api/utils.rb
173
+ - lib/cuba_api/cors.rb~
174
+ - lib/cuba_api/input_filter.rb~
175
+ - lib/cuba_api/response_status.rb~
176
+ - lib/cuba_api/reponse_status.rb~
177
+ - lib/cuba_api/write_aspect.rb
176
178
  - lib/cuba_api/write_aspects.rb~
177
- - lib/cuba_api/write_aspect.rb~
178
179
  - lib/cuba_api/serializer.rb~
180
+ - lib/cuba_api/ext2mime_rack.rb~
179
181
  - lib/cuba_api/response_status.rb
180
- - lib/cuba_api/serializer.rb
181
- - lib/cuba_api/write_aspect.rb
182
+ - lib/cuba_api/cors.rb
183
+ - lib/cuba_api/utils.rb~
184
+ - lib/cuba_api/guard.rb
182
185
  - lib/cuba_api/current_user.rb~
183
- - lib/cuba_api/input_filter.rb~
186
+ - lib/cuba_api/config.rb
187
+ - lib/cuba_api/accept_content.rb
188
+ - lib/cuba_api/ext2mime_rack.rb
184
189
  - lib/cuba_api/input_filter.rb
185
- - lib/cuba_api/reponse_status.rb~
186
- - lib/cuba_api/config.rb~
187
- - lib/cuba_api/guard.rb~
190
+ - lib/cuba_api/accept_content.rb~
188
191
  - lib/cuba_api/reloader_rack.rb~
189
- - lib/cuba_api/utils.rb
192
+ - lib/cuba_api/no_session_rack.rb~
193
+ - lib/cuba_api/serializer.rb
194
+ - lib/cuba_api/no_session_rack.rb
195
+ - lib/cuba_api/guard.rb~
190
196
  - lib/cuba_api/current_user.rb
191
- - lib/cuba_api/utils.rb~
192
- - lib/cuba_api/config.rb
193
- - spec/response_status_spec.rb~
197
+ - spec/serializer_spec.rb
198
+ - spec/cors_with_config_spec.rb~
199
+ - spec/accept_spec.rb
194
200
  - spec/current_user_spec.rb
195
- - spec/spec_helper.rb
196
- - spec/response_status_spec.rb
197
201
  - spec/config_spec.rb
198
202
  - spec/input_filter_spec.rb
199
- - spec/current_user_spec.rb~
200
- - spec/aspects_spec.rb~
201
- - spec/aspects_spec.rb
202
- - spec/serializer_spec.rb
203
- - spec/spec_helper.rb~
204
- - spec/input_filter_spec.rb~
205
203
  - spec/serializer_spec.rb~
204
+ - spec/aspects_spec.rb~
206
205
  - spec/accept_spec.rb~
206
+ - spec/cors_with_config_spec.rb
207
+ - spec/spec_helper.rb~
208
+ - spec/response_status_spec.rb
209
+ - spec/spec_helper.rb
210
+ - spec/response_status_spec.rb~
211
+ - spec/cors_spec.rb
212
+ - spec/current_user_spec.rb~
213
+ - spec/aspects_spec.rb
207
214
  - spec/config_spec.rb~
208
- - spec/accept_spec.rb
215
+ - spec/input_filter_spec.rb~
216
+ - spec/cors_spec.rb~
209
217
  - Gemfile
210
218
  homepage: http://github.com/mkristian/cuba-api
211
219
  licenses:
@@ -216,17 +224,15 @@ require_paths:
216
224
  - lib
217
225
  required_ruby_version: !ruby/object:Gem::Requirement
218
226
  requirements:
219
- - - ">="
227
+ - - '>='
220
228
  - !ruby/object:Gem::Version
221
- version: !binary |-
222
- MA==
229
+ version: '0'
223
230
  none: false
224
231
  required_rubygems_version: !ruby/object:Gem::Requirement
225
232
  requirements:
226
- - - ">="
233
+ - - '>='
227
234
  - !ruby/object:Gem::Version
228
- version: !binary |-
229
- MA==
235
+ version: '0'
230
236
  none: false
231
237
  requirements: []
232
238
  rubyforge_project:
@@ -235,10 +241,12 @@ signing_key:
235
241
  specification_version: 3
236
242
  summary: set of plugins for using cuba as API server
237
243
  test_files:
244
+ - spec/serializer_spec.rb
245
+ - spec/accept_spec.rb
238
246
  - spec/current_user_spec.rb
239
- - spec/response_status_spec.rb
240
247
  - spec/config_spec.rb
241
248
  - spec/input_filter_spec.rb
249
+ - spec/cors_with_config_spec.rb
250
+ - spec/response_status_spec.rb
251
+ - spec/cors_spec.rb
242
252
  - spec/aspects_spec.rb
243
- - spec/serializer_spec.rb
244
- - spec/accept_spec.rb