rack-server-pages 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +22 -0
  3. data/README.md +222 -78
  4. data/RELEASING.md +79 -0
  5. data/UPGRADING.md +23 -0
  6. data/lib/rack/server_pages.rb +84 -7
  7. data/lib/rack-server-pages/version.rb +1 -1
  8. data/rack-server-pages.gemspec +3 -6
  9. metadata +8 -63
  10. data/.github/workflows/lint.yml +0 -15
  11. data/.github/workflows/test.yml +0 -37
  12. data/.gitignore +0 -11
  13. data/.rspec +0 -2
  14. data/.rubocop.yml +0 -10
  15. data/.rubocop_todo.yml +0 -372
  16. data/Gemfile +0 -46
  17. data/Guardfile +0 -16
  18. data/Rakefile +0 -12
  19. data/config.ru +0 -49
  20. data/public/CHANGES.erb +0 -3
  21. data/public/README.erb +0 -3
  22. data/public/_layout.html.erb +0 -9
  23. data/public/folder/sample.erb +0 -14
  24. data/public/folder/special-sub.folder-@/sample.erb +0 -14
  25. data/public/folder/subfolder/(sub-folder)/sample-in-sub-folder.extension.erb +0 -14
  26. data/public/folder/subfolder/sample.erb +0 -14
  27. data/public/folder//320/277/320/276-/321/200/321/203/321/201/321/201/320/272/320/270//320/277/321/200/320/270/320/274/320/265/321/200.erb +0 -14
  28. data/public/index.html +0 -23
  29. data/public/info.php +0 -89
  30. data/public/rack_logo.png +0 -0
  31. data/public/rack_logo@2x.png +0 -0
  32. data/public/sample.erb +0 -14
  33. data/public/style.css.sass +0 -99
  34. data/views/about.html.slim +0 -11
  35. data/views/article.html.md +0 -16
  36. data/views/betty.css.sass +0 -11
  37. data/views/contact.xml.builder +0 -5
  38. data/views/examples/_layout.html.erb +0 -14
  39. data/views/examples/_time.html.erb +0 -4
  40. data/views/examples/builder.xml.builder +0 -2
  41. data/views/examples/coffee.js.coffee +0 -0
  42. data/views/examples/erb.html.erb +0 -2
  43. data/views/examples/haml.html.haml +0 -6
  44. data/views/examples/html.html +0 -1
  45. data/views/examples/index.html.erb +0 -9
  46. data/views/examples/less.css.less +0 -0
  47. data/views/examples/liquid.html.liquid +0 -0
  48. data/views/examples/markaby.html.mab +0 -0
  49. data/views/examples/markdown.html.markdown +0 -6
  50. data/views/examples/nokogiri.xml.nokogiri +0 -1
  51. data/views/examples/radius.html.radius +0 -0
  52. data/views/examples/rdoc.html.rdoc +0 -0
  53. data/views/examples/robots.txt +0 -1
  54. data/views/examples/sass.css.sass +0 -11
  55. data/views/examples/scss.css.scss +0 -0
  56. data/views/examples/slim.html.slim +0 -2
  57. data/views/examples/source.html.slim +0 -9
  58. data/views/examples/textile.html.textile +0 -0
  59. data/views/examples/wiki.html.wiki +0 -0
  60. data/views/examples/yajl.json.yajl +0 -0
  61. data/views/script.js.coffee +0 -13
@@ -2,9 +2,9 @@
2
2
  require 'rack'
3
3
  require 'rack/utils'
4
4
  require 'rack/mime'
5
- require 'rack/logger'
6
5
  require 'time'
7
6
  require 'forwardable'
7
+ require 'digest/sha2'
8
8
 
9
9
  module Rack
10
10
  class ServerPages
@@ -40,10 +40,49 @@ module Rack
40
40
  @app
41
41
  else
42
42
  file = select_template_file(files)
43
- (tpl = Template[file]) ? server_page(tpl) : Rack::Files.new(file.split(path_info).first)
43
+ (tpl = Template[file]) ? server_page(tpl) : static_file(file, path_info)
44
44
  end.call(env)
45
45
  end
46
46
 
