simple-httpd 0.3.0 → 0.3.1

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -0
  3. data/Gemfile +3 -1
  4. data/VERSION +1 -1
  5. data/bin/simple-httpd +1 -3
  6. data/examples/ex1.services/ex1_service_module.rb +8 -0
  7. data/examples/ex1/root.rb +4 -0
  8. data/examples/ex1/spec.rb +7 -0
  9. data/examples/ex2/info.rb +5 -3
  10. data/examples/ex3/example_service.rb +3 -2
  11. data/lib/simple/httpd.rb +37 -28
  12. data/lib/simple/httpd/base_controller.rb +6 -0
  13. data/lib/simple/httpd/base_controller/build_url.rb +1 -1
  14. data/lib/simple/httpd/base_controller/debug.rb +2 -0
  15. data/lib/simple/httpd/base_controller/error_handling.rb +21 -38
  16. data/lib/simple/httpd/base_controller/json.rb +2 -31
  17. data/lib/simple/httpd/base_controller/request.rb +23 -0
  18. data/lib/simple/httpd/base_controller/result.rb +19 -0
  19. data/lib/simple/httpd/cli.rb +71 -30
  20. data/lib/simple/httpd/helpers.rb +35 -3
  21. data/lib/simple/httpd/mount.rb +66 -0
  22. data/lib/simple/httpd/rack/dynamic_mount.rb +52 -32
  23. data/lib/simple/httpd/rack/static_mount.rb +20 -14
  24. data/lib/simple/httpd/route.rb +79 -0
  25. data/lib/simple/httpd/server.rb +28 -16
  26. data/lib/simple/httpd/service_adapter.rb +108 -0
  27. data/simple-httpd.gemspec +2 -1
  28. data/spec/simple/httpd/base_controller/httpd_cors_spec.rb +8 -3
  29. data/spec/simple/httpd/base_controller/httpd_url_building_spec.rb +17 -0
  30. data/spec/simple/httpd/helpers_spec.rb +25 -8
  31. data/spec/simple/httpd/loading_helpers_spec.rb +15 -0
  32. data/spec/simple/httpd/rspec_httpd_spec.rb +25 -9
  33. data/spec/simple/httpd/services/service_explicit_spec.rb +0 -5
  34. data/spec/simple/httpd/services/sideloading_spec.rb +9 -0
  35. data/spec/spec_helper.rb +2 -3
  36. metadata +31 -12
  37. data/examples/services/example_service.rb +0 -25
  38. data/lib/simple/httpd/mount_spec.rb +0 -106
  39. data/lib/simple/httpd/service.rb +0 -70
  40. data/lib/simple/service.rb +0 -69
  41. data/lib/simple/service/action.rb +0 -78
  42. data/lib/simple/service/context.rb +0 -46
  43. data/spec/simple/httpd/services/service_spec.rb +0 -34
@@ -1,3 +1,5 @@
1
+ # rubocop:disable Metrics/PerceivedComplexity, Metrics/AbcSize
2
+
1
3
  class Simple::Httpd
2
4
  module Server
3
5
  extend self
@@ -8,16 +10,13 @@ class Simple::Httpd
8
10
  def <<(msg); end
9
11
  end
10
12
 
11
- def listen!(app, environment: "development", host: nil, port:, logger: nil)
13
+ def listen!(app, environment: "development", host: nil, port:)
12
14
  expect! app != nil
13
15
 
14
16
  host ||= "127.0.0.1"
15
17
  URI("http://#{host}:#{port}") # validate host and port
16
18
 
17
- logger ||= ::Simple::Httpd.logger
18
-
19
- prepare_logger!(logger)
20
- logger.info "Starting httpd server on http://#{host}:#{port}/"
19
+ ::Simple::Httpd.logger.info "Starting httpd server on http://#{host}:#{port}/"
21
20
 
22
21
  app = ::Rack::Lint.new(app) if environment != "production"
23
22
 
@@ -30,32 +29,45 @@ class Simple::Httpd
30
29
  Host: host,
31
30
  Port: port,
32
31
  environment: environment,
33
- Logger: logger,
32
+ Logger: build_logger,
34
33
  AccessLog: [[NullLogger, ""]]
35
34
  end
36
35
 
37
36
  private
38
37
 
