syntropy 0.29.0 → 0.31.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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -2
  3. data/CHANGELOG.md +22 -0
  4. data/README.md +0 -2
  5. data/bin/syntropy +8 -86
  6. data/cmd/_banner.rb +16 -0
  7. data/cmd/help.rb +12 -0
  8. data/cmd/serve.rb +95 -0
  9. data/cmd/test.rb +40 -0
  10. data/examples/{counter.rb → basic/counter.rb} +1 -1
  11. data/examples/{templates.rb → basic/templates.rb} +1 -1
  12. data/examples/mcp-oauth/.ruby-version +1 -0
  13. data/examples/mcp-oauth/Gemfile +8 -0
  14. data/examples/mcp-oauth/README.md +128 -0
  15. data/examples/mcp-oauth/app/.well-known/oauth-authorization-server.rb +18 -0
  16. data/examples/mcp-oauth/app/.well-known/oauth-protected-resource.rb +10 -0
  17. data/examples/mcp-oauth/app/_lib/auth_store.rb +23 -0
  18. data/examples/mcp-oauth/app/index.md +1 -0
  19. data/examples/mcp-oauth/app/mcp.rb +38 -0
  20. data/examples/mcp-oauth/app/oauth/authorize.rb +26 -0
  21. data/examples/mcp-oauth/app/oauth/consent.rb +86 -0
  22. data/examples/mcp-oauth/app/oauth/register.rb +15 -0
  23. data/examples/mcp-oauth/app/oauth/token.rb +79 -0
  24. data/examples/mcp-oauth/app/signin.rb +85 -0
  25. data/examples/mcp-oauth/test/helper.rb +9 -0
  26. data/examples/mcp-oauth/test/test_app.rb +27 -0
  27. data/examples/mcp-oauth/test/test_oauth.rb +628 -0
  28. data/lib/syntropy/app.rb +23 -12
  29. data/lib/syntropy/applets/builtin/default_error_handler.rb +3 -3
  30. data/lib/syntropy/applets/builtin/req.rb +1 -1
  31. data/lib/syntropy/dev_mode.rb +1 -1
  32. data/lib/syntropy/errors.rb +19 -12
  33. data/lib/syntropy/http/client.rb +43 -0
  34. data/lib/syntropy/http/client_connection.rb +36 -0
  35. data/lib/syntropy/http/io_extensions.rb +148 -0
  36. data/lib/syntropy/http/server.rb +174 -0
  37. data/lib/syntropy/http/server_connection.rb +367 -0
  38. data/lib/syntropy/http/status.rb +76 -0
  39. data/lib/syntropy/http.rb +7 -0
  40. data/lib/syntropy/json_api.rb +2 -5
  41. data/lib/syntropy/logger.rb +5 -1
  42. data/lib/syntropy/mime_types.rb +37 -0
  43. data/lib/syntropy/papercraft_extensions.rb +1 -1
  44. data/lib/syntropy/request/mock_adapter.rb +60 -0
  45. data/lib/syntropy/request/request_info.rb +255 -0
  46. data/lib/syntropy/request/response.rb +206 -0
  47. data/lib/syntropy/request/validation.rb +146 -0
  48. data/lib/syntropy/request.rb +99 -0
  49. data/lib/syntropy/routing_tree.rb +2 -1
  50. data/lib/syntropy/test.rb +65 -0
  51. data/lib/syntropy/utils.rb +1 -1
  52. data/lib/syntropy/version.rb +1 -1
  53. data/lib/syntropy.rb +4 -27
  54. data/syntropy.gemspec +2 -4
  55. data/test/app/.well-known/foo.rb +3 -0
  56. data/test/app/about/_error.rb +1 -1
  57. data/test/app/api+.rb +1 -1
  58. data/test/app_custom/_site.rb +1 -1
  59. data/test/bm_router_proc.rb +3 -3
  60. data/test/helper.rb +4 -27
  61. data/test/test_app.rb +83 -98
  62. data/test/test_caching.rb +2 -2
  63. data/test/test_errors.rb +6 -6
  64. data/test/test_http_client.rb +52 -0
  65. data/test/test_http_client_connection.rb +43 -0
  66. data/test/{test_connection.rb → test_http_server_connection.rb} +32 -32
  67. data/test/test_json_api.rb +14 -12
  68. data/test/test_mock_adapter.rb +59 -0
  69. data/test/{test_request_extensions.rb → test_request.rb} +150 -18
  70. data/test/test_response.rb +112 -0
  71. data/test/test_routing_tree.rb +15 -3
  72. data/test/test_server.rb +1 -1
  73. metadata +57 -35
  74. data/lib/syntropy/connection.rb +0 -402
  75. data/lib/syntropy/request_extensions.rb +0 -308
  76. data/lib/syntropy/server.rb +0 -173
  77. /data/examples/{bad.rb → basic/bad.rb} +0 -0
  78. /data/examples/{card.rb → basic/card.rb} +0 -0
  79. /data/examples/{counter.js → basic/counter.js} +0 -0
  80. /data/examples/{counter_api.rb → basic/counter_api.rb} +0 -0
  81. /data/examples/{favicon.ico → basic/favicon.ico} +0 -0
  82. /data/examples/{index.md → basic/index.md} +0 -0
