├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── .rubocop.yml ├── CHANGELOG.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── examples ├── rack │ ├── Gemfile │ ├── Gemfile.lock │ ├── config.ru │ └── public │ │ ├── public │ │ └── static.txt │ │ └── static.txt ├── rails5 │ ├── .gitignore │ ├── .ruby-version │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── Rakefile │ ├── app │ │ ├── assets │ │ │ ├── config │ │ │ │ └── manifest.js │ │ │ ├── images │ │ │ │ └── .keep │ │ │ ├── javascripts │ │ │ │ ├── application.js │ │ │ │ ├── cable.js │ │ │ │ └── channels │ │ │ │ │ └── .keep │ │ │ └── stylesheets │ │ │ │ └── application.css │ │ ├── channels │ │ │ └── application_cable │ │ │ │ ├── channel.rb │ │ │ │ └── connection.rb │ │ ├── controllers │ │ │ ├── application_controller.rb │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ ├── cors_controller.rb │ │ │ └── welcome_controller.rb │ │ ├── helpers │ │ │ └── application_helper.rb │ │ ├── jobs │ │ │ └── application_job.rb │ │ ├── mailers │ │ │ └── application_mailer.rb │ │ ├── models │ │ │ ├── application_record.rb │ │ │ └── concerns │ │ │ │ └── .keep │ │ └── views │ │ │ └── layouts │ │ │ ├── application.html.erb │ │ │ ├── mailer.html.erb │ │ │ └── mailer.text.erb │ ├── bin │ │ ├── bundle │ │ ├── rails │ │ ├── rake │ │ ├── setup │ │ ├── spring │ │ ├── update │ │ └── yarn │ ├── config.ru │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── cable.yml │ │ ├── credentials.yml.enc │ │ ├── database.yml │ │ ├── environment.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers │ │ │ ├── application_controller_renderer.rb │ │ │ ├── assets.rb │ │ │ ├── backtrace_silencers.rb │ │ │ ├── content_security_policy.rb │ │ │ ├── cookies_serializer.rb │ │ │ ├── cors.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ ├── new_framework_defaults_5_2.rb │ │ │ └── wrap_parameters.rb │ │ ├── locales │ │ │ └── en.yml │ │ ├── puma.rb │ │ ├── routes.rb │ │ ├── spring.rb │ │ └── storage.yml │ ├── db │ │ └── seeds.rb │ ├── lib │ │ ├── assets │ │ │ └── .keep │ │ └── tasks │ │ │ └── .keep │ ├── log │ │ └── .keep │ ├── package.json │ ├── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ ├── favicon.ico │ │ ├── robots.txt │ │ └── static.txt │ ├── storage │ │ └── .keep │ ├── test │ │ ├── application_system_test_case.rb │ │ ├── controllers │ │ │ └── .keep │ │ ├── fixtures │ │ │ ├── .keep │ │ │ └── files │ │ │ │ └── .keep │ │ ├── helpers │ │ │ └── .keep │ │ ├── integration │ │ │ └── .keep │ │ ├── mailers │ │ │ └── .keep │ │ ├── models │ │ │ └── .keep │ │ ├── system │ │ │ └── .keep │ │ └── test_helper.rb │ └── vendor │ │ └── .keep └── rails6 │ ├── .browserslistrc │ ├── .gitattributes │ ├── .gitignore │ ├── .ruby-version │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── Rakefile │ ├── app │ ├── assets │ │ ├── config │ │ │ └── manifest.js │ │ ├── images │ │ │ └── .keep │ │ └── stylesheets │ │ │ └── application.css │ ├── channels │ │ └── application_cable │ │ │ ├── channel.rb │ │ │ └── connection.rb │ ├── controllers │ │ ├── application_controller.rb │ │ ├── concerns │ │ │ └── .keep │ │ ├── cors_controller.rb │ │ └── welcome_controller.rb │ ├── helpers │ │ └── application_helper.rb │ ├── javascript │ │ ├── channels │ │ │ ├── consumer.js │ │ │ └── index.js │ │ └── packs │ │ │ └── application.js │ ├── jobs │ │ └── application_job.rb │ ├── mailers │ │ └── application_mailer.rb │ ├── models │ │ ├── application_record.rb │ │ └── concerns │ │ │ └── .keep │ └── views │ │ └── layouts │ │ ├── application.html.erb │ │ ├── mailer.html.erb │ │ └── mailer.text.erb │ ├── babel.config.js │ ├── bin │ ├── bundle │ ├── rails │ ├── rake │ ├── setup │ ├── spring │ ├── webpack │ ├── webpack-dev-server │ └── yarn │ ├── config.ru │ ├── config │ ├── application.rb │ ├── boot.rb │ ├── cable.yml │ ├── credentials.yml.enc │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── application_controller_renderer.rb │ │ ├── assets.rb │ │ ├── backtrace_silencers.rb │ │ ├── content_security_policy.rb │ │ ├── cookies_serializer.rb │ │ ├── cors.rb │ │ ├── filter_parameter_logging.rb │ │ ├── inflections.rb │ │ ├── mime_types.rb │ │ ├── permissions_policy.rb │ │ └── wrap_parameters.rb │ ├── locales │ │ └── en.yml │ ├── puma.rb │ ├── routes.rb │ ├── spring.rb │ ├── storage.yml │ ├── webpack │ │ ├── development.js │ │ ├── environment.js │ │ ├── production.js │ │ └── test.js │ └── webpacker.yml │ ├── db │ └── seeds.rb │ ├── lib │ ├── assets │ │ └── .keep │ └── tasks │ │ └── .keep │ ├── log │ └── .keep │ ├── package.json │ ├── postcss.config.js │ ├── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ ├── apple-touch-icon-precomposed.png │ ├── apple-touch-icon.png │ ├── favicon.ico │ ├── robots.txt │ └── static.txt │ ├── storage │ └── .keep │ ├── test │ ├── application_system_test_case.rb │ ├── channels │ │ └── application_cable │ │ │ └── connection_test.rb │ ├── controllers │ │ └── .keep │ ├── fixtures │ │ └── files │ │ │ └── .keep │ ├── helpers │ │ └── .keep │ ├── integration │ │ └── .keep │ ├── mailers │ │ └── .keep │ ├── models │ │ └── .keep │ ├── system │ │ └── .keep │ └── test_helper.rb │ ├── vendor │ └── .keep │ └── yarn.lock ├── lib └── rack │ ├── cors.rb │ └── cors │ ├── resource.rb │ ├── resources.rb │ ├── resources │ └── cors_misconfiguration_error.rb │ ├── result.rb │ └── version.rb ├── rack-cors.gemspec └── test ├── .rubocop.yml ├── cors ├── expect.js ├── mocha.css ├── mocha.js ├── runner.html ├── test.cors.coffee └── test.cors.js └── unit ├── cors_test.rb ├── dsl_test.rb ├── insecure.ru ├── non_http.ru └── test.ru /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | test: 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | ruby: 13 | - "2.4" 14 | - "2.5" 15 | - "2.6" 16 | - "2.7" 17 | - "3.0" 18 | - "3.1" 19 | - "3.2" 20 | - "3.3" 21 | - "3.4" 22 | - truffleruby-head 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v3 26 | - uses: ruby/setup-ruby@v1 27 | with: 28 | ruby-version: ${{ matrix.ruby }} 29 | bundler-cache: true 30 | - run: bundle exec rake test 31 | 32 | rubocop: 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@v3 36 | - uses: ruby/setup-ruby@v1 37 | with: 38 | ruby-version: 3.2.1 39 | bundler-cache: true 40 | - run: bundle exec rubocop 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .idea 6 | .yardoc 7 | /Gemfile.lock 8 | InstalledFiles 9 | _yardoc 10 | coverage 11 | doc/ 12 | lib/bundler/man 13 | pkg 14 | rdoc 15 | spec/reports 16 | test/tmp 17 | test/version_tmp 18 | tmp 19 | 20 | *.swp 21 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | AllCops: 3 | Exclude: 4 | - "examples/**/*" 5 | - "vendor/**/*" 6 | 7 | # Disables 8 | Layout/LineLength: 9 | Enabled: false 10 | Style/Documentation: 11 | Enabled: false 12 | Metrics/ClassLength: 13 | Enabled: false 14 | Metrics/MethodLength: 15 | Enabled: false 16 | Metrics/BlockLength: 17 | Enabled: false 18 | Style/HashEachMethods: 19 | Enabled: false 20 | Style/HashTransformKeys: 21 | Enabled: false 22 | Style/HashTransformValues: 23 | Enabled: false 24 | Style/DoubleNegation: 25 | Enabled: false 26 | Metrics/CyclomaticComplexity: 27 | Enabled: false 28 | Metrics/PerceivedComplexity: 29 | Enabled: false 30 | Metrics/AbcSize: 31 | Enabled: false 32 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | ## 3.0.0 - 2025-05-16 5 | ### Changed 6 | - Update Rack dependency to >= 3.0.14 7 | - Remove support for Ruby 2.3 8 | - Add logger as explicit dependency 9 | 10 | ## 2.0.2 - 2024-03-04 11 | ### Changed 12 | - Fix file permission issues with 2.0.1 release 13 | - Security: Fixes CVE-2024-27456, GHSA-785g-282q-pwvx 14 | 15 | ## 2.0.1 - 2023-02-17 16 | ### Changed 17 | - Use Rack::Utils::HeaderHash when Rack 2.x is detected 18 | 19 | ## 2.0.0 - 2023-02-14 20 | ### Changed 21 | - Refactored codebase 22 | - Support declaring custom protocols in origin 23 | - Lowercased header names as defined by Rack spec 24 | - Fix issue with duplicate headers because of header name case 25 | 26 | ## 1.1.1 - 2019-12-29 27 | ### Changed 28 | - Allow //* to match // and / paths 29 | 30 | ## 1.1.0 - 2019-11-19 31 | ### Changed 32 | - Use Rack::Utils.escape_path instead of Rack::Utils.escape 33 | - Require Rack 2.0 for escape_path method 34 | - Don't try to clean path if invalid. 35 | - Return 400 (Bad Request) on preflights with invalid path 36 | 37 | ## 1.0.6 - 2019-11-14 38 | ### Changed 39 | - Use Rack::Utils.escape to make compat with Rack 1.6.0 40 | 41 | ## 1.0.5 - 2019-11-14 42 | ### Changed 43 | - Update Gem spec to require rack >= 1.6.0 44 | 45 | ## 1.0.4 - 2019-11-13 46 | ### Security 47 | - Escape and resolve path before evaluating resource rules (thanks to Colby Morgan) 48 | 49 | ## 1.0.3 - 2019-03-24 50 | ### Changed 51 | - Don't send 'Content-Type' header with pre-flight requests 52 | - Allow ruby array for vary header config 53 | 54 | ## 1.0.2 - 2017-10-22 55 | ### Fixed 56 | - Automatically allow simple headers when headers are set 57 | 58 | ## 1.0.1 - 2017-07-18 59 | ### Fixed 60 | - Allow lambda origin configuration 61 | 62 | ## 1.0.0 - 2017-07-15 63 | ### Security 64 | - Don't implicitly accept 'null' origins when 'file://' is specified 65 | (https://github.com/cyu/rack-cors/pull/134) 66 | - Ignore '' origins (https://github.com/cyu/rack-cors/issues/139) 67 | - Default credentials option on resources to false 68 | (https://github.com/cyu/rack-cors/issues/95) 69 | - Don't allow credentials option to be true if '*' is specified is origin 70 | (https://github.com/cyu/rack-cors/pull/142) 71 | - Don't reflect Origin header when '*' is specified as origin 72 | (https://github.com/cyu/rack-cors/pull/142) 73 | 74 | ### Fixed 75 | - Don't respond immediately on non-matching preflight requests instead of 76 | sending them through the app (https://github.com/cyu/rack-cors/pull/106) 77 | 78 | ## 0.4.1 - 2017-02-01 79 | ### Fixed 80 | - Return miss result in X-Rack-CORS instead of incorrectly returning 81 | preflight-hit 82 | 83 | ## 0.4.0 - 2015-04-15 84 | ### Changed 85 | - Don't set HTTP_ORIGIN with HTTP_X_ORIGIN if nil 86 | 87 | ### Added 88 | - Calculate vary headers for non-CORS resources 89 | - Support custom vary headers for resource 90 | - Support :if option for resource 91 | - Support :any as a possible value for :methods option 92 | 93 | ### Fixed 94 | - Don't symbolize incoming HTTP request methods 95 | 96 | ## 0.3.1 - 2014-12-27 97 | ### Changed 98 | - Changed the env key to rack.cors to avoid Rack::Lint warnings 99 | 100 | ## 0.3.0 - 2014-10-19 101 | ### Added 102 | - Added support for defining a logger with a Proc 103 | - Return a X-Rack-CORS header when in debug mode detailing how Rack::Cors 104 | processed a request 105 | - Added support for non HTTP/HTTPS origins when just a domain is specified 106 | 107 | ### Changed 108 | - Changed the log level of the fallback logger to DEBUG 109 | - Print warning when attempting to use :any as an allowed method 110 | - Treat incoming `Origin: null` headers as file:// 111 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | # Specify your gem's dependencies in rack-cors.gemspec 6 | gemspec 7 | 8 | gem 'pry-byebug', '~> 3.6.0' 9 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Calvin Yu 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rack CORS Middleware [![Build Status](https://github.com/cyu/rack-cors/actions/workflows/ci.yaml/badge.svg)](https://github.com/cyu/rack-cors/actions) 2 | 3 | `Rack::Cors` provides support for Cross-Origin Resource Sharing (CORS) for Rack compatible web applications. 4 | 5 | The [CORS spec](http://www.w3.org/TR/cors/) allows web applications to make cross domain AJAX calls without using workarounds such as JSONP. See [further explanations on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) 6 | 7 | ## Installation 8 | 9 | Install the gem: 10 | 11 | `gem install rack-cors` 12 | 13 | Or in your Gemfile: 14 | 15 | ```ruby 16 | gem 'rack-cors' 17 | ``` 18 | 19 | 20 | ## Configuration 21 | 22 | ### Rails Configuration 23 | For Rails, you'll need to add this middleware on application startup. A practical way to do this is with an initializer file. For example, the following will allow GET, POST, PATCH, or PUT requests from any origin on any resource: 24 | 25 | ```ruby 26 | # config/initializers/cors.rb 27 | 28 | Rails.application.config.middleware.insert_before 0, Rack::Cors do 29 | allow do 30 | origins '*' 31 | resource '*', headers: :any, methods: [:get, :post, :patch, :put] 32 | end 33 | end 34 | ``` 35 | 36 | NOTE: If you create application with `--api` option, configuration is automatically generated in `config/initializers/cors.rb`. 37 | 38 | We use `insert_before` to make sure `Rack::Cors` runs at the beginning of the stack to make sure it isn't interfered with by other middleware (see `Rack::Cache` note in **Common Gotchas** section). Basic setup examples for Rails 5 & Rails 6 can be found in the examples/ directory. 39 | 40 | See The [Rails Guide to Rack](http://guides.rubyonrails.org/rails_on_rack.html) for more details on rack middlewares or watch the [railscast](http://railscasts.com/episodes/151-rack-middleware). 41 | 42 | Read more about it here in the [Rails Guides](https://guides.rubyonrails.org/configuring.html#configuring-middleware) 43 | 44 | ### Rack Configuration 45 | 46 | NOTE: If you're running Rails, adding `config/initializers/cors.rb` should be enough. There is no need to update `config.ru` as well. 47 | 48 | In `config.ru`, configure `Rack::Cors` by passing a block to the `use` command: 49 | 50 | ```ruby 51 | use Rack::Cors do 52 | allow do 53 | origins 'localhost:3000', '127.0.0.1:3000', 54 | /\Ahttp:\/\/192\.168\.0\.\d{1,3}(:\d+)?\z/ 55 | # regular expressions can be used here 56 | 57 | resource '/file/list_all/', :headers => 'x-domain-token' 58 | resource '/file/at/*', 59 | methods: [:get, :post, :delete, :put, :patch, :options, :head], 60 | headers: 'x-domain-token', 61 | expose: ['Some-Custom-Response-Header'], 62 | max_age: 600 63 | # headers to expose 64 | end 65 | 66 | allow do 67 | origins '*' 68 | resource '/public/*', headers: :any, methods: :get 69 | 70 | # Only allow a request for a specific host 71 | resource '/api/v1/*', 72 | headers: :any, 73 | methods: :get, 74 | if: proc { |env| env['HTTP_HOST'] == 'api.example.com' } 75 | end 76 | end 77 | ``` 78 | 79 | ### Configuration Reference 80 | 81 | #### Middleware Options 82 | * **debug** (boolean): Enables debug logging and `X-Rack-CORS` HTTP headers for debugging. 83 | * **logger** (Object or Proc): Specify the logger to log to. If a proc is provided, it will be called when a logger is needed. This is helpful in cases where the logger is initialized after `Rack::Cors` is initially configured, like `Rails.logger`. 84 | 85 | #### Origin 86 | Origins can be specified as a string, a regular expression, or as '\*' to allow all origins. 87 | 88 | **\*SECURITY NOTE:** Be careful when using regular expressions to not accidentally be too inclusive. For example, the expression `/https:\/\/example\.com/` will match the domain *example.com.randomdomainname.co.uk*. It is recommended that any regular expression be enclosed with start & end string anchors, like `\Ahttps:\/\/example\.com\z`. 89 | 90 | Additionally, origins can be specified dynamically via a block of the following form: 91 | ```ruby 92 | origins { |source, env| true || false } 93 | ``` 94 | 95 | A Resource path can be specified as exact string match (`/path/to/file.txt`) or with a '\*' wildcard (`/all/files/in/*`). A resource can take the following options: 96 | 97 | * **methods** (string or array or `:any`): The HTTP methods allowed for the resource. 98 | * **headers** (string or array or `:any`): The HTTP headers that will be allowed in the CORS resource request. Use `:any` to allow for any headers in the actual request. 99 | * **expose** (string or array): The HTTP headers in the resource response can be exposed to the client. 100 | * **credentials** (boolean, default: `false`): Sets the `Access-Control-Allow-Credentials` response header. **Note:** If a wildcard (`*`) origin is specified, this option cannot be set to `true`. Read this [security article](http://web-in-security.blogspot.de/2017/07/cors-misconfigurations-on-large-scale.html) for more information. 101 | * **max_age** (number): Sets the `Access-Control-Max-Age` response header. 102 | * **if** (Proc): If the result of the proc is true, will process the request as a valid CORS request. 103 | * **vary** (string or array): A list of HTTP headers to add to the 'Vary' header. 104 | 105 | 106 | ## Common Gotchas 107 | 108 | ### Origin Matching 109 | 110 | * When specifying an origin, make sure that it does not have a trailing slash. 111 | 112 | * When specifying an HTTP origin that uses the scheme's default port (e.g. `http://example.test:80`), some clients may not strip the port which could result in unexpected blocked requests (additional context [here](https://github.com/request/request/pull/2904)). 113 | 114 | ### Testing Postman and/or cURL 115 | 116 | * Make sure you're passing in an `Origin:` header. That header is required to trigger a CORS response. Here's [a good SO post](https://stackoverflow.com/questions/12173990/how-can-you-debug-a-cors-request-with-curl) about using cURL for testing CORS. 117 | * Make sure your origin does not have a trailing slash. 118 | 119 | ### Positioning in the Middleware Stack 120 | 121 | Positioning of `Rack::Cors` in the middleware stack is very important. In the Rails example above we put it above all other middleware which, in our experience, provides the most consistent results. 122 | 123 | Here are some scenarios where incorrect positioning have created issues: 124 | 125 | * **Serving static files.** Insert before `ActionDispatch::Static` so that static files are served with the proper CORS headers. **NOTE:** this might not work in production as static files are usually served from the web server (Nginx, Apache) and not the Rails container. 126 | 127 | * **Caching in the middleware.** Insert before `Rack::Cache` so that the proper CORS headers are written and not cached ones. 128 | 129 | * **Authentication via Warden** Warden will return immediately if a resource that requires authentication is accessed without authentication. If `Warden::Manager`is in the stack before `Rack::Cors`, it will return without the correct CORS headers being applied, resulting in a failed CORS request. 130 | 131 | You can run the following command to see what the middleware stack looks like: 132 | 133 | ```bash 134 | bundle exec rails middleware 135 | ``` 136 | 137 | Note that the middleware stack is different in production. For example, the `ActionDispatch::Static` middleware will not be part of the stack if `config.serve_static_assets = false`. You can run this to see what your middleware stack looks like in production: 138 | 139 | ```bash 140 | RAILS_ENV=production bundle exec rails middleware 141 | ``` 142 | 143 | ### Serving static files 144 | 145 | If you trying to serve CORS headers on static assets (like CSS, JS, Font files), keep in mind that static files are usually served directly from web servers and never runs through the Rails container (including the middleware stack where `Rack::Cors` resides). 146 | 147 | In Heroku, you can serve static assets through the Rails container by setting `config.serve_static_assets = true` in `production.rb`. 148 | 149 | ### Custom Protocols (chrome-extension://, ionic://, etc.) 150 | 151 | Prior to 2.0.0, `http://`, `https://`, and `file://` are the only protocols supported in the `origins` list. If you wish to specify an origin that 152 | has a custom protocol (`chrome-extension://`, `ionic://`, etc.) simply exclude the protocol. [See issue.](https://github.com/cyu/rack-cors/issues/100) 153 | 154 | For example, instead of specifying `chrome-extension://aomjjhallfgjeglblehebfpbcfeobpga` specify `aomjjhallfgjeglblehebfpbcfeobpga` in `origins`. 155 | 156 | As of 2.0.0 (currently in RC1), you can specify origins with a custom protocol. 157 | 158 | ### Rails 6 Host Matching 159 | 160 | Rails 6 will block requests from unauthorized hosts, and this issue can be confused as a CORS related error. So in development, if you're making requests using something other than localhost or 127.0.0.1, make sure the server host has been authorized. [More info here](https://guides.rubyonrails.org/configuring.html#actiondispatch-hostauthorization) 161 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler/gem_tasks' 4 | 5 | require 'rake/testtask' 6 | Rake::TestTask.new(:test) do |test| 7 | test.libs << 'lib' << 'test' 8 | test.pattern = 'test/**/*_test.rb' 9 | test.verbose = true 10 | end 11 | 12 | task default: :test 13 | 14 | require 'rdoc/task' 15 | Rake::RDocTask.new do |rdoc| 16 | version = File.exist?('VERSION') ? File.read('VERSION') : '' 17 | 18 | rdoc.rdoc_dir = 'rdoc' 19 | rdoc.title = "rack-cors #{version}" 20 | rdoc.rdoc_files.include('README*') 21 | rdoc.rdoc_files.include('lib/**/*.rb') 22 | end 23 | -------------------------------------------------------------------------------- /examples/rack/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } 6 | 7 | gem 'rack' 8 | gem 'rack-cors', '>= 1.1.0' 9 | -------------------------------------------------------------------------------- /examples/rack/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | rack (2.2.3) 5 | rack-cors (1.1.1) 6 | rack (>= 2.0.0) 7 | 8 | PLATFORMS 9 | ruby 10 | 11 | DEPENDENCIES 12 | rack 13 | rack-cors (>= 1.1.0) 14 | 15 | BUNDLED WITH 16 | 1.17.3 17 | -------------------------------------------------------------------------------- /examples/rack/config.ru: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rack/cors' 4 | 5 | app = Rack::Builder.app do 6 | use Rack::Cors, debug: true, logger: Logger.new(STDOUT) do 7 | allow do 8 | origins '*' 9 | 10 | resource '/cors', 11 | headers: :any, 12 | methods: [:post], 13 | max_age: 0 14 | 15 | resource '*', 16 | headers: :any, 17 | methods: %i[get post delete put patch options head], 18 | max_age: 0 19 | end 20 | end 21 | 22 | use Rack::Static, urls: ['/static.txt'], root: 'public' 23 | 24 | map '/cors' do 25 | run lambda { |env| 26 | [ 27 | 200, 28 | { 'Content-Type' => 'text/plain' }, 29 | env[Rack::REQUEST_METHOD] == 'HEAD' ? [] : ['OK!'] 30 | ] 31 | } 32 | end 33 | 34 | run lambda { |env| 35 | [ 36 | 200, 37 | { 'Content-Type' => 'text/plain' }, 38 | env[Rack::REQUEST_METHOD] == 'HEAD' ? [] : ['Hello world'] 39 | ] 40 | } 41 | end 42 | 43 | run app 44 | -------------------------------------------------------------------------------- /examples/rack/public/public/static.txt: -------------------------------------------------------------------------------- 1 | hello world 2 | -------------------------------------------------------------------------------- /examples/rack/public/static.txt: -------------------------------------------------------------------------------- 1 | hello world 2 | -------------------------------------------------------------------------------- /examples/rails5/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-journal 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/* 16 | /tmp/* 17 | !/log/.keep 18 | !/tmp/.keep 19 | 20 | # Ignore uploaded files in development 21 | /storage/* 22 | !/storage/.keep 23 | 24 | /node_modules 25 | /yarn-error.log 26 | 27 | /public/assets 28 | .byebug_history 29 | 30 | # Ignore master key for decrypting credentials and more. 31 | /config/master.key 32 | -------------------------------------------------------------------------------- /examples/rails5/.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.2 2 | -------------------------------------------------------------------------------- /examples/rails5/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 3 | 4 | ruby '2.7.2' 5 | 6 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 7 | gem 'rails', '~> 5.2.3' 8 | # Use sqlite3 as the database for Active Record 9 | gem 'sqlite3' 10 | # Use Puma as the app server 11 | gem 'puma', '~> 3.12' 12 | # Use SCSS for stylesheets 13 | gem 'sass-rails', '~> 5.0' 14 | # Use Uglifier as compressor for JavaScript assets 15 | gem 'uglifier', '>= 1.3.0' 16 | # See https://github.com/rails/execjs#readme for more supported runtimes 17 | # gem 'mini_racer', platforms: :ruby 18 | 19 | # Use CoffeeScript for .coffee assets and views 20 | gem 'coffee-rails', '~> 4.2' 21 | # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks 22 | gem 'turbolinks', '~> 5' 23 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 24 | gem 'jbuilder', '~> 2.5' 25 | # Use Redis adapter to run Action Cable in production 26 | # gem 'redis', '~> 4.0' 27 | # Use ActiveModel has_secure_password 28 | # gem 'bcrypt', '~> 3.1.7' 29 | 30 | # Use ActiveStorage variant 31 | # gem 'mini_magick', '~> 4.8' 32 | 33 | # Use Capistrano for deployment 34 | # gem 'capistrano-rails', group: :development 35 | 36 | # Reduces boot times through caching; required in config/boot.rb 37 | gem 'bootsnap', '>= 1.1.0', require: false 38 | 39 | group :development, :test do 40 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console 41 | gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] 42 | end 43 | 44 | group :development do 45 | # Access an interactive console on exception pages or by calling 'console' anywhere in the code. 46 | gem 'web-console', '>= 3.3.0' 47 | gem 'listen', '>= 3.0.5', '< 3.2' 48 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 49 | gem 'spring' 50 | gem 'spring-watcher-listen', '~> 2.0.0' 51 | end 52 | 53 | group :test do 54 | # Adds support for Capybara system testing and selenium driver 55 | gem 'capybara', '>= 2.15' 56 | gem 'selenium-webdriver' 57 | # Easy installation and use of chromedriver to run system tests with Chrome 58 | gem 'chromedriver-helper' 59 | end 60 | 61 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 62 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] 63 | 64 | gem 'rack-cors', '>= 1.1.0' 65 | -------------------------------------------------------------------------------- /examples/rails5/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (5.2.4.4) 5 | actionpack (= 5.2.4.4) 6 | nio4r (~> 2.0) 7 | websocket-driver (>= 0.6.1) 8 | actionmailer (5.2.4.4) 9 | actionpack (= 5.2.4.4) 10 | actionview (= 5.2.4.4) 11 | activejob (= 5.2.4.4) 12 | mail (~> 2.5, >= 2.5.4) 13 | rails-dom-testing (~> 2.0) 14 | actionpack (5.2.4.4) 15 | actionview (= 5.2.4.4) 16 | activesupport (= 5.2.4.4) 17 | rack (~> 2.0, >= 2.0.8) 18 | rack-test (>= 0.6.3) 19 | rails-dom-testing (~> 2.0) 20 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 21 | actionview (5.2.4.4) 22 | activesupport (= 5.2.4.4) 23 | builder (~> 3.1) 24 | erubi (~> 1.4) 25 | rails-dom-testing (~> 2.0) 26 | rails-html-sanitizer (~> 1.0, >= 1.0.3) 27 | activejob (5.2.4.4) 28 | activesupport (= 5.2.4.4) 29 | globalid (>= 0.3.6) 30 | activemodel (5.2.4.4) 31 | activesupport (= 5.2.4.4) 32 | activerecord (5.2.4.4) 33 | activemodel (= 5.2.4.4) 34 | activesupport (= 5.2.4.4) 35 | arel (>= 9.0) 36 | activestorage (5.2.4.4) 37 | actionpack (= 5.2.4.4) 38 | activerecord (= 5.2.4.4) 39 | marcel (~> 0.3.1) 40 | activesupport (5.2.4.4) 41 | concurrent-ruby (~> 1.0, >= 1.0.2) 42 | i18n (>= 0.7, < 2) 43 | minitest (~> 5.1) 44 | tzinfo (~> 1.1) 45 | addressable (2.7.0) 46 | public_suffix (>= 2.0.2, < 5.0) 47 | archive-zip (0.12.0) 48 | io-like (~> 0.3.0) 49 | arel (9.0.0) 50 | bindex (0.8.1) 51 | bootsnap (1.5.1) 52 | msgpack (~> 1.0) 53 | builder (3.2.4) 54 | byebug (11.1.3) 55 | capybara (3.34.0) 56 | addressable 57 | mini_mime (>= 0.1.3) 58 | nokogiri (~> 1.8) 59 | rack (>= 1.6.0) 60 | rack-test (>= 0.6.3) 61 | regexp_parser (~> 1.5) 62 | xpath (~> 3.2) 63 | childprocess (3.0.0) 64 | chromedriver-helper (2.1.1) 65 | archive-zip (~> 0.10) 66 | nokogiri (~> 1.8) 67 | coffee-rails (4.2.2) 68 | coffee-script (>= 2.2.0) 69 | railties (>= 4.0.0) 70 | coffee-script (2.4.1) 71 | coffee-script-source 72 | execjs 73 | coffee-script-source (1.12.2) 74 | concurrent-ruby (1.1.7) 75 | crass (1.0.6) 76 | erubi (1.10.0) 77 | execjs (2.7.0) 78 | ffi (1.14.0) 79 | globalid (0.4.2) 80 | activesupport (>= 4.2.0) 81 | i18n (1.8.5) 82 | concurrent-ruby (~> 1.0) 83 | io-like (0.3.1) 84 | jbuilder (2.10.1) 85 | activesupport (>= 5.0.0) 86 | listen (3.1.5) 87 | rb-fsevent (~> 0.9, >= 0.9.4) 88 | rb-inotify (~> 0.9, >= 0.9.7) 89 | ruby_dep (~> 1.2) 90 | loofah (2.8.0) 91 | crass (~> 1.0.2) 92 | nokogiri (>= 1.5.9) 93 | mail (2.7.1) 94 | mini_mime (>= 0.1.1) 95 | marcel (0.3.3) 96 | mimemagic (~> 0.3.2) 97 | method_source (1.0.0) 98 | mimemagic (0.3.5) 99 | mini_mime (1.0.2) 100 | mini_portile2 (2.4.0) 101 | minitest (5.14.2) 102 | msgpack (1.3.3) 103 | nio4r (2.5.4) 104 | nokogiri (1.10.10) 105 | mini_portile2 (~> 2.4.0) 106 | public_suffix (4.0.6) 107 | puma (3.12.6) 108 | rack (2.2.3) 109 | rack-cors (1.1.1) 110 | rack (>= 2.0.0) 111 | rack-test (1.1.0) 112 | rack (>= 1.0, < 3) 113 | rails (5.2.4.4) 114 | actioncable (= 5.2.4.4) 115 | actionmailer (= 5.2.4.4) 116 | actionpack (= 5.2.4.4) 117 | actionview (= 5.2.4.4) 118 | activejob (= 5.2.4.4) 119 | activemodel (= 5.2.4.4) 120 | activerecord (= 5.2.4.4) 121 | activestorage (= 5.2.4.4) 122 | activesupport (= 5.2.4.4) 123 | bundler (>= 1.3.0) 124 | railties (= 5.2.4.4) 125 | sprockets-rails (>= 2.0.0) 126 | rails-dom-testing (2.0.3) 127 | activesupport (>= 4.2.0) 128 | nokogiri (>= 1.6) 129 | rails-html-sanitizer (1.3.0) 130 | loofah (~> 2.3) 131 | railties (5.2.4.4) 132 | actionpack (= 5.2.4.4) 133 | activesupport (= 5.2.4.4) 134 | method_source 135 | rake (>= 0.8.7) 136 | thor (>= 0.19.0, < 2.0) 137 | rake (13.0.1) 138 | rb-fsevent (0.10.4) 139 | rb-inotify (0.10.1) 140 | ffi (~> 1.0) 141 | regexp_parser (1.8.2) 142 | ruby_dep (1.5.0) 143 | rubyzip (2.3.0) 144 | sass (3.7.4) 145 | sass-listen (~> 4.0.0) 146 | sass-listen (4.0.0) 147 | rb-fsevent (~> 0.9, >= 0.9.4) 148 | rb-inotify (~> 0.9, >= 0.9.7) 149 | sass-rails (5.1.0) 150 | railties (>= 5.2.0) 151 | sass (~> 3.1) 152 | sprockets (>= 2.8, < 4.0) 153 | sprockets-rails (>= 2.0, < 4.0) 154 | tilt (>= 1.1, < 3) 155 | selenium-webdriver (3.142.7) 156 | childprocess (>= 0.5, < 4.0) 157 | rubyzip (>= 1.2.2) 158 | spring (2.1.1) 159 | spring-watcher-listen (2.0.1) 160 | listen (>= 2.7, < 4.0) 161 | spring (>= 1.2, < 3.0) 162 | sprockets (3.7.2) 163 | concurrent-ruby (~> 1.0) 164 | rack (> 1, < 3) 165 | sprockets-rails (3.2.2) 166 | actionpack (>= 4.0) 167 | activesupport (>= 4.0) 168 | sprockets (>= 3.0.0) 169 | sqlite3 (1.4.2) 170 | thor (1.0.1) 171 | thread_safe (0.3.6) 172 | tilt (2.0.10) 173 | turbolinks (5.2.1) 174 | turbolinks-source (~> 5.2) 175 | turbolinks-source (5.2.0) 176 | tzinfo (1.2.9) 177 | thread_safe (~> 0.1) 178 | uglifier (4.2.0) 179 | execjs (>= 0.3.0, < 3) 180 | web-console (3.7.0) 181 | actionview (>= 5.0) 182 | activemodel (>= 5.0) 183 | bindex (>= 0.4.0) 184 | railties (>= 5.0) 185 | websocket-driver (0.7.3) 186 | websocket-extensions (>= 0.1.0) 187 | websocket-extensions (0.1.5) 188 | xpath (3.2.0) 189 | nokogiri (~> 1.8) 190 | 191 | PLATFORMS 192 | ruby 193 | 194 | DEPENDENCIES 195 | bootsnap (>= 1.1.0) 196 | byebug 197 | capybara (>= 2.15) 198 | chromedriver-helper 199 | coffee-rails (~> 4.2) 200 | jbuilder (~> 2.5) 201 | listen (>= 3.0.5, < 3.2) 202 | puma (~> 3.12) 203 | rack-cors (>= 1.1.0) 204 | rails (~> 5.2.3) 205 | sass-rails (~> 5.0) 206 | selenium-webdriver 207 | spring 208 | spring-watcher-listen (~> 2.0.0) 209 | sqlite3 210 | turbolinks (~> 5) 211 | tzinfo-data 212 | uglifier (>= 1.3.0) 213 | web-console (>= 3.3.0) 214 | 215 | RUBY VERSION 216 | ruby 2.7.2p137 217 | 218 | BUNDLED WITH 219 | 1.17.3 220 | -------------------------------------------------------------------------------- /examples/rails5/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | This README would normally document whatever steps are necessary to get the 4 | application up and running. 5 | 6 | Things you may want to cover: 7 | 8 | * Ruby version 9 | 10 | * System dependencies 11 | 12 | * Configuration 13 | 14 | * Database creation 15 | 16 | * Database initialization 17 | 18 | * How to run the test suite 19 | 20 | * Services (job queues, cache servers, search engines, etc.) 21 | 22 | * Deployment instructions 23 | 24 | * ... 25 | -------------------------------------------------------------------------------- /examples/rails5/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /examples/rails5/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../javascripts .js 3 | //= link_directory ../stylesheets .css 4 | -------------------------------------------------------------------------------- /examples/rails5/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/app/assets/images/.keep -------------------------------------------------------------------------------- /examples/rails5/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's 5 | // vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. JavaScript code in this file should be added after the last require_* statement. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require rails-ujs 14 | //= require activestorage 15 | //= require turbolinks 16 | //= require_tree . 17 | -------------------------------------------------------------------------------- /examples/rails5/app/assets/javascripts/cable.js: -------------------------------------------------------------------------------- 1 | // Action Cable provides the framework to deal with WebSockets in Rails. 2 | // You can generate new channels where WebSocket features live using the `rails generate channel` command. 3 | // 4 | //= require action_cable 5 | //= require_self 6 | //= require_tree ./channels 7 | 8 | (function() { 9 | this.App || (this.App = {}); 10 | 11 | App.cable = ActionCable.createConsumer(); 12 | 13 | }).call(this); 14 | -------------------------------------------------------------------------------- /examples/rails5/app/assets/javascripts/channels/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/app/assets/javascripts/channels/.keep -------------------------------------------------------------------------------- /examples/rails5/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's 6 | * vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /examples/rails5/app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /examples/rails5/app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /examples/rails5/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | end 3 | -------------------------------------------------------------------------------- /examples/rails5/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /examples/rails5/app/controllers/cors_controller.rb: -------------------------------------------------------------------------------- 1 | class CorsController < ApplicationController 2 | skip_before_action :verify_authenticity_token 3 | def create 4 | render plain: 'OK!' 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /examples/rails5/app/controllers/welcome_controller.rb: -------------------------------------------------------------------------------- 1 | class WelcomeController < ApplicationController 2 | skip_before_action :verify_authenticity_token 3 | def index 4 | render plain: "Hello world" 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /examples/rails5/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /examples/rails5/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /examples/rails5/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /examples/rails5/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /examples/rails5/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/app/models/concerns/.keep -------------------------------------------------------------------------------- /examples/rails5/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CorsExample 5 | <%= csrf_meta_tags %> 6 | <%= csp_meta_tag %> 7 | 8 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 9 | <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> 10 | 11 | 12 | 13 | <%= yield %> 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/rails5/app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/rails5/app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /examples/rails5/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /examples/rails5/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../config/application', __dir__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /examples/rails5/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /examples/rails5/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | include FileUtils 4 | 5 | # path to your application root. 6 | APP_ROOT = File.expand_path('..', __dir__) 7 | 8 | def system!(*args) 9 | system(*args) || abort("\n== Command #{args} failed ==") 10 | end 11 | 12 | chdir APP_ROOT do 13 | # This script is a starting point to setup your application. 14 | # Add necessary setup steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # Install JavaScript dependencies if using Yarn 21 | # system('bin/yarn') 22 | 23 | # puts "\n== Copying sample files ==" 24 | # unless File.exist?('config/database.yml') 25 | # cp 'config/database.yml.sample', 'config/database.yml' 26 | # end 27 | 28 | puts "\n== Preparing database ==" 29 | system! 'bin/rails db:setup' 30 | 31 | puts "\n== Removing old logs and tempfiles ==" 32 | system! 'bin/rails log:clear tmp:clear' 33 | 34 | puts "\n== Restarting application server ==" 35 | system! 'bin/rails restart' 36 | end 37 | -------------------------------------------------------------------------------- /examples/rails5/bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads Spring without using Bundler, in order to be fast. 4 | # It gets overwritten when you run the `spring binstub` command. 5 | 6 | unless defined?(Spring) 7 | require 'rubygems' 8 | require 'bundler' 9 | 10 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read) 11 | spring = lockfile.specs.detect { |spec| spec.name == 'spring' } 12 | if spring 13 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path 14 | gem 'spring', spring.version 15 | require 'spring/binstub' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /examples/rails5/bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | include FileUtils 4 | 5 | # path to your application root. 6 | APP_ROOT = File.expand_path('..', __dir__) 7 | 8 | def system!(*args) 9 | system(*args) || abort("\n== Command #{args} failed ==") 10 | end 11 | 12 | chdir APP_ROOT do 13 | # This script is a way to update your development environment automatically. 14 | # Add necessary update steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # Install JavaScript dependencies if using Yarn 21 | # system('bin/yarn') 22 | 23 | puts "\n== Updating database ==" 24 | system! 'bin/rails db:migrate' 25 | 26 | puts "\n== Removing old logs and tempfiles ==" 27 | system! 'bin/rails log:clear tmp:clear' 28 | 29 | puts "\n== Restarting application server ==" 30 | system! 'bin/rails restart' 31 | end 32 | -------------------------------------------------------------------------------- /examples/rails5/bin/yarn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_ROOT = File.expand_path('..', __dir__) 3 | Dir.chdir(APP_ROOT) do 4 | begin 5 | exec "yarnpkg", *ARGV 6 | rescue Errno::ENOENT 7 | $stderr.puts "Yarn executable was not detected in the system." 8 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" 9 | exit 1 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /examples/rails5/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /examples/rails5/config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require 'rails/all' 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module CorsExample 10 | class Application < Rails::Application 11 | # Initialize configuration defaults for originally generated Rails version. 12 | config.load_defaults 5.2 13 | 14 | # Settings in config/environments/* take precedence over those specified here. 15 | # Application configuration can go into files in config/initializers 16 | # -- all .rb files in that directory are automatically loaded after loading 17 | # the framework and any gems in your application. 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /examples/rails5/config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | require 'bootsnap/setup' # Speed up boot time by caching expensive operations. 5 | -------------------------------------------------------------------------------- /examples/rails5/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: cors_example_production 11 | -------------------------------------------------------------------------------- /examples/rails5/config/credentials.yml.enc: -------------------------------------------------------------------------------- 1 | pcTnCPuxmh6e0F+DDJ/MpLHpjc3VQa78gg4KCThzXGXCVA/6mBIyJErH01U5rEpTb0es6kngx9YcOhoL/XfjlACq2aWoYJF1ya+BdBxWFWaoNe8zQCjlojWr1bH6+7CKesmm9PrRJz4/F4sO4JI2M5kYAknL6oZvrHIpbT9bMBfTmWyt5KqAHpYw4jJe3TGJZm3f9yW8DE/lyVdGqhvXRsV2bY331t0ZbrTVtvpZnz1wvRClNhncnArQxdhMKtIstu2Le2cxSzZ3JdzZMkMdZ1RYuu6Lb/CNb2srot2hvOz7lCv0NPWHN/wFYx8mVQCQFUHUM2Ivm58Tk8D0/O5kKFVIuJiBS/WXHTSiGZ84K1+vs+uxtZoVzwnZDEIBduLkJq3MK08+lJh7+RIqVOCK2hQ6sJEYJDEP/To5--zJX48+3nynECWcwR--5EVcjs47GujPxYnAeTn+wg== -------------------------------------------------------------------------------- /examples/rails5/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /examples/rails5/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /examples/rails5/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable/disable caching. By default caching is disabled. 16 | # Run rails dev:cache to toggle caching. 17 | if Rails.root.join('tmp', 'caching-dev.txt').exist? 18 | config.action_controller.perform_caching = true 19 | 20 | config.cache_store = :memory_store 21 | config.public_file_server.headers = { 22 | 'Cache-Control' => "public, max-age=#{2.days.to_i}" 23 | } 24 | else 25 | config.action_controller.perform_caching = false 26 | 27 | config.cache_store = :null_store 28 | end 29 | 30 | # Store uploaded files on the local file system (see config/storage.yml for options) 31 | config.active_storage.service = :local 32 | 33 | # Don't care if the mailer can't send. 34 | config.action_mailer.raise_delivery_errors = false 35 | 36 | config.action_mailer.perform_caching = false 37 | 38 | # Print deprecation notices to the Rails logger. 39 | config.active_support.deprecation = :log 40 | 41 | # Raise an error on page load if there are pending migrations. 42 | config.active_record.migration_error = :page_load 43 | 44 | # Highlight code that triggered database queries in logs. 45 | config.active_record.verbose_query_logs = true 46 | 47 | # Debug mode disables concatenation and preprocessing of assets. 48 | # This option may cause significant delays in view rendering with a large 49 | # number of complex assets. 50 | config.assets.debug = true 51 | 52 | # Suppress logger output for asset requests. 53 | config.assets.quiet = true 54 | 55 | # Raises error for missing translations 56 | # config.action_view.raise_on_missing_translations = true 57 | 58 | # Use an evented file watcher to asynchronously detect changes in source code, 59 | # routes, locales, etc. This feature depends on the listen gem. 60 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker 61 | end 62 | -------------------------------------------------------------------------------- /examples/rails5/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] 18 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). 19 | # config.require_master_key = true 20 | 21 | # Disable serving static files from the `/public` folder by default since 22 | # Apache or NGINX already handles this. 23 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? 24 | 25 | # Compress JavaScripts and CSS. 26 | config.assets.js_compressor = :uglifier 27 | # config.assets.css_compressor = :sass 28 | 29 | # Do not fallback to assets pipeline if a precompiled asset is missed. 30 | config.assets.compile = false 31 | 32 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb 33 | 34 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 35 | # config.action_controller.asset_host = 'http://assets.example.com' 36 | 37 | # Specifies the header that your server uses for sending files. 38 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 39 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 40 | 41 | # Store uploaded files on the local file system (see config/storage.yml for options) 42 | config.active_storage.service = :local 43 | 44 | # Mount Action Cable outside main process or domain 45 | # config.action_cable.mount_path = nil 46 | # config.action_cable.url = 'wss://example.com/cable' 47 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] 48 | 49 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 50 | # config.force_ssl = true 51 | 52 | # Use the lowest log level to ensure availability of diagnostic information 53 | # when problems arise. 54 | config.log_level = :debug 55 | 56 | # Prepend all log lines with the following tags. 57 | config.log_tags = [ :request_id ] 58 | 59 | # Use a different cache store in production. 60 | # config.cache_store = :mem_cache_store 61 | 62 | # Use a real queuing backend for Active Job (and separate queues per environment) 63 | # config.active_job.queue_adapter = :resque 64 | # config.active_job.queue_name_prefix = "cors_example_#{Rails.env}" 65 | 66 | config.action_mailer.perform_caching = false 67 | 68 | # Ignore bad email addresses and do not raise email delivery errors. 69 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 70 | # config.action_mailer.raise_delivery_errors = false 71 | 72 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 73 | # the I18n.default_locale when a translation cannot be found). 74 | config.i18n.fallbacks = true 75 | 76 | # Send deprecation notices to registered listeners. 77 | config.active_support.deprecation = :notify 78 | 79 | # Use default logging formatter so that PID and timestamp are not suppressed. 80 | config.log_formatter = ::Logger::Formatter.new 81 | 82 | # Use a different logger for distributed setups. 83 | # require 'syslog/logger' 84 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') 85 | 86 | if ENV["RAILS_LOG_TO_STDOUT"].present? 87 | logger = ActiveSupport::Logger.new(STDOUT) 88 | logger.formatter = config.log_formatter 89 | config.logger = ActiveSupport::TaggedLogging.new(logger) 90 | end 91 | 92 | # Do not dump schema after migrations. 93 | config.active_record.dump_schema_after_migration = false 94 | end 95 | -------------------------------------------------------------------------------- /examples/rails5/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure public file server for tests with Cache-Control for performance. 16 | config.public_file_server.enabled = true 17 | config.public_file_server.headers = { 18 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}" 19 | } 20 | 21 | # Show full error reports and disable caching. 22 | config.consider_all_requests_local = true 23 | config.action_controller.perform_caching = false 24 | 25 | # Raise exceptions instead of rendering exception templates. 26 | config.action_dispatch.show_exceptions = false 27 | 28 | # Disable request forgery protection in test environment. 29 | config.action_controller.allow_forgery_protection = false 30 | 31 | # Store uploaded files on the local file system in a temporary directory 32 | config.active_storage.service = :test 33 | 34 | config.action_mailer.perform_caching = false 35 | 36 | # Tell Action Mailer not to deliver emails to the real world. 37 | # The :test delivery method accumulates sent emails in the 38 | # ActionMailer::Base.deliveries array. 39 | config.action_mailer.delivery_method = :test 40 | 41 | # Print deprecation notices to the stderr. 42 | config.active_support.deprecation = :stderr 43 | 44 | # Raises error for missing translations 45 | # config.action_view.raise_on_missing_translations = true 46 | end 47 | -------------------------------------------------------------------------------- /examples/rails5/config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /examples/rails5/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | # Add Yarn node_modules folder to the asset load path. 9 | Rails.application.config.assets.paths << Rails.root.join('node_modules') 10 | 11 | # Precompile additional assets. 12 | # application.js, application.css, and all non-JS/CSS in the app/assets 13 | # folder are already added. 14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 15 | -------------------------------------------------------------------------------- /examples/rails5/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /examples/rails5/config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy 4 | # For further information see the following documentation 5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy 6 | 7 | # Rails.application.config.content_security_policy do |policy| 8 | # policy.default_src :self, :https 9 | # policy.font_src :self, :https, :data 10 | # policy.img_src :self, :https, :data 11 | # policy.object_src :none 12 | # policy.script_src :self, :https 13 | # policy.style_src :self, :https 14 | 15 | # # Specify URI for violation reports 16 | # # policy.report_uri "/csp-violation-report-endpoint" 17 | # end 18 | 19 | # If you are using UJS then enable automatic nonce generation 20 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } 21 | 22 | # Report CSP violations to a specified URI 23 | # For further information see the following documentation: 24 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only 25 | # Rails.application.config.content_security_policy_report_only = true 26 | -------------------------------------------------------------------------------- /examples/rails5/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /examples/rails5/config/initializers/cors.rb: -------------------------------------------------------------------------------- 1 | # Avoid CORS issues when API is called from the frontend app. 2 | # Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests. 3 | 4 | # Read more: https://github.com/cyu/rack-cors 5 | 6 | Rails.application.config.middleware.insert_before 0, Rack::Cors, debug: true, logger: (-> { Rails.logger }) do 7 | allow do 8 | origins '*' 9 | 10 | resource '/cors', 11 | :headers => :any, 12 | :methods => [:post], 13 | :max_age => 0 14 | 15 | resource '*', 16 | headers: :any, 17 | methods: [:get, :post, :put, :patch, :delete, :options, :head], 18 | :max_age => 0 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /examples/rails5/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /examples/rails5/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /examples/rails5/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /examples/rails5/config/initializers/new_framework_defaults_5_2.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains migration options to ease your Rails 5.2 upgrade. 4 | # 5 | # Once upgraded flip defaults one by one to migrate to the new default. 6 | # 7 | # Read the Guide for Upgrading Ruby on Rails for more info on each option. 8 | 9 | # Make Active Record use stable #cache_key alongside new #cache_version method. 10 | # This is needed for recyclable cache keys. 11 | # Rails.application.config.active_record.cache_versioning = true 12 | 13 | # Use AES-256-GCM authenticated encryption for encrypted cookies. 14 | # Also, embed cookie expiry in signed or encrypted cookies for increased security. 15 | # 16 | # This option is not backwards compatible with earlier Rails versions. 17 | # It's best enabled when your entire app is migrated and stable on 5.2. 18 | # 19 | # Existing cookies will be converted on read then written with the new scheme. 20 | # Rails.application.config.action_dispatch.use_authenticated_cookie_encryption = true 21 | 22 | # Use AES-256-GCM authenticated encryption as default cipher for encrypting messages 23 | # instead of AES-256-CBC, when use_authenticated_message_encryption is set to true. 24 | # Rails.application.config.active_support.use_authenticated_message_encryption = true 25 | 26 | # Add default protection from forgery to ActionController::Base instead of in 27 | # ApplicationController. 28 | # Rails.application.config.action_controller.default_protect_from_forgery = true 29 | 30 | # Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and 31 | # 'f' after migrating old data. 32 | # Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true 33 | 34 | # Use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header. 35 | # Rails.application.config.active_support.use_sha1_digests = true 36 | 37 | # Make `form_with` generate id attributes for any generated HTML tags. 38 | # Rails.application.config.action_view.form_with_generates_ids = true 39 | -------------------------------------------------------------------------------- /examples/rails5/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /examples/rails5/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at http://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /examples/rails5/config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 8 | threads threads_count, threads_count 9 | 10 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 11 | # 12 | port ENV.fetch("PORT") { 3000 } 13 | 14 | # Specifies the `environment` that Puma will run in. 15 | # 16 | environment ENV.fetch("RAILS_ENV") { "development" } 17 | 18 | # Specifies the `pidfile` that Puma will use. 19 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 20 | 21 | # Specifies the number of `workers` to boot in clustered mode. 22 | # Workers are forked webserver processes. If using threads and workers together 23 | # the concurrency of the application would be max `threads` * `workers`. 24 | # Workers do not work on JRuby or Windows (both of which do not support 25 | # processes). 26 | # 27 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 28 | 29 | # Use the `preload_app!` method when specifying a `workers` number. 30 | # This directive tells Puma to first boot the application and load code 31 | # before forking the application. This takes advantage of Copy On Write 32 | # process behavior so workers use less memory. 33 | # 34 | # preload_app! 35 | 36 | # Allow puma to be restarted by `rails restart` command. 37 | plugin :tmp_restart 38 | -------------------------------------------------------------------------------- /examples/rails5/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html 3 | resources :cors 4 | match '/', to: "welcome#index", via: [:get, :post, :put, :delete, :options, :head, :patch] 5 | match '/*glob', to: "welcome#index", via: [:get, :post, :put, :delete, :options, :head, :patch] 6 | end 7 | -------------------------------------------------------------------------------- /examples/rails5/config/spring.rb: -------------------------------------------------------------------------------- 1 | %w[ 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ].each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /examples/rails5/config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket 23 | 24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /examples/rails5/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) 7 | # Character.create(name: 'Luke', movie: movies.first) 8 | -------------------------------------------------------------------------------- /examples/rails5/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/lib/assets/.keep -------------------------------------------------------------------------------- /examples/rails5/lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/lib/tasks/.keep -------------------------------------------------------------------------------- /examples/rails5/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/log/.keep -------------------------------------------------------------------------------- /examples/rails5/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cors_example", 3 | "private": true, 4 | "dependencies": {} 5 | } 6 | -------------------------------------------------------------------------------- /examples/rails5/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /examples/rails5/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /examples/rails5/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /examples/rails5/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /examples/rails5/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/public/apple-touch-icon.png -------------------------------------------------------------------------------- /examples/rails5/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/public/favicon.ico -------------------------------------------------------------------------------- /examples/rails5/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /examples/rails5/public/static.txt: -------------------------------------------------------------------------------- 1 | Hello world 2 | -------------------------------------------------------------------------------- /examples/rails5/storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/storage/.keep -------------------------------------------------------------------------------- /examples/rails5/test/application_system_test_case.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase 4 | driven_by :selenium, using: :chrome, screen_size: [1400, 1400] 5 | end 6 | -------------------------------------------------------------------------------- /examples/rails5/test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/test/controllers/.keep -------------------------------------------------------------------------------- /examples/rails5/test/fixtures/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/test/fixtures/.keep -------------------------------------------------------------------------------- /examples/rails5/test/fixtures/files/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/test/fixtures/files/.keep -------------------------------------------------------------------------------- /examples/rails5/test/helpers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/test/helpers/.keep -------------------------------------------------------------------------------- /examples/rails5/test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/test/integration/.keep -------------------------------------------------------------------------------- /examples/rails5/test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/test/mailers/.keep -------------------------------------------------------------------------------- /examples/rails5/test/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/test/models/.keep -------------------------------------------------------------------------------- /examples/rails5/test/system/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/test/system/.keep -------------------------------------------------------------------------------- /examples/rails5/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | require_relative '../config/environment' 3 | require 'rails/test_help' 4 | 5 | class ActiveSupport::TestCase 6 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 7 | fixtures :all 8 | 9 | # Add more helper methods to be used by all tests here... 10 | end 11 | -------------------------------------------------------------------------------- /examples/rails5/vendor/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails5/vendor/.keep -------------------------------------------------------------------------------- /examples/rails6/.browserslistrc: -------------------------------------------------------------------------------- 1 | defaults 2 | -------------------------------------------------------------------------------- /examples/rails6/.gitattributes: -------------------------------------------------------------------------------- 1 | # See https://git-scm.com/docs/gitattributes for more about git attribute files. 2 | 3 | # Mark the database schema as having been generated. 4 | db/schema.rb linguist-generated 5 | 6 | # Mark the yarn lockfile as having been generated. 7 | yarn.lock linguist-generated 8 | 9 | # Mark any vendored files as having been vendored. 10 | vendor/* linguist-vendored 11 | -------------------------------------------------------------------------------- /examples/rails6/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-* 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/* 16 | /tmp/* 17 | !/log/.keep 18 | !/tmp/.keep 19 | 20 | # Ignore pidfiles, but keep the directory. 21 | /tmp/pids/* 22 | !/tmp/pids/ 23 | !/tmp/pids/.keep 24 | 25 | # Ignore uploaded files in development. 26 | /storage/* 27 | !/storage/.keep 28 | 29 | /public/assets 30 | .byebug_history 31 | 32 | # Ignore master key for decrypting credentials and more. 33 | /config/master.key 34 | 35 | /public/packs 36 | /public/packs-test 37 | /node_modules 38 | /yarn-error.log 39 | yarn-debug.log* 40 | .yarn-integrity 41 | -------------------------------------------------------------------------------- /examples/rails6/.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.2 2 | -------------------------------------------------------------------------------- /examples/rails6/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 3 | 4 | ruby '2.7.2' 5 | 6 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 7 | gem 'rails', '~> 6.1.0' 8 | # Use sqlite3 as the database for Active Record 9 | gem 'sqlite3', '~> 1.4' 10 | # Use Puma as the app server 11 | gem 'puma', '~> 5.0' 12 | # Use SCSS for stylesheets 13 | gem 'sass-rails', '>= 6' 14 | # Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker 15 | gem 'webpacker', '~> 5.0' 16 | # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks 17 | gem 'turbolinks', '~> 5' 18 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 19 | gem 'jbuilder', '~> 2.7' 20 | # Use Redis adapter to run Action Cable in production 21 | # gem 'redis', '~> 4.0' 22 | # Use Active Model has_secure_password 23 | # gem 'bcrypt', '~> 3.1.7' 24 | 25 | # Use Active Storage variant 26 | # gem 'image_processing', '~> 1.2' 27 | 28 | # Reduces boot times through caching; required in config/boot.rb 29 | gem 'bootsnap', '>= 1.4.4', require: false 30 | 31 | group :development, :test do 32 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console 33 | gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] 34 | end 35 | 36 | group :development do 37 | # Access an interactive console on exception pages or by calling 'console' anywhere in the code. 38 | gem 'web-console', '>= 4.1.0' 39 | # Display performance information such as SQL time and flame graphs for each request in your browser. 40 | # Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md 41 | gem 'rack-mini-profiler', '~> 2.0' 42 | gem 'listen', '~> 3.3' 43 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 44 | gem 'spring' 45 | end 46 | 47 | group :test do 48 | # Adds support for Capybara system testing and selenium driver 49 | gem 'capybara', '>= 3.26' 50 | gem 'selenium-webdriver' 51 | # Easy installation and use of web drivers to run system tests with browsers 52 | gem 'webdrivers' 53 | end 54 | 55 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 56 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] 57 | 58 | gem 'rack-cors', '>= 1.1.0' 59 | -------------------------------------------------------------------------------- /examples/rails6/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (6.1.0) 5 | actionpack (= 6.1.0) 6 | activesupport (= 6.1.0) 7 | nio4r (~> 2.0) 8 | websocket-driver (>= 0.6.1) 9 | actionmailbox (6.1.0) 10 | actionpack (= 6.1.0) 11 | activejob (= 6.1.0) 12 | activerecord (= 6.1.0) 13 | activestorage (= 6.1.0) 14 | activesupport (= 6.1.0) 15 | mail (>= 2.7.1) 16 | actionmailer (6.1.0) 17 | actionpack (= 6.1.0) 18 | actionview (= 6.1.0) 19 | activejob (= 6.1.0) 20 | activesupport (= 6.1.0) 21 | mail (~> 2.5, >= 2.5.4) 22 | rails-dom-testing (~> 2.0) 23 | actionpack (6.1.0) 24 | actionview (= 6.1.0) 25 | activesupport (= 6.1.0) 26 | rack (~> 2.0, >= 2.0.9) 27 | rack-test (>= 0.6.3) 28 | rails-dom-testing (~> 2.0) 29 | rails-html-sanitizer (~> 1.0, >= 1.2.0) 30 | actiontext (6.1.0) 31 | actionpack (= 6.1.0) 32 | activerecord (= 6.1.0) 33 | activestorage (= 6.1.0) 34 | activesupport (= 6.1.0) 35 | nokogiri (>= 1.8.5) 36 | actionview (6.1.0) 37 | activesupport (= 6.1.0) 38 | builder (~> 3.1) 39 | erubi (~> 1.4) 40 | rails-dom-testing (~> 2.0) 41 | rails-html-sanitizer (~> 1.1, >= 1.2.0) 42 | activejob (6.1.0) 43 | activesupport (= 6.1.0) 44 | globalid (>= 0.3.6) 45 | activemodel (6.1.0) 46 | activesupport (= 6.1.0) 47 | activerecord (6.1.0) 48 | activemodel (= 6.1.0) 49 | activesupport (= 6.1.0) 50 | activestorage (6.1.0) 51 | actionpack (= 6.1.0) 52 | activejob (= 6.1.0) 53 | activerecord (= 6.1.0) 54 | activesupport (= 6.1.0) 55 | marcel (~> 0.3.1) 56 | mimemagic (~> 0.3.2) 57 | activesupport (6.1.0) 58 | concurrent-ruby (~> 1.0, >= 1.0.2) 59 | i18n (>= 1.6, < 2) 60 | minitest (>= 5.1) 61 | tzinfo (~> 2.0) 62 | zeitwerk (~> 2.3) 63 | addressable (2.7.0) 64 | public_suffix (>= 2.0.2, < 5.0) 65 | bindex (0.8.1) 66 | bootsnap (1.5.1) 67 | msgpack (~> 1.0) 68 | builder (3.2.4) 69 | byebug (11.1.3) 70 | capybara (3.34.0) 71 | addressable 72 | mini_mime (>= 0.1.3) 73 | nokogiri (~> 1.8) 74 | rack (>= 1.6.0) 75 | rack-test (>= 0.6.3) 76 | regexp_parser (~> 1.5) 77 | xpath (~> 3.2) 78 | childprocess (3.0.0) 79 | concurrent-ruby (1.1.7) 80 | crass (1.0.6) 81 | erubi (1.10.0) 82 | ffi (1.14.0) 83 | globalid (0.4.2) 84 | activesupport (>= 4.2.0) 85 | i18n (1.8.5) 86 | concurrent-ruby (~> 1.0) 87 | jbuilder (2.10.1) 88 | activesupport (>= 5.0.0) 89 | listen (3.3.3) 90 | rb-fsevent (~> 0.10, >= 0.10.3) 91 | rb-inotify (~> 0.9, >= 0.9.10) 92 | loofah (2.8.0) 93 | crass (~> 1.0.2) 94 | nokogiri (>= 1.5.9) 95 | mail (2.7.1) 96 | mini_mime (>= 0.1.1) 97 | marcel (0.3.3) 98 | mimemagic (~> 0.3.2) 99 | method_source (1.0.0) 100 | mimemagic (0.3.5) 101 | mini_mime (1.0.2) 102 | mini_portile2 (2.4.0) 103 | minitest (5.14.2) 104 | msgpack (1.3.3) 105 | nio4r (2.5.4) 106 | nokogiri (1.10.10) 107 | mini_portile2 (~> 2.4.0) 108 | public_suffix (4.0.6) 109 | puma (5.1.1) 110 | nio4r (~> 2.0) 111 | rack (2.2.3) 112 | rack-cors (1.1.1) 113 | rack (>= 2.0.0) 114 | rack-mini-profiler (2.2.0) 115 | rack (>= 1.2.0) 116 | rack-proxy (0.6.5) 117 | rack 118 | rack-test (1.1.0) 119 | rack (>= 1.0, < 3) 120 | rails (6.1.0) 121 | actioncable (= 6.1.0) 122 | actionmailbox (= 6.1.0) 123 | actionmailer (= 6.1.0) 124 | actionpack (= 6.1.0) 125 | actiontext (= 6.1.0) 126 | actionview (= 6.1.0) 127 | activejob (= 6.1.0) 128 | activemodel (= 6.1.0) 129 | activerecord (= 6.1.0) 130 | activestorage (= 6.1.0) 131 | activesupport (= 6.1.0) 132 | bundler (>= 1.15.0) 133 | railties (= 6.1.0) 134 | sprockets-rails (>= 2.0.0) 135 | rails-dom-testing (2.0.3) 136 | activesupport (>= 4.2.0) 137 | nokogiri (>= 1.6) 138 | rails-html-sanitizer (1.3.0) 139 | loofah (~> 2.3) 140 | railties (6.1.0) 141 | actionpack (= 6.1.0) 142 | activesupport (= 6.1.0) 143 | method_source 144 | rake (>= 0.8.7) 145 | thor (~> 1.0) 146 | rake (13.0.2) 147 | rb-fsevent (0.10.4) 148 | rb-inotify (0.10.1) 149 | ffi (~> 1.0) 150 | regexp_parser (1.8.2) 151 | rubyzip (2.3.0) 152 | sass-rails (6.0.0) 153 | sassc-rails (~> 2.1, >= 2.1.1) 154 | sassc (2.4.0) 155 | ffi (~> 1.9) 156 | sassc-rails (2.1.2) 157 | railties (>= 4.0.0) 158 | sassc (>= 2.0) 159 | sprockets (> 3.0) 160 | sprockets-rails 161 | tilt 162 | selenium-webdriver (3.142.7) 163 | childprocess (>= 0.5, < 4.0) 164 | rubyzip (>= 1.2.2) 165 | semantic_range (2.3.1) 166 | spring (2.1.1) 167 | sprockets (4.0.2) 168 | concurrent-ruby (~> 1.0) 169 | rack (> 1, < 3) 170 | sprockets-rails (3.2.2) 171 | actionpack (>= 4.0) 172 | activesupport (>= 4.0) 173 | sprockets (>= 3.0.0) 174 | sqlite3 (1.4.2) 175 | thor (1.0.1) 176 | tilt (2.0.10) 177 | turbolinks (5.2.1) 178 | turbolinks-source (~> 5.2) 179 | turbolinks-source (5.2.0) 180 | tzinfo (2.0.4) 181 | concurrent-ruby (~> 1.0) 182 | web-console (4.1.0) 183 | actionview (>= 6.0.0) 184 | activemodel (>= 6.0.0) 185 | bindex (>= 0.4.0) 186 | railties (>= 6.0.0) 187 | webdrivers (4.4.1) 188 | nokogiri (~> 1.6) 189 | rubyzip (>= 1.3.0) 190 | selenium-webdriver (>= 3.0, < 4.0) 191 | webpacker (5.2.1) 192 | activesupport (>= 5.2) 193 | rack-proxy (>= 0.6.1) 194 | railties (>= 5.2) 195 | semantic_range (>= 2.3.0) 196 | websocket-driver (0.7.3) 197 | websocket-extensions (>= 0.1.0) 198 | websocket-extensions (0.1.5) 199 | xpath (3.2.0) 200 | nokogiri (~> 1.8) 201 | zeitwerk (2.4.2) 202 | 203 | PLATFORMS 204 | ruby 205 | 206 | DEPENDENCIES 207 | bootsnap (>= 1.4.4) 208 | byebug 209 | capybara (>= 3.26) 210 | jbuilder (~> 2.7) 211 | listen (~> 3.3) 212 | puma (~> 5.0) 213 | rack-cors (>= 1.1.0) 214 | rack-mini-profiler (~> 2.0) 215 | rails (~> 6.1.0) 216 | sass-rails (>= 6) 217 | selenium-webdriver 218 | spring 219 | sqlite3 (~> 1.4) 220 | turbolinks (~> 5) 221 | tzinfo-data 222 | web-console (>= 4.1.0) 223 | webdrivers 224 | webpacker (~> 5.0) 225 | 226 | RUBY VERSION 227 | ruby 2.7.2p137 228 | 229 | BUNDLED WITH 230 | 2.1.4 231 | -------------------------------------------------------------------------------- /examples/rails6/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | This README would normally document whatever steps are necessary to get the 4 | application up and running. 5 | 6 | Things you may want to cover: 7 | 8 | * Ruby version 9 | 10 | * System dependencies 11 | 12 | * Configuration 13 | 14 | * Database creation 15 | 16 | * Database initialization 17 | 18 | * How to run the test suite 19 | 20 | * Services (job queues, cache servers, search engines, etc.) 21 | 22 | * Deployment instructions 23 | 24 | * ... 25 | -------------------------------------------------------------------------------- /examples/rails6/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative "config/application" 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /examples/rails6/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../stylesheets .css 3 | -------------------------------------------------------------------------------- /examples/rails6/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/app/assets/images/.keep -------------------------------------------------------------------------------- /examples/rails6/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's 6 | * vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /examples/rails6/app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /examples/rails6/app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /examples/rails6/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | end 3 | -------------------------------------------------------------------------------- /examples/rails6/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /examples/rails6/app/controllers/cors_controller.rb: -------------------------------------------------------------------------------- 1 | class CorsController < ApplicationController 2 | skip_before_action :verify_authenticity_token 3 | def create 4 | render plain: 'OK!' 5 | end 6 | end 7 | 8 | -------------------------------------------------------------------------------- /examples/rails6/app/controllers/welcome_controller.rb: -------------------------------------------------------------------------------- 1 | class WelcomeController < ApplicationController 2 | skip_before_action :verify_authenticity_token 3 | def index 4 | render plain: "Hello world" 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /examples/rails6/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /examples/rails6/app/javascript/channels/consumer.js: -------------------------------------------------------------------------------- 1 | // Action Cable provides the framework to deal with WebSockets in Rails. 2 | // You can generate new channels where WebSocket features live using the `bin/rails generate channel` command. 3 | 4 | import { createConsumer } from "@rails/actioncable" 5 | 6 | export default createConsumer() 7 | -------------------------------------------------------------------------------- /examples/rails6/app/javascript/channels/index.js: -------------------------------------------------------------------------------- 1 | // Load all the channels within this directory and all subdirectories. 2 | // Channel files must be named *_channel.js. 3 | 4 | const channels = require.context('.', true, /_channel\.js$/) 5 | channels.keys().forEach(channels) 6 | -------------------------------------------------------------------------------- /examples/rails6/app/javascript/packs/application.js: -------------------------------------------------------------------------------- 1 | // This file is automatically compiled by Webpack, along with any other files 2 | // present in this directory. You're encouraged to place your actual application logic in 3 | // a relevant structure within app/javascript and only use these pack files to reference 4 | // that code so it'll be compiled. 5 | 6 | import Rails from "@rails/ujs" 7 | import Turbolinks from "turbolinks" 8 | import * as ActiveStorage from "@rails/activestorage" 9 | import "channels" 10 | 11 | Rails.start() 12 | Turbolinks.start() 13 | ActiveStorage.start() 14 | -------------------------------------------------------------------------------- /examples/rails6/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | # Automatically retry jobs that encountered a deadlock 3 | # retry_on ActiveRecord::Deadlocked 4 | 5 | # Most jobs are safe to ignore if the underlying records are no longer available 6 | # discard_on ActiveJob::DeserializationError 7 | end 8 | -------------------------------------------------------------------------------- /examples/rails6/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /examples/rails6/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /examples/rails6/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/app/models/concerns/.keep -------------------------------------------------------------------------------- /examples/rails6/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rails6 5 | 6 | <%= csrf_meta_tags %> 7 | <%= csp_meta_tag %> 8 | 9 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 10 | <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> 11 | 12 | 13 | 14 | <%= yield %> 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/rails6/app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/rails6/app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /examples/rails6/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | var validEnv = ['development', 'test', 'production'] 3 | var currentEnv = api.env() 4 | var isDevelopmentEnv = api.env('development') 5 | var isProductionEnv = api.env('production') 6 | var isTestEnv = api.env('test') 7 | 8 | if (!validEnv.includes(currentEnv)) { 9 | throw new Error( 10 | 'Please specify a valid `NODE_ENV` or ' + 11 | '`BABEL_ENV` environment variables. Valid values are "development", ' + 12 | '"test", and "production". Instead, received: ' + 13 | JSON.stringify(currentEnv) + 14 | '.' 15 | ) 16 | } 17 | 18 | return { 19 | presets: [ 20 | isTestEnv && [ 21 | '@babel/preset-env', 22 | { 23 | targets: { 24 | node: 'current' 25 | } 26 | } 27 | ], 28 | (isProductionEnv || isDevelopmentEnv) && [ 29 | '@babel/preset-env', 30 | { 31 | forceAllTransforms: true, 32 | useBuiltIns: 'entry', 33 | corejs: 3, 34 | modules: false, 35 | exclude: ['transform-typeof-symbol'] 36 | } 37 | ] 38 | ].filter(Boolean), 39 | plugins: [ 40 | 'babel-plugin-macros', 41 | '@babel/plugin-syntax-dynamic-import', 42 | isTestEnv && 'babel-plugin-dynamic-import-node', 43 | '@babel/plugin-transform-destructuring', 44 | [ 45 | '@babel/plugin-proposal-class-properties', 46 | { 47 | loose: true 48 | } 49 | ], 50 | [ 51 | '@babel/plugin-proposal-object-rest-spread', 52 | { 53 | useBuiltIns: true 54 | } 55 | ], 56 | [ 57 | '@babel/plugin-transform-runtime', 58 | { 59 | helpers: false 60 | } 61 | ], 62 | [ 63 | '@babel/plugin-transform-regenerator', 64 | { 65 | async: false 66 | } 67 | ] 68 | ].filter(Boolean) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /examples/rails6/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'bundle' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "rubygems" 12 | 13 | m = Module.new do 14 | module_function 15 | 16 | def invoked_as_script? 17 | File.expand_path($0) == File.expand_path(__FILE__) 18 | end 19 | 20 | def env_var_version 21 | ENV["BUNDLER_VERSION"] 22 | end 23 | 24 | def cli_arg_version 25 | return unless invoked_as_script? # don't want to hijack other binstubs 26 | return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` 27 | bundler_version = nil 28 | update_index = nil 29 | ARGV.each_with_index do |a, i| 30 | if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN 31 | bundler_version = a 32 | end 33 | next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ 34 | bundler_version = $1 35 | update_index = i 36 | end 37 | bundler_version 38 | end 39 | 40 | def gemfile 41 | gemfile = ENV["BUNDLE_GEMFILE"] 42 | return gemfile if gemfile && !gemfile.empty? 43 | 44 | File.expand_path("../../Gemfile", __FILE__) 45 | end 46 | 47 | def lockfile 48 | lockfile = 49 | case File.basename(gemfile) 50 | when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) 51 | else "#{gemfile}.lock" 52 | end 53 | File.expand_path(lockfile) 54 | end 55 | 56 | def lockfile_version 57 | return unless File.file?(lockfile) 58 | lockfile_contents = File.read(lockfile) 59 | return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ 60 | Regexp.last_match(1) 61 | end 62 | 63 | def bundler_version 64 | @bundler_version ||= 65 | env_var_version || cli_arg_version || 66 | lockfile_version 67 | end 68 | 69 | def bundler_requirement 70 | return "#{Gem::Requirement.default}.a" unless bundler_version 71 | 72 | bundler_gem_version = Gem::Version.new(bundler_version) 73 | 74 | requirement = bundler_gem_version.approximate_recommendation 75 | 76 | return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") 77 | 78 | requirement += ".a" if bundler_gem_version.prerelease? 79 | 80 | requirement 81 | end 82 | 83 | def load_bundler! 84 | ENV["BUNDLE_GEMFILE"] ||= gemfile 85 | 86 | activate_bundler 87 | end 88 | 89 | def activate_bundler 90 | gem_error = activation_error_handling do 91 | gem "bundler", bundler_requirement 92 | end 93 | return if gem_error.nil? 94 | require_error = activation_error_handling do 95 | require "bundler/version" 96 | end 97 | return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) 98 | warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" 99 | exit 42 100 | end 101 | 102 | def activation_error_handling 103 | yield 104 | nil 105 | rescue StandardError, LoadError => e 106 | e 107 | end 108 | end 109 | 110 | m.load_bundler! 111 | 112 | if m.invoked_as_script? 113 | load Gem.bin_path("bundler", "bundle") 114 | end 115 | -------------------------------------------------------------------------------- /examples/rails6/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | load File.expand_path("spring", __dir__) 3 | APP_PATH = File.expand_path('../config/application', __dir__) 4 | require_relative "../config/boot" 5 | require "rails/commands" 6 | -------------------------------------------------------------------------------- /examples/rails6/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | load File.expand_path("spring", __dir__) 3 | require_relative "../config/boot" 4 | require "rake" 5 | Rake.application.run 6 | -------------------------------------------------------------------------------- /examples/rails6/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "fileutils" 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path('..', __dir__) 6 | 7 | def system!(*args) 8 | system(*args) || abort("\n== Command #{args} failed ==") 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to set up or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at any time and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # Install JavaScript dependencies 21 | system! 'bin/yarn' 22 | 23 | # puts "\n== Copying sample files ==" 24 | # unless File.exist?('config/database.yml') 25 | # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' 26 | # end 27 | 28 | puts "\n== Preparing database ==" 29 | system! 'bin/rails db:prepare' 30 | 31 | puts "\n== Removing old logs and tempfiles ==" 32 | system! 'bin/rails log:clear tmp:clear' 33 | 34 | puts "\n== Restarting application server ==" 35 | system! 'bin/rails restart' 36 | end 37 | -------------------------------------------------------------------------------- /examples/rails6/bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | if !defined?(Spring) && [nil, "development", "test"].include?(ENV["RAILS_ENV"]) 3 | # Load Spring without loading other gems in the Gemfile, for speed. 4 | require "bundler" 5 | Bundler.locked_gems.specs.find { |spec| spec.name == "spring" }&.tap do |spring| 6 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path 7 | gem "spring", spring.version 8 | require "spring/binstub" 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /examples/rails6/bin/webpack: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" 4 | ENV["NODE_ENV"] ||= "development" 5 | 6 | require "pathname" 7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 8 | Pathname.new(__FILE__).realpath) 9 | 10 | require "bundler/setup" 11 | 12 | require "webpacker" 13 | require "webpacker/webpack_runner" 14 | 15 | APP_ROOT = File.expand_path("..", __dir__) 16 | Dir.chdir(APP_ROOT) do 17 | Webpacker::WebpackRunner.run(ARGV) 18 | end 19 | -------------------------------------------------------------------------------- /examples/rails6/bin/webpack-dev-server: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" 4 | ENV["NODE_ENV"] ||= "development" 5 | 6 | require "pathname" 7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 8 | Pathname.new(__FILE__).realpath) 9 | 10 | require "bundler/setup" 11 | 12 | require "webpacker" 13 | require "webpacker/dev_server_runner" 14 | 15 | APP_ROOT = File.expand_path("..", __dir__) 16 | Dir.chdir(APP_ROOT) do 17 | Webpacker::DevServerRunner.run(ARGV) 18 | end 19 | -------------------------------------------------------------------------------- /examples/rails6/bin/yarn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | 4 | APP_ROOT = File.expand_path('..', __dir__) 5 | Dir.chdir(APP_ROOT) do 6 | executable_path = ENV["PATH"].split(File::PATH_SEPARATOR).find do |path| 7 | normalized_path = File.expand_path(path) 8 | 9 | normalized_path != __dir__ && File.executable?(Pathname.new(normalized_path).join('yarn')) 10 | end 11 | 12 | if executable_path 13 | exec File.expand_path(Pathname.new(executable_path).join('yarn')), *ARGV 14 | else 15 | $stderr.puts "Yarn executable was not detected in the system." 16 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" 17 | exit 1 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /examples/rails6/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative "config/environment" 4 | 5 | run Rails.application 6 | Rails.application.load_server 7 | -------------------------------------------------------------------------------- /examples/rails6/config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative "boot" 2 | 3 | require "rails/all" 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module Rails6 10 | class Application < Rails::Application 11 | # Initialize configuration defaults for originally generated Rails version. 12 | config.load_defaults 6.1 13 | 14 | # Configuration for the application, engines, and railties goes here. 15 | # 16 | # These settings can be overridden in specific environments using the files 17 | # in config/environments, which are processed later. 18 | # 19 | # config.time_zone = "Central Time (US & Canada)" 20 | # config.eager_load_paths << Rails.root.join("extras") 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /examples/rails6/config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require "bundler/setup" # Set up gems listed in the Gemfile. 4 | require "bootsnap/setup" # Speed up boot time by caching expensive operations. 5 | -------------------------------------------------------------------------------- /examples/rails6/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: test 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: rails6_production 11 | -------------------------------------------------------------------------------- /examples/rails6/config/credentials.yml.enc: -------------------------------------------------------------------------------- 1 | XN/v2/Y0Gm7X15uD+o5UHJoC1vWkOCc4J6HYnm0CCxipX3izJ24NIDdgdfGSsLl039XVNfpy6868fwVeS7bP1M+bU5s0Yn3eovxpn9GaydEanfKZmKPSlm5N9MeQujKzuMLo2kRuQKJCs41geV/tQ4tCUVVQw7ODkLTfQSa4NUJX9zOs2gVhqnei4DW8bx9oRXiQZDMHW+7SShzfINCktzUdoaexL3TZYIeYx5jHoz0ROKVFPO1K8JMstuO7TRLIoxCuwOgB6fwuik+d70fooaOb0Etcl/aKJwBsPtGpseyzc6G2FXoQGp+UX+v9XBcZiyxB2QPbPplqxm0iF0JFPAdR8Dm+Y8bJ60ohJJdgEjSml6lc7Hic0C7lOQpmIaK6rg6YOFG7T92zzcFxXQZSe4wJ6ZILMT0Sy6Vu--TTYYpDe/sqVFFHC1--Kc+cOpgDLWRjpezIjzySdQ== -------------------------------------------------------------------------------- /examples/rails6/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite. Versions 3.8.0 and up are supported. 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /examples/rails6/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /examples/rails6/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # In the development environment your application's code is reloaded any time 7 | # it changes. This slows down response time but is perfect for development 8 | # since you don't have to restart the web server when you make code changes. 9 | config.cache_classes = false 10 | 11 | # Do not eager load code on boot. 12 | config.eager_load = false 13 | 14 | # Show full error reports. 15 | config.consider_all_requests_local = true 16 | 17 | # Enable/disable caching. By default caching is disabled. 18 | # Run rails dev:cache to toggle caching. 19 | if Rails.root.join('tmp', 'caching-dev.txt').exist? 20 | config.action_controller.perform_caching = true 21 | config.action_controller.enable_fragment_cache_logging = true 22 | 23 | config.cache_store = :memory_store 24 | config.public_file_server.headers = { 25 | 'Cache-Control' => "public, max-age=#{2.days.to_i}" 26 | } 27 | else 28 | config.action_controller.perform_caching = false 29 | 30 | config.cache_store = :null_store 31 | end 32 | 33 | # Store uploaded files on the local file system (see config/storage.yml for options). 34 | config.active_storage.service = :local 35 | 36 | # Don't care if the mailer can't send. 37 | config.action_mailer.raise_delivery_errors = false 38 | 39 | config.action_mailer.perform_caching = false 40 | 41 | # Print deprecation notices to the Rails logger. 42 | config.active_support.deprecation = :log 43 | 44 | # Raise exceptions for disallowed deprecations. 45 | config.active_support.disallowed_deprecation = :raise 46 | 47 | # Tell Active Support which deprecation messages to disallow. 48 | config.active_support.disallowed_deprecation_warnings = [] 49 | 50 | # Raise an error on page load if there are pending migrations. 51 | config.active_record.migration_error = :page_load 52 | 53 | # Highlight code that triggered database queries in logs. 54 | config.active_record.verbose_query_logs = true 55 | 56 | # Debug mode disables concatenation and preprocessing of assets. 57 | # This option may cause significant delays in view rendering with a large 58 | # number of complex assets. 59 | config.assets.debug = true 60 | 61 | # Suppress logger output for asset requests. 62 | config.assets.quiet = true 63 | 64 | # Raises error for missing translations. 65 | # config.i18n.raise_on_missing_translations = true 66 | 67 | # Annotate rendered view with file names. 68 | # config.action_view.annotate_rendered_view_with_filenames = true 69 | 70 | # Use an evented file watcher to asynchronously detect changes in source code, 71 | # routes, locales, etc. This feature depends on the listen gem. 72 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker 73 | 74 | # Uncomment if you wish to allow Action Cable access from any origin. 75 | # config.action_cable.disable_request_forgery_protection = true 76 | 77 | config.hosts << "127.0.0.1.xip.io" 78 | end 79 | -------------------------------------------------------------------------------- /examples/rails6/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # Code is not reloaded between requests. 7 | config.cache_classes = true 8 | 9 | # Eager load code on boot. This eager loads most of Rails and 10 | # your application in memory, allowing both threaded web servers 11 | # and those relying on copy on write to perform better. 12 | # Rake tasks automatically ignore this option for performance. 13 | config.eager_load = true 14 | 15 | # Full error reports are disabled and caching is turned on. 16 | config.consider_all_requests_local = false 17 | config.action_controller.perform_caching = true 18 | 19 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] 20 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). 21 | # config.require_master_key = true 22 | 23 | # Disable serving static files from the `/public` folder by default since 24 | # Apache or NGINX already handles this. 25 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? 26 | 27 | # Compress CSS using a preprocessor. 28 | # config.assets.css_compressor = :sass 29 | 30 | # Do not fallback to assets pipeline if a precompiled asset is missed. 31 | config.assets.compile = false 32 | 33 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 34 | # config.asset_host = 'http://assets.example.com' 35 | 36 | # Specifies the header that your server uses for sending files. 37 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 38 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 39 | 40 | # Store uploaded files on the local file system (see config/storage.yml for options). 41 | config.active_storage.service = :local 42 | 43 | # Mount Action Cable outside main process or domain. 44 | # config.action_cable.mount_path = nil 45 | # config.action_cable.url = 'wss://example.com/cable' 46 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] 47 | 48 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 49 | # config.force_ssl = true 50 | 51 | # Include generic and useful information about system operation, but avoid logging too much 52 | # information to avoid inadvertent exposure of personally identifiable information (PII). 53 | config.log_level = :info 54 | 55 | # Prepend all log lines with the following tags. 56 | config.log_tags = [ :request_id ] 57 | 58 | # Use a different cache store in production. 59 | # config.cache_store = :mem_cache_store 60 | 61 | # Use a real queuing backend for Active Job (and separate queues per environment). 62 | # config.active_job.queue_adapter = :resque 63 | # config.active_job.queue_name_prefix = "rails6_production" 64 | 65 | config.action_mailer.perform_caching = false 66 | 67 | # Ignore bad email addresses and do not raise email delivery errors. 68 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 69 | # config.action_mailer.raise_delivery_errors = false 70 | 71 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 72 | # the I18n.default_locale when a translation cannot be found). 73 | config.i18n.fallbacks = true 74 | 75 | # Send deprecation notices to registered listeners. 76 | config.active_support.deprecation = :notify 77 | 78 | # Log disallowed deprecations. 79 | config.active_support.disallowed_deprecation = :log 80 | 81 | # Tell Active Support which deprecation messages to disallow. 82 | config.active_support.disallowed_deprecation_warnings = [] 83 | 84 | # Use default logging formatter so that PID and timestamp are not suppressed. 85 | config.log_formatter = ::Logger::Formatter.new 86 | 87 | # Use a different logger for distributed setups. 88 | # require "syslog/logger" 89 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') 90 | 91 | if ENV["RAILS_LOG_TO_STDOUT"].present? 92 | logger = ActiveSupport::Logger.new(STDOUT) 93 | logger.formatter = config.log_formatter 94 | config.logger = ActiveSupport::TaggedLogging.new(logger) 95 | end 96 | 97 | # Do not dump schema after migrations. 98 | config.active_record.dump_schema_after_migration = false 99 | 100 | # Inserts middleware to perform automatic connection switching. 101 | # The `database_selector` hash is used to pass options to the DatabaseSelector 102 | # middleware. The `delay` is used to determine how long to wait after a write 103 | # to send a subsequent read to the primary. 104 | # 105 | # The `database_resolver` class is used by the middleware to determine which 106 | # database is appropriate to use based on the time delay. 107 | # 108 | # The `database_resolver_context` class is used by the middleware to set 109 | # timestamps for the last write to the primary. The resolver uses the context 110 | # class timestamps to determine how long to wait before reading from the 111 | # replica. 112 | # 113 | # By default Rails will store a last write timestamp in the session. The 114 | # DatabaseSelector middleware is designed as such you can define your own 115 | # strategy for connection switching and pass that into the middleware through 116 | # these configuration options. 117 | # config.active_record.database_selector = { delay: 2.seconds } 118 | # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver 119 | # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session 120 | end 121 | -------------------------------------------------------------------------------- /examples/rails6/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | # The test environment is used exclusively to run your application's 4 | # test suite. You never need to work with it otherwise. Remember that 5 | # your test database is "scratch space" for the test suite and is wiped 6 | # and recreated between test runs. Don't rely on the data there! 7 | 8 | Rails.application.configure do 9 | # Settings specified here will take precedence over those in config/application.rb. 10 | 11 | config.cache_classes = false 12 | config.action_view.cache_template_loading = true 13 | 14 | # Do not eager load code on boot. This avoids loading your whole application 15 | # just for the purpose of running a single test. If you are using a tool that 16 | # preloads Rails for running tests, you may have to set it to true. 17 | config.eager_load = false 18 | 19 | # Configure public file server for tests with Cache-Control for performance. 20 | config.public_file_server.enabled = true 21 | config.public_file_server.headers = { 22 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}" 23 | } 24 | 25 | # Show full error reports and disable caching. 26 | config.consider_all_requests_local = true 27 | config.action_controller.perform_caching = false 28 | config.cache_store = :null_store 29 | 30 | # Raise exceptions instead of rendering exception templates. 31 | config.action_dispatch.show_exceptions = false 32 | 33 | # Disable request forgery protection in test environment. 34 | config.action_controller.allow_forgery_protection = false 35 | 36 | # Store uploaded files on the local file system in a temporary directory. 37 | config.active_storage.service = :test 38 | 39 | config.action_mailer.perform_caching = false 40 | 41 | # Tell Action Mailer not to deliver emails to the real world. 42 | # The :test delivery method accumulates sent emails in the 43 | # ActionMailer::Base.deliveries array. 44 | config.action_mailer.delivery_method = :test 45 | 46 | # Print deprecation notices to the stderr. 47 | config.active_support.deprecation = :stderr 48 | 49 | # Raise exceptions for disallowed deprecations. 50 | config.active_support.disallowed_deprecation = :raise 51 | 52 | # Tell Active Support which deprecation messages to disallow. 53 | config.active_support.disallowed_deprecation_warnings = [] 54 | 55 | # Raises error for missing translations. 56 | # config.i18n.raise_on_missing_translations = true 57 | 58 | # Annotate rendered view with file names. 59 | # config.action_view.annotate_rendered_view_with_filenames = true 60 | end 61 | -------------------------------------------------------------------------------- /examples/rails6/config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /examples/rails6/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | # Add Yarn node_modules folder to the asset load path. 9 | Rails.application.config.assets.paths << Rails.root.join('node_modules') 10 | 11 | # Precompile additional assets. 12 | # application.js, application.css, and all non-JS/CSS in the app/assets 13 | # folder are already added. 14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 15 | -------------------------------------------------------------------------------- /examples/rails6/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code 7 | # by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'". 8 | Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"] 9 | -------------------------------------------------------------------------------- /examples/rails6/config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy 4 | # For further information see the following documentation 5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy 6 | 7 | # Rails.application.config.content_security_policy do |policy| 8 | # policy.default_src :self, :https 9 | # policy.font_src :self, :https, :data 10 | # policy.img_src :self, :https, :data 11 | # policy.object_src :none 12 | # policy.script_src :self, :https 13 | # policy.style_src :self, :https 14 | # # If you are using webpack-dev-server then specify webpack-dev-server host 15 | # policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development? 16 | 17 | # # Specify URI for violation reports 18 | # # policy.report_uri "/csp-violation-report-endpoint" 19 | # end 20 | 21 | # If you are using UJS then enable automatic nonce generation 22 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } 23 | 24 | # Set the nonce only to specific directives 25 | # Rails.application.config.content_security_policy_nonce_directives = %w(script-src) 26 | 27 | # Report CSP violations to a specified URI 28 | # For further information see the following documentation: 29 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only 30 | # Rails.application.config.content_security_policy_report_only = true 31 | -------------------------------------------------------------------------------- /examples/rails6/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /examples/rails6/config/initializers/cors.rb: -------------------------------------------------------------------------------- 1 | # Avoid CORS issues when API is called from the frontend app. 2 | # Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests. 3 | 4 | # Read more: https://github.com/cyu/rack-cors 5 | 6 | Rails.application.config.middleware.insert_before 0, Rack::Cors, debug: true, logger: (-> { Rails.logger }) do 7 | allow do 8 | origins '*' 9 | 10 | resource '/cors', 11 | :headers => :any, 12 | :methods => [:post], 13 | :max_age => 0 14 | 15 | resource '*', 16 | :headers => :any, 17 | :methods => [:get, :post, :delete, :put, :patch, :options, :head], 18 | :max_age => 0 19 | end 20 | end 21 | 22 | -------------------------------------------------------------------------------- /examples/rails6/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [ 5 | :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn 6 | ] 7 | -------------------------------------------------------------------------------- /examples/rails6/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /examples/rails6/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /examples/rails6/config/initializers/permissions_policy.rb: -------------------------------------------------------------------------------- 1 | # Define an application-wide HTTP permissions policy. For further 2 | # information see https://developers.google.com/web/updates/2018/06/feature-policy 3 | # 4 | # Rails.application.config.permissions_policy do |f| 5 | # f.camera :none 6 | # f.gyroscope :none 7 | # f.microphone :none 8 | # f.usb :none 9 | # f.fullscreen :self 10 | # f.payment :self, "https://secure.example.com" 11 | # end 12 | -------------------------------------------------------------------------------- /examples/rails6/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /examples/rails6/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at https://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /examples/rails6/config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 8 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } 9 | threads min_threads_count, max_threads_count 10 | 11 | # Specifies the `worker_timeout` threshold that Puma will use to wait before 12 | # terminating a worker in development environments. 13 | # 14 | worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" 15 | 16 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 17 | # 18 | port ENV.fetch("PORT") { 3000 } 19 | 20 | # Specifies the `environment` that Puma will run in. 21 | # 22 | environment ENV.fetch("RAILS_ENV") { "development" } 23 | 24 | # Specifies the `pidfile` that Puma will use. 25 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 26 | 27 | # Specifies the number of `workers` to boot in clustered mode. 28 | # Workers are forked web server processes. If using threads and workers together 29 | # the concurrency of the application would be max `threads` * `workers`. 30 | # Workers do not work on JRuby or Windows (both of which do not support 31 | # processes). 32 | # 33 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 34 | 35 | # Use the `preload_app!` method when specifying a `workers` number. 36 | # This directive tells Puma to first boot the application and load code 37 | # before forking the application. This takes advantage of Copy On Write 38 | # process behavior so workers use less memory. 39 | # 40 | # preload_app! 41 | 42 | # Allow puma to be restarted by `rails restart` command. 43 | plugin :tmp_restart 44 | -------------------------------------------------------------------------------- /examples/rails6/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html 3 | resources :cors 4 | match '/', to: "welcome#index", via: [:get, :post, :put, :delete, :options, :head, :patch] 5 | match '/*glob', to: "welcome#index", via: [:get, :post, :put, :delete, :options, :head, :patch] 6 | end 7 | -------------------------------------------------------------------------------- /examples/rails6/config/spring.rb: -------------------------------------------------------------------------------- 1 | Spring.watch( 2 | ".ruby-version", 3 | ".rbenv-vars", 4 | "tmp/restart.txt", 5 | "tmp/caching-dev.txt" 6 | ) 7 | -------------------------------------------------------------------------------- /examples/rails6/config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket 23 | 24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /examples/rails6/config/webpack/development.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development' 2 | 3 | const environment = require('./environment') 4 | 5 | module.exports = environment.toWebpackConfig() 6 | -------------------------------------------------------------------------------- /examples/rails6/config/webpack/environment.js: -------------------------------------------------------------------------------- 1 | const { environment } = require('@rails/webpacker') 2 | 3 | module.exports = environment 4 | -------------------------------------------------------------------------------- /examples/rails6/config/webpack/production.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV || 'production' 2 | 3 | const environment = require('./environment') 4 | 5 | module.exports = environment.toWebpackConfig() 6 | -------------------------------------------------------------------------------- /examples/rails6/config/webpack/test.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development' 2 | 3 | const environment = require('./environment') 4 | 5 | module.exports = environment.toWebpackConfig() 6 | -------------------------------------------------------------------------------- /examples/rails6/config/webpacker.yml: -------------------------------------------------------------------------------- 1 | # Note: You must restart bin/webpack-dev-server for changes to take effect 2 | 3 | default: &default 4 | source_path: app/javascript 5 | source_entry_path: packs 6 | public_root_path: public 7 | public_output_path: packs 8 | cache_path: tmp/cache/webpacker 9 | webpack_compile_output: true 10 | 11 | # Additional paths webpack should lookup modules 12 | # ['app/assets', 'engine/foo/app/assets'] 13 | additional_paths: [] 14 | 15 | # Reload manifest.json on all requests so we reload latest compiled packs 16 | cache_manifest: false 17 | 18 | # Extract and emit a css file 19 | extract_css: false 20 | 21 | static_assets_extensions: 22 | - .jpg 23 | - .jpeg 24 | - .png 25 | - .gif 26 | - .tiff 27 | - .ico 28 | - .svg 29 | - .eot 30 | - .otf 31 | - .ttf 32 | - .woff 33 | - .woff2 34 | 35 | extensions: 36 | - .mjs 37 | - .js 38 | - .sass 39 | - .scss 40 | - .css 41 | - .module.sass 42 | - .module.scss 43 | - .module.css 44 | - .png 45 | - .svg 46 | - .gif 47 | - .jpeg 48 | - .jpg 49 | 50 | development: 51 | <<: *default 52 | compile: true 53 | 54 | # Reference: https://webpack.js.org/configuration/dev-server/ 55 | dev_server: 56 | https: false 57 | host: localhost 58 | port: 3035 59 | public: localhost:3035 60 | hmr: false 61 | # Inline should be set to true if using HMR 62 | inline: true 63 | overlay: true 64 | compress: true 65 | disable_host_check: true 66 | use_local_ip: false 67 | quiet: false 68 | pretty: false 69 | headers: 70 | 'Access-Control-Allow-Origin': '*' 71 | watch_options: 72 | ignored: '**/node_modules/**' 73 | 74 | 75 | test: 76 | <<: *default 77 | compile: true 78 | 79 | # Compile test packs to a separate directory 80 | public_output_path: packs-test 81 | 82 | production: 83 | <<: *default 84 | 85 | # Production depends on precompilation of packs prior to booting for performance. 86 | compile: false 87 | 88 | # Extract and emit a css file 89 | extract_css: true 90 | 91 | # Cache manifest.json for performance 92 | cache_manifest: true 93 | -------------------------------------------------------------------------------- /examples/rails6/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) 7 | # Character.create(name: 'Luke', movie: movies.first) 8 | -------------------------------------------------------------------------------- /examples/rails6/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/lib/assets/.keep -------------------------------------------------------------------------------- /examples/rails6/lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/lib/tasks/.keep -------------------------------------------------------------------------------- /examples/rails6/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/log/.keep -------------------------------------------------------------------------------- /examples/rails6/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rails6", 3 | "private": true, 4 | "dependencies": { 5 | "@rails/actioncable": "^6.0.0", 6 | "@rails/activestorage": "^6.0.0", 7 | "@rails/ujs": "^6.0.0", 8 | "@rails/webpacker": "5.2.1", 9 | "turbolinks": "^5.2.0" 10 | }, 11 | "version": "0.1.0", 12 | "devDependencies": { 13 | "webpack-dev-server": "^3.11.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/rails6/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-import'), 4 | require('postcss-flexbugs-fixes'), 5 | require('postcss-preset-env')({ 6 | autoprefixer: { 7 | flexbox: 'no-2009' 8 | }, 9 | stage: 3 10 | }) 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /examples/rails6/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /examples/rails6/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /examples/rails6/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /examples/rails6/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /examples/rails6/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/public/apple-touch-icon.png -------------------------------------------------------------------------------- /examples/rails6/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/public/favicon.ico -------------------------------------------------------------------------------- /examples/rails6/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /examples/rails6/public/static.txt: -------------------------------------------------------------------------------- 1 | Hello world 2 | -------------------------------------------------------------------------------- /examples/rails6/storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/storage/.keep -------------------------------------------------------------------------------- /examples/rails6/test/application_system_test_case.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase 4 | driven_by :selenium, using: :chrome, screen_size: [1400, 1400] 5 | end 6 | -------------------------------------------------------------------------------- /examples/rails6/test/channels/application_cable/connection_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase 4 | # test "connects with cookies" do 5 | # cookies.signed[:user_id] = 42 6 | # 7 | # connect 8 | # 9 | # assert_equal connection.user_id, "42" 10 | # end 11 | end 12 | -------------------------------------------------------------------------------- /examples/rails6/test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/test/controllers/.keep -------------------------------------------------------------------------------- /examples/rails6/test/fixtures/files/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/test/fixtures/files/.keep -------------------------------------------------------------------------------- /examples/rails6/test/helpers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/test/helpers/.keep -------------------------------------------------------------------------------- /examples/rails6/test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/test/integration/.keep -------------------------------------------------------------------------------- /examples/rails6/test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/test/mailers/.keep -------------------------------------------------------------------------------- /examples/rails6/test/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/test/models/.keep -------------------------------------------------------------------------------- /examples/rails6/test/system/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/test/system/.keep -------------------------------------------------------------------------------- /examples/rails6/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | require_relative "../config/environment" 3 | require "rails/test_help" 4 | 5 | class ActiveSupport::TestCase 6 | # Run tests in parallel with specified workers 7 | parallelize(workers: :number_of_processors) 8 | 9 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 10 | fixtures :all 11 | 12 | # Add more helper methods to be used by all tests here... 13 | end 14 | -------------------------------------------------------------------------------- /examples/rails6/vendor/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyu/rack-cors/f73bcd39b91c19ffa3d059dccc5d6ae62f24340a/examples/rails6/vendor/.keep -------------------------------------------------------------------------------- /lib/rack/cors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'logger' 4 | require_relative 'cors/resources' 5 | require_relative 'cors/resource' 6 | require_relative 'cors/result' 7 | require_relative 'cors/version' 8 | 9 | module Rack 10 | class Cors 11 | HTTP_ORIGIN = 'HTTP_ORIGIN' 12 | HTTP_X_ORIGIN = 'HTTP_X_ORIGIN' 13 | 14 | HTTP_ACCESS_CONTROL_REQUEST_METHOD = 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' 15 | HTTP_ACCESS_CONTROL_REQUEST_HEADERS = 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' 16 | 17 | PATH_INFO = 'PATH_INFO' 18 | REQUEST_METHOD = 'REQUEST_METHOD' 19 | 20 | RACK_LOGGER = 'rack.logger' 21 | RACK_CORS = 22 | # retaining the old key for backwards compatibility 23 | ENV_KEY = 'rack.cors' 24 | 25 | OPTIONS = 'OPTIONS' 26 | 27 | DEFAULT_VARY_HEADERS = ['Origin'].freeze 28 | 29 | def initialize(app, opts = {}, &block) 30 | @app = app 31 | @debug_mode = !!opts[:debug] 32 | @logger = @logger_proc = nil 33 | 34 | logger = opts[:logger] 35 | if logger 36 | if logger.respond_to? :call 37 | @logger_proc = opts[:logger] 38 | else 39 | @logger = logger 40 | end 41 | end 42 | 43 | return unless block_given? 44 | 45 | if block.arity == 1 46 | block.call(self) 47 | else 48 | instance_eval(&block) 49 | end 50 | end 51 | 52 | def debug? 53 | @debug_mode 54 | end 55 | 56 | def allow(&block) 57 | all_resources << (resources = Resources.new) 58 | 59 | if block.arity == 1 60 | block.call(resources) 61 | else 62 | resources.instance_eval(&block) 63 | end 64 | end 65 | 66 | def call(env) 67 | env[HTTP_ORIGIN] ||= env[HTTP_X_ORIGIN] if env[HTTP_X_ORIGIN] 68 | 69 | path = evaluate_path(env) 70 | 71 | add_headers = nil 72 | if env[HTTP_ORIGIN] 73 | debug(env) do 74 | ['Incoming Headers:', 75 | " Origin: #{env[HTTP_ORIGIN]}", 76 | " Path-Info: #{path}", 77 | " Access-Control-Request-Method: #{env[HTTP_ACCESS_CONTROL_REQUEST_METHOD]}", 78 | " Access-Control-Request-Headers: #{env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]}"].join("\n") 79 | end 80 | 81 | if env[REQUEST_METHOD] == OPTIONS && env[HTTP_ACCESS_CONTROL_REQUEST_METHOD] 82 | return [400, {}, []] unless Rack::Utils.valid_path?(path) 83 | 84 | headers = process_preflight(env, path) 85 | debug(env) do 86 | "Preflight Headers:\n" + 87 | headers.collect { |kv| " #{kv.join(': ')}" }.join("\n") 88 | end 89 | return [200, headers, []] 90 | else 91 | add_headers = process_cors(env, path) 92 | end 93 | else 94 | Result.miss(env, Result::MISS_NO_ORIGIN) 95 | end 96 | 97 | # This call must be done BEFORE calling the app because for some reason 98 | # env[PATH_INFO] gets changed after that and it won't match. (At least 99 | # in rails 4.1.6) 100 | vary_resource = resource_for_path(path) 101 | 102 | status, headers, body = @app.call env 103 | 104 | if add_headers 105 | headers = add_headers.merge(headers) 106 | debug(env) do 107 | add_headers.each_pair do |key, value| 108 | headers["x-rack-cors-original-#{key}"] = value if headers.key?(key) 109 | end 110 | end 111 | end 112 | 113 | # Vary header should ALWAYS mention Origin if there's ANY chance for the 114 | # response to be different depending on the Origin header value. 115 | # Better explained here: http://www.fastly.com/blog/best-practices-for-using-the-vary-header/ 116 | if vary_resource 117 | vary = headers['vary'] 118 | cors_vary_headers = if vary_resource.vary_headers&.any? 119 | vary_resource.vary_headers 120 | else 121 | DEFAULT_VARY_HEADERS 122 | end 123 | headers['vary'] = ((vary ? [vary].flatten.map { |v| v.split(/,\s*/) }.flatten : []) + cors_vary_headers).uniq.join(', ') 124 | end 125 | 126 | result = env[ENV_KEY] 127 | result.append_header(headers) if debug? && result 128 | 129 | [status, headers, body] 130 | end 131 | 132 | protected 133 | 134 | def debug(env, message = nil, &block) 135 | (@logger || select_logger(env)).debug(message, &block) if debug? 136 | end 137 | 138 | def select_logger(env) 139 | @logger = if @logger_proc 140 | logger_proc = @logger_proc 141 | @logger_proc = nil 142 | logger_proc.call 143 | 144 | elsif defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger 145 | Rails.logger 146 | 147 | elsif env[RACK_LOGGER] 148 | env[RACK_LOGGER] 149 | 150 | else 151 | ::Logger.new(STDOUT).tap { |logger| logger.level = ::Logger::Severity::DEBUG } 152 | end 153 | end 154 | 155 | def evaluate_path(env) 156 | path = env[PATH_INFO] 157 | 158 | if path 159 | path = Rack::Utils.unescape_path(path) 160 | 161 | path = Rack::Utils.clean_path_info(path) if Rack::Utils.valid_path?(path) 162 | end 163 | 164 | path 165 | end 166 | 167 | def all_resources 168 | @all_resources ||= [] 169 | end 170 | 171 | def process_preflight(env, path) 172 | result = Result.preflight(env) 173 | 174 | resource, error = match_resource(path, env) 175 | unless resource 176 | result.miss(error) 177 | return {} 178 | end 179 | 180 | resource.process_preflight(env, result) 181 | end 182 | 183 | def process_cors(env, path) 184 | resource, error = match_resource(path, env) 185 | if resource 186 | Result.hit(env) 187 | cors = resource.to_headers(env) 188 | cors 189 | 190 | else 191 | Result.miss(env, error) 192 | nil 193 | end 194 | end 195 | 196 | def resource_for_path(path_info) 197 | all_resources.each do |r| 198 | found = r.resource_for_path(path_info) 199 | return found if found 200 | end 201 | nil 202 | end 203 | 204 | def match_resource(path, env) 205 | origin = env[HTTP_ORIGIN] 206 | 207 | origin_matched = false 208 | all_resources.each do |r| 209 | next unless r.allow_origin?(origin, env) 210 | 211 | origin_matched = true 212 | found = r.match_resource(path, env) 213 | return [found, nil] if found 214 | end 215 | 216 | [nil, origin_matched ? Result::MISS_NO_PATH : Result::MISS_NO_ORIGIN] 217 | end 218 | end 219 | end 220 | -------------------------------------------------------------------------------- /lib/rack/cors/resource.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Rack 4 | class Cors 5 | class Resource 6 | # All CORS routes need to accept CORS simple headers at all times 7 | # {https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers} 8 | CORS_SIMPLE_HEADERS = %w[accept accept-language content-language content-type].freeze 9 | 10 | attr_accessor :path, :methods, :headers, :expose, :max_age, :credentials, :pattern, :if_proc, :vary_headers 11 | 12 | def initialize(public_resource, path, opts = {}) 13 | raise CorsMisconfigurationError if public_resource && opts[:credentials] == true 14 | 15 | self.path = path 16 | self.credentials = public_resource ? false : (opts[:credentials] == true) 17 | self.max_age = opts[:max_age] || 7200 18 | self.pattern = compile(path) 19 | self.if_proc = opts[:if] 20 | self.vary_headers = opts[:vary] && [opts[:vary]].flatten 21 | @public_resource = public_resource 22 | 23 | self.headers = case opts[:headers] 24 | when :any then :any 25 | when nil then nil 26 | else 27 | [opts[:headers]].flatten.collect(&:downcase) 28 | end 29 | 30 | self.methods = case opts[:methods] 31 | when :any then %i[get head post put patch delete options] 32 | else 33 | ensure_enum(opts[:methods]) || [:get] 34 | end.map(&:to_s) 35 | 36 | self.expose = opts[:expose] ? [opts[:expose]].flatten : nil 37 | end 38 | 39 | def matches_path?(path) 40 | pattern =~ path 41 | end 42 | 43 | def match?(path, env) 44 | matches_path?(path) && (if_proc.nil? || if_proc.call(env)) 45 | end 46 | 47 | def process_preflight(env, result) 48 | headers = {} 49 | 50 | request_method = env[Rack::Cors::HTTP_ACCESS_CONTROL_REQUEST_METHOD] 51 | result.miss(Result::MISS_NO_METHOD) && (return headers) if request_method.nil? 52 | result.miss(Result::MISS_DENY_METHOD) && (return headers) unless methods.include?(request_method.downcase) 53 | 54 | request_headers = env[Rack::Cors::HTTP_ACCESS_CONTROL_REQUEST_HEADERS] 55 | result.miss(Result::MISS_DENY_HEADER) && (return headers) if request_headers && !allow_headers?(request_headers) 56 | 57 | result.hit = true 58 | headers.merge(to_preflight_headers(env)) 59 | end 60 | 61 | def to_headers(env) 62 | h = { 63 | 'access-control-allow-origin' => origin_for_response_header(env[Rack::Cors::HTTP_ORIGIN]), 64 | 'access-control-allow-methods' => methods.collect { |m| m.to_s.upcase }.join(', '), 65 | 'access-control-expose-headers' => expose.nil? ? '' : expose.join(', '), 66 | 'access-control-max-age' => max_age.to_s 67 | } 68 | h['access-control-allow-credentials'] = 'true' if credentials 69 | header_proc.call(h) 70 | end 71 | 72 | protected 73 | 74 | def public_resource? 75 | @public_resource 76 | end 77 | 78 | def origin_for_response_header(origin) 79 | return '*' if public_resource? 80 | 81 | origin 82 | end 83 | 84 | def to_preflight_headers(env) 85 | h = to_headers(env) 86 | h.merge!('access-control-allow-headers' => env[Rack::Cors::HTTP_ACCESS_CONTROL_REQUEST_HEADERS]) if env[Rack::Cors::HTTP_ACCESS_CONTROL_REQUEST_HEADERS] 87 | h 88 | end 89 | 90 | def allow_headers?(request_headers) 91 | headers = self.headers || [] 92 | return true if headers == :any 93 | 94 | request_headers = request_headers.split(/,\s*/) if request_headers.is_a?(String) 95 | request_headers.all? do |header| 96 | header = header.downcase 97 | CORS_SIMPLE_HEADERS.include?(header) || headers.include?(header) 98 | end 99 | end 100 | 101 | def ensure_enum(var) 102 | return nil if var.nil? 103 | 104 | [var].flatten 105 | end 106 | 107 | def compile(path) 108 | if path.respond_to? :to_str 109 | special_chars = %w[. + ( ) $] 110 | pattern = 111 | path.to_str.gsub(%r{((:\w+)|/\*|[\*#{special_chars.join}])}) do |match| 112 | case match 113 | when '/*' 114 | '\\/?(.*?)' 115 | when '*' 116 | '(.*?)' 117 | when *special_chars 118 | Regexp.escape(match) 119 | else 120 | '([^/?&#]+)' 121 | end 122 | end 123 | /^#{pattern}$/ 124 | elsif path.respond_to? :match 125 | path 126 | else 127 | raise TypeError, path 128 | end 129 | end 130 | 131 | def header_proc 132 | @header_proc ||= begin 133 | if defined?(Rack::Headers) 134 | ->(h) { h } 135 | else 136 | ->(h) { Rack::Utils::HeaderHash.new(h) } 137 | end 138 | end 139 | end 140 | end 141 | end 142 | end 143 | -------------------------------------------------------------------------------- /lib/rack/cors/resources.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'resources/cors_misconfiguration_error' 4 | 5 | module Rack 6 | class Cors 7 | class Resources 8 | attr_reader :resources 9 | 10 | def initialize 11 | @origins = [] 12 | @resources = [] 13 | @public_resources = false 14 | end 15 | 16 | def origins(*args, &blk) 17 | @origins = args.flatten.reject { |s| s == '' }.map do |n| 18 | case n 19 | when Proc, Regexp, %r{^[a-z][a-z0-9.+-]*://} 20 | n 21 | when '*' 22 | @public_resources = true 23 | n 24 | else 25 | Regexp.compile("^[a-z][a-z0-9.+-]*:\\\/\\\/#{Regexp.quote(n)}$") 26 | end 27 | end.flatten 28 | @origins.push(blk) if blk 29 | end 30 | 31 | def resource(path, opts = {}) 32 | @resources << Resource.new(public_resources?, path, opts) 33 | end 34 | 35 | def public_resources? 36 | @public_resources 37 | end 38 | 39 | def allow_origin?(source, env = {}) 40 | return true if public_resources? 41 | 42 | !!@origins.detect do |origin| 43 | if origin.is_a?(Proc) 44 | origin.call(source, env) 45 | elsif origin.is_a?(Regexp) 46 | source =~ origin 47 | else 48 | source == origin 49 | end 50 | end 51 | end 52 | 53 | def match_resource(path, env) 54 | @resources.detect { |r| r.match?(path, env) } 55 | end 56 | 57 | def resource_for_path(path) 58 | @resources.detect { |r| r.matches_path?(path) } 59 | end 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /lib/rack/cors/resources/cors_misconfiguration_error.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Rack 4 | class Cors 5 | class Resource 6 | class CorsMisconfigurationError < StandardError 7 | def message 8 | 'Allowing credentials for wildcard origins is insecure.' \ 9 | " Please specify more restrictive origins or set 'credentials' to false in your CORS configuration." 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/rack/cors/result.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Rack 4 | class Cors 5 | class Result 6 | HEADER_KEY = 'x-rack-cors' 7 | 8 | MISS_NO_ORIGIN = 'no-origin' 9 | MISS_NO_PATH = 'no-path' 10 | 11 | MISS_NO_METHOD = 'no-method' 12 | MISS_DENY_METHOD = 'deny-method' 13 | MISS_DENY_HEADER = 'deny-header' 14 | 15 | attr_accessor :preflight, :hit, :miss_reason 16 | 17 | def hit? 18 | !!hit 19 | end 20 | 21 | def preflight? 22 | !!preflight 23 | end 24 | 25 | def miss(reason) 26 | self.hit = false 27 | self.miss_reason = reason 28 | end 29 | 30 | def self.hit(env) 31 | r = Result.new 32 | r.preflight = false 33 | r.hit = true 34 | env[Rack::Cors::ENV_KEY] = r 35 | end 36 | 37 | def self.miss(env, reason) 38 | r = Result.new 39 | r.preflight = false 40 | r.hit = false 41 | r.miss_reason = reason 42 | env[Rack::Cors::ENV_KEY] = r 43 | end 44 | 45 | def self.preflight(env) 46 | r = Result.new 47 | r.preflight = true 48 | env[Rack::Cors::ENV_KEY] = r 49 | end 50 | 51 | def append_header(headers) 52 | headers[HEADER_KEY] = if hit? 53 | preflight? ? 'preflight-hit' : 'hit' 54 | else 55 | [ 56 | (preflight? ? 'preflight-miss' : 'miss'), 57 | miss_reason 58 | ].join('; ') 59 | end 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /lib/rack/cors/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Rack 4 | class Cors 5 | VERSION = '3.0.0' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /rack-cors.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | lib = File.expand_path('lib', __dir__) 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 5 | require 'rack/cors/version' 6 | 7 | Gem::Specification.new do |spec| 8 | spec.name = 'rack-cors' 9 | spec.version = Rack::Cors::VERSION 10 | spec.authors = ['Calvin Yu'] 11 | spec.email = ['me@sourcebender.com'] 12 | spec.description = 'Middleware that will make Rack-based apps CORS compatible. Fork the project here: https://github.com/cyu/rack-cors' 13 | spec.summary = 'Middleware for enabling Cross-Origin Resource Sharing in Rack apps' 14 | spec.homepage = 'https://github.com/cyu/rack-cors' 15 | spec.license = 'MIT' 16 | 17 | spec.files = Dir['CHANGELOG.md', 'README.md', 'LICENSE.txt', 'lib/**/*'] 18 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 19 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 20 | spec.require_paths = ['lib'] 21 | 22 | spec.metadata = { 23 | 'changelog_uri' => 'https://github.com/cyu/rack-cors/blob/master/CHANGELOG.md', 24 | 'funding_uri' => 'https://github.com/sponsors/cyu' 25 | } 26 | 27 | spec.add_dependency 'logger' 28 | spec.add_dependency 'rack', '>= 3.0.14' 29 | spec.add_development_dependency 'bundler', '>= 1.16.0', '< 3' 30 | spec.add_development_dependency 'minitest' 31 | spec.add_development_dependency 'mocha' 32 | spec.add_development_dependency 'pry', '~> 0.12' 33 | spec.add_development_dependency 'rack-test', '>= 1.1.0' 34 | spec.add_development_dependency 'rake', '~> 12.3.0' 35 | spec.add_development_dependency 'rubocop', '~> 0.80.1' 36 | end 37 | -------------------------------------------------------------------------------- /test/.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | inherit_from: ../.rubocop.yml 3 | 4 | # Disables 5 | Style/ClassAndModuleChildren: 6 | Enabled: false 7 | Security/Eval: 8 | Enabled: false 9 | -------------------------------------------------------------------------------- /test/cors/mocha.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | body { 4 | margin:0; 5 | } 6 | 7 | #mocha { 8 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | margin: 60px 50px; 10 | } 11 | 12 | #mocha ul, #mocha li { 13 | margin: 0; 14 | padding: 0; 15 | } 16 | 17 | #mocha ul { 18 | list-style: none; 19 | } 20 | 21 | #mocha h1, #mocha h2 { 22 | margin: 0; 23 | } 24 | 25 | #mocha h1 { 26 | margin-top: 15px; 27 | font-size: 1em; 28 | font-weight: 200; 29 | } 30 | 31 | #mocha h1 a { 32 | text-decoration: none; 33 | color: inherit; 34 | } 35 | 36 | #mocha h1 a:hover { 37 | text-decoration: underline; 38 | } 39 | 40 | #mocha .suite .suite h1 { 41 | margin-top: 0; 42 | font-size: .8em; 43 | } 44 | 45 | #mocha .hidden { 46 | display: none; 47 | } 48 | 49 | #mocha h2 { 50 | font-size: 12px; 51 | font-weight: normal; 52 | cursor: pointer; 53 | } 54 | 55 | #mocha .suite { 56 | margin-left: 15px; 57 | } 58 | 59 | #mocha .test { 60 | margin-left: 15px; 61 | overflow: hidden; 62 | } 63 | 64 | #mocha .test.pending:hover h2::after { 65 | content: '(pending)'; 66 | font-family: arial, sans-serif; 67 | } 68 | 69 | #mocha .test.pass.medium .duration { 70 | background: #C09853; 71 | } 72 | 73 | #mocha .test.pass.slow .duration { 74 | background: #B94A48; 75 | } 76 | 77 | #mocha .test.pass::before { 78 | content: '✓'; 79 | font-size: 12px; 80 | display: block; 81 | float: left; 82 | margin-right: 5px; 83 | color: #00d6b2; 84 | } 85 | 86 | #mocha .test.pass .duration { 87 | font-size: 9px; 88 | margin-left: 5px; 89 | padding: 2px 5px; 90 | color: white; 91 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 92 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 93 | box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 94 | -webkit-border-radius: 5px; 95 | -moz-border-radius: 5px; 96 | -ms-border-radius: 5px; 97 | -o-border-radius: 5px; 98 | border-radius: 5px; 99 | } 100 | 101 | #mocha .test.pass.fast .duration { 102 | display: none; 103 | } 104 | 105 | #mocha .test.pending { 106 | color: #0b97c4; 107 | } 108 | 109 | #mocha .test.pending::before { 110 | content: '◦'; 111 | color: #0b97c4; 112 | } 113 | 114 | #mocha .test.fail { 115 | color: #c00; 116 | } 117 | 118 | #mocha .test.fail pre { 119 | color: black; 120 | } 121 | 122 | #mocha .test.fail::before { 123 | content: '✖'; 124 | font-size: 12px; 125 | display: block; 126 | float: left; 127 | margin-right: 5px; 128 | color: #c00; 129 | } 130 | 131 | #mocha .test pre.error { 132 | color: #c00; 133 | max-height: 300px; 134 | overflow: auto; 135 | } 136 | 137 | #mocha .test pre { 138 | display: block; 139 | float: left; 140 | clear: left; 141 | font: 12px/1.5 monaco, monospace; 142 | margin: 5px; 143 | padding: 15px; 144 | border: 1px solid #eee; 145 | border-bottom-color: #ddd; 146 | -webkit-border-radius: 3px; 147 | -webkit-box-shadow: 0 1px 3px #eee; 148 | -moz-border-radius: 3px; 149 | -moz-box-shadow: 0 1px 3px #eee; 150 | } 151 | 152 | #mocha .test h2 { 153 | position: relative; 154 | } 155 | 156 | #mocha .test a.replay { 157 | position: absolute; 158 | top: 3px; 159 | right: 0; 160 | text-decoration: none; 161 | vertical-align: middle; 162 | display: block; 163 | width: 15px; 164 | height: 15px; 165 | line-height: 15px; 166 | text-align: center; 167 | background: #eee; 168 | font-size: 15px; 169 | -moz-border-radius: 15px; 170 | border-radius: 15px; 171 | -webkit-transition: opacity 200ms; 172 | -moz-transition: opacity 200ms; 173 | transition: opacity 200ms; 174 | opacity: 0.3; 175 | color: #888; 176 | } 177 | 178 | #mocha .test:hover a.replay { 179 | opacity: 1; 180 | } 181 | 182 | #mocha-report.pass .test.fail { 183 | display: none; 184 | } 185 | 186 | #mocha-report.fail .test.pass { 187 | display: none; 188 | } 189 | 190 | #mocha-error { 191 | color: #c00; 192 | font-size: 1.5em; 193 | font-weight: 100; 194 | letter-spacing: 1px; 195 | } 196 | 197 | #mocha-stats { 198 | position: fixed; 199 | top: 15px; 200 | right: 10px; 201 | font-size: 12px; 202 | margin: 0; 203 | color: #888; 204 | } 205 | 206 | #mocha-stats .progress { 207 | float: right; 208 | padding-top: 0; 209 | } 210 | 211 | #mocha-stats em { 212 | color: black; 213 | } 214 | 215 | #mocha-stats a { 216 | text-decoration: none; 217 | color: inherit; 218 | } 219 | 220 | #mocha-stats a:hover { 221 | border-bottom: 1px solid #eee; 222 | } 223 | 224 | #mocha-stats li { 225 | display: inline-block; 226 | margin: 0 5px; 227 | list-style: none; 228 | padding-top: 11px; 229 | } 230 | 231 | #mocha-stats canvas { 232 | width: 40px; 233 | height: 40px; 234 | } 235 | 236 | #mocha code .comment { color: #ddd } 237 | #mocha code .init { color: #2F6FAD } 238 | #mocha code .string { color: #5890AD } 239 | #mocha code .keyword { color: #8A6343 } 240 | #mocha code .number { color: #2F6FAD } 241 | 242 | @media screen and (max-device-width: 480px) { 243 | #mocha { 244 | margin: 60px 0px; 245 | } 246 | 247 | #mocha #stats { 248 | position: absolute; 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /test/cors/runner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mocha Tests 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/cors/test.cors.coffee: -------------------------------------------------------------------------------- 1 | CORS_SERVER = '127.0.0.1.xip.io:3000' 2 | 3 | mocha.setup({ignoreLeaks: true}); 4 | 5 | describe 'CORS', -> 6 | 7 | it 'should allow access to dynamic resource', (done) -> 8 | $.get "http://#{CORS_SERVER}/", (data, status, xhr) -> 9 | expect(data).to.eql('Hello world') 10 | done() 11 | 12 | it 'should allow PUT access to dynamic resource', (done) -> 13 | $.ajax("http://#{CORS_SERVER}/", type: 'PUT').done (data, textStatus, jqXHR) -> 14 | expect(data).to.eql('Hello world') 15 | done() 16 | 17 | it 'should allow PATCH access to dynamic resource', (done) -> 18 | $.ajax("http://#{CORS_SERVER}/", type: 'PATCH').done (data, textStatus, jqXHR) -> 19 | expect(data).to.eql('Hello world') 20 | done() 21 | 22 | it 'should allow HEAD access to dynamic resource', (done) -> 23 | $.ajax("http://#{CORS_SERVER}/", type: 'HEAD').done (data, textStatus, jqXHR) -> 24 | expect(jqXHR.status).to.eql(200) 25 | done() 26 | 27 | it 'should allow DELETE access to dynamic resource', (done) -> 28 | $.ajax("http://#{CORS_SERVER}/", type: 'DELETE').done (data, textStatus, jqXHR) -> 29 | expect(data).to.eql('Hello world') 30 | done() 31 | 32 | it 'should allow OPTIONS access to dynamic resource', (done) -> 33 | $.ajax("http://#{CORS_SERVER}/", type: 'OPTIONS').done (data, textStatus, jqXHR) -> 34 | expect(jqXHR.status).to.eql(200) 35 | done() 36 | 37 | it 'should allow access to static resource', (done) -> 38 | $.get "http://#{CORS_SERVER}/static.txt", (data, status, xhr) -> 39 | expect($.trim(data)).to.eql("Hello world") 40 | done() 41 | 42 | it 'should allow post resource', (done) -> 43 | $.ajax 44 | type: 'POST' 45 | url: "http://#{CORS_SERVER}/cors" 46 | beforeSend: (xhr) -> xhr.setRequestHeader('X-Requested-With', 'XMLHTTPRequest') 47 | success:(data, status, xhr) -> 48 | expect($.trim(data)).to.eql("OK!") 49 | done() 50 | -------------------------------------------------------------------------------- /test/cors/test.cors.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 2.3.1 2 | (function() { 3 | var CORS_SERVER; 4 | 5 | CORS_SERVER = '127.0.0.1.xip.io:3000'; 6 | 7 | mocha.setup({ 8 | ignoreLeaks: true 9 | }); 10 | 11 | describe('CORS', function() { 12 | it('should allow access to dynamic resource', function(done) { 13 | return $.get(`http://${CORS_SERVER}/`, function(data, status, xhr) { 14 | expect(data).to.eql('Hello world'); 15 | return done(); 16 | }); 17 | }); 18 | it('should allow PUT access to dynamic resource', function(done) { 19 | return $.ajax(`http://${CORS_SERVER}/`, { 20 | type: 'PUT' 21 | }).done(function(data, textStatus, jqXHR) { 22 | expect(data).to.eql('Hello world'); 23 | return done(); 24 | }); 25 | }); 26 | it('should allow PATCH access to dynamic resource', function(done) { 27 | return $.ajax(`http://${CORS_SERVER}/`, { 28 | type: 'PATCH' 29 | }).done(function(data, textStatus, jqXHR) { 30 | expect(data).to.eql('Hello world'); 31 | return done(); 32 | }); 33 | }); 34 | it('should allow HEAD access to dynamic resource', function(done) { 35 | return $.ajax(`http://${CORS_SERVER}/`, { 36 | type: 'HEAD' 37 | }).done(function(data, textStatus, jqXHR) { 38 | expect(jqXHR.status).to.eql(200); 39 | return done(); 40 | }); 41 | }); 42 | it('should allow DELETE access to dynamic resource', function(done) { 43 | return $.ajax(`http://${CORS_SERVER}/`, { 44 | type: 'DELETE' 45 | }).done(function(data, textStatus, jqXHR) { 46 | expect(data).to.eql('Hello world'); 47 | return done(); 48 | }); 49 | }); 50 | it('should allow OPTIONS access to dynamic resource', function(done) { 51 | return $.ajax(`http://${CORS_SERVER}/`, { 52 | type: 'OPTIONS' 53 | }).done(function(data, textStatus, jqXHR) { 54 | expect(jqXHR.status).to.eql(200); 55 | return done(); 56 | }); 57 | }); 58 | it('should allow access to static resource', function(done) { 59 | return $.get(`http://${CORS_SERVER}/static.txt`, function(data, status, xhr) { 60 | expect($.trim(data)).to.eql("Hello world"); 61 | return done(); 62 | }); 63 | }); 64 | return it('should allow post resource', function(done) { 65 | return $.ajax({ 66 | type: 'POST', 67 | url: `http://${CORS_SERVER}/cors`, 68 | beforeSend: function(xhr) { 69 | return xhr.setRequestHeader('X-Requested-With', 'XMLHTTPRequest'); 70 | }, 71 | success: function(data, status, xhr) { 72 | expect($.trim(data)).to.eql("OK!"); 73 | return done(); 74 | } 75 | }); 76 | }); 77 | }); 78 | 79 | }).call(this); 80 | -------------------------------------------------------------------------------- /test/unit/cors_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rack/builder' 4 | require 'rack/lint' 5 | require 'minitest/autorun' 6 | require 'rack/test' 7 | require 'mocha/minitest' 8 | require 'rack/cors' 9 | require 'ostruct' 10 | 11 | Rack::Test::Session.class_eval do 12 | unless defined? :options 13 | def options(uri, params = {}, env = {}, &block) 14 | env = env_for(uri, env.merge(method: 'OPTIONS', params: params)) 15 | process_request(uri, env, &block) 16 | end 17 | end 18 | end 19 | 20 | Rack::Test::Methods.class_eval do 21 | def_delegator :current_session, :options 22 | end 23 | 24 | module Minitest::Assertions 25 | def assert_cors_success(response) 26 | assert !response.headers['Access-Control-Allow-Origin'].nil?, 'Expected a successful CORS response' 27 | end 28 | 29 | def assert_not_cors_success(response) 30 | assert response.headers['Access-Control-Allow-Origin'].nil?, 'Expected a failed CORS response' 31 | end 32 | end 33 | 34 | class CaptureResult 35 | def initialize(app, options = {}) 36 | @app = app 37 | @result_holder = options[:holder] 38 | end 39 | 40 | def call(env) 41 | response = @app.call(env) 42 | @result_holder.cors_result = env[Rack::Cors::RACK_CORS] 43 | response 44 | end 45 | end 46 | 47 | class FakeProxy 48 | def initialize(app, _options = {}) 49 | @app = app 50 | end 51 | 52 | def call(env) 53 | status, headers, body = @app.call(env) 54 | headers['vary'] = %w[Origin User-Agent] 55 | [status, headers, body] 56 | end 57 | end 58 | 59 | Rack::MockResponse.infect_an_assertion :assert_cors_success, :must_render_cors_success, :only_one_argument 60 | Rack::MockResponse.infect_an_assertion :assert_not_cors_success, :wont_render_cors_success, :only_one_argument 61 | 62 | describe Rack::Cors do 63 | include Rack::Test::Methods 64 | 65 | attr_accessor :cors_result 66 | 67 | def load_app(name, options = {}) 68 | test = self 69 | Rack::Builder.new do 70 | use CaptureResult, holder: test 71 | eval File.read(File.dirname(__FILE__) + "/#{name}.ru") 72 | use FakeProxy if options[:proxy] 73 | map('/') do 74 | run(lambda do |_env| 75 | [200, { 'content-type' => 'text/html' }, ['success']] 76 | end) 77 | end 78 | end 79 | end 80 | 81 | let(:app) { load_app('test') } 82 | 83 | it 'should support simple CORS request' do 84 | successful_cors_request 85 | _(cors_result).must_be :hit 86 | end 87 | 88 | it "should not return CORS headers if Origin header isn't present" do 89 | get '/' 90 | _(last_response).wont_render_cors_success 91 | _(cors_result).wont_be :hit 92 | end 93 | 94 | it 'should support OPTIONS CORS request' do 95 | successful_cors_request '/options', method: :options 96 | end 97 | 98 | it 'should support regex origins configuration' do 99 | successful_cors_request origin: 'http://192.168.0.1:1234' 100 | end 101 | 102 | it 'should support subdomain example' do 103 | successful_cors_request origin: 'http://subdomain.example.com' 104 | end 105 | 106 | it 'should support proc origins configuration' do 107 | successful_cors_request '/proc-origin', origin: 'http://10.10.10.10:3000' 108 | end 109 | 110 | it 'should support lambda origin configuration' do 111 | successful_cors_request '/lambda-origin', origin: 'http://10.10.10.10:3000' 112 | end 113 | 114 | it 'should support proc origins configuration (inverse)' do 115 | cors_request '/proc-origin', origin: 'http://bad.guy' 116 | _(last_response).wont_render_cors_success 117 | end 118 | 119 | it 'should not mix up path rules across origins' do 120 | header 'Origin', 'http://10.10.10.10:3000' 121 | get '/' # / is configured in a separate rule block 122 | _(last_response).wont_render_cors_success 123 | end 124 | 125 | it 'should support alternative X-Origin header' do 126 | header 'X-Origin', 'http://localhost:3000' 127 | get '/' 128 | _(last_response).must_render_cors_success 129 | end 130 | 131 | it 'should support expose header configuration' do 132 | successful_cors_request '/expose_single_header' 133 | _(last_response.headers['Access-Control-Expose-Headers']).must_equal 'expose-test' 134 | end 135 | 136 | it 'should support expose multiple header configuration' do 137 | successful_cors_request '/expose_multiple_headers' 138 | _(last_response.headers['Access-Control-Expose-Headers']).must_equal 'expose-test-1, expose-test-2' 139 | end 140 | 141 | # Explanation: http://www.fastly.com/blog/best-practices-for-using-the-vary-header/ 142 | it "should add Vary header if resource matches even if Origin header isn't present" do 143 | get '/' 144 | _(last_response).wont_render_cors_success 145 | _(last_response.headers['Vary']).must_equal 'Origin' 146 | end 147 | 148 | it 'should add Vary header based on :vary option' do 149 | successful_cors_request '/vary_test' 150 | _(last_response.headers['Vary']).must_equal 'Origin, Host' 151 | end 152 | 153 | it 'decode URL and resolve paths before resource matching' do 154 | header 'Origin', 'http://localhost:3000' 155 | get '/public/a/..%2F..%2Fprivate/stuff' 156 | _(last_response).wont_render_cors_success 157 | end 158 | 159 | describe 'with upstream Vary headers' do 160 | let(:app) { load_app('test', { proxy: true }) } 161 | 162 | it 'should add to them' do 163 | successful_cors_request '/vary_test' 164 | _(last_response.headers['Vary']).must_equal 'Origin, User-Agent, Host' 165 | end 166 | end 167 | 168 | it 'should add Vary header if Access-Control-Allow-Origin header was added and if it is specific' do 169 | successful_cors_request '/', origin: 'http://192.168.0.3:8080' 170 | _(last_response.headers['Access-Control-Allow-Origin']).must_equal 'http://192.168.0.3:8080' 171 | _(last_response.headers['Vary']).wont_be_nil 172 | end 173 | 174 | it 'should add Vary header even if Access-Control-Allow-Origin header was added and it is generic (*)' do 175 | successful_cors_request '/public_without_credentials', origin: 'http://192.168.1.3:8080' 176 | _(last_response.headers['Access-Control-Allow-Origin']).must_equal '*' 177 | _(last_response.headers['Vary']).must_equal 'Origin' 178 | end 179 | 180 | it 'should support multi allow configurations for the same resource' do 181 | successful_cors_request '/multi-allow-config', origin: 'http://mucho-grande.com' 182 | _(last_response.headers['Access-Control-Allow-Origin']).must_equal 'http://mucho-grande.com' 183 | _(last_response.headers['Vary']).must_equal 'Origin' 184 | 185 | successful_cors_request '/multi-allow-config', origin: 'http://192.168.1.3:8080' 186 | _(last_response.headers['Access-Control-Allow-Origin']).must_equal '*' 187 | _(last_response.headers['Vary']).must_equal 'Origin' 188 | end 189 | 190 | it 'should not return CORS headers on OPTIONS request if Access-Control-Allow-Origin is not present' do 191 | options '/get-only' 192 | _(last_response.headers['Access-Control-Allow-Origin']).must_be_nil 193 | end 194 | 195 | it 'should not apply CORS headers if it does not match conditional on resource' do 196 | header 'Origin', 'http://192.168.0.1:1234' 197 | get '/conditional' 198 | _(last_response).wont_render_cors_success 199 | end 200 | 201 | it 'should apply CORS headers if it does match conditional on resource' do 202 | header 'X-OK', '1' 203 | successful_cors_request '/conditional', origin: 'http://192.168.0.1:1234' 204 | end 205 | 206 | it 'should not allow everything if Origin is configured as blank string' do 207 | cors_request '/blank-origin', origin: 'http://example.net' 208 | _(last_response).wont_render_cors_success 209 | end 210 | 211 | it 'should not allow credentials for public resources' do 212 | successful_cors_request '/public' 213 | _(last_response.headers['Access-Control-Allow-Credentials']).must_be_nil 214 | end 215 | 216 | describe 'logging' do 217 | it 'should not log debug messages if debug option is false' do 218 | app = mock 219 | app.stubs(:call).returns(200, {}, ['']) 220 | 221 | logger = mock 222 | logger.expects(:debug).never 223 | 224 | cors = Rack::Cors.new(app, debug: false, logger: logger) {} 225 | cors.send(:debug, {}, 'testing') 226 | end 227 | 228 | it 'should log debug messages if debug option is true' do 229 | app = mock 230 | app.stubs(:call).returns(200, {}, ['']) 231 | 232 | logger = mock 233 | logger.expects(:debug) 234 | 235 | cors = Rack::Cors.new(app, debug: true, logger: logger) {} 236 | cors.send(:debug, {}, 'testing') 237 | end 238 | 239 | it 'should use rack.logger if available' do 240 | app = mock 241 | app.stubs(:call).returns([200, {}, ['']]) 242 | 243 | logger = mock 244 | logger.expects(:debug).at_least_once 245 | 246 | cors = Rack::Cors.new(app, debug: true) {} 247 | cors.call({ 'rack.logger' => logger, 'HTTP_ORIGIN' => 'test.com' }) 248 | end 249 | 250 | it 'should use logger proc' do 251 | app = mock 252 | app.stubs(:call).returns([200, {}, ['']]) 253 | 254 | logger = mock 255 | logger.expects(:debug) 256 | 257 | cors = Rack::Cors.new(app, debug: true, logger: proc { logger }) {} 258 | cors.call({ 'HTTP_ORIGIN' => 'test.com' }) 259 | end 260 | 261 | describe 'with Rails setup' do 262 | after do 263 | ::Rails.logger = nil if defined?(::Rails) 264 | end 265 | 266 | it 'should use Rails.logger if available' do 267 | app = mock 268 | app.stubs(:call).returns([200, {}, ['']]) 269 | 270 | logger = mock 271 | logger.expects(:debug) 272 | 273 | ::Rails = OpenStruct.new(logger: logger) 274 | 275 | cors = Rack::Cors.new(app, debug: true) {} 276 | cors.call({ 'HTTP_ORIGIN' => 'test.com' }) 277 | end 278 | end 279 | 280 | it 'should use Logger if none is set' do 281 | app = mock 282 | app.stubs(:call).returns([200, {}, ['']]) 283 | 284 | logger = mock 285 | Logger.expects(:new).returns(logger) 286 | logger.expects(:tap).returns(logger) 287 | logger.expects(:debug) 288 | 289 | cors = Rack::Cors.new(app, debug: true) {} 290 | cors.call({ 'HTTP_ORIGIN' => 'test.com' }) 291 | end 292 | end 293 | 294 | describe 'preflight requests' do 295 | it 'should fail if origin is invalid' do 296 | preflight_request('http://allyourdataarebelongtous.com', '/') 297 | _(last_response).wont_render_cors_success 298 | _(cors_result).wont_be :hit 299 | _(cors_result).must_be :preflight 300 | end 301 | 302 | it 'should fail if Access-Control-Request-Method is not allowed' do 303 | preflight_request('http://localhost:3000', '/get-only', method: :post) 304 | _(last_response).wont_render_cors_success 305 | _(cors_result.miss_reason).must_equal Rack::Cors::Result::MISS_DENY_METHOD 306 | _(cors_result).wont_be :hit 307 | _(cors_result).must_be :preflight 308 | end 309 | 310 | it 'should fail if header is not allowed' do 311 | preflight_request('http://localhost:3000', '/single_header', headers: 'Fooey') 312 | _(last_response).wont_render_cors_success 313 | _(cors_result.miss_reason).must_equal Rack::Cors::Result::MISS_DENY_HEADER 314 | _(cors_result).wont_be :hit 315 | _(cors_result).must_be :preflight 316 | end 317 | 318 | it 'should allow any header if headers = :any' do 319 | preflight_request('http://localhost:3000', '/', headers: 'Fooey') 320 | _(last_response).must_render_cors_success 321 | end 322 | 323 | it 'should allow any method if methods = :any' do 324 | preflight_request('http://localhost:3000', '/', methods: :any) 325 | _(last_response).must_render_cors_success 326 | end 327 | 328 | it 'allows PATCH method' do 329 | preflight_request('http://localhost:3000', '/', methods: [:patch]) 330 | _(last_response).must_render_cors_success 331 | end 332 | 333 | it 'should allow header case insensitive match' do 334 | preflight_request('http://localhost:3000', '/single_header', headers: 'X-Domain-Token') 335 | _(last_response).must_render_cors_success 336 | end 337 | 338 | it 'should allow multiple headers match' do 339 | # Webkit style 340 | preflight_request('http://localhost:3000', '/two_headers', headers: 'X-Requested-With, X-Domain-Token') 341 | _(last_response).must_render_cors_success 342 | 343 | # Gecko style 344 | preflight_request('http://localhost:3000', '/two_headers', headers: 'x-requested-with,x-domain-token') 345 | _(last_response).must_render_cors_success 346 | end 347 | 348 | it "should allow '*' origins to allow any origin" do 349 | preflight_request('http://locohost:3000', '/public') 350 | _(last_response).must_render_cors_success 351 | _(last_response.headers['Access-Control-Allow-Origin']).must_equal '*' 352 | end 353 | 354 | it "should allow resource paths containing '$' char" do 355 | preflight_request('http://localhost:3000', '/$batch', method: :post) 356 | _(last_response).must_render_cors_success 357 | _(last_response.headers['Access-Control-Allow-Origin']).wont_equal nil 358 | _(last_response.headers['Access-Control-Allow-Methods']).must_equal 'POST' 359 | end 360 | 361 | it "should allow '//' resource if match pattern is //*" do 362 | preflight_request('http://localhost:3000', '/wildcard/') 363 | _(last_response).must_render_cors_success 364 | _(last_response.headers['Access-Control-Allow-Origin']).wont_equal nil 365 | end 366 | 367 | it "should allow '/' resource if match pattern is //*" do 368 | preflight_request('http://localhost:3000', '/wildcard') 369 | _(last_response).must_render_cors_success 370 | _(last_response.headers['Access-Control-Allow-Origin']).wont_equal nil 371 | end 372 | 373 | it "should allow '*' origin to allow any origin, and set '*' if no credentials required" do 374 | preflight_request('http://locohost:3000', '/public_without_credentials') 375 | _(last_response).must_render_cors_success 376 | _(last_response.headers['Access-Control-Allow-Origin']).must_equal '*' 377 | end 378 | 379 | it 'should return "file://" as header with "file://" as origin' do 380 | preflight_request('file://', '/') 381 | _(last_response).must_render_cors_success 382 | _(last_response.headers['Access-Control-Allow-Origin']).must_equal 'file://' 383 | end 384 | 385 | it 'supports custom protocols in origin' do 386 | preflight_request('custom-protocol://abcdefg', '/') 387 | _(last_response).must_render_cors_success 388 | _(last_response.headers['Access-Control-Allow-Origin']).must_equal 'custom-protocol://abcdefg' 389 | end 390 | 391 | describe '' do 392 | let(:app) do 393 | test = self 394 | Rack::Builder.new do 395 | use CaptureResult, holder: test 396 | use Rack::Cors, debug: true, logger: Logger.new(StringIO.new) do 397 | allow do 398 | origins '*' 399 | resource '/', methods: :post 400 | end 401 | end 402 | map('/') do 403 | run ->(_env) { [500, {}, ['FAIL!']] } 404 | end 405 | end 406 | end 407 | 408 | it 'should not send failed preflight requests thru the app' do 409 | preflight_request('http://localhost', '/', method: :unsupported) 410 | _(last_response).wont_render_cors_success 411 | _(last_response.status).must_equal 200 412 | _(cors_result).must_be :preflight 413 | _(cors_result).wont_be :hit 414 | _(cors_result.miss_reason).must_equal Rack::Cors::Result::MISS_DENY_METHOD 415 | end 416 | end 417 | end 418 | 419 | describe 'with insecure configuration' do 420 | let(:app) { load_app('insecure') } 421 | 422 | it 'should raise an error' do 423 | _(proc { cors_request '/public' }).must_raise Rack::Cors::Resource::CorsMisconfigurationError 424 | end 425 | end 426 | 427 | describe 'with non HTTP config' do 428 | let(:app) { load_app('non_http') } 429 | 430 | it 'should support non http/https origins' do 431 | successful_cors_request '/public', origin: 'content://com.company.app' 432 | end 433 | end 434 | 435 | describe 'Rack::Lint' do 436 | def app 437 | @app ||= Rack::Builder.new do 438 | use Rack::Cors 439 | use Rack::Lint 440 | run ->(_env) { [200, { 'content-type' => 'text/html' }, ['hello']] } 441 | end 442 | end 443 | 444 | it 'is lint-compliant with non-CORS request' do 445 | get '/' 446 | _(last_response.status).must_equal 200 447 | end 448 | end 449 | 450 | describe 'with app overriding CORS header' do 451 | let(:app) do 452 | Rack::Builder.new do 453 | use Rack::Cors, debug: true, logger: Logger.new(StringIO.new) do 454 | allow do 455 | origins '*' 456 | resource '/' 457 | end 458 | end 459 | map('/') do 460 | run ->(_env) { [200, { 'Access-Control-Allow-Origin' => 'http://foo.net' }, ['success']] } 461 | end 462 | end 463 | end 464 | 465 | it 'should return app header' do 466 | successful_cors_request origin: 'http://example.net' 467 | _(last_response.headers['Access-Control-Allow-Origin']).must_equal 'http://foo.net' 468 | end 469 | 470 | it 'should return original headers if in debug' do 471 | successful_cors_request origin: 'http://example.net' 472 | _(last_response.headers['X-Rack-CORS-Original-Access-Control-Allow-Origin']).must_equal '*' 473 | end 474 | end 475 | 476 | describe 'with headers set to nil' do 477 | let(:app) do 478 | Rack::Builder.new do 479 | use Rack::Cors do 480 | allow do 481 | origins '*' 482 | resource '/', headers: nil 483 | end 484 | end 485 | map('/') do 486 | run ->(_env) { [200, { 'content-type' => 'text/html' }, ['hello']] } 487 | end 488 | end 489 | end 490 | 491 | it 'should succeed with CORS simple headers' do 492 | preflight_request('http://localhost:3000', '/', headers: 'Accept') 493 | _(last_response).must_render_cors_success 494 | end 495 | end 496 | 497 | describe 'with custom allowed headers' do 498 | let(:app) do 499 | Rack::Builder.new do 500 | use Rack::Cors do 501 | allow do 502 | origins '*' 503 | resource '/', headers: [] 504 | end 505 | end 506 | map('/') do 507 | run ->(_env) { [200, { 'content-type' => 'text/html' }, ['hello']] } 508 | end 509 | end 510 | end 511 | 512 | it 'should succeed with CORS simple headers' do 513 | preflight_request('http://localhost:3000', '/', headers: 'Accept') 514 | _(last_response).must_render_cors_success 515 | preflight_request('http://localhost:3000', '/', headers: 'Accept-Language') 516 | _(last_response).must_render_cors_success 517 | preflight_request('http://localhost:3000', '/', headers: 'Content-Type') 518 | _(last_response).must_render_cors_success 519 | preflight_request('http://localhost:3000', '/', headers: 'Content-Language') 520 | _(last_response).must_render_cors_success 521 | end 522 | end 523 | 524 | protected 525 | 526 | def cors_request(*args) 527 | path = args.first.is_a?(String) ? args.first : '/' 528 | 529 | opts = { method: :get, origin: 'http://localhost:3000' } 530 | opts.merge! args.last if args.last.is_a?(Hash) 531 | 532 | header 'origin', opts[:origin] 533 | current_session.__send__ opts[:method], path, {}, test: self 534 | end 535 | 536 | def successful_cors_request(*args) 537 | cors_request(*args) 538 | _(last_response).must_render_cors_success 539 | end 540 | 541 | def preflight_request(origin, path, opts = {}) 542 | header 'Origin', origin 543 | unless opts.key?(:method) && opts[:method].nil? 544 | header 'Access-Control-Request-Method', opts[:method] ? opts[:method].to_s.upcase : 'GET' 545 | end 546 | header 'Access-Control-Request-Headers', opts[:headers] if opts[:headers] 547 | options path 548 | end 549 | end 550 | -------------------------------------------------------------------------------- /test/unit/dsl_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rubygems' 4 | require 'minitest/autorun' 5 | require 'rack/cors' 6 | 7 | describe Rack::Cors, 'DSL' do 8 | it 'should support explicit config object dsl mode' do 9 | cors = Rack::Cors.new(proc {}) do |cfg| 10 | cfg.allow do |allow| 11 | allow.origins 'localhost:3000', '127.0.0.1:3000' do |source, env| 12 | source == 'http://10.10.10.10:3000' && 13 | env['USER_AGENT'] == 'test-agent' 14 | end 15 | allow.resource '/get-only', methods: :get 16 | allow.resource '/', headers: :any 17 | end 18 | end 19 | resources = cors.send :all_resources 20 | 21 | _(resources.length).must_equal 1 22 | _(resources.first.allow_origin?('http://localhost:3000')).must_equal true 23 | _(resources.first.allow_origin?('http://10.10.10.10:3000', { 'USER_AGENT' => 'test-agent' })).must_equal true 24 | _(resources.first.allow_origin?('http://10.10.10.10:3001', { 'USER_AGENT' => 'test-agent' })).wont_equal true 25 | _(resources.first.allow_origin?('http://10.10.10.10:3000', { 'USER_AGENT' => 'other-agent' })).wont_equal true 26 | end 27 | 28 | it 'should support implicit config object dsl mode' do 29 | cors = Rack::Cors.new(proc {}) do 30 | allow do 31 | origins 'localhost:3000', '127.0.0.1:3000' do |source, env| 32 | source == 'http://10.10.10.10:3000' && 33 | env['USER_AGENT'] == 'test-agent' 34 | end 35 | resource '/get-only', methods: :get 36 | resource '/', headers: :any 37 | end 38 | end 39 | resources = cors.send :all_resources 40 | 41 | _(resources.length).must_equal 1 42 | _(resources.first.allow_origin?('http://localhost:3000')).must_equal true 43 | _(resources.first.allow_origin?('http://10.10.10.10:3000', { 'USER_AGENT' => 'test-agent' })).must_equal true 44 | _(resources.first.allow_origin?('http://10.10.10.10:3001', { 'USER_AGENT' => 'test-agent' })).wont_equal true 45 | _(resources.first.allow_origin?('http://10.10.10.10:3000', { 'USER_AGENT' => 'other-agent' })).wont_equal true 46 | end 47 | 48 | it 'should support "file://" origin' do 49 | cors = Rack::Cors.new(proc {}) do 50 | allow do 51 | origins 'file://' 52 | resource '/', headers: :any 53 | end 54 | end 55 | resources = cors.send :all_resources 56 | 57 | _(resources.first.allow_origin?('file://')).must_equal true 58 | end 59 | 60 | it 'should default credentials option to false' do 61 | cors = Rack::Cors.new(proc {}) do 62 | allow do 63 | origins 'example.net' 64 | resource '/', headers: :any 65 | end 66 | end 67 | resources = cors.send :all_resources 68 | _(resources.first.resources.first.credentials).must_equal false 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /test/unit/insecure.ru: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rack/cors' 4 | 5 | use Rack::Cors do 6 | allow do 7 | origins '*' 8 | resource '/public', credentials: true 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/unit/non_http.ru: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rack/cors' 4 | 5 | use Rack::Cors do 6 | allow do 7 | origins 'com.company.app' 8 | resource '/public' 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/unit/test.ru: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rack/cors' 4 | 5 | # use Rack::Cors, :debug => true, :logger => ::Logger.new(STDOUT) do 6 | use Rack::Lint 7 | use Rack::Cors do 8 | allow do 9 | origins 'localhost:3000', 10 | '127.0.0.1:3000', 11 | %r{http://192\.168\.0\.\d{1,3}(:\d+)?}, 12 | 'file://', 13 | %r{http://(.*?)\.example\.com}, 14 | 'custom-protocol://abcdefg' 15 | 16 | resource '/get-only', methods: :get 17 | resource '/', headers: :any, methods: :any 18 | resource '/options', methods: :options 19 | resource '/single_header', headers: 'x-domain-token' 20 | resource '/two_headers', headers: %w[x-domain-token x-requested-with] 21 | resource '/expose_single_header', expose: 'expose-test' 22 | resource '/expose_multiple_headers', expose: %w[expose-test-1 expose-test-2] 23 | resource '/conditional', methods: :get, if: proc { |env| !!env['HTTP_X_OK'] } 24 | resource '/vary_test', methods: :get, vary: %w[Origin Host] 25 | resource '/patch_test', methods: :patch 26 | resource '/$batch', methods: :post 27 | resource '/wildcard/*', methods: :any 28 | # resource '/file/at/*', 29 | # :methods => [:get, :post, :put, :delete], 30 | # :headers => :any, 31 | # :max_age => 0 32 | end 33 | 34 | allow do 35 | origins do |source, _env| 36 | source.end_with?('10.10.10.10:3000') 37 | end 38 | resource '/proc-origin' 39 | end 40 | 41 | allow do 42 | origins ->(source, _env) { source.end_with?('10.10.10.10:3000') } 43 | resource '/lambda-origin' 44 | end 45 | 46 | allow do 47 | origins '*' 48 | resource '/public' 49 | resource '/public/*' 50 | resource '/public_without_credentials', credentials: false 51 | end 52 | 53 | allow do 54 | origins 'mucho-grande.com' 55 | resource '/multi-allow-config', max_age: 600 56 | end 57 | 58 | allow do 59 | origins '*' 60 | resource '/multi-allow-config', max_age: 300, credentials: false 61 | end 62 | 63 | allow do 64 | origins '' 65 | resource '/blank-origin' 66 | end 67 | end 68 | --------------------------------------------------------------------------------