cuba-api 0.4.0 → 0.5.0

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.
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