simple-httpd 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +7 -0
- data/Gemfile +3 -1
- data/VERSION +1 -1
- data/bin/simple-httpd +1 -3
- data/examples/ex1.services/ex1_service_module.rb +8 -0
- data/examples/ex1/root.rb +4 -0
- data/examples/ex1/spec.rb +7 -0
- data/examples/ex2/info.rb +5 -3
- data/examples/ex3/example_service.rb +3 -2
- data/lib/simple/httpd.rb +37 -28
- data/lib/simple/httpd/base_controller.rb +6 -0
- data/lib/simple/httpd/base_controller/build_url.rb +1 -1
- data/lib/simple/httpd/base_controller/debug.rb +2 -0
- data/lib/simple/httpd/base_controller/error_handling.rb +21 -38
- data/lib/simple/httpd/base_controller/json.rb +2 -31
- data/lib/simple/httpd/base_controller/request.rb +23 -0
- data/lib/simple/httpd/base_controller/result.rb +19 -0
- data/lib/simple/httpd/cli.rb +71 -30
- data/lib/simple/httpd/helpers.rb +35 -3
- data/lib/simple/httpd/mount.rb +66 -0
- data/lib/simple/httpd/rack/dynamic_mount.rb +52 -32
- data/lib/simple/httpd/rack/static_mount.rb +20 -14
- data/lib/simple/httpd/route.rb +79 -0
- data/lib/simple/httpd/server.rb +28 -16
- data/lib/simple/httpd/service_adapter.rb +108 -0
- data/simple-httpd.gemspec +2 -1
- data/spec/simple/httpd/base_controller/httpd_cors_spec.rb +8 -3
- data/spec/simple/httpd/base_controller/httpd_url_building_spec.rb +17 -0
- data/spec/simple/httpd/helpers_spec.rb +25 -8
- data/spec/simple/httpd/loading_helpers_spec.rb +15 -0
- data/spec/simple/httpd/rspec_httpd_spec.rb +25 -9
- data/spec/simple/httpd/services/service_explicit_spec.rb +0 -5
- data/spec/simple/httpd/services/sideloading_spec.rb +9 -0
- data/spec/spec_helper.rb +2 -3
- metadata +31 -12
- data/examples/services/example_service.rb +0 -25
- data/lib/simple/httpd/mount_spec.rb +0 -106
- data/lib/simple/httpd/service.rb +0 -70
- data/lib/simple/service.rb +0 -69
- data/lib/simple/service/action.rb +0 -78
- data/lib/simple/service/context.rb +0 -46
- data/spec/simple/httpd/services/service_spec.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a7ef636de1fafcba61a0e8d7ed71a235d9c4700633f8ef8a899028415ffa1c7
|
4
|
+
data.tar.gz: 2018dc0e1bd99ec1bdc40524bfe2701be509e252cb6655b21e629e996da22614
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd3fc097a2342e19b79c087fec69c92db23085c2352d323c3b284e60eaa764543048f731063e0d3c31ad3e136dc1bb2518456c00519f9231c0f3cde57a96f0d2
|
7
|
+
data.tar.gz: aff819af94b2b12d8e02c1c966dc9eeb9eb6d3b4a805778d609600d2dc9ff33dccb435983ecf4e1221e5346b899ccd7b358d625756fe26b912bf662b94770226
|
data/.rubocop.yml
CHANGED
@@ -8,6 +8,7 @@ AllCops:
|
|
8
8
|
- '*.gemspec'
|
9
9
|
- 'Gemfile'
|
10
10
|
- 'Rakefile'
|
11
|
+
- 'scripts/*.rb'
|
11
12
|
|
12
13
|
Metrics/LineLength:
|
13
14
|
Max: 140
|
@@ -87,3 +88,9 @@ Metrics/ParameterLists:
|
|
87
88
|
|
88
89
|
Style/StringLiteralsInInterpolation:
|
89
90
|
Enabled: false
|
91
|
+
|
92
|
+
Style/DoubleNegation:
|
93
|
+
Enabled: false
|
94
|
+
|
95
|
+
Style/ParallelAssignment:
|
96
|
+
Enabled: false
|
data/Gemfile
CHANGED
@@ -6,12 +6,14 @@ gemspec
|
|
6
6
|
# --- Local overrides for runtime dependencies ------------------------------
|
7
7
|
|
8
8
|
# gem "simple-cli", path: "../simple-cli"
|
9
|
+
# gem "simple-service", path: "../simple-service"
|
9
10
|
|
10
11
|
# --- Development and test dependencies ------------------------------
|
11
12
|
|
12
13
|
group :development, :test do
|
13
|
-
gem "rspec-httpd", "~> 0.3.
|
14
|
+
gem "rspec-httpd", "~> 0.3.2"
|
14
15
|
# gem "rspec-httpd", path: "../rspec-httpd"
|
16
|
+
# # gem "simple-http", path: "../simple-http"
|
15
17
|
|
16
18
|
gem 'rake', '~> 11'
|
17
19
|
gem 'rspec', '~> 3.7'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.1
|
data/bin/simple-httpd
CHANGED
data/examples/ex1/root.rb
CHANGED
data/examples/ex2/info.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
get
|
2
|
-
|
3
|
-
|
1
|
+
[:get, :post, :put, :delete, :head].each do |verb|
|
2
|
+
send verb, "/inspect" do
|
3
|
+
content_type :text
|
4
|
+
request.env.map { |key, value| "#{key}=#{value}\n" }.grep(/^[A-Z]/).sort.join
|
5
|
+
end
|
4
6
|
end
|
@@ -7,7 +7,8 @@ mount_service ExplicitService do |service|
|
|
7
7
|
post "/echo/:a" => :explicit_echo
|
8
8
|
|
9
9
|
put "/echo_context" do
|
10
|
-
|
11
|
-
|
10
|
+
::Simple::Service.with_context(context) do
|
11
|
+
::Simple::Service.invoke(service, :echo_context)
|
12
|
+
end
|
12
13
|
end
|
13
14
|
end
|
data/lib/simple/httpd.rb
CHANGED
@@ -11,20 +11,29 @@ require "simple/service"
|
|
11
11
|
require "simple/httpd/helpers"
|
12
12
|
require "simple/httpd/base_controller"
|
13
13
|
require "simple/httpd/version"
|
14
|
-
require "simple/httpd/
|
14
|
+
require "simple/httpd/mount"
|
15
15
|
require "simple/httpd/server"
|
16
16
|
|
17
|
-
require "simple/httpd/
|
17
|
+
require "simple/httpd/service_adapter"
|
18
18
|
|
19
19
|
class Simple::Httpd
|
20
20
|
SELF = self
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
# returns a logger for Simple::Httpd.
|
23
|
+
#
|
24
|
+
# Initially we default to <tt>::Simple::CLI.logger</tt>. This gives colored
|
25
|
+
# logging during loading and mounting. Note that Simple::Httpd::Server builds
|
26
|
+
# its own logger instance to to pass that along to the web server.
|
27
|
+
def self.logger
|
28
|
+
@logger ||= ::Simple::CLI.logger
|
24
29
|
end
|
25
30
|
|
26
|
-
def self.
|
27
|
-
@logger
|
31
|
+
def self.custom_logger?
|
32
|
+
@logger && @logger != ::Simple::CLI.logger
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.logger=(logger)
|
36
|
+
@logger = logger
|
28
37
|
end
|
29
38
|
|
30
39
|
# Converts the passed in args into a Simple::Httpd application.
|
@@ -34,43 +43,49 @@ class Simple::Httpd
|
|
34
43
|
# respond to call/3) it redirects to <tt>Server.listen!</tt> right
|
35
44
|
# away - this way this method can be used as a helper method
|
36
45
|
# to easily start a Rack server.
|
37
|
-
def self.listen!(*
|
46
|
+
def self.listen!(*mounts, environment: "development", host: nil, port:, &block)
|
38
47
|
# If there is no argument but a block use the block as a rack server
|
39
48
|
if block
|
40
|
-
raise ArgumentError, "Can't deal w/block *and*
|
49
|
+
raise ArgumentError, "Can't deal w/block *and* mounts" unless mounts.empty?
|
41
50
|
|
42
51
|
app = block
|
43
|
-
elsif
|
52
|
+
elsif mounts.length == 1 && mounts.first.respond_to?(:call)
|
44
53
|
# there is one argument, and that looks like a Rack app: return that.
|
45
|
-
app =
|
54
|
+
app = mounts.first
|
46
55
|
else
|
47
56
|
# Build a Httpd app, and listen
|
48
|
-
app = build(*
|
57
|
+
app = build(*mounts)
|
49
58
|
app.rack
|
50
59
|
end
|
51
60
|
|
52
|
-
Server.listen!(app, environment: environment, host: host, port: port
|
61
|
+
Server.listen!(app, environment: environment, host: host, port: port)
|
53
62
|
end
|
54
63
|
|
55
64
|
# Converts the passed in arguments into a Simple::Httpd application.
|
56
65
|
#
|
57
66
|
# For a description of mounts see <tt>#add</tt>
|
58
|
-
def self.build(*
|
59
|
-
new(*
|
67
|
+
def self.build(*mounts)
|
68
|
+
new(*mounts)
|
60
69
|
end
|
61
70
|
|
62
71
|
private
|
63
72
|
|
64
73
|
# Builds a Simple::Httpd application.
|
65
|
-
def initialize(*
|
66
|
-
@
|
67
|
-
|
68
|
-
mount(
|
74
|
+
def initialize(*mounts)
|
75
|
+
@mounts = []
|
76
|
+
mounts.map do |mount|
|
77
|
+
mount(mount, at: nil)
|
69
78
|
end
|
70
79
|
end
|
71
80
|
|
72
81
|
public
|
73
82
|
|
83
|
+
def route_descriptions
|
84
|
+
@mounts.inject([]) do |ary, mount|
|
85
|
+
ary.concat mount.route_descriptions
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
74
89
|
# Adds one or more mount_points
|
75
90
|
#
|
76
91
|
# Each entry in mounts can be either:
|
@@ -79,10 +94,10 @@ class Simple::Httpd
|
|
79
94
|
# - a string denoting a mount_point, e.g. "path/to/root:/")
|
80
95
|
# - a string denoting a "/" mount_point (e.g. "path", which is shorthand for "path:/")
|
81
96
|
#
|
82
|
-
def mount(
|
97
|
+
def mount(mount, at: nil)
|
83
98
|
raise ArgumentError, "Cannot mount onto an already built app" if built?
|
84
99
|
|
85
|
-
@
|
100
|
+
@mounts << Mount.build(mount, at: at)
|
86
101
|
end
|
87
102
|
|
88
103
|
extend Forwardable
|
@@ -97,8 +112,8 @@ class Simple::Httpd
|
|
97
112
|
def build_rack
|
98
113
|
uri_map = {}
|
99
114
|
|
100
|
-
@
|
101
|
-
apps =
|
115
|
+
@mounts.group_by(&:mount_point).map do |mount_point, mounts|
|
116
|
+
apps = mounts.map(&:build_rack_apps).flatten
|
102
117
|
uri_map[mount_point] = Rack.merge(apps)
|
103
118
|
end
|
104
119
|
|
@@ -108,10 +123,4 @@ class Simple::Httpd
|
|
108
123
|
def built?
|
109
124
|
@rack != nil
|
110
125
|
end
|
111
|
-
|
112
|
-
public
|
113
|
-
|
114
|
-
def listen!(environment:, port:, logger:)
|
115
|
-
SELF.listen!(rack, environment: environment, port: port, logger: logger)
|
116
|
-
end
|
117
126
|
end
|
@@ -17,6 +17,12 @@ class Simple::Httpd::BaseController < Sinatra::Base
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
require_relative "./route"
|
21
|
+
|
22
|
+
class Simple::Httpd::BaseController
|
23
|
+
extend ::Simple::Httpd::RouteDescriptions
|
24
|
+
end
|
25
|
+
|
20
26
|
Dir.chdir __dir__ do
|
21
27
|
Dir.glob("base_controller/*.rb").sort.each do |file|
|
22
28
|
require_relative file
|
@@ -28,7 +28,7 @@ class Simple::Httpd::BaseController
|
|
28
28
|
private
|
29
29
|
|
30
30
|
def build_url_query(params)
|
31
|
-
params = params.reject { |_k, v| v.nil? || v.empty? }
|
31
|
+
params = params.reject { |_k, v| v.nil? || v.to_s.empty? }
|
32
32
|
return nil if params.empty?
|
33
33
|
|
34
34
|
params.map { |k, value| "#{k}=#{escape(value.to_s)}" }.join("&")
|
@@ -1,7 +1,5 @@
|
|
1
1
|
require_relative "./json"
|
2
2
|
|
3
|
-
# rubocop:disable Metrics/ClassLength
|
4
|
-
|
5
3
|
class Simple::Httpd::BaseController
|
6
4
|
H = ::Simple::Httpd::Helpers
|
7
5
|
|
@@ -9,8 +7,6 @@ class Simple::Httpd::BaseController
|
|
9
7
|
set :dump_errors, false
|
10
8
|
set :raise_errors, false
|
11
9
|
|
12
|
-
set :raise_errors, true if ENV["RACK_ENV"] == "test"
|
13
|
-
|
14
10
|
private
|
15
11
|
|
16
12
|
def stringify_hash(hsh)
|
@@ -127,19 +123,27 @@ class Simple::Httpd::BaseController
|
|
127
123
|
|
128
124
|
# -- print unspecified errors.
|
129
125
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
126
|
+
if ENV["RACK_ENV"] == "production"
|
127
|
+
error do |exc|
|
128
|
+
content_type :text
|
129
|
+
status 500
|
130
|
+
exc.class.name
|
131
|
+
end
|
132
|
+
else
|
133
|
+
error do |exc|
|
134
|
+
content_type :text
|
135
|
+
message = <<~MSG
|
136
|
+
=== #{exc.class.name} =====================
|
137
|
+
#{exc.message.chomp}
|
138
|
+
|
139
|
+
#{H.filtered_stacktrace(exc.backtrace).join("\n")}
|
140
|
+
==================================================================
|
141
|
+
MSG
|
142
|
+
|
143
|
+
STDERR.puts message
|
144
|
+
status 500
|
145
|
+
"\n#{message}\n"
|
146
|
+
end
|
143
147
|
end
|
144
148
|
|
145
149
|
private
|
@@ -152,25 +156,4 @@ class Simple::Httpd::BaseController
|
|
152
156
|
exc.message
|
153
157
|
# "#{exc.message}, from #{exc.backtrace.join("\n\t")}"
|
154
158
|
end
|
155
|
-
|
156
|
-
def remove_wd(str)
|
157
|
-
@wd ||= Dir.getwd
|
158
|
-
|
159
|
-
if str.start_with?(@wd)
|
160
|
-
str[(@wd.length + 1)..-1]
|
161
|
-
else
|
162
|
-
str
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
def filtered_backtrace(exc, count: 20)
|
167
|
-
lines = exc.backtrace.map do |line|
|
168
|
-
next "...\n" if line =~ /\.rvm\b/
|
169
|
-
|
170
|
-
"#{remove_wd(line)}\n"
|
171
|
-
end
|
172
|
-
|
173
|
-
s = lines[0, count].join("")
|
174
|
-
s.gsub(/(\.\.\.\n)+/, " ... (lines removed) ...\n")
|
175
|
-
end
|
176
159
|
end
|
@@ -12,42 +12,13 @@ class Simple::Httpd::BaseController
|
|
12
12
|
|
13
13
|
configure :development, :test do
|
14
14
|
begin
|
15
|
-
@@neatjson = true
|
16
15
|
require "neatjson"
|
17
16
|
rescue LoadError
|
18
|
-
|
17
|
+
:nop
|
19
18
|
end
|
20
19
|
|
21
20
|
def generate_json(result)
|
22
|
-
|
23
|
-
JSON.neat_generate(result)
|
24
|
-
else
|
25
|
-
JSON.pretty_generate(result)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
public
|
31
|
-
|
32
|
-
def parsed_body
|
33
|
-
return @parsed_body if defined? @parsed_body
|
34
|
-
|
35
|
-
@parsed_body = parse_body
|
36
|
-
rescue RuntimeError => e
|
37
|
-
raise ArgumentError, e.to_s
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def parse_body
|
43
|
-
case request.media_type
|
44
|
-
when "application/json"
|
45
|
-
request.body.rewind
|
46
|
-
body = request.body.read
|
47
|
-
body == "" ? {} : JSON.parse(body)
|
48
|
-
else
|
49
|
-
# parses form data
|
50
|
-
request.POST
|
21
|
+
JSON.respond_to?(:neat_generate) ? JSON.neat_generate(result) : JSON.pretty_generate(result)
|
51
22
|
end
|
52
23
|
end
|
53
24
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Simple::Httpd::BaseController
|
2
|
+
def parsed_body
|
3
|
+
return @parsed_body if defined? @parsed_body
|
4
|
+
|
5
|
+
@parsed_body = parse_body
|
6
|
+
rescue RuntimeError => e
|
7
|
+
raise ArgumentError, e.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def parse_body
|
13
|
+
case request.media_type
|
14
|
+
when "application/json"
|
15
|
+
request.body.rewind
|
16
|
+
body = request.body.read
|
17
|
+
body == "" ? {} : JSON.parse(body)
|
18
|
+
else
|
19
|
+
# parses form data
|
20
|
+
request.POST
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class ::Simple::Httpd::BaseController
|
2
|
+
private
|
3
|
+
|
4
|
+
# encodes the result, according to its payload.
|
5
|
+
#
|
6
|
+
# This function is used by the service integration code, but
|
7
|
+
# is potentially useful outside.
|
8
|
+
def encode_result(result)
|
9
|
+
case result
|
10
|
+
when Array, Hash
|
11
|
+
json(result)
|
12
|
+
when String
|
13
|
+
content_type :text
|
14
|
+
result
|
15
|
+
else
|
16
|
+
result
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|