restrack 1.6.1 → 1.6.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -128,7 +128,7 @@ which can be accessed separately through @post_params and @get_params.
128
128
 
129
129
 
130
130
  ## URLs and Controller relationships
131
- RESTRack enforces a strict URL pattern through the contruct of controller relationships, rather than a routing file.
131
+ RESTRack enforces a strict URL pattern through the construct of controller relationships, rather than a routing file.
132
132
  Defining a controller for a resource means that you plan to expose that resource to requests to your service.
133
133
  Defining a controller relationship means that you plan to expose a path from this resource to another.
134
134
 
data/README.markdown.html CHANGED
@@ -159,7 +159,7 @@ end
159
159
 
160
160
  <h2>URLs and Controller relationships</h2>
161
161
 
162
- <p>RESTRack enforces a strict URL pattern through the contruct of controller relationships, rather than a routing file.
162
+ <p>RESTRack enforces a strict URL pattern through the construct of controller relationships, rather than a routing file.
163
163
  Defining a controller for a resource means that you plan to expose that resource to requests to your service.
164
164
  Defining a controller relationship means that you plan to expose a path from this resource to another.</p>
165
165
 
@@ -11,6 +11,10 @@ module RESTRack
11
11
  @request_id = opts[:request_id] || get_request_id
12
12
  # Write input details to logs
13
13
  RESTRack.request_log.info "{#{@request_id}} #{@request.request_method} #{@request.path_info} requested from #{@request.ip}"
14
+ @headers = Rack::Utils::HeaderHash.new
15
+ @request.env.select {|k,v| k.start_with? 'HTTP_'}.each do |k,v|
16
+ @headers[k.sub(/^HTTP_/, '')] = v
17
+ end
14
18
  end
15
19
 
16
20
  def prepare
@@ -28,9 +32,15 @@ module RESTRack
28
32
  end
29
33
  # Determine MIME type from extension
30
34
  @mime_type = get_mime_type_from( extension )
31
-
35
+ # Now safe to raise exceptions
32
36
  raise HTTP400BadRequest, "Request path of #{@request.path_info} is invalid" if @request.path_info.include?('//')
33
37
 
38
+ # For CORS support
39
+ if RESTRack::CONFIG[:CORS]
40
+ raise HTTP403Forbidden unless RESTRack::CONFIG[:CORS]['Access-Control-Allow-Origin'] == '*' or RESTRack::CONFIG[:CORS]['Access-Control-Allow-Origin'].include?(@headers['Origin'])
41
+ raise HTTP403Forbidden unless @request.env['REQUEST_METHOD'] == 'OPTIONS' or RESTRack::CONFIG[:CORS]['Access-Control-Allow-Methods'] == '*' or RESTRack::CONFIG[:CORS]['Access-Control-Allow-Methods'].include?(@request.env['REQUEST_METHOD'])
42
+ end
43
+
34
44
  # Pull input data from POST body
35
45
  @post_params = parse_body( @request )
36
46
  @get_params = parse_query_string( @request )
@@ -146,4 +156,4 @@ module RESTRack
146
156
  end
147
157
 
148
158
  end # class ResourceRequest
149
- end # module RESTRack
159
+ end # module RESTRack
@@ -1,14 +1,19 @@
1
1
  module RESTRack
2
2
  class Response
3
- attr_reader :status, :content_type, :body, :mime_type
3
+ attr_reader :status, :content_type, :body, :mime_type, :headers
4
4
 
5
5
  def initialize(request)
6
6
  @request = request
7
7
  begin
8
8
  @request.prepare
9
9
  RESTRack.log.debug "{#{@request.request_id}} Retrieving Output"
10
- @body = @request.active_controller.call
11
- @status = body.blank? ? 204 : 200
10
+ if RESTRack::CONFIG[:CORS] and @request.request.env['REQUEST_METHOD'] == 'OPTIONS'
11
+ @body = ''
12
+ @status = 200
13
+ else
14
+ @body = @request.active_controller.call
15
+ @status = body.blank? ? 204 : 200
16
+ end
12
17
  RESTRack.log.debug "(#{@request.request_id}) HTTP200OK '#{@request.mime_type.to_s}' response data:\n" + @body.inspect
