rack-cors 0.1.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.

Potentially problematic release.


This version of rack-cors might be problematic. Click here for more details.

Files changed (4) hide show
  1. data/Rakefile +12 -0
  2. data/VERSION +1 -0
  3. data/lib/rack/cors.rb +130 -0
  4. metadata +64 -0
@@ -0,0 +1,12 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "rack-cors"
5
+ gemspec.summary = "Middleware for enabling Cross-Origin Resource Sharing in Rack apps"
6
+ gemspec.email = "csyu77@gmail.com"
7
+ gemspec.homepage = "http://github.com/cyu/rack-cors"
8
+ gemspec.authors = ["Calvin Yu"]
9
+ end
10
+ rescue LoadError
11
+ puts "Jeweler not available. Install it with: gem install jeweler"
12
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,130 @@
1
+ module Rack
2
+ class Cors
3
+
4
+ def initialize(app)
5
+ @app = app
6
+ yield self if block_given?
7
+ end
8
+
9
+ def allow
10
+ all_resources << (resources = Resources.new)
11
+ yield resources
12
+ end
13
+
14
+ def call(env)
15
+ cors_headers = nil
16
+ if env['HTTP_ORIGIN']
17
+ if env['REQUEST_METHOD'] == 'OPTIONS'
18
+ headers = process_preflight(env)
19
+ return [200, headers, []] if headers
20
+ end
21
+ cors_headers = process_cors(env)
22
+ end
23
+ status, headers, body = @app.call env
24
+ headers = headers.merge(cors_headers) if cors_headers
25
+ [status, headers, body]
26
+ end
27
+
28
+ protected
29
+ def all_resources
30
+ @all_resources ||= []
31
+ end
32
+
33
+ def process_preflight(env)
34
+ resource = find_resource(env['HTTP_ORIGIN'], env['PATH_INFO'])
35
+ resource.to_preflight_headers(env) if resource
36
+ end
37
+
38
+ def process_cors(env)
39
+ resource = find_resource(env['HTTP_ORIGIN'], env['PATH_INFO'])
40
+ resource.to_headers(env) if resource
41
+ end
42
+
43
+ def find_resource(origin, path)
44
+ allowed = all_resources.detect {|r| r.allow_origin?(origin)}
45
+ allowed ? allowed.find_resource(path) : nil
46
+ end
47
+
48
+ class Resources
49
+ def initialize
50
+ @origins = []
51
+ @resources = []
52
+ end
53
+
54
+ def origins(*args)
55
+ @origins = args.flatten.collect{|n| "http://#{n}" unless n.match(/^https?:\/\//)}
56
+ end
57
+
58
+ def resource(path, opts={})
59
+ @resources << Resource.new(path, opts)
60
+ end
61
+
62
+ def allow_origin?(source)
63
+ @origins.include?(source)
64
+ end
65
+
66
+ def find_resource(path)
67
+ @resources.detect{|r| r.match?(path)}
68
+ end
69
+ end
70
+
71
+ class Resource
72
+ attr_accessor :path, :methods, :headers, :max_age, :credentials, :pattern
73
+
74
+ def initialize(path, opts = {})
75
+ self.path = path
76
+ self.methods = ensure_enum(opts[:methods]) || [:get]
77
+ self.credentials = opts[:credentials] || true
78
+ self.headers = ensure_enum(opts[:headers]) || nil
79
+ self.max_age = opts[:max_age] || 1728000
80
+ self.pattern = compile(path)
81
+ end
82
+
83
+ def match?(path)
84
+ pattern =~ path
85
+ end
86
+
87
+ def to_headers(env)
88
+ { 'Access-Control-Allow-Origin' => env['HTTP_ORIGIN'],
89
+ 'Access-Control-Allow-Methods' => methods.collect{|m| m.to_s.upcase}.join(', '),
90
+ 'Access-Control-Allow-Credentials' => credentials.to_s,
91
+ 'Access-Control-Max-Age' => max_age.to_s }
92
+ end
93
+
94
+ def to_preflight_headers(env)
95
+ h = to_headers(env)
96
+ h.merge!('Access-Control-Allow-Headers' => headers.join(', ')) if headers
97
+ h
98
+ end
99
+
100
+ protected
101
+ def ensure_enum(v)
102
+ return nil if v.nil?
103
+ [v] unless v.respond_to?(:join)
104
+ end
105
+
106
+ def compile(path)
107
+ if path.respond_to? :to_str
108
+ special_chars = %w{. + ( )}
109
+ pattern =
110
+ path.to_str.gsub(/((:\w+)|[\*#{special_chars.join}])/) do |match|
111
+ case match
112
+ when "*"
113
+ "(.*?)"
114
+ when *special_chars
115
+ Regexp.escape(match)
116
+ else
117
+ "([^/?&#]+)"
118
+ end
119
+ end
120
+ /^#{pattern}$/
121
+ elsif path.respond_to? :match
122
+ path
123
+ else
124
+ raise TypeError, path
125
+ end
126
+ end
127
+ end
128
+
129
+ end
130
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-cors
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Calvin Yu
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-02 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description:
22
+ email: csyu77@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - Rakefile
31
+ - VERSION
32
+ - lib/rack/cors.rb
33
+ has_rdoc: true
34
+ homepage: http://github.com/cyu/rack-cors
35
+ licenses: []
36
+
37
+ post_install_message:
38
+ rdoc_options:
39
+ - --charset=UTF-8
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ requirements: []
57
+
58
+ rubyforge_project:
59
+ rubygems_version: 1.3.6
60
+ signing_key:
61
+ specification_version: 3
62
+ summary: Middleware for enabling Cross-Origin Resource Sharing in Rack apps
63
+ test_files: []
64
+