cuba-api 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -7,6 +7,11 @@ 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
 
10
+ security
11
+ --------
12
+
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
+
10
15
  cuba\_-api/config.rb
11
16
  ------------------
12
17
 
@@ -46,26 +46,15 @@ module CubaApi
46
46
  end
47
47
 
48
48
  def accept_content( obj, options = {} )
49
- script = env[ 'SCRIPT_NAME' ]
50
- if script =~ /\./
51
- extension = script.sub( /^.*\./, '' )
52
- mime = ClassMethods::MIMES[ extension.to_sym ] || []
53
- _accept( obj, mime.first )
54
- else
55
- _accept( obj, env[ 'HTTP_ACCEPT' ] )
56
- end
57
- end
58
-
59
- def _accept( obj, mime )
49
+ mime = env[ 'HTTP_ACCEPT' ]
60
50
  if self.class.mimes.key?( mime )
61
51
  res[ "Content-Type" ] = mime + "; charset=utf-8"
62
52
  obj.send self.class[ :mimes ][ mime ]
63
53
  else
64
- head 404
54
+ head :not_found
65
55
  nil
66
56
  end
67
57
  end
68
- private :_accept
69
58
 
70
59
  def self.included( base )
71
60
  base.append_aspect :accept_content
@@ -0,0 +1,19 @@
1
+ module CubaApi
2
+ class Ext2MimeRack
3
+ def initialize( app, *allowed)
4
+ @app = app
5
+ @allowed = allowed
6
+ end
7
+
8
+ def call(env)
9
+ ext = env[ 'PATH_INFO' ].sub( /.*\./, '' )
10
+ if ext && @allowed.member?( ext )
11
+ mime = Rack::Mime.mime_type( '.' + ext )
12
+ env[ 'PATH_INFO_ORIG' ] = env[ 'PATH_INFO' ].dup
13
+ env[ 'HTTP_ACCEPT' ] = mime
14
+ env[ 'PATH_INFO' ].sub!( /\..*/, '' )
15
+ end
16
+ status, headers, body = @app.call(env)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ module CubaApi
2
+ class Ext2MimeRack
3
+ def initialize( app, *allowed)
4
+ @app = app
5
+ @allowed = allowed
6
+ end
7
+
8
+ def call(env)
9
+ ext = env[ 'PATH_INFO' ].sub( /.*\./, '' )
10
+ if ext && @allowed.member?( ext )
11
+ mime = Rack::Mime.mime_type( '.' + ext )
12
+ env[ 'HTTP_ACCEPT' ] = mime
13
+ env[ 'PATH_INFO' ].sub!( /\..*/, '' )
14
+ end
15
+ status, headers, body = @app.call(env)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,50 @@
1
+ module CubaApi
2
+ class Reloader
3
+
4
+ def self.parse( basedir, baseconstant )
5
+ Dir[ File.join( basedir, '**', '*.rb' ) ].each do |f|
6
+ last_modified = File.mtime( f ).to_f
7
+ if ! File.directory?( f ) && last_modified > @max_last_modified.to_f
8
+ @max_last_modified = last_modified
9
+ yield f
10
+ end
11
+ end
12
+ end
13
+
14
+ def self.maybe_remove_constant( f, basedir, baseconstant )
15
+ c = baseconstant
16
+ cname = nil
17
+ f.sub( /#{basedir}/, '' ).split( /\/|\./ ).each do |name|
18
+ if name != 'rb'
19
+ ( c = c.const_get( cname ) ) rescue nil
20
+ cname = name.split('_').each { |a| a.capitalize! }.join.to_sym
21
+ end
22
+ end
23
+ c.send( :remove_const, cname ) rescue nil
24
+ end
25
+
26
+ def self.doit( basedir, baseconstant )
27
+ if @max_last_modified
28
+ parse( basedir, baseconstant ) do |f|
29
+ maybe_remove_constant( f, basedir, baseconstant )
30
+ puts "[CubaAPI::Reloader] #{f}: #{load f}"
31
+ end
32
+ else
33
+ parse( basedir, baseconstant ) {}
34
+ end
35
+ end
36
+ end
37
+
38
+ class ReloaderRack
39
+ def initialize( app, basedir, baseconstant)
40
+ @app = app
41
+ @basedir = basedir
42
+ @baseconstant = baseconstant
43
+ end
44
+
45
+ def call(env)
46
+ Reloader.doit( @basedir, @baseconstant )
47
+ status, headers, body = @app.call(env)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,12 @@
1
+ module CubaApi
2
+ class Ext2MimeRack
3
+ def initialize( app, *allowed)
4
+ @app = app
5
+ @allowed = allowed
6
+ end
7
+
8
+ def call(env)
9
+ status, headers, body = @app.call(env)
10
+ end
11
+ end
12
+ end
@@ -7,7 +7,7 @@ module CubaApi
7
7
  obj = obj.errors
8
8
  elsif req.post?
9
9
  res.status = 201 # Created
10
- if obj.respond_to?( :id )
10
+ if obj.respond_to?( :id ) && ! res[ 'Location' ]
11
11
  res[ 'Location' ] = env[ 'SCRIPT_NAME' ].to_s+ "/#{obj.id}"
12
12
  end
13
13
  elsif req.delete?
@@ -0,0 +1,49 @@
1
+ module CubaApi
2
+ module Utils
3
+
4
+ def to_float( name, default = nil )
5
+ v = req[ name ]
6
+ if v
7
+ v.to_f
8
+ else
9
+ default
10
+ end
11
+ end
12
+
13
+ def to_int( name, default = nil )
14
+ v = req[ name ]
15
+ if v
16
+ v.to_i
17
+ else
18
+ default
19
+ end
20
+ end
21
+
22
+ def offset_n_limit( method, set )
23
+ count = set.count
24
+ offset = to_int( 'offset' ).to_i
25
+ limit = ( to_int( 'count' ) || count ) - 1 + offset
26
+ { method => set[ offset..limit ], :offset => offset, :total_count => count }
27
+ end
28
+
29
+ def last_modified( last )
30
+ res[ 'Last-Modified' ] = last.rfc2822
31
+ end
32
+
33
+ def modified_since
34
+ @modified_since ||=
35
+ if date = env[ 'HTTP_IF_MODIFIED_SINCE' ]
36
+ DateTime.parse( date )
37
+ end
38
+ end
39
+
40
+ def expires_in( minutes )
41
+ now = DateTime.now
42
+ res[ 'Expires' ] = ( now + minutes / 1440.0 ).rfc2822
43
+ end
44
+
45
+ def content_type( mime )
46
+ res[ 'Content-Type' ] = mime if mime
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,42 @@
1
+ module CubaApi
2
+ module Utils
3
+
4
+ def to_float( name, default = nil )
5
+ v = req[ name ]
6
+ if v
7
+ v.to_f
8
+ else
9
+ default
10
+ end
11
+ end
12
+
13
+ def to_int( name, default = nil )
14
+ v = req[ name ]
15
+ if v
16
+ v.to_i
17
+ else
18
+ default
19
+ end
20
+ end
21
+
22
+ def offset_n_limit( method, set )
23
+ count = set.count
24
+ offset = to_int( 'offset' ).to_i
25
+ limit = ( to_int( 'count' ) || count ) - 1 + offset
26
+ { method => set[ offset..limit ], :offset => offset, :total_count => count }
27
+ end
28
+
29
+ def last_modified( last )
30
+ res[ 'Last-Modified' ] = last.rfc2822
31
+ end
32
+
33
+ def expires_in( minutes )
34
+ now = DateTime.now
35
+ res[ 'Expires' ] = ( now + minutes / 1440.0 ).rfc2822
36
+ end
37
+
38
+ def content_type( mime )
39
+ header[ 'Content-Type' ] = mime
40
+ end
41
+ end
42
+ end
@@ -40,8 +40,9 @@ module CubaApi
40
40
  end
41
41
 
42
42
  def head( status )
43
- res.status = status
44
- res.write ''
43
+ res.status = Rack::Utils.status_code( status )
44
+ res.write Rack::Utils::HTTP_STATUS_CODES[ res.status ]
45
+ res['Content-Type' ] = 'text/plain'
45
46
  end
46
47
 
47
48
  def write( obj, options = {} )
data/spec/accept_spec.rb CHANGED
@@ -31,7 +31,7 @@ describe CubaApi::AcceptContent do
31
31
 
32
32
  _, _, resp = Cuba.call({"SCRIPT_NAME" => "/bla.yaml"})
33
33
  resp[ 0 ] = resp[ 0 ].sub(/.*!/, "---!").sub( /\n\n/, "\n")
34
- resp.join.must.eq "---!ruby/object:B {}\n"
34
+ resp.join.must.eq "Not Found"
35
35
 
36
36
  _, _, resp = Cuba.call({"HTTP_ACCEPT" => "application/x-yaml"})
37
37
  resp[ 0 ] = resp[ 0 ].sub(/.*!/, "---!").sub( /\n\n/, "\n")
@@ -53,11 +53,9 @@ describe CubaApi::AcceptContent do
53
53
  it 'gives preference to script extension' do
54
54
  skip("to_yaml add extra line with ...") if defined?( JRUBY_VERSION ) and (( JRUBY_VERSION =~ /^1.6./ ) == 0 ) and ( nil == (RUBY_VERSION =~ /^1.8/) )
55
55
 
56
- _, _, resp = Cuba.call({"SCRIPT_NAME" => "/bla.yaml", "HTTP_ACCEPT" => "application/xml"})
56
+ status, _, resp = Cuba.call({"SCRIPT_NAME" => "/bla.yaml", "HTTP_ACCEPT" => "application/xml"})
57
57
  resp[ 0 ] = resp[ 0 ].sub(/.*!/, "---!").sub( /\n\n/, "\n")
58
- resp.join.must.eq "---!ruby/object:B {}\n"
59
-
60
- status, _, _ = Cuba.call({"SCRIPT_NAME" => "/bla.xml", "HTTP_ACCEPT" => "application/x-yaml"})
58
+ resp.join.must.eq "Not Found"
61
59
  status.must.eq 404
62
60
  end
63
61
  end
data/spec/spec_helper.rb CHANGED
@@ -2,3 +2,20 @@ require 'cuba'
2
2
  ENV["MT_NO_EXPECTATIONS"] = "true"
3
3
 
4
4
  require 'mustard'
5
+
6
+ module Mustard
7
+ class Failure < MiniTest::Assertion
8
+ def initialize( *args )
9
+ super
10
+ begin
11
+ raise
12
+ rescue => e
13
+ @result = e.backtrace.detect { |l| nil == ( l =~ /lib\/mustard/ || l =~ /spec\/spec_helper.rb/ ) }
14
+ end
15
+ end
16
+
17
+ def backtrace
18
+ [@result]
19
+ end
20
+ end
21
+ end
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: cuba-api
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.0
5
+ version: 0.3.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Christian Meier
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-02 00:00:00.000000000 Z
12
+ date: 2013-02-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cuba
@@ -49,13 +49,13 @@ dependencies:
49
49
  requirements:
50
50
  - - "~>"
51
51
  - !ruby/object:Gem::Version
52
- version: '0.5'
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
- version: '0.5'
58
+ version: '0.8'
59
59
  none: false
60
60
  prerelease: false
61
61
  type: :runtime
@@ -166,8 +166,11 @@ files:
166
166
  - README.md
167
167
  - lib/cuba_api.rb
168
168
  - lib/cuba_api.rb~
169
+ - lib/cuba_api/reloader_rack.rb~
169
170
  - lib/cuba_api/input_filter.rb~
170
171
  - lib/cuba_api/write_aspects.rb~
172
+ - lib/cuba_api/ext2mime_rack.rb~
173
+ - lib/cuba_api/utils.rb
171
174
  - lib/cuba_api/guard.rb
172
175
  - lib/cuba_api/serializer.rb~
173
176
  - lib/cuba_api/accept_content.rb~
@@ -182,8 +185,11 @@ files:
182
185
  - lib/cuba_api/guard.rb~
183
186
  - lib/cuba_api/accept_content.rb
184
187
  - lib/cuba_api/config.rb~
188
+ - lib/cuba_api/utils.rb~
189
+ - lib/cuba_api/reloader_rack.rb
185
190
  - lib/cuba_api/serializer.rb
186
191
  - lib/cuba_api/response_status.rb
192
+ - lib/cuba_api/ext2mime_rack.rb
187
193
  - spec/serializer_spec.rb
188
194
  - spec/input_filter_spec.rb~
189
195
  - spec/config_spec.rb~