@@ -2,31 +2,116 @@
2
2
 
3
3
  require_relative 'helper'
4
4
 
5
- class MethodValidationTest < Minitest::Test
6
- VE = Syntropy::ValidationError
5
+ class RequestInfoTest < Minitest::Test
6
+ def test_uri
7
+ r = Syntropy::MockAdapter.mock(':path' => '/test/path')
8
+ assert_equal '/test/path', r.path
9
+ assert_equal({}, r.query)
7
10
 
8
- def test_validate_http_method
9
- @req = mock_req(':method' => 'GET', ':path' => '/foo')
11
+ r = Syntropy::MockAdapter.mock(':path' => '/test/path?a=1&b=2&c=3%2f4')
12
+ assert_equal '/test/path', r.path
13
+ assert_equal({ a: '1', b: '2', c: '3/4' }, r.query)
14
+ end
10
15
 
11
- assert_equal 'get', @req.validate_http_method('get', 'head')
12
- assert_raises(Syntropy::Error) { @req.validate_http_method('post', 'put') }
13
- assert_raises(Syntropy::Error) { @req.validate_http_method() }
16
+ def test_query
17
+ r = Syntropy::MockAdapter.mock(':path' => '/GponForm/diag_Form?images/')
18
+ assert_equal '/GponForm/diag_Form', r.path
19
+ assert_equal({:'images/' => true}, r.query)
20
+
21
+ r = Syntropy::MockAdapter.mock(':path' => '/?a=1&b=2')
22
+ assert_equal '/', r.path
23
+ assert_equal({a: '1', b: '2'}, r.query)
24
+
25
+ r = Syntropy::MockAdapter.mock(':path' => '/?l=a&t=&x=42')
26
+ assert_equal({l: 'a', t: '', x: '42'}, r.query)
14
27
  end
15
28
 
16
- def test_respond_by_http_method
17
- @req = mock_req(':method' => 'GET', ':path' => '/foo')
29
+ def test_host
30
+ r = Syntropy::MockAdapter.mock(':path' => '/')
31
+ assert_nil r.host
32
+ assert_nil r.authority
18
33
 
