static-rails 0.0.9 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +26 -43
- data/.gitignore +2 -0
- data/CHANGELOG.md +29 -0
- data/Gemfile.lock +33 -32
- data/lib/generators/templates/static.rb +3 -3
- data/lib/static-rails/configuration.rb +1 -1
- data/lib/static-rails/file_handler.rb +172 -0
- data/lib/static-rails/gets_csrf_token.rb +9 -11
- data/lib/static-rails/proxy_middleware.rb +0 -1
- data/lib/static-rails/railtie.rb +1 -1
- data/lib/static-rails/server_store.rb +0 -4
- data/lib/static-rails/site_middleware.rb +1 -1
- data/lib/static-rails/site_plus_csrf_middleware.rb +2 -2
- data/lib/static-rails/static_middleware.rb +32 -10
- data/lib/static-rails/version.rb +1 -1
- data/script/setup +28 -0
- data/script/test +11 -0
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a6e7ad52cd960477f61b0faaa6364968844e8d2862714e35340531a12aa82e5
|
4
|
+
data.tar.gz: 0a66a78cfdec31a91354c8815e1ec612a44345230bfb5115cdd1afc999bbcc85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fca6f6a4ffa3a2893019d583853d1e790e8a28e90fb6140a53ce4f5dfdf4b34abfb5d9a350f3a4e5d6e5245a3461f6b303f62208cd55b9158c1256e38f35f1f8
|
7
|
+
data.tar.gz: 4d03d6226092c97f5fe9f35283c77d4544f3addb4766d42a01eb6cd69568763ab24ff5220181e0f7b5f7cce69722b073367b098bd1e525c37923b449ca460903
|
data/.circleci/config.yml
CHANGED
@@ -13,31 +13,17 @@ jobs:
|
|
13
13
|
# One of the apps needs hugo
|
14
14
|
- run: sudo apt-get update && sudo apt-get install -y --no-install-recommends hugo
|
15
15
|
|
16
|
+
# Make sure we use the right Bundler
|
17
|
+
- run: gem install bundler --version `tail -1 Gemfile.lock`
|
18
|
+
|
16
19
|
# Bundle install dependencies
|
17
20
|
- type: cache-restore
|
18
21
|
key: v1-main-{{ checksum "Gemfile.lock" }}
|
19
22
|
|
20
|
-
- run: gem install bundler --version `tail -1 Gemfile.lock`
|
21
|
-
- run: bundle install --path vendor/bundle
|
22
|
-
|
23
|
-
- type: cache-save
|
24
|
-
key: v1-main-{{ checksum "Gemfile.lock" }}
|
25
|
-
paths:
|
26
|
-
- vendor/bundle
|
27
|
-
|
28
23
|
# Bundle install dependencies for example app
|
29
24
|
- type: cache-restore
|
30
25
|
key: v1-example-{{ checksum "example/Gemfile.lock" }}
|
31
26
|
|
32
|
-
- run: |
|
33
|
-
cd example
|
34
|
-
bundle install --path vendor/bundle
|
35
|
-
|
36
|
-
- type: cache-save
|
37
|
-
key: v1-example-{{ checksum "example/Gemfile.lock" }}
|
38
|
-
paths:
|
39
|
-
- example/vendor/bundle
|
40
|
-
|
41
27
|
# Yarn dependencies
|
42
28
|
- restore_cache:
|
43
29
|
keys:
|
@@ -45,29 +31,10 @@ jobs:
|
|
45
31
|
# fallback to using the latest cache if no exact match is found
|
46
32
|
- v2-yarn-
|
47
33
|
|
48
|
-
- run: |
|
49
|
-
cd example
|
50
|
-
yarn install
|
51
|
-
|
52
|
-
- save_cache:
|
53
|
-
paths:
|
54
|
-
- example/node_modules
|
55
|
-
- ~/.cache
|
56
|
-
key: v2-yarn-{{ checksum "example/yarn.lock" }}
|
57
|
-
|
58
34
|
# Bundle install dependencies for jekyll app
|
59
35
|
- type: cache-restore
|
60
36
|
key: v1-jekyll-{{ checksum "example/static/docs/Gemfile.lock" }}
|
61
37
|
|
62
|
-
- run: |
|
63
|
-
cd example/static/docs
|
64
|
-
bundle install --path vendor/bundle
|
65
|
-
|
66
|
-
- type: cache-save
|
67
|
-
key: v1-jekyll-{{ checksum "example/static/docs/Gemfile.lock" }}
|
68
|
-
paths:
|
69
|
-
- example/static/docs/vendor/bundle
|
70
|
-
|
71
38
|
# Npm install for Eleventy app
|
72
39
|
- restore_cache:
|
73
40
|
keys:
|
@@ -75,16 +42,32 @@ jobs:
|
|
75
42
|
# fallback to using the latest cache if no exact match is found
|
76
43
|
- v1-eleventy-
|
77
44
|
|
78
|
-
- run:
|
79
|
-
|
80
|
-
|
45
|
+
- run: ./script/setup
|
46
|
+
|
47
|
+
- type: cache-save
|
48
|
+
key: v1-main-{{ checksum "Gemfile.lock" }}
|
49
|
+
paths:
|
50
|
+
- vendor/bundle
|
51
|
+
|
52
|
+
- type: cache-save
|
53
|
+
key: v1-example-{{ checksum "example/Gemfile.lock" }}
|
54
|
+
paths:
|
55
|
+
- example/vendor/bundle
|
56
|
+
|
57
|
+
- save_cache:
|
58
|
+
paths:
|
59
|
+
- example/node_modules
|
60
|
+
- ~/.cache
|
61
|
+
key: v2-yarn-{{ checksum "example/yarn.lock" }}
|
62
|
+
|
63
|
+
- type: cache-save
|
64
|
+
key: v1-jekyll-{{ checksum "example/static/docs/Gemfile.lock" }}
|
65
|
+
paths:
|
66
|
+
- example/static/docs/vendor/bundle
|
81
67
|
|
82
68
|
- save_cache:
|
83
69
|
paths:
|
84
70
|
- example/static/blog-docs/node_modules
|
85
71
|
key: v1-eleventy-{{ checksum "example/static/blog-docs/package-lock.json" }}
|
86
72
|
|
87
|
-
- run:
|
88
|
-
- run: |
|
89
|
-
cd example
|
90
|
-
./script/test
|
73
|
+
- run: ./script/test
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,32 @@
|
|
1
|
+
## 0.0.14
|
2
|
+
|
3
|
+
* HTML & XML won't be cached by default in production
|
4
|
+
[#20](https://github.com/testdouble/static-rails/pull/20)
|
5
|
+
|
6
|
+
## 0.0.13
|
7
|
+
|
8
|
+
* 404 pages served in production via a site's `compile_404_file_path` setting
|
9
|
+
will now also send the HTTP status code of 404 instead of 200
|
10
|
+
|
11
|
+
## 0.0.12
|
12
|
+
|
13
|
+
* Fix an issue in which enabling force_ssl would result in redirects to the
|
14
|
+
obfuscated `/_static_rails/` path. Resolved this by placing the static-rails
|
15
|
+
middleware after `ActionDispatch::SSL`. Note that this will break if you
|
16
|
+
remove `Rack::SendFile` from your app's middleware stack
|
17
|
+
|
18
|
+
## 0.0.11
|
19
|
+
|
20
|
+
* Inline the `ActionDispatch::FileHandler` from Rails master so that we can
|
21
|
+
target a single stable version of its API and control what MIME types it
|
22
|
+
considers to be compressible (bonus is that it effectively backports brotli
|
23
|
+
compression to pre-6.1 rails apps)
|
24
|
+
|
25
|
+
## 0.0.10
|
26
|
+
|
27
|
+
* Change default `cache-control` header for static assets being served from disk
|
28
|
+
from `no-cache` to `"public; max-age=31536000"`
|
29
|
+
|
1
30
|
## 0.0.9
|
2
31
|
|
3
32
|
* When using CSRF protection, the artificial path info will now be
|
data/Gemfile.lock
CHANGED
@@ -1,51 +1,51 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
static-rails (0.0.
|
4
|
+
static-rails (0.0.14)
|
5
5
|
rack-proxy (~> 0.6)
|
6
6
|
railties (>= 5.0.0)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
actionpack (6.0.3.
|
12
|
-
actionview (= 6.0.3.
|
13
|
-
activesupport (= 6.0.3.
|
11
|
+
actionpack (6.0.3.3)
|
12
|
+
actionview (= 6.0.3.3)
|
13
|
+
activesupport (= 6.0.3.3)
|
14
14
|
rack (~> 2.0, >= 2.0.8)
|
15
15
|
rack-test (>= 0.6.3)
|
16
16
|
rails-dom-testing (~> 2.0)
|
17
17
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
18
|
-
actionview (6.0.3.
|
19
|
-
activesupport (= 6.0.3.
|
18
|
+
actionview (6.0.3.3)
|
19
|
+
activesupport (= 6.0.3.3)
|
20
20
|
builder (~> 3.1)
|
21
21
|
erubi (~> 1.4)
|
22
22
|
rails-dom-testing (~> 2.0)
|
23
23
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
24
|
-
activesupport (6.0.3.
|
24
|
+
activesupport (6.0.3.3)
|
25
25
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
26
26
|
i18n (>= 0.7, < 2)
|
27
27
|
minitest (~> 5.1)
|
28
28
|
tzinfo (~> 1.1)
|
29
29
|
zeitwerk (~> 2.2, >= 2.2.2)
|
30
|
-
ast (2.4.
|
30
|
+
ast (2.4.1)
|
31
31
|
builder (3.2.4)
|
32
|
-
concurrent-ruby (1.1.
|
32
|
+
concurrent-ruby (1.1.7)
|
33
33
|
crass (1.0.6)
|
34
34
|
erubi (1.9.0)
|
35
|
-
i18n (1.8.
|
35
|
+
i18n (1.8.5)
|
36
36
|
concurrent-ruby (~> 1.0)
|
37
|
-
loofah (2.
|
37
|
+
loofah (2.7.0)
|
38
38
|
crass (~> 1.0.2)
|
39
39
|
nokogiri (>= 1.5.9)
|
40
40
|
method_source (1.0.0)
|
41
41
|
mini_portile2 (2.4.0)
|
42
|
-
minitest (5.14.
|
43
|
-
nokogiri (1.10.
|
42
|
+
minitest (5.14.2)
|
43
|
+
nokogiri (1.10.10)
|
44
44
|
mini_portile2 (~> 2.4.0)
|
45
|
-
parallel (1.19.
|
46
|
-
parser (2.7.1.
|
47
|
-
ast (~> 2.4.
|
48
|
-
rack (2.2.
|
45
|
+
parallel (1.19.2)
|
46
|
+
parser (2.7.1.4)
|
47
|
+
ast (~> 2.4.1)
|
48
|
+
rack (2.2.3)
|
49
49
|
rack-proxy (0.6.5)
|
50
50
|
rack
|
51
51
|
rack-test (1.1.0)
|
@@ -55,39 +55,40 @@ GEM
|
|
55
55
|
nokogiri (>= 1.6)
|
56
56
|
rails-html-sanitizer (1.3.0)
|
57
57
|
loofah (~> 2.3)
|
58
|
-
railties (6.0.3.
|
59
|
-
actionpack (= 6.0.3.
|
60
|
-
activesupport (= 6.0.3.
|
58
|
+
railties (6.0.3.3)
|
59
|
+
actionpack (= 6.0.3.3)
|
60
|
+
activesupport (= 6.0.3.3)
|
61
61
|
method_source
|
62
62
|
rake (>= 0.8.7)
|
63
63
|
thor (>= 0.20.3, < 2.0)
|
64
64
|
rainbow (3.0.0)
|
65
65
|
rake (13.0.1)
|
66
|
-
regexp_parser (1.
|
66
|
+
regexp_parser (1.8.0)
|
67
67
|
rexml (3.2.4)
|
68
|
-
rubocop (0.
|
68
|
+
rubocop (0.91.1)
|
69
69
|
parallel (~> 1.10)
|
70
|
-
parser (>= 2.7.
|
70
|
+
parser (>= 2.7.1.1)
|
71
71
|
rainbow (>= 2.2.2, < 4.0)
|
72
72
|
regexp_parser (>= 1.7)
|
73
73
|
rexml
|
74
|
-
rubocop-ast (>= 0.0.
|
74
|
+
rubocop-ast (>= 0.4.0, < 1.0)
|
75
75
|
ruby-progressbar (~> 1.7)
|
76
76
|
unicode-display_width (>= 1.4.0, < 2.0)
|
77
|
-
rubocop-ast (0.
|
78
|
-
parser (>= 2.7.
|
79
|
-
rubocop-performance (1.
|
80
|
-
rubocop (>= 0.
|
77
|
+
rubocop-ast (0.4.2)
|
78
|
+
parser (>= 2.7.1.4)
|
79
|
+
rubocop-performance (1.8.1)
|
80
|
+
rubocop (>= 0.87.0)
|
81
|
+
rubocop-ast (>= 0.4.0)
|
81
82
|
ruby-progressbar (1.10.1)
|
82
|
-
standard (0.
|
83
|
-
rubocop (
|
84
|
-
rubocop-performance (
|
83
|
+
standard (0.6.2)
|
84
|
+
rubocop (= 0.91.1)
|
85
|
+
rubocop-performance (= 1.8.1)
|
85
86
|
thor (1.0.1)
|
86
87
|
thread_safe (0.3.6)
|
87
88
|
tzinfo (1.2.7)
|
88
89
|
thread_safe (~> 0.1)
|
89
90
|
unicode-display_width (1.7.0)
|
90
|
-
zeitwerk (2.
|
91
|
+
zeitwerk (2.4.0)
|
91
92
|
|
92
93
|
PLATFORMS
|
93
94
|
ruby
|
@@ -34,14 +34,14 @@ StaticRails.config do |config|
|
|
34
34
|
# url_root_path: "/",
|
35
35
|
#
|
36
36
|
# # Don't serve/redirect routes whose paths start with these strings
|
37
|
-
# url_skip_paths_starting_with: ["/api"]
|
37
|
+
# url_skip_paths_starting_with: ["/api"],
|
38
38
|
#
|
39
39
|
# # Whether to run the local development/test server or not
|
40
40
|
# start_server: !Rails.env.production?,
|
41
41
|
#
|
42
42
|
# # If start_server is true, wait to proxy requests to the server until it
|
43
43
|
# # can connect to server_host over TCP on server_port
|
44
|
-
# ping_server: true
|
44
|
+
# ping_server: true,
|
45
45
|
#
|
46
46
|
# # Any environment variables you need to pass to the server & compile
|
47
47
|
# # commands as a hash (e.g. `env: {"BUNDLE_PATH" => "vendor/bundle"}`)
|
@@ -65,7 +65,7 @@ StaticRails.config do |config|
|
|
65
65
|
# compile_command: "hugo",
|
66
66
|
#
|
67
67
|
# # The destination of production-compiled assets, relative to Rails root
|
68
|
-
# compile_dir: "static/blog/dist"
|
68
|
+
# compile_dir: "static/blog/dist",
|
69
69
|
#
|
70
70
|
# # A 404 page to be sent when serving compiled assets and no file matches
|
71
71
|
# compile_404_file_path: "404.html"
|
@@ -0,0 +1,172 @@
|
|
1
|
+
module StaticRails
|
2
|
+
# This class was extracted from Ruby on Rails:
|
3
|
+
#
|
4
|
+
# - actionpack/lib/action_dispatch/middleware/static.rb
|
5
|
+
#
|
6
|
+
# Copyright (c) 2005-2020 David Heinemeier Hansson, Ryan Edward Hall, Jeremy Daer
|
7
|
+
#
|
8
|
+
# License here: https://github.com/rails/rails/blob/master/MIT-LICENSE
|
9
|
+
#
|
10
|
+
# This endpoint serves static files from disk using Rack::File.
|
11
|
+
#
|
12
|
+
# URL paths are matched with static files according to expected
|
13
|
+
# conventions: +path+, +path+.html, +path+/index.html.
|
14
|
+
#
|
15
|
+
# Precompressed versions of these files are checked first. Brotli (.br)
|
16
|
+
# and gzip (.gz) files are supported. If +path+.br exists, this
|
17
|
+
# endpoint returns that file with a +Content-Encoding: br+ header.
|
18
|
+
#
|
19
|
+
# If no matching file is found, this endpoint responds 404 Not Found.
|
20
|
+
#
|
21
|
+
# Pass the +root+ directory to search for matching files, an optional
|
22
|
+
# +index: "index"+ to change the default +path+/index.html, and optional
|
23
|
+
# additional response headers.
|
24
|
+
class FileHandler
|
25
|
+
# Accept-Encoding value -> file extension
|
26
|
+
PRECOMPRESSED = {
|
27
|
+
"br" => ".br",
|
28
|
+
"gzip" => ".gz",
|
29
|
+
"identity" => nil
|
30
|
+
}
|
31
|
+
|
32
|
+
def initialize(root, index: "index", headers: {}, precompressed: %i[br gzip], compressible_content_types: /\A(?:text\/|application\/javascript)/)
|
33
|
+
@root = root.chomp("/").b
|
34
|
+
@index = index
|
35
|
+
|
36
|
+
@precompressed = Array(precompressed).map(&:to_s) | %w[identity]
|
37
|
+
@compressible_content_types = compressible_content_types
|
38
|
+
|
39
|
+
@file_server = ::Rack::File.new(@root, headers)
|
40
|
+
end
|
41
|
+
|
42
|
+
def call(env)
|
43
|
+
attempt(env) || @file_server.call(env)
|
44
|
+
end
|
45
|
+
|
46
|
+
def attempt(env)
|
47
|
+
request = Rack::Request.new env
|
48
|
+
|
49
|
+
if request.get? || request.head?
|
50
|
+
if (found = find_file(request.path_info, accept_encoding: request.accept_encoding))
|
51
|
+
serve request, *found
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def serve(request, filepath, content_headers)
|
57
|
+
original, request.path_info = request.path_info, ::Rack::Utils.escape_path(filepath).b
|
58
|
+
|
59
|
+
@file_server.call(request.env).tap do |status, headers, body|
|
60
|
+
# Omit Content-Encoding/Type/etc headers for 304 Not Modified
|
61
|
+
if status != 304
|
62
|
+
headers.update(content_headers)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
ensure
|
66
|
+
request.path_info = original
|
67
|
+
end
|
68
|
+
|
69
|
+
# Match a URI path to a static file to be served.
|
70
|
+
#
|
71
|
+
# Used by the +Static+ class to negotiate a servable file in the
|
72
|
+
# +public/+ directory (see Static#call).
|
73
|
+
#
|
74
|
+
# Checks for +path+, +path+.html, and +path+/index.html files,
|
75
|
+
# in that order, including .br and .gzip compressed extensions.
|
76
|
+
#
|
77
|
+
# If a matching file is found, the path and necessary response headers
|
78
|
+
# (Content-Type, Content-Encoding) are returned.
|
79
|
+
def find_file(path_info, accept_encoding:)
|
80
|
+
each_candidate_filepath(path_info) do |filepath, content_type|
|
81
|
+
if (response = try_files(filepath, content_type, accept_encoding: accept_encoding))
|
82
|
+
return response
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def try_files(filepath, content_type, accept_encoding:)
|
90
|
+
headers = {"Content-Type" => content_type}
|
91
|
+
|
92
|
+
if compressible? content_type
|
93
|
+
try_precompressed_files filepath, headers, accept_encoding: accept_encoding
|
94
|
+
elsif file_readable? filepath
|
95
|
+
[filepath, headers]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def try_precompressed_files(filepath, headers, accept_encoding:)
|
100
|
+
each_precompressed_filepath(filepath) do |content_encoding, precompressed_filepath|
|
101
|
+
if file_readable? precompressed_filepath
|
102
|
+
# Identity encoding is default, so we skip Accept-Encoding
|
103
|
+
# negotiation and needn't set Content-Encoding.
|
104
|
+
#
|
105
|
+
# Vary header is expected when we've found other available
|
106
|
+
# encodings that Accept-Encoding ruled out.
|
107
|
+
if content_encoding == "identity"
|
108
|
+
return precompressed_filepath, headers
|
109
|
+
else
|
110
|
+
headers["Vary"] = "Accept-Encoding"
|
111
|
+
|
112
|
+
if accept_encoding.any? { |enc, _| /\b#{content_encoding}\b/i.match?(enc) }
|
113
|
+
headers["Content-Encoding"] = content_encoding
|
114
|
+
return precompressed_filepath, headers
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def file_readable?(path)
|
122
|
+
file_stat = File.stat(File.join(@root, path.b))
|
123
|
+
rescue SystemCallError
|
124
|
+
false
|
125
|
+
else
|
126
|
+
file_stat.file? && file_stat.readable?
|
127
|
+
end
|
128
|
+
|
129
|
+
def compressible?(content_type)
|
130
|
+
@compressible_content_types.match?(content_type)
|
131
|
+
end
|
132
|
+
|
133
|
+
def each_precompressed_filepath(filepath)
|
134
|
+
@precompressed.each do |content_encoding|
|
135
|
+
precompressed_ext = PRECOMPRESSED.fetch(content_encoding)
|
136
|
+
yield content_encoding, "#{filepath}#{precompressed_ext}"
|
137
|
+
end
|
138
|
+
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
|
142
|
+
def each_candidate_filepath(path_info)
|
143
|
+
return unless (path = clean_path(path_info))
|
144
|
+
|
145
|
+
ext = ::File.extname(path)
|
146
|
+
content_type = ::Rack::Mime.mime_type(ext, nil)
|
147
|
+
yield path, content_type || "text/plain"
|
148
|
+
|
149
|
+
# Tack on .html and /index.html only for paths that don't have
|
150
|
+
# an explicit, resolvable file extension. No need to check
|
151
|
+
# for foo.js.html and foo.js/index.html.
|
152
|
+
unless content_type
|
153
|
+
default_ext = ::ActionController::Base.default_static_extension
|
154
|
+
if ext != default_ext
|
155
|
+
default_content_type = ::Rack::Mime.mime_type(default_ext, "text/plain")
|
156
|
+
|
157
|
+
yield "#{path}#{default_ext}", default_content_type
|
158
|
+
yield "#{path}/#{@index}#{default_ext}", default_content_type
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
nil
|
163
|
+
end
|
164
|
+
|
165
|
+
def clean_path(path_info)
|
166
|
+
path = ::Rack::Utils.unescape_path path_info.chomp("/")
|
167
|
+
if ::Rack::Utils.valid_path? path
|
168
|
+
::Rack::Utils.clean_path_info path
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -10,16 +10,18 @@ module StaticRails
|
|
10
10
|
|
11
11
|
private
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
[
|
14
|
+
:csrf_token_hmac,
|
15
|
+
:mask_token,
|
16
|
+
:xor_byte_strings
|
17
|
+
].each do |method|
|
18
|
+
define_method method do |*args, **kwargs, &blk|
|
19
|
+
ActionController::RequestForgeryProtection.instance_method(method).bind(self).call(*args, **kwargs, &blk)
|
20
|
+
end
|
19
21
|
end
|
20
22
|
|
21
23
|
def masked_authenticity_token(session, form_options: {})
|
22
|
-
ActionController::RequestForgeryProtection.instance_method(:masked_authenticity_token).bind(self).call(session, form_options)
|
24
|
+
ActionController::RequestForgeryProtection.instance_method(:masked_authenticity_token).bind(self).call(session, form_options: form_options)
|
23
25
|
end
|
24
26
|
|
25
27
|
def global_csrf_token(session)
|
@@ -30,10 +32,6 @@ module StaticRails
|
|
30
32
|
ActionController::RequestForgeryProtection.instance_method(:real_csrf_token).bind(self).call(session)
|
31
33
|
end
|
32
34
|
|
33
|
-
def xor_byte_strings(s1, s2)
|
34
|
-
ActionController::RequestForgeryProtection.instance_method(:xor_byte_strings).bind(self).call(s1, s2)
|
35
|
-
end
|
36
|
-
|
37
35
|
def per_form_csrf_tokens
|
38
36
|
false
|
39
37
|
end
|
@@ -17,7 +17,6 @@ module StaticRails
|
|
17
17
|
|
18
18
|
server_store = ServerStore.instance
|
19
19
|
server_store.ensure_all_servers_are_started
|
20
|
-
server_store.ensure_servers_are_up
|
21
20
|
|
22
21
|
req = Rack::Request.new(env)
|
23
22
|
if (req.get? || req.head?) && (site = @matches_request_to_static_site.call(req))
|
data/lib/static-rails/railtie.rb
CHANGED
@@ -10,7 +10,7 @@ module StaticRails
|
|
10
10
|
end
|
11
11
|
|
12
12
|
initializer "static_rails.middleware" do
|
13
|
-
config.app_middleware.
|
13
|
+
config.app_middleware.insert_after Rack::Sendfile, SiteMiddleware
|
14
14
|
config.app_middleware.use SitePlusCsrfMiddleware
|
15
15
|
end
|
16
16
|
|
@@ -40,7 +40,7 @@ module StaticRails
|
|
40
40
|
#
|
41
41
|
# (By the way, this was all Matthew Draper's bright idea. You can
|
42
42
|
# compliment him here: https://github.com/matthewd )
|
43
|
-
@app.call(env.merge("PATH_INFO" => PATH_INFO_OBFUSCATION + env["PATH_INFO"]))
|
43
|
+
@app.call(env.merge("PATH_INFO" => "/" + PATH_INFO_OBFUSCATION + env["PATH_INFO"]))
|
44
44
|
elsif StaticRails.config.proxy_requests
|
45
45
|
@proxy_middleware.call(env)
|
46
46
|
elsif StaticRails.config.serve_compiled_assets
|
@@ -13,10 +13,10 @@ module StaticRails
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def call(env)
|
16
|
-
return @app.call(env) unless env["PATH_INFO"]&.start_with?(PATH_INFO_OBFUSCATION) || @determines_whether_to_handle_request.call(env)
|
16
|
+
return @app.call(env) unless env["PATH_INFO"]&.start_with?(/\/?#{PATH_INFO_OBFUSCATION}/) || @determines_whether_to_handle_request.call(env)
|
17
17
|
|
18
18
|
env = env.merge(
|
19
|
-
"PATH_INFO" => env["PATH_INFO"].gsub(
|
19
|
+
"PATH_INFO" => env["PATH_INFO"].gsub(/^\/?#{PATH_INFO_OBFUSCATION}/, "")
|
20
20
|
)
|
21
21
|
status, headers, body = super(env)
|
22
22
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require "rack-proxy"
|
2
|
-
require "action_dispatch/middleware/static"
|
3
2
|
|
3
|
+
require_relative "file_handler"
|
4
4
|
require_relative "matches_request_to_static_site"
|
5
5
|
|
6
6
|
module StaticRails
|
@@ -18,9 +18,8 @@ module StaticRails
|
|
18
18
|
if (req.get? || req.head?) && (site = @matches_request_to_static_site.call(req))
|
19
19
|
file_handler = file_handler_for(site)
|
20
20
|
path = req.path_info.gsub(/^#{site.url_root_path}/, "").chomp("/")
|
21
|
-
if (
|
22
|
-
|
23
|
-
return file_handler.serve(req)
|
21
|
+
if (result = serve_file_for(file_handler, site, path, req))
|
22
|
+
return result
|
24
23
|
end
|
25
24
|
end
|
26
25
|
|
@@ -32,16 +31,39 @@ module StaticRails
|
|
32
31
|
# The same file handler used by Rails when serving up files from /public
|
33
32
|
# See: actionpack/lib/action_dispatch/middleware/static.rb
|
34
33
|
def file_handler_for(site)
|
35
|
-
@file_handlers[site] ||=
|
36
|
-
StaticRails.config.app.root.join(site.compile_dir).to_s
|
34
|
+
@file_handlers[site] ||= FileHandler.new(
|
35
|
+
StaticRails.config.app.root.join(site.compile_dir).to_s,
|
36
|
+
headers: {
|
37
|
+
"cache-control" => "public; max-age=31536000"
|
38
|
+
},
|
39
|
+
compressible_content_types: /^text\/|[\/+](javascript|json|text|xml|css|yaml)$/i
|
37
40
|
)
|
38
41
|
end
|
39
42
|
|
40
|
-
def
|
41
|
-
if (
|
42
|
-
|
43
|
+
def serve_file_for(file_handler, site, path, req)
|
44
|
+
if (found = file_handler.find_file(path, accept_encoding: req.accept_encoding))
|
45
|
+
serve_file(file_handler, found, req)
|
43
46
|
elsif site.compile_404_file_path.present?
|
44
|
-
file_handler.
|
47
|
+
found = file_handler.find_file(site.compile_404_file_path, accept_encoding: req.accept_encoding)
|
48
|
+
serve_file(file_handler, found, req, 404)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def serve_file(file_handler, file, req, status_override = nil)
|
53
|
+
return unless file
|
54
|
+
file_handler.serve(req, *file).tap do |result|
|
55
|
+
result[0] = status_override unless status_override.nil?
|
56
|
+
override_cache_control_if_we_probably_shouldnt_cache!(file, result[1])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
PROBABLY_SHOULDNT_CACHE_MIME_TYPES = [
|
61
|
+
"text/html", "application/xml", "application/rss+xml"
|
62
|
+
]
|
63
|
+
def override_cache_control_if_we_probably_shouldnt_cache!(file, headers = {})
|
64
|
+
mime_type = file[1]["Content-Type"]
|
65
|
+
if PROBABLY_SHOULDNT_CACHE_MIME_TYPES.include?(mime_type)
|
66
|
+
headers["cache-control"] = "no-cache, no-store"
|
45
67
|
end
|
46
68
|
end
|
47
69
|
end
|
data/lib/static-rails/version.rb
CHANGED
data/script/setup
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
echo "--> Installing static-rails' Ruby deps"
|
6
|
+
bundle install --path vendor/bundle
|
7
|
+
|
8
|
+
echo "--> Installing example app's Ruby deps"
|
9
|
+
cd example
|
10
|
+
bundle install --path vendor/bundle
|
11
|
+
cd ..
|
12
|
+
|
13
|
+
echo "--> Installing example app's JS deps"
|
14
|
+
cd example
|
15
|
+
yarn install
|
16
|
+
cd ..
|
17
|
+
|
18
|
+
echo "--> Installing example app's Jekyll site's Ruby deps"
|
19
|
+
cd example/static/docs
|
20
|
+
bundle install --path vendor/bundle
|
21
|
+
cd ../../..
|
22
|
+
|
23
|
+
echo "--> Installing example app's Eleventy site's JS deps"
|
24
|
+
cd example/static/blog-docs
|
25
|
+
npm install
|
26
|
+
cd ../../..
|
27
|
+
|
28
|
+
|
data/script/test
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: static-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Searls
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.6'
|
41
|
-
description:
|
41
|
+
description:
|
42
42
|
email:
|
43
43
|
- searls@gmail.com
|
44
44
|
executables: []
|
@@ -64,6 +64,7 @@ files:
|
|
64
64
|
- lib/static-rails/configuration.rb
|
65
65
|
- lib/static-rails/determines_whether_to_handle_request.rb
|
66
66
|
- lib/static-rails/error.rb
|
67
|
+
- lib/static-rails/file_handler.rb
|
67
68
|
- lib/static-rails/gets_csrf_token.rb
|
68
69
|
- lib/static-rails/matches_request_to_static_site.rb
|
69
70
|
- lib/static-rails/proxy_middleware.rb
|
@@ -80,13 +81,15 @@ files:
|
|
80
81
|
- lib/static-rails/version.rb
|
81
82
|
- lib/static-rails/waits_for_connection.rb
|
82
83
|
- lib/tasks/static-rails.rake
|
84
|
+
- script/setup
|
85
|
+
- script/test
|
83
86
|
- static-rails.gemspec
|
84
87
|
homepage: https://github.com/testdouble/static-rails
|
85
88
|
licenses:
|
86
89
|
- MIT
|
87
90
|
metadata:
|
88
91
|
homepage_uri: https://github.com/testdouble/static-rails
|
89
|
-
post_install_message:
|
92
|
+
post_install_message:
|
90
93
|
rdoc_options: []
|
91
94
|
require_paths:
|
92
95
|
- lib
|
@@ -102,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
105
|
version: '0'
|
103
106
|
requirements: []
|
104
107
|
rubygems_version: 3.1.2
|
105
|
-
signing_key:
|
108
|
+
signing_key:
|
106
109
|
specification_version: 4
|
107
110
|
summary: Build & serve static sites (e.g. Jekyll, Hugo) from your Rails app
|
108
111
|
test_files: []
|