47
+ module StaticFiles
48
+ def static_file(file, path_info)
49
+ root = file.split(path_info).first
50
+ return Rack::Files.new(root) unless ::File.file?(file) && ::File.readable?(file)
51
+
52
+ headers = static_headers(file)
53
+ files = Rack::Files.new(root, headers)
54
+ lambda do |env|
55
+ if @config.static_etags && %w[GET HEAD].include?(env['REQUEST_METHOD']) && matching_etag?(env['HTTP_IF_NONE_MATCH'], headers[Rack::ETAG])
56
+ [304, headers.dup, []]
57
+ else
58
+ files.call(static_request_env(env))
59
+ end
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def static_request_env(env)
66
+ # If-None-Match takes precedence over If-Modified-Since.
67
+ ignore_modified_since = !@config.static_timestamps || (@config.static_etags && env.key?('HTTP_IF_NONE_MATCH'))
68
+ ignore_modified_since ? env.merge('HTTP_IF_MODIFIED_SINCE' => nil) : env
69
+ end
70
+
71
+ def static_headers(file)
72
+ headers = @config.static_etags ? { Rack::ETAG => %("#{Digest::SHA256.file(file).hexdigest}") } : {}
73
+ @config.static_cache_control ? headers.merge(Rack::CACHE_CONTROL => @config.static_cache_control) : headers
74
+ end
75
+
76
+ def matching_etag?(condition, etag)
77
+ condition.to_s.split(',').any? do |candidate|
78
+ candidate = candidate.strip.sub(%r{\AW/}, '')
79
+ candidate == '*' || candidate == etag
80
+ end
81
+ end
82
+ end
83
+
84
+ include StaticFiles
85
+
47
86
  def find_template_files(path_info)
48
87
  if m = path_info.match(@path_regex)
49
88
  @config.view_paths.inject([]) do |files, path|
@@ -67,7 +106,7 @@ module Rack
67
106
 
68
107
  def server_page(template)
69
108
  lambda do |env|
70
- @binding.new(env).tap do |scope|
109
+ @binding.new(env, self).tap do |scope|
71
110
  catch(:halt) do
72
111
  begin
73
112
  @config.filter.invoke(scope, :before)
@@ -88,6 +127,36 @@ module Rack
88
127
  end
89
128
  end
90
129
 