19
- @req.respond_by_http_method(
20
- 'get' => ['GET foo', {}],
21
- 'post' => ['POST foo', {}]
34
+ r = Syntropy::MockAdapter.mock('host' => 'my.example.com')
35
+ assert_equal 'my.example.com', r.host
36
+ assert_equal 'my.example.com', r.authority
37
+
38
+ r = Syntropy::MockAdapter.mock(':authority' => 'my.foo.com')
39
+ assert_equal 'my.foo.com', r.host
40
+ assert_equal 'my.foo.com', r.authority
41
+ end
42
+
43
+ def test_full_uri
44
+ r = Syntropy::MockAdapter.mock(
45
+ ':scheme' => 'https',
46
+ 'host' => 'foo.bar',
47
+ ':path' => '/hey?a=b&c=d'
22
48
  )
23
- assert_equal 'GET foo', @req.response_body
24
49
 
25
- assert_raises(Syntropy::Error) {
26
- @req.respond_by_http_method(
27
- 'post' => ['POST foo', {}]
28
- )
29
- }
50
+ assert_equal 'https://foo.bar/hey?a=b&c=d', r.full_uri
51
+ end
52
+
53
+ def test_cookies
54
+ r = Syntropy::MockAdapter.mock
55
+
56
+ assert_equal({}, r.cookies)
57
+
58
+ r = Syntropy::MockAdapter.mock(
59
+ 'cookie' => 'uaid=a%2Fb; lastLocus=settings; signin_ref=/'
60
+ )
61
+
62
+ assert_equal({
63
+ 'uaid' => 'a/b',
64
+ 'lastLocus' => 'settings',
65
+ 'signin_ref' => '/'
66
+ }, r.cookies)
67
+ end
68
+
69
+ def test_content_type
70
+ r = Syntropy::MockAdapter.mock(
71
+ ':scheme' => 'https',
72
+ 'host' => 'foo.bar',
73
+ ':path' => '/hey?a=b&c=d',
74
+ 'content-type' => 'text/plain'
75
+ )
76
+ assert_equal 'text/plain', r.content_type
77
+
78
+ r = Syntropy::MockAdapter.mock(
79
+ ':scheme' => 'https',
80
+ 'host' => 'foo.bar',
81
+ ':path' => '/hey?a=b&c=d',
82
+ 'content-type' => 'text/plain; charset=utf-8'
83
+ )
84
+ assert_equal 'text/plain', r.content_type
85
+
86
+ r = Syntropy::MockAdapter.mock(
87
+ ':scheme' => 'https',
88
+ 'host' => 'foo.bar',
89
+ ':path' => '/hey?a=b&c=d',
90
+ 'content-type' => 'text/plain ; charset=utf-8'
91
+ )
92
+ assert_equal 'text/plain', r.content_type
93
+ end
94
+
95
+ def test_rewrite!
96
+ r = Syntropy::MockAdapter.mock(
97
+ ':scheme' => 'https',
98
+ 'host' => 'foo.bar',
99
+ ':path' => '/hey/ho?a=b&c=d'
100
+ )
101
+
102
+ assert_equal '/hey/ho', r.path
103
+ assert_equal URI.parse('/hey/ho?a=b&c=d'), r.uri
104
+ assert_equal 'https://foo.bar/hey/ho?a=b&c=d', r.full_uri
105
+
106
+ r.rewrite!('/hhh', '/')
107
+ assert_equal '/hey/ho', r.path
108
+ assert_equal URI.parse('/hey/ho?a=b&c=d'), r.uri
109
+ assert_equal 'https://foo.bar/hey/ho?a=b&c=d', r.full_uri
110
+
111
+ r.rewrite!('/hey', '/')
112
+ assert_equal '/ho', r.path
113
+ assert_equal URI.parse('/ho?a=b&c=d'), r.uri
114
+ assert_equal 'https://foo.bar/ho?a=b&c=d', r.full_uri
30
115
  end
31
116
  end
32
117
 
@@ -90,6 +175,53 @@ class ValidationTest < Minitest::Test
90
175
  assert_raises(VE) { @req.validate('foo', :bool) }
91
176
  assert_raises(VE) { @req.validate(nil, :bool) }
92
177
  end
178
+
179
+ def test_validate_http_method
180
+ @req = mock_req(':method' => 'GET', ':path' => '/foo')
181
+
182
+ assert_equal 'get', @req.validate_http_method('get', 'head')
183
+ assert_raises(Syntropy::Error) { @req.validate_http_method('post', 'put') }
184
+ assert_raises(Syntropy::Error) { @req.validate_http_method() }
185
+ end
186
+
187
+ def test_respond_by_http_method
188
+ @req = mock_req(':method' => 'GET', ':path' => '/foo')
189
+
190
+ @req.respond_by_http_method(
191
+ 'get' => ['GET foo', {}],
192
+ 'post' => ['POST foo', {}]
193
+ )
194
+ assert_equal 'GET foo', @req.response_body
195
+
196
+ assert_raises(Syntropy::Error) {
197
+ @req.respond_by_http_method(
198
+ 'post' => ['POST foo', {}]
199
+ )
200
+ }
201
+ end
202
+
203
+ def test_validate_content_type
204
+ @req = mock_req(':method' => 'POST', ':path' => '/foo')
205
+
206
+ assert_raises(Syntropy::InvalidRequestContentTypeError) {
207
+ @req.validate_content_type('application/json')
208
+ }
209
+
210
+ @req = mock_req(':method' => 'POST', ':path' => '/foo', 'content-type' => 'application/json')
211
+ assert_equal 'application/json', @req.validate_content_type(
212
+ 'application/json', 'text/plain'
213
+ )
214
+
215
+ @req = mock_req(':method' => 'POST', ':path' => '/foo', 'content-type' => 'text/html; charset=utf-8')
216
+ assert_equal 'text/html', @req.validate_content_type(
217
+ 'text/plain', 'text/html'
218
+ )
219
+
220
+ @req = mock_req(':method' => 'POST', ':path' => '/foo', 'content-type' => 'text/html ; charset=utf-8')
221
+ assert_equal 'text/html', @req.validate_content_type(
222
+ 'text/plain', 'text/html'
223
+ )
224
+ end
93
225
  end
94
226
 
95
227
  class FormDataTest < Minitest::Test
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+
5
+ class RedirectTest < Minitest::Test
6
+ def test_redirect
7
+ r = Syntropy::MockAdapter.mock
8
+ r.redirect('/foo')
9
+
10
+ assert_equal [
11
+ [:respond, r, nil, {":status"=>302, "Location"=>"/foo"}]
12
+ ], r.adapter.calls
13
+ end
14
+
15
+ def test_redirect_wirth_status
16
+ r = Syntropy::MockAdapter.mock
17
+ r.redirect('/bar', Syntropy::HTTP::MOVED_PERMANENTLY)
18
+
19
+ assert_equal [
20
+ [:respond, r, nil, {":status"=>301, "Location"=>"/bar"}]
21
+ ], r.adapter.calls
22
+ end
23
+ end
24
+
25
+ class StaticFileResponeTest < Minitest::Test
26
+ def setup
27
+ @path = File.join(__dir__, 'helper.rb')
28
+ @stat = File.stat(@path)
29
+
30
+ @etag = Syntropy::StaticFileCaching.file_stat_to_etag(@stat)
31
+ @last_modified = Syntropy::StaticFileCaching.file_stat_to_last_modified(@stat)
32
+ @content = IO.read(@path)
33
+ end
34
+
35
+ def test_serve_file_non_existent
36
+ r = Syntropy::MockAdapter.mock
37
+ r.serve_file('foo.rb', base_path: __dir__)
38
+ assert_equal [
39
+ [:respond, r, nil, { ':status' => Syntropy::HTTP::NOT_FOUND }]
40
+ ], r.adapter.calls
41
+ end
42
+ end
43
+
44
+ class UpgradeTest < Minitest::Test
45
+ def test_upgrade
46
+ r = Syntropy::MockAdapter.mock
47
+ r.upgrade('df')
48
+
49
+ assert_equal [
50
+ [
51
+ :respond,
52
+ r,
53
+ nil,
54
+ {
55
+ ':status' => 101,
56
+ 'Upgrade' => 'df',
57
+ 'Connection' => 'upgrade'
58
+ }
59
+ ],
60
+ [
61
+ :with_stream
62
+ ]
63
+ ], r.adapter.calls
64
+
65
+
66
+ r = Syntropy::MockAdapter.mock
67
+ r.upgrade('df', { 'foo' => 'bar' })
68
+
69
+ assert_equal [
70
+ [
71
+ :respond,
72
+ r,
73
+ nil,
74
+ {
75
+ ':status' => 101,
76
+ 'Upgrade' => 'df',
77
+ 'Connection' => 'upgrade',
78
+ 'foo' => 'bar'
79
+ }
80
+ ],
81
+ [
82
+ :with_stream
83
+ ]
84
+ ], r.adapter.calls
85
+ end
86
+
87
+ def test_websocket_upgrade
88
+ r = Syntropy::MockAdapter.mock(
89
+ 'connection' => 'upgrade',
90
+ 'upgrade' => 'websocket',
91
+ 'sec-websocket-version' => '23',
92
+ 'sec-websocket-key' => 'abcdefghij'
93
+ )
94
+
95
+ assert_equal 'websocket', r.upgrade_protocol
96
+
97
+ r.upgrade_to_websocket('foo' => 'baz')
98
+ accept = Digest::SHA1.base64digest('abcdefghij258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
99
+
100
+ assert_equal [
101
+ [:respond, r, nil, {
102
+ ':status' => 101,
103
+ 'Upgrade' => 'websocket',
104
+ 'Connection' => 'upgrade',
105
+ 'foo' => 'baz',
106
+ 'Sec-WebSocket-Accept' => accept
107
+ }],
108
+ [:with_stream],
109
+ [:websocket_connection, r]
110
+ ], r.adapter.calls
111
+ end
112
+ end
@@ -46,6 +46,9 @@ class RoutingTreeTest < Minitest::Test
46
46
  'old': {
47
47
  'index.html': '',
48
48
  'baz.html': ''
49
+ },
50
+ '.well-known': {
51
+ 'foo.rb': ''
49
52
  }
50
53
  }
51
54
  }
