goliath 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of goliath might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/goliath.gemspec +1 -0
- data/lib/goliath/connection.rb +15 -11
- data/lib/goliath/constants.rb +1 -0
- data/lib/goliath/rack/default_response_format.rb +3 -9
- data/lib/goliath/rack/formatters/json.rb +1 -1
- data/lib/goliath/rack/params.rb +1 -1
- data/lib/goliath/request.rb +35 -18
- data/lib/goliath/response.rb +2 -0
- data/lib/goliath/version.rb +1 -1
- data/spec/integration/async_request_processing.rb +2 -2
- data/spec/integration/chunked_streaming_spec.rb +1 -1
- data/spec/integration/early_abort_spec.rb +5 -5
- data/spec/integration/echo_spec.rb +7 -7
- data/spec/integration/empty_body_spec.rb +2 -2
- data/spec/integration/event_stream_spec.rb +3 -3
- data/spec/integration/exception_handling_spec.rb +16 -16
- data/spec/integration/http_log_spec.rb +16 -16
- data/spec/integration/jsonp_spec.rb +6 -6
- data/spec/integration/keepalive_spec.rb +2 -2
- data/spec/integration/pipelining_spec.rb +3 -3
- data/spec/integration/reloader_spec.rb +3 -3
- data/spec/integration/template_spec.rb +7 -7
- data/spec/integration/test_helper_spec.rb +3 -3
- data/spec/integration/trace_spec.rb +2 -2
- data/spec/integration/valid_spec.rb +8 -8
- data/spec/integration/websocket_spec.rb +2 -2
- data/spec/spec_helper.rb +1 -3
- data/spec/unit/api_spec.rb +1 -1
- data/spec/unit/connection_spec.rb +8 -8
- data/spec/unit/console_spec.rb +3 -3
- data/spec/unit/env_spec.rb +9 -9
- data/spec/unit/headers_spec.rb +8 -8
- data/spec/unit/rack/default_mime_type_spec.rb +3 -3
- data/spec/unit/rack/formatters/json_spec.rb +35 -13
- data/spec/unit/rack/formatters/plist_spec.rb +8 -8
- data/spec/unit/rack/formatters/xml_spec.rb +18 -18
- data/spec/unit/rack/formatters/yaml_spec.rb +13 -13
- data/spec/unit/rack/heartbeat_spec.rb +15 -15
- data/spec/unit/rack/params_spec.rb +62 -60
- data/spec/unit/rack/render_spec.rb +14 -14
- data/spec/unit/rack/validation/boolean_value_spec.rb +6 -6
- data/spec/unit/rack/validation/default_params_spec.rb +13 -13
- data/spec/unit/rack/validation/numeric_range_spec.rb +17 -17
- data/spec/unit/rack/validation/param_spec.rb +75 -75
- data/spec/unit/rack/validation/request_method_spec.rb +9 -9
- data/spec/unit/rack/validation/required_param_spec.rb +28 -28
- data/spec/unit/rack/validation/required_value_spec.rb +19 -19
- data/spec/unit/request_spec.rb +18 -18
- data/spec/unit/response_spec.rb +6 -6
- data/spec/unit/runner_spec.rb +31 -31
- data/spec/unit/server_spec.rb +21 -21
- data/spec/unit/validation/standard_http_errors_spec.rb +6 -6
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2bfab8c9906a1737abc3e7cdf163a52e13e516c7
|
4
|
+
data.tar.gz: a1ac6184a35dbfe56a04d117872d31b7c3647c71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 833e67c341fde76ca1e5d69430f0f0c2d70186de0474979421fbbeeac78d5755eb79bfde0495e606105fb71f0291a6e8fa6be4c3e55ea6da2d663b8aa6c20937
|
7
|
+
data.tar.gz: 15de365fe175166182ead10d6c397971d33391e190f994552216433ebf121be35732805cd56cc364c3f9f0a5361589cd4205954014288fd52ab995d6807ccc93
|
data/goliath.gemspec
CHANGED
@@ -38,6 +38,7 @@ Gem::Specification.new do |s|
|
|
38
38
|
s.add_development_dependency 'amqp', '>=0.7.1'
|
39
39
|
s.add_development_dependency 'em-websocket-client'
|
40
40
|
s.add_development_dependency 'em-eventsource'
|
41
|
+
s.add_development_dependency 'rack', '< 2'
|
41
42
|
|
42
43
|
s.add_development_dependency 'tilt', '>=1.2.2'
|
43
44
|
s.add_development_dependency 'haml', '>=3.0.25'
|
data/lib/goliath/connection.rb
CHANGED
@@ -23,12 +23,13 @@ module Goliath
|
|
23
23
|
@parser = Http::Parser.new
|
24
24
|
@parser.on_headers_complete = proc do |h|
|
25
25
|
env = Goliath::Env.new
|
26
|
-
env[SERVER_PORT]
|
27
|
-
env[RACK_LOGGER]
|
28
|
-
env[OPTIONS]
|
29
|
-
env[STATUS]
|
30
|
-
env[CONFIG]
|
31
|
-
env[REMOTE_ADDR]
|
26
|
+
env[SERVER_PORT] = port.to_s
|
27
|
+
env[RACK_LOGGER] = logger
|
28
|
+
env[OPTIONS] = options
|
29
|
+
env[STATUS] = status
|
30
|
+
env[CONFIG] = config
|
31
|
+
env[REMOTE_ADDR] = remote_address
|
32
|
+
env[RACK_URL_SCHEME] = options[:ssl] ? "https" : "http"
|
32
33
|
|
33
34
|
r = Goliath::Request.new(@app, self, env)
|
34
35
|
r.parse_header(h, @parser) do
|
@@ -41,7 +42,8 @@ module Goliath
|
|
41
42
|
end
|
42
43
|
|
43
44
|
@parser.on_body = proc do |data|
|
44
|
-
@requests.first
|
45
|
+
req = @requests.first
|
46
|
+
req.parse(data) unless req.env[:terminate_connection]
|
45
47
|
end
|
46
48
|
|
47
49
|
@parser.on_message_complete = proc do
|
@@ -83,15 +85,17 @@ module Goliath
|
|
83
85
|
end
|
84
86
|
|
85
87
|
def terminate_request(keep_alive)
|
86
|
-
if
|
87
|
-
@current = req
|
88
|
-
@current.succeed
|
89
|
-
elsif @current
|
88
|
+
if @current
|
90
89
|
@current.close
|
91
90
|
@current = nil
|
92
91
|
end
|
93
92
|
|
94
93
|
close_connection_after_writing rescue nil if !keep_alive
|
94
|
+
|
95
|
+
if req = @pending.shift
|
96
|
+
@current = req
|
97
|
+
@current.succeed
|
98
|
+
end
|
95
99
|
end
|
96
100
|
|
97
101
|
def remote_address
|
data/lib/goliath/constants.rb
CHANGED
@@ -4,17 +4,11 @@ module Goliath
|
|
4
4
|
include Goliath::Rack::AsyncMiddleware
|
5
5
|
|
6
6
|
def post_process(env, status, headers, body)
|
7
|
-
|
8
|
-
|
9
|
-
new_body = []
|
10
|
-
if body.respond_to?(:each)
|
11
|
-
body.each { |chunk| new_body << chunk }
|
7
|
+
if body.is_a?(String)
|
8
|
+
[status, headers, [body]]
|
12
9
|
else
|
13
|
-
|
10
|
+
[status, headers, body]
|
14
11
|
end
|
15
|
-
new_body.collect! { |item| item.to_s }
|
16
|
-
|
17
|
-
[status, headers, new_body.flatten]
|
18
12
|
end
|
19
13
|
end
|
20
14
|
end
|
data/lib/goliath/rack/params.rb
CHANGED
@@ -4,7 +4,7 @@ require 'rack/utils'
|
|
4
4
|
module Goliath
|
5
5
|
module Rack
|
6
6
|
URL_ENCODED = %r{^application/x-www-form-urlencoded}
|
7
|
-
JSON_ENCODED = %r{^application/json}
|
7
|
+
JSON_ENCODED = %r{^application/((vnd\.api\+)?json|javascript)}
|
8
8
|
|
9
9
|
# A middle ware to parse params. This will parse both the
|
10
10
|
# query string parameters and the body and place them into
|
data/lib/goliath/request.rb
CHANGED
@@ -197,22 +197,14 @@ module Goliath
|
|
197
197
|
callback do
|
198
198
|
begin
|
199
199
|
@response.status, @response.headers, @response.body = status, headers, body
|
200
|
-
@response.each { |chunk| @conn.send_data(chunk) }
|
201
|
-
|
202
|
-
elapsed_time = (Time.now.to_f - @env[:start_time]) * 1000
|
203
|
-
begin
|
204
|
-
Goliath::Request.log_block.call(@env, @response, elapsed_time)
|
205
|
-
rescue => err
|
206
|
-
# prevent an infinite loop if the block raised an error
|
207
|
-
@env[RACK_LOGGER].error("log block raised #{err}")
|
208
|
-
end
|
209
200
|
|
210
|
-
@
|
201
|
+
stream_data(@response.each) do
|
202
|
+
terminate_request
|
203
|
+
end
|
211
204
|
rescue Exception => e
|
212
205
|
server_exception(e)
|
213
206
|
end
|
214
207
|
end
|
215
|
-
|
216
208
|
rescue Exception => e
|
217
209
|
server_exception(e)
|
218
210
|
end
|
@@ -220,6 +212,31 @@ module Goliath
|
|
220
212
|
|
221
213
|
private
|
222
214
|
|
215
|
+
# Writes each chunk of the response data in a new tick. This achieves
|
216
|
+
# streaming, because EventMachine flushes the sent data to the socket at
|
217
|
+
# the end of each tick.
|
218
|
+
def stream_data(chunks, &block)
|
219
|
+
@conn.send_data(chunks.next)
|
220
|
+
EM.next_tick { stream_data(chunks, &block) }
|
221
|
+
rescue StopIteration
|
222
|
+
block.call
|
223
|
+
rescue Exception => e
|
224
|
+
server_exception(e)
|
225
|
+
end
|
226
|
+
|
227
|
+
# Logs the response time and terminates the request.
|
228
|
+
def terminate_request
|
229
|
+
elapsed_time = (Time.now.to_f - @env[:start_time]) * 1000
|
230
|
+
begin
|
231
|
+
Goliath::Request.log_block.call(@env, @response, elapsed_time)
|
232
|
+
rescue => err
|
233
|
+
# prevent an infinite loop if the block raised an error
|
234
|
+
@env[RACK_LOGGER].error("log block raised #{err}")
|
235
|
+
end
|
236
|
+
|
237
|
+
@conn.terminate_request(keep_alive)
|
238
|
+
end
|
239
|
+
|
223
240
|
# Handles logging server exceptions
|
224
241
|
#
|
225
242
|
# @param e [Exception] The exception to log
|
@@ -228,20 +245,20 @@ module Goliath
|
|
228
245
|
if e.is_a?(Goliath::Validation::Error)
|
229
246
|
status, headers, body = [e.status_code, e.headers, ('{"error":"%s"}' % e.message)]
|
230
247
|
else
|
231
|
-
|
232
|
-
|
248
|
+
logthis = "#{e.backtrace[0]}: #{e.message} (#{e.class})\n"
|
249
|
+
e.backtrace[1..-1].each do |bt|
|
250
|
+
logthis += " from #{bt}\n"
|
251
|
+
end
|
252
|
+
@env.logger.error(logthis)
|
253
|
+
@env[RACK_EXCEPTION] = e
|
233
254
|
|
255
|
+
message = Goliath.env?(:production) ? 'An error happened' : e.message
|
234
256
|
status, headers, body = [500, {}, message]
|
235
257
|
end
|
236
258
|
|
237
259
|
headers['Content-Length'] = body.bytesize.to_s
|
238
260
|
@env[:terminate_connection] = true
|
239
261
|
post_process([status, headers, body])
|
240
|
-
|
241
|
-
# Mark the request as complete to force a flush on the response.
|
242
|
-
# Note: #on_body and #response hooks may still fire if the data
|
243
|
-
# is already in the parser buffer.
|
244
|
-
succeed
|
245
262
|
end
|
246
263
|
|
247
264
|
# Used to determine if the connection should be kept open
|
data/lib/goliath/response.rb
CHANGED
data/lib/goliath/version.rb
CHANGED
@@ -13,8 +13,8 @@ describe 'Async Request processing' do
|
|
13
13
|
|
14
14
|
post_request(request_data, err) do |c|
|
15
15
|
resp = MultiJson.load(c.response)
|
16
|
-
resp['body'].
|
17
|
-
resp['head'].
|
16
|
+
expect(resp['body']).to match('some=data')
|
17
|
+
expect(resp['head']).to include('X-Upload')
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -27,7 +27,7 @@ describe "ChunkedStreaming" do
|
|
27
27
|
it "should stream content" do
|
28
28
|
with_api(ChunkedStreaming, {:verbose => true, :log_stdout => true}) do |server|
|
29
29
|
streaming_client_connect('/streaming') do |client|
|
30
|
-
client.receive.
|
30
|
+
expect(client.receive).to eq("chunked")
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -11,7 +11,7 @@ describe EarlyAbort do
|
|
11
11
|
it "should return OK" do
|
12
12
|
with_api(EarlyAbort) do
|
13
13
|
get_request({}, err) do |c|
|
14
|
-
c.response.
|
14
|
+
expect(c.response).to eq("OK")
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -24,8 +24,8 @@ describe EarlyAbort do
|
|
24
24
|
}
|
25
25
|
|
26
26
|
post_request(request_data, err) do |c|
|
27
|
-
c.response.
|
28
|
-
File.exist?("/tmp/goliath-test-error.log").
|
27
|
+
expect(c.response).to eq("{\"error\":\"Can't handle requests with X-Crash: true.\"}")
|
28
|
+
expect(File.exist?("/tmp/goliath-test-error.log")).to be false
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -35,8 +35,8 @@ describe EarlyAbort do
|
|
35
35
|
request_data = { :body => "a" * 20 }
|
36
36
|
|
37
37
|
post_request(request_data, err) do |c|
|
38
|
-
c.response.
|
39
|
-
File.exist?("/tmp/goliath-test-error.log").
|
38
|
+
expect(c.response).to match(/Payload size can't exceed 10 bytes/)
|
39
|
+
expect(File.exist?("/tmp/goliath-test-error.log")).to be false
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -10,7 +10,7 @@ describe Echo do
|
|
10
10
|
with_api(Echo) do
|
11
11
|
get_request({:query => {:echo => 'test'}}, err) do |c|
|
12
12
|
b = MultiJson.load(c.response)
|
13
|
-
b['response'].
|
13
|
+
expect(b['response']).to eq('test')
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -19,8 +19,8 @@ describe Echo do
|
|
19
19
|
with_api(Echo) do
|
20
20
|
get_request({}, err) do |c|
|
21
21
|
b = MultiJson.load(c.response)
|
22
|
-
b['error'].
|
23
|
-
b['error'].
|
22
|
+
expect(b['error']).not_to be_nil
|
23
|
+
expect(b['error']).to eq('echo identifier missing')
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -29,7 +29,7 @@ describe Echo do
|
|
29
29
|
with_api(Echo) do
|
30
30
|
post_request({:body => {'echo' => 'test'}}, err) do |c|
|
31
31
|
b = MultiJson.load(c.response)
|
32
|
-
b['response'].
|
32
|
+
expect(b['response']).to eq('test')
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
@@ -42,7 +42,7 @@ describe Echo do
|
|
42
42
|
post_request({:body => body.to_s,
|
43
43
|
:head => head}, err) do |c|
|
44
44
|
b = MultiJson.load(c.response)
|
45
|
-
b['response'].
|
45
|
+
expect(b['response']).to eq('test')
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -55,7 +55,7 @@ describe Echo do
|
|
55
55
|
post_request({:body => body.to_s,
|
56
56
|
:head => head}, err) do |c|
|
57
57
|
b = MultiJson.load(c.response)
|
58
|
-
b['response'].
|
58
|
+
expect(b['response']).to eq('My Echo')
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -64,7 +64,7 @@ describe Echo do
|
|
64
64
|
with_api(Echo) do
|
65
65
|
patch_request({:body => {'echo' => 'test'}}, err) do |c|
|
66
66
|
b = MultiJson.load(c.response)
|
67
|
-
b['response'].
|
67
|
+
expect(b['response']).to eq('test')
|
68
68
|
end
|
69
69
|
end
|
70
70
|
end
|
@@ -12,8 +12,8 @@ describe 'Empty body API' do
|
|
12
12
|
it 'serves a 201 with no body' do
|
13
13
|
with_api(Empty) do
|
14
14
|
get_request({}, err) do |c|
|
15
|
-
c.response_header.status.
|
16
|
-
c.response_header['CONTENT_LENGTH'].
|
15
|
+
expect(c.response_header.status).to eq(201)
|
16
|
+
expect(c.response_header['CONTENT_LENGTH']).to eq('0')
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -30,8 +30,8 @@ describe 'EventStream' do
|
|
30
30
|
sse_client_connect('/stream') do |client|
|
31
31
|
client.listen_to('custom_event')
|
32
32
|
EventStreamEndpoint.events.push(name: 'custom_event', data: 'content')
|
33
|
-
client.receive_on('custom_event').
|
34
|
-
client.receive.
|
33
|
+
expect(client.receive_on('custom_event')).to eq(['content'])
|
34
|
+
expect(client.receive).to eq([])
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -42,7 +42,7 @@ describe 'EventStream' do
|
|
42
42
|
with_api(EventStreamEndpoint, {:verbose => true, :log_stdout => true}) do |server|
|
43
43
|
sse_client_connect('/stream') do |client|
|
44
44
|
EventStreamEndpoint.events.push(data: 'content')
|
45
|
-
client.receive.
|
45
|
+
expect(client.receive).to eq(['content'])
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -83,8 +83,8 @@ describe ExceptionHandlingAPI do
|
|
83
83
|
it 'returns a normal response' do
|
84
84
|
with_api(ExceptionHandlingAPI) do
|
85
85
|
get_request({ query: query }, err) do |c|
|
86
|
-
c.response_header.status.
|
87
|
-
c.response.
|
86
|
+
expect(c.response_header.status).to eq(200)
|
87
|
+
expect(c.response).to eq('No exceptions raised')
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
@@ -96,8 +96,8 @@ describe ExceptionHandlingAPI do
|
|
96
96
|
it 'handles the exception using ExceptionHandlingMiddleware' do
|
97
97
|
with_api(ExceptionHandlingAPI) do
|
98
98
|
get_request({ query: query }, err) do |c|
|
99
|
-
c.response_header.status.
|
100
|
-
c.response.
|
99
|
+
expect(c.response_header.status).to eq(200)
|
100
|
+
expect(c.response).to eq('Exception raised: zoinks')
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
@@ -109,8 +109,8 @@ describe ExceptionHandlingAPI do
|
|
109
109
|
it 'handles the exception using ExceptionHandlingMiddleware' do
|
110
110
|
with_api(ExceptionHandlingAPI) do
|
111
111
|
get_request({ query: query }, err) do |c|
|
112
|
-
c.response_header.status.
|
113
|
-
c.response.
|
112
|
+
expect(c.response_header.status).to eq(200)
|
113
|
+
expect(c.response).to eq('Exception raised: jinkies')
|
114
114
|
end
|
115
115
|
end
|
116
116
|
end
|
@@ -122,8 +122,8 @@ describe ExceptionHandlingAPI do
|
|
122
122
|
it 'returns a validation error generated by Goliath::Rack::Params' do
|
123
123
|
with_api(ExceptionHandlingAPI) do
|
124
124
|
get_request({ query: query }, err) do |c|
|
125
|
-
c.response_header.status.
|
126
|
-
c.response.
|
125
|
+
expect(c.response_header.status).to eq(400)
|
126
|
+
expect(c.response).to eq("[:error, \"Invalid parameters: Rack::Utils::ParameterTypeError\"]")
|
127
127
|
end
|
128
128
|
end
|
129
129
|
end
|
@@ -154,8 +154,8 @@ describe PassiveExceptionHandlingAPI do
|
|
154
154
|
it 'returns a normal response' do
|
155
155
|
with_api(PassiveExceptionHandlingAPI) do
|
156
156
|
get_request({ query: query }, err) do |c|
|
157
|
-
c.response_header.status.
|
158
|
-
c.response.
|
157
|
+
expect(c.response_header.status).to eq(200)
|
158
|
+
expect(c.response).to eq('No exceptions raised')
|
159
159
|
end
|
160
160
|
end
|
161
161
|
end
|
@@ -167,8 +167,8 @@ describe PassiveExceptionHandlingAPI do
|
|
167
167
|
it 'returns the server error generated by Goliath::Request#process' do
|
168
168
|
with_api(PassiveExceptionHandlingAPI) do
|
169
169
|
get_request({ query: query }, err) do |c|
|
170
|
-
c.response_header.status.
|
171
|
-
c.response.
|
170
|
+
expect(c.response_header.status).to eq(500)
|
171
|
+
expect(c.response).to eq('ruh-roh')
|
172
172
|
end
|
173
173
|
end
|
174
174
|
end
|
@@ -180,8 +180,8 @@ describe PassiveExceptionHandlingAPI do
|
|
180
180
|
it 'returns the validation error generated by Goliath::API#call' do
|
181
181
|
with_api(PassiveExceptionHandlingAPI) do
|
182
182
|
get_request({ query: query }, err) do |c|
|
183
|
-
c.response_header.status.
|
184
|
-
c.response.
|
183
|
+
expect(c.response_header.status).to eq(500)
|
184
|
+
expect(c.response).to eq('[:error, "puppy-power"]')
|
185
185
|
end
|
186
186
|
end
|
187
187
|
end
|
@@ -193,8 +193,8 @@ describe PassiveExceptionHandlingAPI do
|
|
193
193
|
it 'returns a validation error generated by Goliath::Rack::Params' do
|
194
194
|
with_api(PassiveExceptionHandlingAPI) do
|
195
195
|
get_request({ query: query }, err) do |c|
|
196
|
-
c.response_header.status.
|
197
|
-
c.response.
|
196
|
+
expect(c.response_header.status).to eq(400)
|
197
|
+
expect(c.response).to eq('[:error, "Invalid parameters: Rack::Utils::ParameterTypeError"]')
|
198
198
|
end
|
199
199
|
end
|
200
200
|
end
|