restrack 1.6.1 → 1.6.2

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