@@ -72,7 +75,9 @@ class RoutingTreeTest < Minitest::Test
72
75
  assert_nil root[:parent]
73
76
  assert_nil root[:param]
74
77
  assert_nil root[:target]
75
- assert_equal ['[]', 'about', 'api', 'assets', 'old', 'posts'], root[:children].keys.sort_by(&:to_s)
78
+ assert_equal [
79
+ '.well-known', '[]', 'about', 'api', 'assets', 'old', 'posts'
80
+ ], root[:children].keys.sort_by(&:to_s)
76
81
 
77
82
  entry = @rt.static_map['/docs']
78
83
  assert_equal File.join(@rt.root_dir, 'index.rb'), entry[:target][:fn]
@@ -132,18 +137,25 @@ class RoutingTreeTest < Minitest::Test
132
137
  assets = root[:children]['assets']
133
138
  refute_nil assets
134
139
  assert_nil assets[:target]
140
+
141
+ well_known = root[:children]['.well-known']
142
+ refute_nil well_known
143
+ assert_nil well_known[:target]
135
144
  end
136
145
 
137
146
  def test_static_map
138
147
  map = @rt.static_map
139
- assert_equal 7, map.size
148
+ assert_equal 8, map.size
140
149
 
141
150
  keys = map.keys.sort