39
- # When Webrick is being shut down via SIGTERM - which we do at least during
40
- # rspec-httpd triggered runs - it sends a fatal message to the logger. We catch
41
- # it - to "downgrade" it to INFO - but we still abort.
42
- def prepare_logger!(logger)
38
+ def build_logger
39
+ # We create a fresh STDERR logger. The log level is taken from Simple::Httpd -
40
+ # but is at maximum :info, since we don't want to log internals of Webrick & co.
41
+ #
42
+ # (Note that our own services would probably use ::Simple::Httpd.logger, which
43
+ # sticks at the current level.)
44
+ if ::Simple::Httpd.custom_logger?
45
+ logger = ::Simple::Httpd.logger
46
+ else
47
+ log_level = ::Simple::Httpd.logger.debug? ? :info : ::Simple::Httpd.logger.level
48
+ logger = ::Logger.new STDERR, level: log_level
49
+ end
50
+
51
+ # When Webrick is being shut down via SIGTERM - which we do at least during
52
+ # rspec-httpd triggered runs - it sends a fatal message to the logger. We catch
53
+ # it - to "downgrade" it to INFO - but we still abort.
43
54
  def logger.fatal(msg, &block)
44
55
  if msg.is_a?(SignalException) && msg.signo == ::Signal.list["TERM"]
45
- if %w(test development).include?(::Simple::Httpd.env)
46
- info "Received SIGTERM: hard killing server (due to running in #{::Simple::Httpd.env.inspect} environment)"
47
- Simple::Httpd::Server.exit!
56
+ env = ::Simple::Httpd.env
57
+ if %w(test development).include?(env)
58
+ ::Simple::Httpd.logger.info "Received SIGTERM: hard killing server (due to running in #{env.inspect} environment)"
59
+ ::Simple::Httpd::Server.send :exit!
48
60
  else
49
- info "Received SIGTERM: shutting down server..."
61
+ ::Simple::Httpd.logger.info "Received SIGTERM: shutting down server..."
50
62
  exit 1
51
63
  end
52
64
  end
53
65
 
54
66
  super
55
67
  end
56
- end
57
68
 
58
- public
69
+ logger
70
+ end
59
71
 
60
72
  def exit!(exit_status = 1)
61
73
  # Run SimpleCov if exists, and if this is the PID that started SimpleCov in the first place.
@@ -0,0 +1,108 @@
1
+ require "simple-service"
2
+
3
+ module Simple::Httpd::ServiceAdapter
4
+ def mount_service(service)
5
+ @service = service
6
+
7
+ instance_eval do
8
+ def dispatch!
9
+ ::Simple::Service.with_context(context)
10
+ super
11
+ ensure
12
+ ::Simple::Service.context = nil
13
+ end
14
+
15
+ yield(service)
16
+ end
17
+ ensure
18
+ @service = nil
19
+ end
20
+
21
+ def get(path, opts = {}, &block)
22
+ install_route("GET", path, opts, &block)
23
+ end
24
+
25
+ def post(path, opts = {}, &block)
26
+ install_route("POST", path, opts, &block)
27
+ end
28
+
29
+ def put(path, opts = {}, &block)
30
+ install_route("PUT", path, opts, &block)
31
+ end
32
+
33
+ def delete(path, opts = {}, &block)
34
+ install_route("DELETE", path, opts, &block)
35
+ end
36
+
37
+ def head(path, opts = {}, &block)
38
+ install_route("HEAD", path, opts, &block)
39
+ end
40
+
41
+ private
42
+
43
+ def service_route?(_verb, path, opts, &block)
44
+ return false unless @service
45
+ return false if block
46
+ return false unless opts.empty?
47
+ return false unless path.is_a?(Hash) && path.size == 1
48
+
49
+ true
50
+ end
51
+
52
+ def install_route(verb, path, opts, &block)
53
+ if service_route?(verb, path, opts, &block)
54
+ path, action_name = *path.first
55
+ handle_service_route(verb, path, action_name)
56
+ else
57
+ handle_non_service_route(verb, path, opts, &block)
58
+ end
59
+ end
60
+
61
+ def handle_service_route(verb, path, action_name)
62
+ # Fetch action's source_location. This also verifies that the action
63
+ # is defined in the first place.
64
+ action = ::Simple::Service.action(@service, action_name)
65
+
66
+ describe_route!(verb: verb, path: path, source_location: action.source_location)
67
+
68
+ # get service reference into binding, to make it available for the route
69
+ # definition's callback block.
70
+ service = @service
71
+
72
+ # define sinatra route.
73
+ route(verb, path) do
74
+ ::Simple::Service.with_context(context) do
75
+ # [TODO] - symbolizing keys opens up this for DDOS effects.
76
+ # THIS MUST BE FIXED IN simple-service.
77
+ flags = self.params.inject({}) { |hsh, (k,v)| hsh.update k.to_sym => v }
78
+ args = self.parsed_body.inject({}) { |hsh, (k,v)| hsh.update k.to_sym => v }
79
+
80
+ result = ::Simple::Service.invoke2(service, action_name, args: args, flags: flags)
81
+ encode_result(result)
82
+ end
83
+ end
84
+ end
85
+
86
+ def handle_non_service_route(verb, path, opts, &block)
87
+ describe_route!(verb: verb, path: path, source_location: block.source_location) if block
88
+
89
+ route(verb, path, opts) do
90
+ result = instance_eval(&block)
91
+ unless headers["Content-Type"]
92
+ result = encode_result(result)
93
+ end
94
+ result
95
+ end
96
+ end
97
+
98
+ module Helpers
99
+ def context
100
+ # We return nil here. nil *is* a valid value for Simple::Service.with_context.
101
+ # Important is that with_context is being called.
102
+ nil
103
+ end
104
+ end
105
+ end
106
+
107
+ ::Simple::Httpd::BaseController.extend(::Simple::Httpd::ServiceAdapter)
108
+ ::Simple::Httpd::BaseController.helpers(::Simple::Httpd::ServiceAdapter::Helpers)
data/simple-httpd.gemspec CHANGED
@@ -26,6 +26,7 @@ Gem::Specification.new do |gem|
26
26
  gem.add_dependency "sinatra", "~> 2"
