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 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: []