142
151
  assert_equal [
143
- '/docs', '/docs/about', '/docs/assets/css/style.css',
152
+ '/docs', '/docs/.well-known/foo', '/docs/about', '/docs/assets/css/style.css',
144
153
  '/docs/assets/img/foo.jpg', '/docs/old', '/docs/old/baz', '/docs/posts'
145
154
  ], keys
146
155
 
156
+ o = map['/docs/.well-known/foo']
157
+ assert_equal File.join(@rt.root_dir, '.well-known/foo.rb'), o[:target][:fn]
158
+
147
159
  o = map['/docs/assets/css/style.css']
148
160
  assert_equal File.join(@rt.root_dir, 'assets/css/style.css'), o[:target][:fn]
149
161
 
data/test/test_server.rb CHANGED
@@ -26,7 +26,7 @@ class ServerTest < Minitest::Test
26
26
  @machine = UM.new
27
27
  @port = 10000 + rand(30000)
28
28
  @env = { bind: "127.0.0.1:#{@port}" }.merge(opts)
29
- @server = Syntropy::Server.new(@machine, @env) { @app&.call(it) }
29
+ @server = Syntropy::HTTP::Server.new(@machine, @env) { @app&.call(it) }
30
30
  @f_server = @machine.spin { run_server }
31
31
 