27
27
  # gem.add_dependency "sinatra-reloader", "~> 1"
28
28
  gem.add_dependency "expectation", "~> 1"
29
- gem.add_dependency "simple-cli", "~> 0.3.0"
29
+ gem.add_dependency "simple-cli", "~> 0.3.3"
30
+ gem.add_dependency "simple-service", "~> 0.1.2"
30
31
  end
31
32
  #require "expectation"
@@ -7,9 +7,14 @@ describe Simple::Httpd do
7
7
  expect(http.response.headers.keys).to include("access-control-allow-origin")
8
8
  end
9
9
 
10
- it "returns CORS headers" do
11
- http.get "/README.txt"
12
- expect(http.response.headers.keys).not_to include("access-control-allow-origin")
10
+ it "sends proper headers in all request methods" do
11
+ verbs = [ :get, :post, :put, :delete, :options, :head ]
12
+ verbs.each do |verb|
13
+ http.send verb, "/info/inspect?qux"
14
+
15
+ expect_response 200
16
+ expect(http.response.headers.keys).to include("access-control-allow-origin")
17
+ end
13
18
  end
14
19
  end
15
20
  end
@@ -0,0 +1,17 @@
1
+ require "spec_helper"
2
+
3
+ describe Simple::Httpd do
4
+ describe "full_url" do
5
+ it "builds a full_url" do
6
+ http.get "/spec/full_url"
7
+ expect_response("http://127.0.0.1:12345/foo?search=s&page=1")
8
+ end
9
+ end
10
+
11
+ describe "url" do
12
+ it "returns X-Processing headers on dynamic responses" do
13
+ http.get "/spec/url"
14
+ expect_response("foo?search=s&page=1")
15
+ end
16
+ end
17
+ end
@@ -1,15 +1,32 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Simple::Httpd do
4
- describe "helpers" do
5
- it "loads helpers from the same directory tree" do
6
- http.get "/helpers/ex2"
7
- expect_response "ex2_helper"
3
+ describe "Simple::Httpd::Helpers" do
4
+ H = Simple::Httpd::Helpers
5
+
6
+ describe ".filtered_stacktrace" do
7
+ def some_stacktrace(depth = 1)
8
+ if depth == 0
9
+ caller
10
+ else
11
+ some_stacktrace(depth-1)
12
+ end
8
13
  end
9
14
 
10
- it "does not load helpers from other directory tree even on the same URL tree" do
11
- http.get "/helpers/ex1"
12
- expect_response status: 404
15
+ def filtered_stacktrace
16
+ H.filtered_stacktrace(some_stacktrace)
17
+ end
18
+
19
+ it "removes .rvm lines" do
20
+ actual = filtered_stacktrace
21
+
22
+ expect(actual.grep(/lines removed/).count).to eq(1)
23
+ expect(actual.grep(/helpers_spec/).count).to be > 1
24
+ expect(actual.grep(/some_stacktrace/).count).to eq(1)
25
+ end
26
+
27
+ it "shortens paths" do
28
+ source_path = filtered_stacktrace.grep(/helpers_spec/).first
29
+ expect(source_path).to start_with("./")
13
30
  end
