utopia 2.8.2 → 2.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a40f8fb67b26f53edba8a76b91c2dddc730127641e918c5f8b9f79b5f20a5275
4
- data.tar.gz: 57ff2d40871d3a5b8e76e4ddf25a0aafc2bebe87e11e15469b08419e78e3124e
3
+ metadata.gz: 05f9ea2c2313177fe0ddab9681776ce465160016ba76ddf961ce32c90613031d
4
+ data.tar.gz: 24cc21d33830e008f34354bf95eaf52bce0a83bde857ba59a03c3e120e1a84e7
5
5
  SHA512:
6
- metadata.gz: 0cf61f5628b5bf6e7386059238d14f141f27a2eea1f7b5f2f0204156fba2538caf8f0850ecd13646fe663a3b7b3044790f3744799abfa3ad5bea13ffc4ac8ab9
7
- data.tar.gz: 43796a9d6ebde85e159139c4dbdecac570c1c07e1f162c214a092cc3b726781bcae4d4834cf0e22d5327eff58473687cbc869138e0ea4fe055d41af57bbdae36
6
+ metadata.gz: 076044052516cd4bf26f476e2dbca23fcf5f9e49673b5f169f317d70ae1b6d560e5c2bf4578e8cdcd0ed368fe4eb328e7d1d083269406f67459c4a7f48f37b33
7
+ data.tar.gz: 07056aba9f2533e1fee4e60f337a2d1cf2b048bca510488c447c1b528ab7d0ee2df37dc8ab32d5d8e4387197eefdc66663efca291d00359134758b158cb73702
@@ -9,13 +9,14 @@ before_install:
9
9
 
10
10
  matrix:
11
11
  include:
12
- - rvm: 2.3
13
12
  - rvm: 2.4
14
13
  - rvm: 2.5
15
14
  - rvm: 2.6
16
15
  env: BENCHMARK=true
17
16
  - rvm: 2.6
18
17
  env: COVERAGE=BriefSummary,Coveralls
18
+ - rvm: 2.6
19
+ os: osx
19
20
  - rvm: ruby-head
20
21
  - rvm: jruby-head
21
22
  - rvm: truffleruby
data/README.md CHANGED
@@ -41,7 +41,7 @@ Create a new site:
41
41
 
42
42
  ## Usage
43
43
 