13
18
  RESTRack.request_log.info "(#{@request.request_id}) HTTP200OK"
14
19
  rescue Exception => exception
@@ -55,7 +60,13 @@ module RESTRack
55
60
  end
56
61
 
57
62
  def output
58
- return [status, {'Content-Type' => content_type}, [package(body)] ]
63
+ @headers ||= {}
64
+ @headers['Content-Type'] = content_type
65
+ if RESTRack::CONFIG[:CORS]
66
+ @headers['Access-Control-Allow-Origin'] = RESTRack::CONFIG[:CORS]['Access-Control-Allow-Origin'] if RESTRack::CONFIG[:CORS]['Access-Control-Allow-Origin']
67
+ @headers['Access-Control-Allow-Methods'] = RESTRack::CONFIG[:CORS]['Access-Control-Allow-Methods'] if RESTRack::CONFIG[:CORS]['Access-Control-Allow-Methods']
68
+ end
69
+ return [status, headers, [package(body)] ]
59
70
  end
60
71
 
61
72
  private
@@ -1,3 +1,3 @@
1
1
  module RESTRack
2
- VERSION = "1.6.1"
2
+ VERSION = "1.6.2"
3
3
  end
@@ -28,6 +28,23 @@
28
28
  :SHOW_STACK: true
29
29
 
30
30
  # String#encode will be called when this value is set
31
- #:TRANSCODE: ISO-8859-1 # UTF-8
31
+ #:TRANSCODE: ISO-8859-1 #or UTF-8 etc
32
32
  # String#force_encoding will be called when this value is set