14
31
  end
15
32
  end
@@ -0,0 +1,15 @@
1
+ require "spec_helper"
2
+
3
+ describe Simple::Httpd do
4
+ describe "helpers" do
5
+ it "loads helpers from the same directory tree" do
6
+ http.get "/helpers/ex2"
7
+ expect_response "ex2_helper"
8
+ end
9
+
10
+ it "does not load helpers from other directory tree even on the same URL tree" do
11
+ http.get "/helpers/ex1"
12
+ expect_response status: 404
13
+ end
14
+ end
15
+ end
@@ -1,17 +1,33 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe "RSpec::Httpd features" do
4
- it "sends proper headers" do
5
- http.get "/info/inspect?qux"
4
+ VERBS_WO_BODY = [ :options, :head ]
6
5
 
7
- result_lines = http.content.split("\n")
6
+ VERBS = [ :get, :post, :put, :delete ]
8
7
 
9
- expect(result_lines).to include("QUERY_STRING=qux")
10
- expect(result_lines).to include("REQUEST_METHOD=GET")
11
- expect(result_lines).to include("REQUEST_PATH=/info/inspect")
12
- expect(result_lines).to include("SERVER_NAME=127.0.0.1")
13
- expect(result_lines).to include("SERVER_PORT=12345")
8
+ VERBS.each do |verb|
9
+ it "sends proper headers in #{verb} request" do
10
+ http.send verb, "/info/inspect?qux"
14
11
 
15
- expect(http.response.headers["content-type"]).to match(/text\/plain/)
12
+ result_lines = http.content.split("\n")
13
+
14
+ expect(result_lines).to include("QUERY_STRING=qux")
15
+ expect(result_lines).to include("REQUEST_METHOD=#{verb.upcase}")
16
+ expect(result_lines).to include("REQUEST_PATH=/info/inspect")
17
+ expect(result_lines).to include("SERVER_NAME=127.0.0.1")
18
+ expect(result_lines).to include("SERVER_PORT=12345")
19
+
20
+ expect(http.response.headers["content-type"]).to match(/text\/plain/)
21
+ end
22
+ end
23
+
24
+ VERBS_WO_BODY = [ :options, :head ]
25
+
26
+ VERBS_WO_BODY.each do |verb|
27
+ it "supports #{verb} methods" do
28
+ http.send verb, "/info/inspect?qux"
29
+
30
+ expect_response 200
31
+ end
16
32
  end
17
33
  end
@@ -22,11 +22,6 @@ describe "explicit mounting of service" do
22
22
  expect_response 422
23
23
  end
24
24
 
25
- it "ignores missing parameters arguments" do
26
- http.post "/example_service/echo/1", { one: "foo", two: "bar" }
27
- expect_response "one: [foo]/two: [bar]/a: [1]/b: []"
28
- end
29
-
30
25
  it "properly extracts arguments and parameters" do
31
26
  http.put "/example_service/echo_context"
32
27
  expect_response /Simple::Service::Context/
@@ -0,0 +1,9 @@
1
+ require "spec_helper"
2
+
3
+ describe "sideloading" do
4
+ # mounting not at root level
5
+ it "sideloads code" do
6
+ http.get "/sideloaded_service"
7
+ expect_response("hello_world")
8
+ end
9
+ end
data/spec/spec_helper.rb CHANGED
@@ -12,15 +12,14 @@ end
12
12
  # You can comment parts of the command below by prepending the line with a '#'
13
13
  HTTPD_COMMAND = <<~CMD
14
14
  PORT=12345
15
- bin/simple-httpd
15
+ bin/simple-httpd start
16
16
  --environment=test
17
17
  examples/ex1
18
18
  examples/ex2
19
19
  examples/ex3
20
20
  examples/v2:api/v2
21
21
  --services=examples/services
22
- Example::Service:service/example
23
- 2> log/test.log
22
+ # 2> log/test.log
24
23
  CMD
25
24
 
26
25
  RSpec::Httpd.configure do |config|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple-httpd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-16 00:00:00.000000000 Z
11
+ date: 2019-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: neatjson
@@ -58,14 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.3.0
61
+ version: 0.3.3
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.3.0
68
+ version: 0.3.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: simple-service
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.1.2
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.1.2
69
83
  description: Super-simple HTTPD server - sinatra w/gimmiks
70
84
  email: eno@radiospiel.org
71
85
  executables: []
@@ -87,15 +101,16 @@ files:
87
101
  - bin/rubocop