130
+ module AssetPaths
131
+ def asset_path(path)
132
+ path, fragment = path.to_s.split('#', 2)
133
+ path, query = path.to_s.split('?', 2)
134
+ path, file = asset_file(path.to_s)
135
+ query = Rack::Utils.parse_query(query)
136
+ query['v'] = Digest::SHA256.file(file).hexdigest
137
+ "#{path}?#{Rack::Utils.build_query(query)}#{fragment && "##{fragment}"}"
138
+ end
139
+
140
+ private
141
+
142
+ def asset_file(path)
143
+ raise ArgumentError, 'asset_path requires a local asset path without parent-directory traversal' unless valid_asset_path?(CGI.unescape(path))
144
+
145
+ path = "#{@config.effective_path}/#{path.sub(%r{\A/}, '')}"
146
+ file = select_template_file(find_template_files(CGI.unescape(path)) || [])
147
+ raise Errno::ENOENT, path unless file && ::File.file?(file)
148
+
149
+ [path, file]
150
+ end
151
+
152
+ def valid_asset_path?(path)
153
+ !path.empty? && (path !~ %r{\A(?:[a-z][a-z0-9+.-]*:|//)}i) &&
154
+ !path.split('/').include?('..') && !path.include?("\0")
155
+ end
156
+ end
157
+
158
+ include AssetPaths
159
+
91
160
  class Filter
92
161
  TYPES = [:before, :after, :on_error].freeze
93
162
  TYPES.each do |type|
@@ -144,7 +213,8 @@ module Rack
144
213
  end
145
214
  end
146
215
 
147
- hash_accessor :view_path, :effective_path, :cache_control, :default_charset, :failure_app, :show_exceptions
216
+ hash_accessor :view_path, :effective_path, :cache_control, :static_cache_control, :static_etags, :static_timestamps,
217
+ :default_charset, :failure_app, :show_exceptions
148
218
 
149
219
  attr_reader :filter
150
220
 
@@ -154,6 +224,8 @@ module Rack
154
224
  super
155
225
  self[:default_charset] ||= 'utf-8'
156
226
  self[:view_path] ||= %w(views public)
227
+ self[:static_etags] = true
228
+ self[:static_timestamps] = true
157
229
  @helpers = []
158
230
  @filter = Filter.new
159
231
  end
@@ -188,7 +260,7 @@ module Rack
188
260
  end
189
261
 
190
262
  def tilt?
191
- @use_tilt.nil? ? (@use_tilt ||= !!defined?(Tilt)) : @use_tilt && defined?(Tilt)
263
+ @use_tilt != false && !!defined?(Tilt) && Tilt.respond_to?(:[])
192
264
  end
193
265
 
194
266
  def use_tilt(bool = true)
@@ -274,6 +346,10 @@ module Rack
274
346
  end
275
347
 
276
348
  module CoreHelper
349
+ def asset_path(path)
350
+ url(@server_pages.asset_path(path))
351
+ end
352
+
277
353
  def redirect(target, status = 302)
278
354
  response.redirect(target, status)
279
355
  halt
@@ -315,7 +391,7 @@ module Rack
315
391
 
316
392
  attr_reader :request, :response
317
393
 
318
- def_delegators :request, :env, :params, :session, :cookies, :logger
394
+ def_delegators :request, :env, :params, :session, :cookies
319
395
  def_delegators :response, :headers, :set_cookies, :delete_cookie
320
396
 
321
397
  class << self
@@ -330,9 +406,10 @@ module Rack
330
406
  end
331
407
  end
332
408
 
333
- def initialize(env)
409
+ def initialize(env, server_pages = nil)
334
410
  @request = Rack::Request.new(env)
335
411
  @response = Rack::Response.new
412
+ @server_pages = server_pages
336
413
  # @response['Content-Type'] = nil
337
414
  end
338
415
 
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  class ServerPages
3
- VERSION = '0.2.0'.freeze
3
+ VERSION = '0.3.0'.freeze
4
4
  end
5
5
  end
@@ -9,13 +9,10 @@ Gem::Specification.new do |s|
9
9
  s.email = ['m@igrs.jp']
10
10
  s.homepage = 'http://github.com/migrs/rack-server-pages'
11
11
  s.licenses = ['MIT']
12
- s.summary = 'Rack middleware and appilcation for serving dynamic pages in very simple way.'
13
- s.description = 'Rack middleware and appilcation for serving dynamic pages in very simple way.
14
- There are no controllers and no models, just only views like a asp, jsp and php!'
12
+ s.summary = 'Rack middleware and appilcation for serving dynamic pages.'
13
+ s.description = 'Rack middleware and appilcation for serving dynamic pages in very simple way, without controllers or models, only views similar to ASP, JSP and PHP.'
15
14
 
16
- s.files = `git ls-files -z`.split("\x0").reject do |f|
17
- f.match(%r{^(spec)/})
18
- end
15
+ s.files = Dir['lib/**/*', 'CHANGES.md', 'README.md', 'UPGRADING.md', 'RELEASING.md', 'LICENSE.md', 'rack-server-pages.gemspec']
19
16
 
20
17
  s.require_paths = ['lib']
21
18
 
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-server-pages
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masato Igarashi
8
8
  - Daniel Doubrovkine
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2024-10-19 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rack
@@ -25,79 +24,27 @@ dependencies:
25
24
  - - ">="
26
25
  - !ruby/object:Gem::Version
27
26
  version: '0'
28
- description: |-
29
- Rack middleware and appilcation for serving dynamic pages in very simple way.
30
- There are no controllers and no models, just only views like a asp, jsp and php!
27
+ description: Rack middleware and appilcation for serving dynamic pages in very simple
28
+ way, without controllers or models, only views similar to ASP, JSP and PHP.
31
29
  email:
32
30
  - m@igrs.jp
33
31
  executables: []
34
32
  extensions: []
35
33
  extra_rdoc_files: []
36
34
  files:
37
- - ".github/workflows/lint.yml"
38
- - ".github/workflows/test.yml"
39
- - ".gitignore"
40
- - ".rspec"
41
- - ".rubocop.yml"
42
- - ".rubocop_todo.yml"
43
35
  - CHANGES.md
44
- - Gemfile
45
- - Guardfile
46
36
  - LICENSE.md
47
37
  - README.md
48
- - Rakefile
49
- - config.ru
38
+ - RELEASING.md
39
+ - UPGRADING.md
50
40
  - lib/rack-server-pages.rb
51
41
  - lib/rack-server-pages/version.rb
52
42
  - lib/rack/server_pages.rb
53
- - public/CHANGES.erb
54
- - public/README.erb
55
- - public/_layout.html.erb
56
- - public/folder/sample.erb
57
- - public/folder/special-sub.folder-@/sample.erb
58
- - public/folder/subfolder/(sub-folder)/sample-in-sub-folder.extension.erb
59
- - public/folder/subfolder/sample.erb
60
- - public/folder/по-русски/пример.erb
61
- - public/index.html
62
- - public/info.php
63
- - public/rack_logo.png
64
- - public/rack_logo@2x.png
65
- - public/sample.erb
66
- - public/style.css.sass
67
43
  - rack-server-pages.gemspec
68
- - views/about.html.slim
69
- - views/article.html.md
70
- - views/betty.css.sass
71
- - views/contact.xml.builder
72
- - views/examples/_layout.html.erb
73
- - views/examples/_time.html.erb
74
- - views/examples/builder.xml.builder
75
- - views/examples/coffee.js.coffee
76
- - views/examples/erb.html.erb
77
- - views/examples/haml.html.haml
78
- - views/examples/html.html
79
- - views/examples/index.html.erb
80
- - views/examples/less.css.less
81
- - views/examples/liquid.html.liquid
82
- - views/examples/markaby.html.mab
83
- - views/examples/markdown.html.markdown
84
- - views/examples/nokogiri.xml.nokogiri
85
- - views/examples/radius.html.radius
86
- - views/examples/rdoc.html.rdoc
87
- - views/examples/robots.txt
88
- - views/examples/sass.css.sass
89
- - views/examples/scss.css.scss
90
- - views/examples/slim.html.slim
91
- - views/examples/source.html.slim
92
- - views/examples/textile.html.textile
93
- - views/examples/wiki.html.wiki
94
- - views/examples/yajl.json.yajl
95
- - views/script.js.coffee
96
44
  homepage: http://github.com/migrs/rack-server-pages
97
45
  licenses:
98
46
  - MIT
99
47
  metadata: {}
100
- post_install_message:
101
48
  rdoc_options: []
102
49
  require_paths:
103
50
  - lib
@@ -112,9 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
59
  - !ruby/object:Gem::Version
113
60
  version: '0'
114
61
  requirements: []
115
- rubygems_version: 3.3.7
116
- signing_key:
62
+ rubygems_version: 4.0.20
117
63
  specification_version: 4
118
- summary: Rack middleware and appilcation for serving dynamic pages in very simple
119
- way.
64
+ summary: Rack middleware and appilcation for serving dynamic pages.
120
65
  test_files: []
@@ -1,15 +0,0 @@
1
- name: lint
2
- on: [push, pull_request]
3
- jobs:
4
- rubocop:
5
- name: RuboCop
6
- runs-on: ubuntu-latest
7
- steps:
8
- - name: Checkout
9
- uses: actions/checkout@v3
10
- - name: Set up Ruby
11
- uses: ruby/setup-ruby@v1
12
- with:
13
- ruby-version: "3.2"
14
- bundler-cache: true
15
- - run: bundle exec rubocop
@@ -1,37 +0,0 @@
1
- ---
2
- name: test
3
- on: [push, pull_request]
4
- jobs:
5
- test:
6
- runs-on: ubuntu-latest
7
- name: test (ruby=${{ matrix.ruby-version }}, rack=${{ matrix.rack-version }})
8
- strategy:
9
- fail-fast: false
10
- matrix:
11
- rack-version:
12
- - "~> 2"
13
- - "~> 3"
14
- ruby-version:
15
- - "3.3"
16
- - "3.2"
17
- - "3.1"
18
- - "3.0"
19
- env:
20
- RACK_VERSION: ${{ matrix.rack-version }}
21
- steps:
22
- - uses: actions/checkout@v4
23
- - uses: ruby/setup-ruby@v1
24
- with:
25
- ruby-version: ${{ matrix.ruby-version }}
26
- bundler-cache: true
27
- - run: bundle show | grep rack
28
- - uses: browser-actions/setup-firefox@latest
29
- with:
30
- firefox-version: "108.0"
31
- - uses: browser-actions/setup-geckodriver@latest
32
- with:
33
- geckodriver-version: "0.34.0"
34
- - uses: GabrielBB/xvfb-action@v1
35
- with:
36
- run: |
37
- bundle exec rake spec
data/.gitignore DELETED
@@ -1,11 +0,0 @@
1
- *.gem
2
- .bundle
3
- Gemfile.lock
4
- pkg/*
5
- .DS_Store
6
- *.swp
7
- tmp/*
8
- .sass-cache
9
- coverage/
10
- .rbenv-version
11
- .rvmrc
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --format=documentation
2
- --color
data/.rubocop.yml DELETED
@@ -1,10 +0,0 @@
1
- AllCops:
2
- NewCops: enable
3
- TargetRubyVersion: 3.0
4
-
5
- inherit_from: .rubocop_todo.yml
6
-
7
- require:
8
- - rubocop-capybara
9
- - rubocop-rake
10
- - rubocop-rspec