44
- There is an excellent documentation wiki included with the source code. Simply clone this repository and `rake documentation:server`. This documentation wiki is editable, so feel free to submit a PR with improvements.
44
+ There is an excellent [documentation wiki](https://ioquatix.github.io/utopia/) included with the source code. Simply clone this repository and `rake documentation:server`. This documentation wiki is editable, so feel free to submit a PR with improvements.
45
45
 
46
46
  ## Contributing
47
47
 
@@ -14,6 +14,7 @@ gem "kramdown-parser-gfm"
14
14
  group :development do
15
15
  # For `rake server`:
16
16
  gem "guard-falcon"
17
+ gem "falcon"
17
18
 
18
19
  # For `rake console`:
19
20
  gem "pry"
@@ -22,8 +23,3 @@ group :development do
22
23
  # For `rspec` testing:
23
24
  gem "rspec"
24
25
  end
25
-
26
- group :production do
27
- # Used for passenger-config to restart server after deployment:
28
- gem "passenger"
29
- end
@@ -4,7 +4,7 @@ Utopia is designed to make deployment to remote servers easy.
4
4
 
5
5
  ## Deployment
6
6
 
7
- The preferred method of deployment to a production server is via git. The `utopia` command assists with setup of a remote git repository on the server. It will setup a `git` `post-update` hook which will deploy the site correctly and restart passenger for that site.
7
+ The preferred method of deployment to a production server is via git. The `utopia` command assists with setup of a remote git repository on the server. It will setup a `git` `post-update` hook which will deploy the site correctly and restart the application server for that site.
8
8
 
9
9
  To setup a server for deployment:
10
10
 
@@ -37,31 +37,7 @@ When you run `rake` tasks or spawn a server, the values in `config/environment.y
37
37
 
38
38
  ## Platform
39
39
 
40
- The best deployment platform for Utopia is Linux. Specifically, [Arch Linux](https://www.archlinux.org/) with the following packages:
41
-
42
- - [nginx-mainline-passenger](https://aur.archlinux.org/packages/nginx-mainline-passenger/)
43
- - [passenger-nginx-module](https://aur.archlinux.org/packages/passenger-nginx-module/)
44
-
45
- There have been issues with the official packages and thus these packages were developed and tested with Utopia deployment in mind.
46
-
47
- ### Sample Nginx Configuration
48
-
49
- Create a configuration file for your site, e.g. `/etc/nginx/sites/www.example.com`:
50
-
51
- ```nginx
52
- server {
53
- listen 80;
54
- server_name www.example.com;
55
- root /srv/http/www.example.com/public;
56
- passenger_enabled on;
57
- }
58
-
59
- server {
60
- listen 80;
61
- server_name example.com;
62
- rewrite ^ http://www.example.com$uri permanent;
63
- }
64
- ```
40
+ The best deployment platform for Utopia is Linux, using [falcon](https://github.com/socketry/falcon).
65
41
 
66
42
  ### Sudo Setup
67
43
 
@@ -1,6 +1,6 @@
1
1
  # Testing
2
2
 
3
- Utopia websites include a default set of tests, and associated `rake test` tasks. These specs can test against the actual running website. By default, `simplecov` is included for coverage testing.
3
+ Utopia websites include a default set of tests, and associated `rake test` tasks. These specs can test against the actual running website. By default, [covered](https://github.com/socketry/covered) is included for coverage testing.
4
4
 
5
5
  ```bash
6
6
  $ rake coverage test
@@ -97,13 +97,13 @@ module Utopia
97
97
  def to_anchor(**options)
98
98
  Trenni::Builder.fragment(options[:builder]) do |builder|
99
99
  if href?
100
- a_attributes = {
100
+ attributes = {
101
101
  :class => options.fetch(:class, 'link'),
102
102
  :href => relative_href(options[:base]),
103
103
  :target => options.fetch(:target, @info[:target])
104
104
  }
105
105
 
106
- builder.inline('a', a_attributes) do
106
+ builder.inline('a', attributes) do
107
107
  builder.text(options[:content] || title)
108
108
  end
109
109
  else
@@ -36,7 +36,7 @@ module Utopia
36
36
  def call(env)
37
37
  response = @app.call(env)
38
38
 
39
- unless response[2].empty? or response[1].include?(Rack::CONTENT_LENGTH)
39
+ unless response[2]&.empty? or response[1].include?(Rack::CONTENT_LENGTH)
40
40
  if content_length = self.content_length_of(response[2])
41
41
  response[1][Rack::CONTENT_LENGTH] = content_length
42
42
  end
@@ -81,7 +81,12 @@ module Utopia
81
81
  def respond!(response)
82
82
  throw :response, response
83
83
  end
84
-
84
+
85
+ # Respond with the response, but only if it's not nil.
86
+ def respond?(response)
87
+ respond!(response) if response
88
+ end
89
+
85
90
  # This will cause the controller middleware to pass on the request.
86
91
  def ignore!
87
92
  throw :response, nil
@@ -180,14 +180,10 @@ module Utopia
180
180
 
181
181
  # Set the Vary: header on the response to indicate that this response should include the header in the cache key.
182
182
  def vary(env, response)
183
- headers = response[1]
183
+ headers = response[1].to_a
184
184
 
185
185
  # This response was based on the Accept-Language header:
186
- if headers['Vary']
187
- headers['Vary'] += ',Accept-Language'
188
- else
189
- headers['Vary'] = 'Accept-Language'
190
- end
186
+ headers << ['Vary', 'Accept-Language']
191
187
 
192
188
  # Althought this header is generally not supported, we supply it anyway as it is useful for debugging:
193
189
  if locale = env[CURRENT_LOCALE_KEY]
@@ -18,8 +18,6 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require 'logger'
22
-
23
21
  require_relative 'http'
24
22
  require_relative 'path'
25
23
 
@@ -126,7 +126,7 @@ module Utopia
126
126
 
127
127
  data = encrypt(session_hash.values)
128
128
 
129
- commit(data, headers)
129
+ commit(data, values[:updated_at], headers)
130
130
  end
131
131
  end
132
132
 
@@ -165,20 +165,26 @@ module Utopia
165
165
  if values[:user_agent] != request.user_agent
166
166
  raise PayloadError, "Invalid session because supplied user agent #{request.user_agent.inspect} does not match session user agent #{values[:user_agent].inspect}!"
167
167
  end
168
+
169
+ if expires_at = expires(values[:updated_at])
170
+ if expires_at < Time.now.utc
171
+ raise PayloadError, "Expired session cookie, user agent submitted a cookie that should have expired at #{expires_at}."
172
+ end
173
+ end
168
174
 
169
175
  return true
170
176
  end
171
177
 
172
- def expires
178
+ def expires(updated_at=Time.now.utc)
173
179
  if @expires_after
174
- return Time.now.utc + @expires_after
180
+ return updated_at + @expires_after
175
181
  end
176
182
  end
177
183
 
178
- def commit(value, headers)
184
+ def commit(value, updated_at, headers)
179
185
  cookie = {
180
186
  value: value,
181
- expires: expires
187
+ expires: expires(updated_at)
182
188
  }.merge(@cookie_defaults)
183
189
 
184
190
  Rack::Utils.set_cookie_header!(headers, @cookie_name, cookie)
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Utopia
22
- VERSION = "2.8.2"
22
+ VERSION = "2.9.0"
23
23
  end
@@ -23,8 +23,3 @@ group :development do
23
23
  gem "rspec"
24
24
  gem "covered"
25
25
  end
26
-
27
- group :production do
28
- # Used for passenger-config to restart server after deployment:
29
- gem "passenger"
30
- end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env -S falcon host
2
+
3
+ load :rack, :self_signed_tls, :supervisor
4
+
5
+ rack 'utopia.localhost', :self_signed_tls
6
+ supervisor
@@ -23,7 +23,7 @@
23
23
  <div>
24
24
  <i class="fa fa-server"></i>
25
25
  <h2>Batteries included</h2>
26
- <p>Utopia includes both a recommended development model and a server deployment model out of the box. This is exposed via the <code>utopia</code> command. We recommend use of <a href="https://www.nginx.com">Nginx</a> and <a href="https://www.phusionpassenger.com">Passenger</a> for server side deployment.</p>
26
+ <p>Utopia includes both a recommended development model and a server deployment model out of the box. This is exposed via the <code>utopia</code> command. We recommend use of <a href="https://github.com/socketry/falcon">Falcon</a> for server side deployment.</p>
27
27
  </div>
28
28
 
29
29
  <div>
@@ -6,8 +6,7 @@ end
6
6
 
7
7
  desc 'Restart the application server'
8
8
  task :restart do
9
- # This task is run after the deployment task above.
10
- if passenger_config = `which passenger-config`.chomp!
11
- sh(passenger_config, 'restart-app', '--ignore-passenger-not-running', SITE_ROOT.to_s)
9
+ if falcon = `which falcon`.chomp! and File.exist?("supervisor.ipc")
10
+ sh(falcon, 'supervisor', 'restart')
12
11
  end
13
12
  end
@@ -1,12 +1,10 @@
1
1
 
2
2
  require "rspec/core/rake_task"
3
3
 
4
- RSpec::Core::RakeTask.new(:test) do |task|
5
- task.rspec_opts = %w{--require simplecov} if ENV['COVERAGE']
6
- end
4
+ RSpec::Core::RakeTask.new(:test)
7
5
 
8
6
  task :coverage do
9
- ENV['COVERAGE'] = 'y'
7
+ ENV['COVERAGE'] = 'PartialSummary'
10
8
  end
11
9
 
12
10
  desc 'Start the development server.'
@@ -1,6 +1,6 @@
1
1
 
2
2
  desc 'Set up the environment for running your web application'
3
- task :environment do |task|
3
+ task :environment => :log do |task|
4
4
  require SITE_ROOT + 'config/environment'
5
5
 
6
6
  # We ensure this is part of the shell environment so if other commands are invoked they will work correctly.
@@ -11,7 +11,7 @@ task :environment do |task|
11
11
  if ENV['UTOPIA_SESSION_SECRET'].nil?
12
12
  require 'securerandom'
13
13
 
14
- warn 'Generating transient session key for development...'
14
+ Utopia.logger.warn 'Generating transient session key for development...'
15
15
  ENV['UTOPIA_SESSION_SECRET'] = SecureRandom.hex(32)
16
16
  end
17
17
  end
@@ -1,5 +1,6 @@
1
1
 
2
2
  require 'covered/rspec'
3
+ require 'async/rspec'
3
4
 
4
5
  RSpec.configure do |config|
5
6
  # Enable flags like --only-failures and --next-failure
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env rspec
2
+
3
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require 'rack/test'
24
+ require 'utopia/controller'
25
+
26
+ require 'async/websocket/client'
27
+ require 'async/websocket/adapters/rack'
28
+
29
+ require 'falcon/server'
30
+ require 'falcon/adapters/rack'
31
+
32
+ require 'async/http/client'
33
+ require 'async/http/endpoint'
34
+
35
+ RSpec.describe Utopia::Controller do
36
+ context Async::WebSocket::Client do
37
+ include Rack::Test::Methods
38
+ include_context Async::RSpec::Reactor
39
+
40
+ let(:endpoint) {Async::HTTP::Endpoint.parse("http://localhost:7050/server/events")}
41
+ let(:app) {Rack::Builder.parse_file(File.expand_path('websocket_spec.ru', __dir__)).first}
42
+ let(:server) {Falcon::Server.new(Falcon::Server.middleware(app), endpoint)}
43
+ let(:client) {Async::HTTP::Client.new(endpoint)}
44
+
45
+ let!(:server_task) do
46
+ reactor.async do
47
+ server.run
48
+ end
49
+ end
50
+
51
+ after do
52
+ server_task.stop
53
+ end
54
+
55
+ it "fails for normal requests" do
56
+ get "/server/events"
57
+
58
+ expect(last_response.status).to be == 400
59
+ end
60
+
61
+ it "can connect to websocket" do
62
+ Async::WebSocket::Client.connect(endpoint) do |connection|
63
+ expect(connection.read).to be == {type: "test", data: "Hello World"}
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,4 @@
1
+
2
+ use Utopia::Controller, root: File.expand_path('websocket_spec', __dir__)
3
+
4
+ run lambda {|env| [404, {}, []]}
@@ -0,0 +1,10 @@
1
+
2
+ prepend Actions
3
+
4
+ on 'events' do |request|
5
+ upgrade = Async::WebSocket::Adapters::Rack.open(request.env) do |connection|
6
+ connection.write({type: "test", data: "Hello World"})
7
+ end
8
+
9
+ respond?(upgrade) or fail!
10
+ end
@@ -102,6 +102,15 @@ module Utopia::SessionSpec
102
102
  get "/session-get?key=foo"
103
103
  expect(last_response.body).to be == ""
104
104
  end
105
+
106
+ it "should fail if expired cookie is sent with the request" do
107
+ session_cookie = last_response['Set-Cookie'].split(';')[0]
108
+ sleep 6 # sleep longer than the session timeout
109
+ header 'Cookie', session_cookie
110
+
111
+ get "/session-get?key=foo"
112
+ expect(last_response.body).to be == ""
113
+ end
105
114
 
106
115
  it "shouldn't fail if ip address is changed" do
107
116
  # Change user agent:
@@ -1,7 +1,7 @@
1
1
 
2
2
  use Utopia::Session,
3
3
  secret: "97111cabf4c1a5e85b8029cf7c61aa44424fc24a",
4
- expires_after: 3600 * 48,
4
+ expires_after: 5,
5
5
  update_timeout: 1
6
6
 
7
7
  run lambda { |env|
@@ -38,9 +38,12 @@ Gem::Specification.new do |spec|
38
38
 
39
39
  spec.add_dependency 'concurrent-ruby', '~> 1.0'
40
40
 
41
+ spec.add_development_dependency 'falcon'
42
+ spec.add_development_dependency 'async-rspec'
43
+ spec.add_development_dependency 'async-websocket'
44
+
41
45
  spec.add_development_dependency 'covered'
42
46
  spec.add_development_dependency 'bundler'
43
47
  spec.add_development_dependency 'rspec', '~> 3.6'
44
- spec.add_development_dependency 'falcon'
45
48
  spec.add_development_dependency 'rake'
46
49
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: utopia
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.2
4
+ version: 2.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-29 00:00:00.000000000 Z
11
+ date: 2019-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: trenni
@@ -137,7 +137,7 @@ dependencies:
137
137
  - !ruby/object:Gem::Version
138
138
  version: '1.0'
139
139
  - !ruby/object:Gem::Dependency
140
- name: covered
140
+ name: falcon
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - ">="
@@ -151,7 +151,7 @@ dependencies:
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
153
  - !ruby/object:Gem::Dependency
154
- name: bundler
154
+ name: async-rspec
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - ">="
@@ -165,21 +165,35 @@ dependencies:
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
167
  - !ruby/object:Gem::Dependency
168
- name: rspec
168
+ name: async-websocket
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
- - - "~>"
171
+ - - ">="
172
172
  - !ruby/object:Gem::Version
173
- version: '3.6'
173
+ version: '0'
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
- - - "~>"
178
+ - - ">="
179
179
  - !ruby/object:Gem::Version
180
- version: '3.6'
180
+ version: '0'
181
181
  - !ruby/object:Gem::Dependency
182
- name: falcon
182
+ name: covered
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: bundler
183
197
  requirement: !ruby/object:Gem::Requirement
184
198
  requirements:
185
199
  - - ">="
@@ -192,6 +206,20 @@ dependencies:
192
206
  - - ">="
193
207
  - !ruby/object:Gem::Version
194
208
  version: '0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: rspec
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: '3.6'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: '3.6'
195
223
  - !ruby/object:Gem::Dependency
196
224
  name: rake
197
225
  requirement: !ruby/object:Gem::Requirement
@@ -617,6 +645,7 @@ files:
617
645
  - setup/site/config.ru
618
646
  - setup/site/config/README.md
619
647
  - setup/site/config/environment.rb
648
+ - setup/site/falcon.rb
620
649
  - setup/site/lib/readme.txt
621
650
  - setup/site/pages/_heading.xnode
622
651
  - setup/site/pages/_page.xnode
@@ -701,6 +730,9 @@ files:
701
730
  - spec/utopia/controller/rewrite_spec.rb
702
731
  - spec/utopia/controller/sequence_spec.rb
703
732
  - spec/utopia/controller/variables_spec.rb
733
+ - spec/utopia/controller/websocket_spec.rb
734
+ - spec/utopia/controller/websocket_spec.ru
735
+ - spec/utopia/controller/websocket_spec/server/controller.rb
704
736
  - spec/utopia/exceptions/handler_spec.rb
705
737
  - spec/utopia/exceptions/handler_spec.ru
706
738
  - spec/utopia/exceptions/handler_spec/controller.rb
@@ -760,7 +792,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
760
792
  - !ruby/object:Gem::Version
761
793
  version: '0'
762
794
  requirements: []
763
- rubygems_version: 3.0.3
795
+ rubygems_version: 3.0.2
764
796
  signing_key:
765
797
  specification_version: 4
766
798
  summary: Utopia is a framework for building dynamic content-driven websites.
@@ -828,6 +860,9 @@ test_files:
828
860
  - spec/utopia/controller/rewrite_spec.rb
829
861
  - spec/utopia/controller/sequence_spec.rb
830
862
  - spec/utopia/controller/variables_spec.rb
863
+ - spec/utopia/controller/websocket_spec.rb
864
+ - spec/utopia/controller/websocket_spec.ru
865
+ - spec/utopia/controller/websocket_spec/server/controller.rb
831
866
  - spec/utopia/exceptions/handler_spec.rb
832
867
  - spec/utopia/exceptions/handler_spec.ru
833
868
  - spec/utopia/exceptions/handler_spec/controller.rb