33
- #:FORCE_ENCODING: ISO-8859-1 # UTF-8
33
+ #:FORCE_ENCODING: ISO-8859-1
34
+
35
+ # CORS Header configuration
36
+ # Supported:
37
+ # - Access-Control-Allow-Origin: http://localhost
38
+ # - Access-Control-Allow-Methods: POST, GET
39
+ # List of all:
40
+ # - Access-Control-Allow-Origin: <origin> | *
41
+ # e.g. Access-Control-Allow-Origin: http://mozilla.com
42
+ # - Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
43
+ # - Access-Control-Max-Age: <delta-seconds>
44
+ # - Access-Control-Allow-Credentials: true | false
45
+ # - Access-Control-Allow-Methods: <method>[, <method>]*
46
+ # e.g. Access-Control-Allow-Methods: POST, GET
47
+ # - Access-Control-Allow-Headers: <field-name>[, <field-name>]*
48
+ #:CORS:
49
+ # Access-Control-Allow-Origin: http://restrack.me
50
+ # Access-Control-Allow-Methods: POST, GET
@@ -0,0 +1,91 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'rack/test'
4
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','loader'))
5
+ require 'pp'
6
+
7
+ class SampleApp::TestCORSHeaders < Test::Unit::TestCase
8
+
9
+ def setup
10
+ @ws = SampleApp::WebService.new
11
+ end
12
+
13
+ def test_cors_on_allowed_domain
14
+ RESTRack::CONFIG[:CORS] = {}
15
+ RESTRack::CONFIG[:CORS]['Access-Control-Allow-Origin'] = 'http://restrack.me'
16
+ RESTRack::CONFIG[:CORS]['Access-Control-Allow-Methods'] = 'POST, GET'
17
+ env = Rack::MockRequest.env_for('/foo_bar/144', {
18
+ :method => 'GET',
19
+ 'HTTP_Origin' => 'http://restrack.me'
20
+ })
21
+ output = @ws.call(env)
22
+ expected_status = 200
23
+ expected_headers = {
24
+ "Content-Type" => "application/json",
25
+ "Access-Control-Allow-Origin" => "http://restrack.me",
26
+ "Access-Control-Allow-Methods" => "POST, GET"
27
+ }
28
+ expected_body = { :foo => 'bar', :baz => 123 }.to_json
29
+ assert_equal expected_status, output[0]
30
+ assert_equal expected_headers, output[1]
31
+ assert_equal expected_body, output[2][0]
32
+ end
33
+
34
+ def test_cors_on_disallowed_domain
35
+ RESTRack::CONFIG[:CORS] = {}
36
+ RESTRack::CONFIG[:CORS]['Access-Control-Allow-Origin'] = 'http://restrack.me'
37
+ RESTRack::CONFIG[:CORS]['Access-Control-Allow-Methods'] = 'POST, GET'
38
+ env = Rack::MockRequest.env_for('/foo_bar/144', {
39
+ :method => 'GET',
40
+ 'HTTP_Origin' => 'http://somehacker.net'
41
+ })
42
+ output = @ws.call(env)
43
+ expected_status = 403
44
+ expected_headers = {
45
+ "Content-Type" => "application/json",
46
+ "Access-Control-Allow-Origin" => "http://restrack.me",
47
+ "Access-Control-Allow-Methods" => "POST, GET"
48
+ }
49
+ assert_equal expected_status, output[0]
50
+ assert_equal expected_headers, output[1]
51
+ end
52
+
53
+ def test_cors_on_disallowed_method
54
+ RESTRack::CONFIG[:CORS] = {}
55
+ RESTRack::CONFIG[:CORS]['Access-Control-Allow-Origin'] = 'http://restrack.me'
56
+ RESTRack::CONFIG[:CORS]['Access-Control-Allow-Methods'] = 'POST, GET'
57
+ env = Rack::MockRequest.env_for('/foo_bar/144', {
58
+ :method => 'PUT',
59
+ 'HTTP_Origin' => 'http://restrack.me'
60
+ })
61
+ output = @ws.call(env)
62
+ expected_status = 403
63
+ expected_headers = {
64
+ "Content-Type" => "application/json",
65
+ "Access-Control-Allow-Origin" => "http://restrack.me",
66
+ "Access-Control-Allow-Methods" => "POST, GET"
67
+ }
68
+ assert_equal expected_status, output[0]
69
+ assert_equal expected_headers, output[1]
70
+ end
71
+
72
+ def test_options_request
73
+ RESTRack::CONFIG[:CORS] = {}
74
+ RESTRack::CONFIG[:CORS]['Access-Control-Allow-Origin'] = 'http://restrack.me'
75
+ RESTRack::CONFIG[:CORS]['Access-Control-Allow-Methods'] = 'POST, GET'
76
+ env = Rack::MockRequest.env_for('/foo_bar/144', {
77
+ :method => 'OPTIONS',
78
+ 'HTTP_Origin' => 'http://restrack.me'
79
+ })
80
+ output = @ws.call(env)
81
+ expected_status = 200
82
+ expected_headers = {
83
+ "Content-Type" => "application/json",
84
+ "Access-Control-Allow-Origin" => "http://restrack.me",
85
+ "Access-Control-Allow-Methods" => "POST, GET"
86
+ }
87
+ assert_equal expected_status, output[0]
88
+ assert_equal expected_headers, output[1]
89
+ end
90
+
91
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restrack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: 1.6.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-12 00:00:00.000000000 Z
12
+ date: 2012-08-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -193,6 +193,7 @@ files:
193
193
  - test/sample_app_1/test/test_controller_actions.rb
194
194
  - test/sample_app_1/test/test_controller_inputs.rb
195
195
  - test/sample_app_1/test/test_controller_modifiers.rb
196
+ - test/sample_app_1/test/test_cors_jsonp_support.rb
196
197
  - test/sample_app_1/test/test_errors.rb
197
198
  - test/sample_app_1/test/test_formats.rb
198
199
  - test/sample_app_1/test/test_resource_request.rb