rocketio 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rocketio.rb +31 -19
- data/lib/rocketio/application.rb +5 -1
- data/lib/rocketio/controller.rb +30 -26
- data/lib/rocketio/controller/error_handlers.rb +0 -11
- data/lib/rocketio/controller/helpers.rb +10 -0
- data/lib/rocketio/controller/response.rb +4 -0
- data/lib/rocketio/util.rb +1 -1
- data/lib/rocketio/version.rb +1 -1
- data/test/error_handlers_test.rb +0 -34
- data/test/json_body.rb +13 -0
- data/test/keyword_arguments.rb +11 -0
- data/test/response_test.rb +19 -0
- metadata +5 -4
- data/lib/rocketio/error_templates/409.html +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac617b26c0a9352ff073f5e194202d8e09f90c4c
|
4
|
+
data.tar.gz: 1e9aa0b25987687e5d1b25193bfb60bf014e6fa2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 143b5e6041e82d762c8a55ad0d4fc759bbd05a5cbaddca814141c76cd04fabc07ae17df6e168525b3f518ec3944140ebc18ce9275be13765dfdd8f70ff363489
|
7
|
+
data.tar.gz: 9e087b5c7c644b4a84ac5830824537902710ea8d3203e882e08b33139184ee6802960d4a85819e173c9360fa9369be29a8dac71a2c69d0c7e204a57ca6d4566e
|
data/lib/rocketio.rb
CHANGED
@@ -62,7 +62,11 @@ module RocketIO
|
|
62
62
|
DEFAULT_CONTENT_TYPE = 'text/html'.freeze
|
63
63
|
CONTENT_LENGTH = 'Content-Length'.freeze
|
64
64
|
CONTENT_DISPOSITION = 'Content-Disposition'.freeze
|
65
|
+
|
65
66
|
APPLICATION_OCTET_STREAM = 'application/octet-stream'.freeze
|
67
|
+
APPLICATION_JSON = 'application/json'.freeze
|
68
|
+
APPLICATION_JSON_REGEXP = /application\/json/i
|
69
|
+
|
66
70
|
DEFAULT_AUTH_REALM = 'AccessRestricted'.freeze
|
67
71
|
DEFAULT_TOKEN_AUTH_REALM = 'Application'.freeze
|
68
72
|
|
@@ -71,31 +75,39 @@ module RocketIO
|
|
71
75
|
HTTP_ACCEPT = 'HTTP_ACCEPT'.freeze
|
72
76
|
REMOTE_USER = 'REMOTE_USER'.freeze
|
73
77
|
|
74
|
-
|
78
|
+
HTTP_CONTENT_TYPE = 'CONTENT_TYPE'.freeze
|
79
|
+
HTTP_CONNECTION = 'HTTP_CONNECTION'.freeze
|
80
|
+
|
75
81
|
HTTP_AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION'].map(&:freeze).freeze
|
76
82
|
HTTP_AUTHORIZATION_MOCKS = {
|
77
83
|
basic: 'Basic Og=='.freeze,
|
78
84
|
digest: 'Digest opaque="", qop="auth", uri="%s"'.freeze
|
79
85
|
}.freeze
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
86
|
+
|
87
|
+
HTTP_UPGRADE = 'HTTP_UPGRADE'.freeze
|
88
|
+
|
89
|
+
UPGRADE = 'upgrade'.freeze
|
90
|
+
WEBSOCKET = 'websocket'.freeze
|
91
|
+
|
92
|
+
HTTP_1_1 = 'HTTP/1.1'.freeze
|
93
|
+
HTTP_VERSION = 'HTTP_VERSION'.freeze
|
94
|
+
HTTP_X_FORWARDED_HOST = 'HTTP_X_FORWARDED_HOST'.freeze
|
95
|
+
HTTP_IF_MATCH = 'HTTP_IF_MATCH'.freeze
|
96
|
+
HTTP_IF_NONE_MATCH = 'HTTP_IF_NONE_MATCH'.freeze
|
97
|
+
HTTP_IF_MODIFIED_SINCE = 'HTTP_IF_MODIFIED_SINCE'.freeze
|
89
98
|
HTTP_IF_UNMODIFIED_SINCE = 'HTTP_IF_UNMODIFIED_SINCE'.freeze
|
90
|
-
HTTP_X_REQUESTED_WITH
|
91
|
-
XML_HTTP_REQUEST
|
92
|
-
|
93
|
-
LOCATION
|
94
|
-
CACHE_CONTROL
|
95
|
-
EXPIRES
|
96
|
-
LAST_MODIFIED
|
97
|
-
|
98
|
-
|
99
|
+
HTTP_X_REQUESTED_WITH = 'HTTP_X_REQUESTED_WITH'.freeze
|
100
|
+
XML_HTTP_REQUEST = 'XMLHttpRequest'.freeze
|
101
|
+
|
102
|
+
LOCATION = 'Location'.freeze
|
103
|
+
CACHE_CONTROL = 'Cache-Control'.freeze
|
104
|
+
EXPIRES = 'Expires'.freeze
|
105
|
+
LAST_MODIFIED = 'Last-Modified'.freeze
|
106
|
+
|
107
|
+
ETAG = 'ETag'.freeze
|
108
|
+
ETAG_KINDS = [:strong, :weak].freeze
|
109
|
+
|
110
|
+
RACK_INPUT = 'rack.input'.freeze
|
99
111
|
|
100
112
|
DROP_BODY_RESPONSES = {204 => true, 205 => true, 304 => true}.freeze
|
101
113
|
|
data/lib/rocketio/application.rb
CHANGED
@@ -13,7 +13,11 @@ module RocketIO
|
|
13
13
|
catch :__response__ do # catch 404 errors and potential `halt` calls from middleware
|
14
14
|
controller, method, path_params = @router.resolve_path(env[PATH_INFO])
|
15
15
|
|
16
|
-
controller
|
16
|
+
unless controller
|
17
|
+
controller = Controller.new
|
18
|
+
controller.instance_variable_set(:@__env__, env)
|
19
|
+
controller.error(404)
|
20
|
+
end
|
17
21
|
|
18
22
|
controller = controller.new(method, path_params)
|
19
23
|
chain = controller.middleware.reverse.inject(controller) {|app,ware| ware.call(app)}
|
data/lib/rocketio/controller.rb
CHANGED
@@ -2,7 +2,7 @@ module RocketIO
|
|
2
2
|
class Controller
|
3
3
|
extend Forwardable
|
4
4
|
|
5
|
-
def_delegators :'self.class', :url, :api, :dirname, :
|
5
|
+
def_delegators :'self.class', :url, :api, :dirname, :path_params_expected
|
6
6
|
def_delegators :request, :session, :request_method
|
7
7
|
def_delegators RocketIO, :environment
|
8
8
|
def_delegators RocketIO, :indifferent_params, :indifferent_hash, :mime_type
|
@@ -15,10 +15,9 @@ module RocketIO
|
|
15
15
|
def_delegators RocketIO, :"#{env}?"
|
16
16
|
end
|
17
17
|
|
18
|
-
def initialize requested_method = RocketIO::INDEX_METHOD, path_params = RocketIO::EMPTY_ARRAY
|
19
|
-
@__requested_method__ = requested_method
|
18
|
+
def initialize requested_method = RocketIO::INDEX_METHOD, path_params = RocketIO::EMPTY_ARRAY
|
19
|
+
@__requested_method__ = requested_method.to_sym
|
20
20
|
@__path_params_array__ = path_params.freeze
|
21
|
-
@__env__ = env if env
|
22
21
|
end
|
23
22
|
|
24
23
|
# call requested method
|
@@ -26,35 +25,35 @@ module RocketIO
|
|
26
25
|
# @param [Hash] env
|
27
26
|
# @return [Rack::Response]
|
28
27
|
#
|
29
|
-
def call env
|
28
|
+
def call env, params: nil
|
30
29
|
@__env__ = env
|
30
|
+
@__params__ = params if params
|
31
31
|
catch :__response__ do
|
32
32
|
|
33
33
|
api[requested_method] || error(501)
|
34
34
|
|
35
35
|
if error_handlers[500]
|
36
36
|
begin
|
37
|
-
__call__
|
37
|
+
__call__
|
38
38
|
rescue Exception => e
|
39
39
|
error(500, e)
|
40
40
|
end
|
41
41
|
else
|
42
|
-
__call__
|
42
|
+
__call__
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
private
|
48
|
-
def __call__
|
48
|
+
def __call__
|
49
49
|
|
50
50
|
validate_or_request_authentication_if_needed
|
51
51
|
validate_or_request_authorization_if_needed
|
52
|
-
validate_parameters
|
53
52
|
|
54
53
|
__run__ proc {
|
55
54
|
invoke_before_filter
|
56
55
|
invoke_around_filter proc {
|
57
|
-
response.body = public_send(requested_method, *
|
56
|
+
response.body = public_send(requested_method, *requested_method_arguments)
|
58
57
|
}
|
59
58
|
invoke_after_filter
|
60
59
|
}
|
@@ -65,6 +64,10 @@ module RocketIO
|
|
65
64
|
response.body ||= RocketIO::EMPTY_ARRAY
|
66
65
|
end
|
67
66
|
|
67
|
+
if env[RocketIO::HTTP_ACCEPT] == RocketIO::APPLICATION_JSON
|
68
|
+
response[RocketIO::CONTENT_TYPE] = RocketIO::APPLICATION_JSON
|
69
|
+
end
|
70
|
+
|
68
71
|
response.finish
|
69
72
|
end
|
70
73
|
|
@@ -76,20 +79,23 @@ module RocketIO
|
|
76
79
|
@__env__
|
77
80
|
end
|
78
81
|
|
79
|
-
def validate_parameters
|
80
|
-
|
81
|
-
if path_params_array.size >= api[requested_method][:parameters_policy][:min]
|
82
|
-
return if api[requested_method][:parameters_policy][:max] == :* ||
|
83
|
-
path_params_array.size <= api[requested_method][:parameters_policy][:max]
|
84
|
-
end
|
85
|
-
|
86
|
-
error(409)
|
87
|
-
end
|
88
|
-
|
89
82
|
def requested_method
|
90
83
|
@__requested_method__
|
91
84
|
end
|
92
85
|
|
86
|
+
def requested_method_arguments
|
87
|
+
if api[requested_method][:params_accepted_as_last_argument?]
|
88
|
+
[
|
89
|
+
*path_params_array,
|
90
|
+
# creating a shallow params copy with symbolized keys
|
91
|
+
# cause Ruby does not accept string keys for keyword arguments
|
92
|
+
params.keys.each_with_object({}) {|k,o| o[k.to_sym] = params[k]}
|
93
|
+
]
|
94
|
+
else
|
95
|
+
path_params_array
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
93
99
|
def path_params_array
|
94
100
|
@__path_params_array__
|
95
101
|
end
|
@@ -105,7 +111,7 @@ module RocketIO
|
|
105
111
|
end
|
106
112
|
|
107
113
|
def params
|
108
|
-
@__params__ ||= indifferent_params(request.params)
|
114
|
+
@__params__ ||= indifferent_params(json? ? __parse_json_body__ : request.params)
|
109
115
|
end
|
110
116
|
|
111
117
|
def request
|
@@ -250,13 +256,11 @@ module RocketIO
|
|
250
256
|
return if self == RocketIO::Controller
|
251
257
|
return unless public_instance_methods(false).include?(meth)
|
252
258
|
|
253
|
-
|
259
|
+
params, path_params = instance_method(meth).parameters.partition {|p| p[0] =~ /\Akey/}
|
254
260
|
|
255
261
|
api[meth] = {
|
256
|
-
|
257
|
-
|
258
|
-
path_params: RocketIO.path_params(parameters).freeze,
|
259
|
-
parameters_policy: RocketIO.parameters_policy(parameters).freeze
|
262
|
+
path_params: RocketIO.path_params(path_params).freeze,
|
263
|
+
params_accepted_as_last_argument?: params.any?,
|
260
264
|
}
|
261
265
|
end
|
262
266
|
|
@@ -73,17 +73,6 @@ module RocketIO
|
|
73
73
|
RocketIO.error_renderer(404, xhr?, env: env)
|
74
74
|
end
|
75
75
|
|
76
|
-
# 409: Wrong number of arguments received
|
77
|
-
error 409 do
|
78
|
-
RocketIO.error_renderer(409, xhr?, {
|
79
|
-
url: url,
|
80
|
-
controller: self.class.to_s,
|
81
|
-
requested_method: requested_method,
|
82
|
-
expected: api[requested_method][:parameters_policy],
|
83
|
-
received: path_params_array
|
84
|
-
})
|
85
|
-
end
|
86
|
-
|
87
76
|
# 501: Not Implemented
|
88
77
|
error 501 do
|
89
78
|
RocketIO.error_renderer(501, xhr?, {
|
@@ -73,6 +73,16 @@ module RocketIO
|
|
73
73
|
env[RocketIO::HTTP_X_REQUESTED_WITH] == RocketIO::XML_HTTP_REQUEST
|
74
74
|
end
|
75
75
|
|
76
|
+
def json?
|
77
|
+
# using regex because Content-Type may look like "application/json;charset=UTF-8"
|
78
|
+
# TODO: consider using Regexp#match? on Ruby 2.4
|
79
|
+
env[HTTP_CONTENT_TYPE] =~ RocketIO::APPLICATION_JSON_REGEXP
|
80
|
+
end
|
81
|
+
|
82
|
+
def __parse_json_body__
|
83
|
+
JSON.parse(env[RACK_INPUT].read)
|
84
|
+
end
|
85
|
+
|
76
86
|
# switch controller and halt with returned response.
|
77
87
|
# any arguments will be passed to requested method.
|
78
88
|
#
|
data/lib/rocketio/util.rb
CHANGED
data/lib/rocketio/version.rb
CHANGED
data/test/error_handlers_test.rb
CHANGED
@@ -32,40 +32,6 @@ spec :ErrorHandlers do
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
context 'Parameters Error' do
|
36
|
-
|
37
|
-
it 'uses default handler' do
|
38
|
-
app mock_app(mock_controller {
|
39
|
-
def index; end
|
40
|
-
})
|
41
|
-
get :x
|
42
|
-
assert(last_response.status) == 409
|
43
|
-
assert(last_response.body) =~ /wrong arguments/i
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'uses custom handler' do
|
47
|
-
app mock_app(mock_controller {
|
48
|
-
def index; end
|
49
|
-
error 409 do
|
50
|
-
'noway'
|
51
|
-
end
|
52
|
-
})
|
53
|
-
get :x
|
54
|
-
assert(last_response.status) == 409
|
55
|
-
assert(last_response.body) == 'noway'
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'can be triggered manually' do
|
59
|
-
called = false
|
60
|
-
app mock_app(mock_controller {
|
61
|
-
define_method(:index) {called = true; error(409)}
|
62
|
-
})
|
63
|
-
get
|
64
|
-
assert(called) == true
|
65
|
-
assert(last_response.status) == 409
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
35
|
context '500: Fatal Error' do
|
70
36
|
|
71
37
|
it 'raises when no handler defined' do
|
data/test/json_body.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'setup'
|
2
|
+
|
3
|
+
spec 'JSON body and params' do
|
4
|
+
it 'is parsing JSON body if request Content-Type contains "application/json"' do
|
5
|
+
app mock_controller {
|
6
|
+
def index; params[:x] end
|
7
|
+
}
|
8
|
+
env[RocketIO::RACK_INPUT] = StringIO.new({x: :y}.to_json)
|
9
|
+
header['Content-Type'] = 'application/json'
|
10
|
+
get
|
11
|
+
assert(last_response.body) == 'y'
|
12
|
+
end
|
13
|
+
end
|
data/test/response_test.rb
CHANGED
@@ -116,4 +116,23 @@ spec RocketIO::Response do
|
|
116
116
|
get
|
117
117
|
assert(last_response).is_ok_with_body ''
|
118
118
|
end
|
119
|
+
|
120
|
+
it "sets Content-Type to application/json when request's Accept header is application/json" do
|
121
|
+
app mock_controller {
|
122
|
+
def index; end
|
123
|
+
}
|
124
|
+
header['Accept'] = 'application/json'
|
125
|
+
get
|
126
|
+
assert(last_response.headers['Content-Type']) == 'application/json'
|
127
|
+
end
|
128
|
+
|
129
|
+
it "responds with a JSON body when request's Accept header is application/json" do
|
130
|
+
body = {x: :y}
|
131
|
+
app mock_controller {
|
132
|
+
define_method(:index) {body}
|
133
|
+
}
|
134
|
+
header['Accept'] = 'application/json'
|
135
|
+
get
|
136
|
+
assert(last_response.body) == body.to_json
|
137
|
+
end
|
119
138
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rocketio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Slee Woo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -174,7 +174,6 @@ files:
|
|
174
174
|
- lib/rocketio/controller/token_auth.rb
|
175
175
|
- lib/rocketio/controller/websocket.rb
|
176
176
|
- lib/rocketio/error_templates/404.html
|
177
|
-
- lib/rocketio/error_templates/409.html
|
178
177
|
- lib/rocketio/error_templates/501.html
|
179
178
|
- lib/rocketio/error_templates/layout.html
|
180
179
|
- lib/rocketio/exceptions.rb
|
@@ -194,6 +193,8 @@ files:
|
|
194
193
|
- test/filters_test.rb
|
195
194
|
- test/halt_test.rb
|
196
195
|
- test/helpers_test.rb
|
196
|
+
- test/json_body.rb
|
197
|
+
- test/keyword_arguments.rb
|
197
198
|
- test/middleware_test.rb
|
198
199
|
- test/redirect_test.rb
|
199
200
|
- test/render/b.erb
|
@@ -241,5 +242,5 @@ rubyforge_project:
|
|
241
242
|
rubygems_version: 2.5.1
|
242
243
|
signing_key:
|
243
244
|
specification_version: 4
|
244
|
-
summary: '["rocketio-0.
|
245
|
+
summary: '["rocketio-0.3.0", "Simple, fast, scalable web framework for Ruby"]'
|
245
246
|
test_files: []
|
@@ -1,11 +0,0 @@
|
|
1
|
-
<h1>409: Wrong arguments</h1>
|
2
|
-
<h3>
|
3
|
-
<b>{{url}}</b> URL resolved to <b>{{controller}}#{{requested_method}}</b> method
|
4
|
-
but it was called with wrong arguments.
|
5
|
-
<div>
|
6
|
-
Expected: {min: {{expected.min}}, max: {{expected.max}}}
|
7
|
-
</div>
|
8
|
-
<div>
|
9
|
-
Received: {{received}}
|
10
|
-
</div>
|
11
|
-
</h3>
|