32
32
  # let server spin and listen to incoming connections
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syntropy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.29.0
4
+ version: 0.31.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
@@ -37,48 +37,34 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: 3.2.0
40
- - !ruby/object:Gem::Dependency
41
- name: qeweney
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: '0.24'
47
- type: :runtime
48
- prerelease: false
49
- version_requirements: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: '0.24'
54
40
  - !ruby/object:Gem::Dependency
55
41
  name: uringmachine
56
42
  requirement: !ruby/object:Gem::Requirement
57
43
  requirements:
58
44
  - - "~>"
59
45
  - !ruby/object:Gem::Version
60
- version: 1.0.0
46
+ version: 1.0.2
61
47
  type: :runtime
62
48
  prerelease: false
63
49
  version_requirements: !ruby/object:Gem::Requirement
64
50
  requirements:
65
51
  - - "~>"
66
52
  - !ruby/object:Gem::Version
67
- version: 1.0.0
53
+ version: 1.0.2
68
54
  - !ruby/object:Gem::Dependency
69
- name: listen
55
+ name: escape_utils
70
56
  requirement: !ruby/object:Gem::Requirement
71
57
  requirements:
72
- - - "~>"
58
+ - - '='
73
59
  - !ruby/object:Gem::Version
74
- version: 3.9.0
60
+ version: 1.3.0
75
61
  type: :runtime
76
62
  prerelease: false
77
63
  version_requirements: !ruby/object:Gem::Requirement
78
64
  requirements:
79
- - - "~>"
65
+ - - '='
80
66
  - !ruby/object:Gem::Version
81
- version: 3.9.0
67
+ version: 1.3.0
82
68
  - !ruby/object:Gem::Dependency
83
69
  name: json
84
70
  requirement: !ruby/object:Gem::Requirement
@@ -153,6 +139,9 @@ files:
153
139
  - Rakefile
154
140
  - TODO.md
155
141
  - bin/syntropy
142
+ - cmd/_banner.rb
143
+ - cmd/help.rb
144
+ - cmd/serve.rb
156
145
  - cmd/setup/template/site/.gitignore
157
146
  - cmd/setup/template/site/Dockerfile
158
147
  - cmd/setup/template/site/Gemfile
@@ -176,15 +165,32 @@ files:
176
165
  - cmd/setup/template/site/site/assets/css/style.css
177
166
  - cmd/setup/template/site/site/assets/img/syntropy.png
178
167
  - cmd/setup/template/site/site/index.rb
168
+ - cmd/test.rb
179
169
  - docker-compose.yml
