static-rails 0.0.9 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6745d74377412999963201634328706d263efcb29eb445a71c84cd427b618084
4
- data.tar.gz: 9ffe84b1fc78ada36ab6699cb1826815e8da0fc0cdbe266c952f563a41c577a6
3
+ metadata.gz: 2a6e7ad52cd960477f61b0faaa6364968844e8d2862714e35340531a12aa82e5
4
+ data.tar.gz: 0a66a78cfdec31a91354c8815e1ec612a44345230bfb5115cdd1afc999bbcc85
5
5
  SHA512:
6
- metadata.gz: 679620aed3269f571bbec98a28537a34e03240e7df57319e34e0c100b85332cdbbbc6a01cf34d62552edbbc971411a881da57a33b54ede1d64b4c0833b7fbc6a
7
- data.tar.gz: a89bc51bded625662eb00666c0d3c2f1034f9d397a84e86d7e30136398d0e53e60d0e8287cce0cda3baea0dc5c7ef037bc629635e7c9854a58b5c8376ddafa2d
6
+ metadata.gz: fca6f6a4ffa3a2893019d583853d1e790e8a28e90fb6140a53ce4f5dfdf4b34abfb5d9a350f3a4e5d6e5245a3461f6b303f62208cd55b9158c1256e38f35f1f8
7
+ data.tar.gz: 4d03d6226092c97f5fe9f35283c77d4544f3addb4766d42a01eb6cd69568763ab24ff5220181e0f7b5f7cce69722b073367b098bd1e525c37923b449ca460903
@@ -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
- cd example/static/blog-docs
80
- npm install
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: bundle exec rake standard:fix
88
- - run: |
89
- cd example
90
- ./script/test
73
+ - run: ./script/test
data/.gitignore CHANGED
@@ -6,3 +6,5 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /vendor/bundle
10
+ /example/vendor/bundle
@@ -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
@@ -1,51 +1,51 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- static-rails (0.0.9)
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.1)
12
- actionview (= 6.0.3.1)
13
- activesupport (= 6.0.3.1)
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.1)
19
- activesupport (= 6.0.3.1)
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.1)
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.0)
30
+ ast (2.4.1)
31
31
  builder (3.2.4)
32
- concurrent-ruby (1.1.6)
32
+ concurrent-ruby (1.1.7)
33
33
  crass (1.0.6)
34
34
  erubi (1.9.0)
35
- i18n (1.8.3)
35
+ i18n (1.8.5)
36
36
  concurrent-ruby (~> 1.0)
37
- loofah (2.5.0)
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.1)
43
- nokogiri (1.10.9)
42
+ minitest (5.14.2)
43
+ nokogiri (1.10.10)
44
44
  mini_portile2 (~> 2.4.0)
45
- parallel (1.19.1)
46
- parser (2.7.1.3)
47
- ast (~> 2.4.0)
48
- rack (2.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.1)
59
- actionpack (= 6.0.3.1)
60
- activesupport (= 6.0.3.1)
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.7.1)
66
+ regexp_parser (1.8.0)
67
67
  rexml (3.2.4)
68
- rubocop (0.85.1)
68
+ rubocop (0.91.1)
69
69
  parallel (~> 1.10)
70
- parser (>= 2.7.0.1)
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.3)
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.0.3)
78
- parser (>= 2.7.0.1)
79
- rubocop-performance (1.6.1)
80
- rubocop (>= 0.71.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.4.7)
83
- rubocop (~> 0.85.0)
84
- rubocop-performance (~> 1.6.0)
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.3.0)
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"
@@ -36,7 +36,7 @@ module StaticRails
36
36
  attr_reader :sites
37
37
  def sites=(sites)
38
38
  @sites = Array.wrap(sites).map { |site|
39
- Site.new(site)
39
+ Site.new(**site)
40
40
  }
41
41
  end
42
42
  end
@@ -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
- def csrf_token_hmac(session, identifier)
14
- ActionController::RequestForgeryProtection.instance_method(:csrf_token_hmac).bind(self).call(session, identifier)
15
- end
16
-
17
- def mask_token(raw_token)
18
- ActionController::RequestForgeryProtection.instance_method(:mask_token).bind(self).call(raw_token)
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))
@@ -10,7 +10,7 @@ module StaticRails
10
10
  end
11
11
 
12
12
  initializer "static_rails.middleware" do
13
- config.app_middleware.insert_before 0, SiteMiddleware
13
+ config.app_middleware.insert_after Rack::Sendfile, SiteMiddleware
14
14
  config.app_middleware.use SitePlusCsrfMiddleware
15
15
  end
16
16
 
@@ -16,10 +16,6 @@ module StaticRails
16
16
  @servers[site] ||= Server.new(site)
17
17
  end
18
18
 
19
- def ensure_servers_are_up
20
- @servers.values.each(&:start)
21
- end
22
-
23
19
  private
24
20
 
25
21
  def initialize
@@ -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(/^#{PATH_INFO_OBFUSCATION}/, "")
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 (match = matching_file_for(file_handler, site, path))
22
- req.path_info = match
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] ||= ActionDispatch::FileHandler.new(
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 matching_file_for(file_handler, site, path)
41
- if (match = file_handler.match?(path))
42
- match
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.match?(site.compile_404_file_path)
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
@@ -1,3 +1,3 @@
1
1
  module StaticRails
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.14"
3
3
  end
@@ -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
+
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ echo "--> Running standard:fix"
6
+ bundle exec rake standard:fix
7
+
8
+ echo "--> Running example app's tests"
9
+ cd example
10
+ ./script/test
11
+ cd ..
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.9
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-06-08 00:00:00.000000000 Z
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: []