rocketio 0.2.1 → 0.3.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.
- 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>
|