180
- - examples/bad.rb
181
- - examples/card.rb
182
- - examples/counter.js
183
- - examples/counter.rb
184
- - examples/counter_api.rb
185
- - examples/favicon.ico
186
- - examples/index.md
187
- - examples/templates.rb
170
+ - examples/basic/bad.rb
171
+ - examples/basic/card.rb
172
+ - examples/basic/counter.js
173
+ - examples/basic/counter.rb
174
+ - examples/basic/counter_api.rb
175
+ - examples/basic/favicon.ico
176
+ - examples/basic/index.md
177
+ - examples/basic/templates.rb
178
+ - examples/mcp-oauth/.ruby-version
179
+ - examples/mcp-oauth/Gemfile
180
+ - examples/mcp-oauth/README.md
181
+ - examples/mcp-oauth/app/.well-known/oauth-authorization-server.rb
182
+ - examples/mcp-oauth/app/.well-known/oauth-protected-resource.rb
183
+ - examples/mcp-oauth/app/_lib/auth_store.rb
184
+ - examples/mcp-oauth/app/index.md
185
+ - examples/mcp-oauth/app/mcp.rb
186
+ - examples/mcp-oauth/app/oauth/authorize.rb
187
+ - examples/mcp-oauth/app/oauth/consent.rb
188
+ - examples/mcp-oauth/app/oauth/register.rb
189
+ - examples/mcp-oauth/app/oauth/token.rb
190
+ - examples/mcp-oauth/app/signin.rb
191
+ - examples/mcp-oauth/test/helper.rb
192
+ - examples/mcp-oauth/test/test_app.rb
193
+ - examples/mcp-oauth/test/test_oauth.rb
188
194
  - lib/syntropy.rb
189
195
  - lib/syntropy/app.rb
190
196
  - lib/syntropy/applets/builtin/auto_refresh/watch.js
@@ -196,22 +202,34 @@ files:
196
202
  - lib/syntropy/applets/builtin/json_api.js
197
203
  - lib/syntropy/applets/builtin/ping.rb
198
204
  - lib/syntropy/applets/builtin/req.rb
199
- - lib/syntropy/connection.rb
200
205
  - lib/syntropy/connection_pool.rb
201
206
  - lib/syntropy/dev_mode.rb
202
207
  - lib/syntropy/errors.rb
208
+ - lib/syntropy/http.rb
209
+ - lib/syntropy/http/client.rb
210
+ - lib/syntropy/http/client_connection.rb
211
+ - lib/syntropy/http/io_extensions.rb
212
+ - lib/syntropy/http/server.rb
213
+ - lib/syntropy/http/server_connection.rb
214
+ - lib/syntropy/http/status.rb
203
215
  - lib/syntropy/json_api.rb
204
216
  - lib/syntropy/logger.rb
205
217
  - lib/syntropy/markdown.rb
218
+ - lib/syntropy/mime_types.rb
206
219
  - lib/syntropy/module.rb
207
220
  - lib/syntropy/papercraft_extensions.rb
208
- - lib/syntropy/request_extensions.rb
221
+ - lib/syntropy/request.rb
222
+ - lib/syntropy/request/mock_adapter.rb
223
+ - lib/syntropy/request/request_info.rb
224
+ - lib/syntropy/request/response.rb
225
+ - lib/syntropy/request/validation.rb
209
226
  - lib/syntropy/routing_tree.rb
210
- - lib/syntropy/server.rb
211
227
  - lib/syntropy/side_run.rb
228
+ - lib/syntropy/test.rb
212
229
  - lib/syntropy/utils.rb
213
230
  - lib/syntropy/version.rb
214
231
  - syntropy.gemspec
232
+ - test/app/.well-known/foo.rb
215
233
  - test/app/_hook.rb
216
234
  - test/app/_layout/default.rb
217
235
  - test/app/_lib/callable.rb
@@ -248,12 +266,16 @@ files:
248
266
  - test/run.rb
249
267
  - test/test_app.rb
250
268
  - test/test_caching.rb
251
- - test/test_connection.rb
252
269
  - test/test_connection_pool.rb
253
270
  - test/test_errors.rb
271
+ - test/test_http_client.rb
272
+ - test/test_http_client_connection.rb
273
+ - test/test_http_server_connection.rb
254
274
  - test/test_json_api.rb
275
+ - test/test_mock_adapter.rb
255
276
  - test/test_module.rb
256
- - test/test_request_extensions.rb
277
+ - test/test_request.rb
278
+ - test/test_response.rb
257
279
  - test/test_routing_tree.rb
258
280
  - test/test_server.rb
259
281
  - test/test_side_run.rb