88
102
  - bin/simple-httpd
89
103
  - examples/README.md
104
+ - examples/ex1.services/ex1_service_module.rb
90
105
  - examples/ex1/ex1_helpers.rb
91
106
  - examples/ex1/root.rb
107
+ - examples/ex1/spec.rb
92
108
  - examples/ex2/README.txt
93
109
  - examples/ex2/ex2_helpers.rb
94
110
  - examples/ex2/helpers.rb
95
111
  - examples/ex2/info.rb
96
112
  - examples/ex2/root.rb
97
113
  - examples/ex3/example_service.rb
98
- - examples/services/example_service.rb
99
114
  - examples/services/explicit_example_service.rb
100
115
  - examples/v2/api.js
101
116
  - examples/v2/jobs.rb
@@ -111,20 +126,20 @@ files:
111
126
  - lib/simple/httpd/base_controller/debug.rb
112
127
  - lib/simple/httpd/base_controller/error_handling.rb
113
128
  - lib/simple/httpd/base_controller/json.rb
129
+ - lib/simple/httpd/base_controller/request.rb
130
+ - lib/simple/httpd/base_controller/result.rb
114
131
  - lib/simple/httpd/base_controller/x_processing.rb
115
132
  - lib/simple/httpd/cli.rb
116
133
  - lib/simple/httpd/helpers.rb
117
- - lib/simple/httpd/mount_spec.rb
134
+ - lib/simple/httpd/mount.rb
118
135
  - lib/simple/httpd/rack.rb
119
136
  - lib/simple/httpd/rack/dynamic_mount.rb
120
137
  - lib/simple/httpd/rack/merger.rb
121
138
  - lib/simple/httpd/rack/static_mount.rb
139
+ - lib/simple/httpd/route.rb
122
140
  - lib/simple/httpd/server.rb
123
- - lib/simple/httpd/service.rb
141
+ - lib/simple/httpd/service_adapter.rb
124
142
  - lib/simple/httpd/version.rb
125
- - lib/simple/service.rb
126
- - lib/simple/service/action.rb
127
- - lib/simple/service/context.rb
128
143
  - log/.gitkeep
129
144
  - scripts/release
130
145
  - scripts/release.rb
@@ -133,13 +148,15 @@ files:
133
148
  - simple-httpd.gemspec
134
149
  - spec/simple/httpd/base_controller/httpd_cors_spec.rb
135
150
  - spec/simple/httpd/base_controller/httpd_debug_spec.rb
151
+ - spec/simple/httpd/base_controller/httpd_url_building_spec.rb
136
152
  - spec/simple/httpd/base_controller/httpd_x_processing_copy.rb
137
153
  - spec/simple/httpd/base_spec.rb
138
154
  - spec/simple/httpd/dynamic_mounting_spec.rb
139
155
  - spec/simple/httpd/helpers_spec.rb
156
+ - spec/simple/httpd/loading_helpers_spec.rb
140
157
  - spec/simple/httpd/rspec_httpd_spec.rb
141
158
  - spec/simple/httpd/services/service_explicit_spec.rb
142
- - spec/simple/httpd/services/service_spec.rb
159
+ - spec/simple/httpd/services/sideloading_spec.rb
143
160
  - spec/simple/httpd/static_mounting_spec.rb
144
161
  - spec/spec_helper.rb
145
162
  - spec/support/004_simplecov.rb
@@ -168,13 +185,15 @@ summary: Super-simple HTTPD server
168
185
  test_files:
169
186
  - spec/simple/httpd/base_controller/httpd_cors_spec.rb
170
187
  - spec/simple/httpd/base_controller/httpd_debug_spec.rb
188
+ - spec/simple/httpd/base_controller/httpd_url_building_spec.rb
171
189
  - spec/simple/httpd/base_controller/httpd_x_processing_copy.rb
172
190
  - spec/simple/httpd/base_spec.rb
173
191
  - spec/simple/httpd/dynamic_mounting_spec.rb
174
192
  - spec/simple/httpd/helpers_spec.rb
193
+ - spec/simple/httpd/loading_helpers_spec.rb
175
194
  - spec/simple/httpd/rspec_httpd_spec.rb
176
195
  - spec/simple/httpd/services/service_explicit_spec.rb
177
- - spec/simple/httpd/services/service_spec.rb
196
+ - spec/simple/httpd/services/sideloading_spec.rb
178
197
  - spec/simple/httpd/static_mounting_spec.rb
179
198
  - spec/spec_helper.rb
180
199
  - spec/support/004_simplecov.rb