midori.rb 0.4.3
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 +7 -0
- data/.editorconfig +9 -0
- data/LICENSE +21 -0
- data/ext/midori/extconf.rb +4 -0
- data/ext/midori/websocket.c +32 -0
- data/lib/midori/api.rb +426 -0
- data/lib/midori/api_engine.rb +109 -0
- data/lib/midori/clean_room.rb +24 -0
- data/lib/midori/configure.rb +12 -0
- data/lib/midori/connection.rb +59 -0
- data/lib/midori/const.rb +118 -0
- data/lib/midori/core_ext/configurable.rb +33 -0
- data/lib/midori/core_ext/define_class.rb +29 -0
- data/lib/midori/core_ext/proc.rb +13 -0
- data/lib/midori/core_ext/string.rb +29 -0
- data/lib/midori/env.rb +18 -0
- data/lib/midori/eventsource.rb +20 -0
- data/lib/midori/exception.rb +22 -0
- data/lib/midori/logger.rb +15 -0
- data/lib/midori/middleware.rb +31 -0
- data/lib/midori/request.rb +115 -0
- data/lib/midori/response.rb +34 -0
- data/lib/midori/route.rb +20 -0
- data/lib/midori/runner.rb +63 -0
- data/lib/midori/sandbox.rb +46 -0
- data/lib/midori/server.rb +106 -0
- data/lib/midori/version.rb +5 -0
- data/lib/midori/websocket.rb +105 -0
- data/lib/midori.rb +37 -0
- data/midori.sublime-project +16 -0
- data/tutorial/README.md +11 -0
- data/tutorial/SUMMARY.md +28 -0
- data/tutorial/advanced/custom_extensions.md +0 -0
- data/tutorial/advanced/deploying_for_production.md +0 -0
- data/tutorial/advanced/error_handling.md +0 -0
- data/tutorial/advanced/rerl.md +0 -0
- data/tutorial/advanced/scaling_project.md +0 -0
- data/tutorial/advanced/unit_testing.md +0 -0
- data/tutorial/essentials/extensions.md +31 -0
- data/tutorial/essentials/getting_started.md +27 -0
- data/tutorial/essentials/installation.md +93 -0
- data/tutorial/essentials/middlewares.md +88 -0
- data/tutorial/essentials/request_handling.md +74 -0
- data/tutorial/essentials/routing.md +136 -0
- data/tutorial/essentials/runner.md +59 -0
- data/tutorial/meta/comparison_with_other_frameworks.md +0 -0
- data/tutorial/meta/join_the_midori_community.md +0 -0
- data/tutorial/meta/next_steps.md +0 -0
- metadata +155 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 710b54063e97c0088cb335bbf2c4719154f0e991
|
4
|
+
data.tar.gz: 0753fd460e35cc8c19e04b6c2ccb561e54d0db69
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a2190c4be4ba8bf93f23d89cb9efb5ed49d5886351689be6bdf2fa0d174d026fad10a13970fcc2a931ff2eb9a384b115615f6f3b2146dbfbb468281f0884f3e9
|
7
|
+
data.tar.gz: a5fa0332c7a506523700728b1970ef32fec0ed9b31c7d8f86d489734fdffcad4499a58ab591247d686769683f97d8d302e255cab8213265988c5f7416b900b56
|
data/.editorconfig
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2016-2017 HeckPsi Lab
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
|
3
|
+
VALUE Midori = Qnil;
|
4
|
+
VALUE MidoriWebSocket = Qnil;
|
5
|
+
|
6
|
+
void Init_midori_ext();
|
7
|
+
VALUE method_midori_websocket_mask(VALUE self, VALUE payload, VALUE mask);
|
8
|
+
|
9
|
+
void Init_midori_ext() {
|
10
|
+
Midori = rb_define_module("Midori");
|
11
|
+
MidoriWebSocket = rb_define_class_under(Midori, "WebSocket", rb_cObject);
|
12
|
+
rb_define_protected_method(MidoriWebSocket, "mask", method_midori_websocket_mask, 2);
|
13
|
+
}
|
14
|
+
|
15
|
+
VALUE method_midori_websocket_mask(VALUE self, VALUE payload, VALUE mask) {
|
16
|
+
long n = RARRAY_LEN(payload), i, p, m;
|
17
|
+
VALUE unmasked = rb_ary_new2(n);
|
18
|
+
|
19
|
+
int mask_array[] = {
|
20
|
+
NUM2INT(rb_ary_entry(mask, 0)),
|
21
|
+
NUM2INT(rb_ary_entry(mask, 1)),
|
22
|
+
NUM2INT(rb_ary_entry(mask, 2)),
|
23
|
+
NUM2INT(rb_ary_entry(mask, 3))
|
24
|
+
};
|
25
|
+
|
26
|
+
for (i = 0; i < n; i++) {
|
27
|
+
p = NUM2INT(rb_ary_entry(payload, i));
|
28
|
+
m = mask_array[i % 4];
|
29
|
+
rb_ary_store(unmasked, i, INT2NUM(p ^ m));
|
30
|
+
}
|
31
|
+
return unmasked;
|
32
|
+
}
|
data/lib/midori/api.rb
ADDED
@@ -0,0 +1,426 @@
|
|
1
|
+
##
|
2
|
+
# This class provides methods to be inherited as route definition.
|
3
|
+
class Midori::API
|
4
|
+
class << self
|
5
|
+
# @!attribute routes
|
6
|
+
# @return [Hash] merged routes defined in the instance
|
7
|
+
# @!attribute scope_middlewares
|
8
|
+
# @return [Array] global middlewares under the scope
|
9
|
+
attr_accessor :routes, :scope_middlewares
|
10
|
+
|
11
|
+
# Init private variables of class
|
12
|
+
# @return [nil] nil
|
13
|
+
def class_initialize
|
14
|
+
@routes = {}
|
15
|
+
Midori::Const::ROUTE_METHODS.map {|method| @routes[method] = []}
|
16
|
+
@routes[:MOUNT] = []
|
17
|
+
@scope_middlewares = []
|
18
|
+
@temp_middlewares = []
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
# Add DELETE method as a DSL for route definition
|
23
|
+
# @param [ String ] path Accepts as part of path in route definition
|
24
|
+
# @yield what to run when route matched
|
25
|
+
# @return [ nil ] nil
|
26
|
+
# @example String as router
|
27
|
+
# delete '/' do
|
28
|
+
# puts 'Hello World'
|
29
|
+
# end
|
30
|
+
def delete(path, &block) end
|
31
|
+
|
32
|
+
# Add GET method as a DSL for route definition
|
33
|
+
# @param [String] path Accepts as part of path in route definition
|
34
|
+
# @yield what to run when route matched
|
35
|
+
# @return [nil] nil
|
36
|
+
# @example String as router
|
37
|
+
# get '/' do
|
38
|
+
# puts 'Hello World'
|
39
|
+
# end
|
40
|
+
def get(path, &block) end
|
41
|
+
|
42
|
+
# Add HEAD method as a DSL for route definition
|
43
|
+
# @param [ String ] path Accepts as part of path in route definition
|
44
|
+
# @yield what to run when route matched
|
45
|
+
# @return [ nil ] nil
|
46
|
+
# @example String as router
|
47
|
+
# head '/' do
|
48
|
+
# puts 'Hello World'
|
49
|
+
# end
|
50
|
+
def head(path, &block) end
|
51
|
+
|
52
|
+
# Add POST method as a DSL for route definition
|
53
|
+
# @param [String] path Accepts as part of path in route definition
|
54
|
+
# @yield what to run when route matched
|
55
|
+
# @return [nil] nil
|
56
|
+
# @example String as router
|
57
|
+
# post '/' do
|
58
|
+
# puts 'Hello World'
|
59
|
+
# end
|
60
|
+
def post(path, &block) end
|
61
|
+
|
62
|
+
# Add PUT method as a DSL for route definition
|
63
|
+
# @param [String] path Accepts as part of path in route definition
|
64
|
+
# @yield what to run when route matched
|
65
|
+
# @return [nil] nil
|
66
|
+
# @example String as router
|
67
|
+
# put '/' do
|
68
|
+
# puts 'Hello World'
|
69
|
+
# end
|
70
|
+
def put(path, &block) end
|
71
|
+
|
72
|
+
# Add CONNECT method as a DSL for route definition
|
73
|
+
# @param [String] path Accepts as part of path in route definition
|
74
|
+
# @yield what to run when route matched
|
75
|
+
# @return [nil] nil
|
76
|
+
# @example String as router
|
77
|
+
# connect '/' do
|
78
|
+
# puts 'Hello World'
|
79
|
+
# end
|
80
|
+
def connect(path, &block) end
|
81
|
+
|
82
|
+
# Add OPTIONS method as a DSL for route definition
|
83
|
+
# @param [String] path Accepts as part of path in route definition
|
84
|
+
# @return [nil] nil
|
85
|
+
# @example String as router
|
86
|
+
# options '/' do
|
87
|
+
# puts 'Hello World'
|
88
|
+
# end
|
89
|
+
def options(path, &block) end
|
90
|
+
|
91
|
+
# Add TRACE method as a DSL for route definition
|
92
|
+
# @param [ String ] path Accepts as part of path in route definition
|
93
|
+
# @yield what to run when route matched
|
94
|
+
# @return [ nil ] nil
|
95
|
+
# @example String as router
|
96
|
+
# trace '/' do
|
97
|
+
# puts 'Hello World'
|
98
|
+
# end
|
99
|
+
def trace(path, &block) end
|
100
|
+
|
101
|
+
# Add COPY method as a DSL for route definition
|
102
|
+
# @param [ String ] path Accepts as part of path in route definition
|
103
|
+
# @yield what to run when route matched
|
104
|
+
# @return [ nil ] nil
|
105
|
+
# @example String as router
|
106
|
+
# copy '/' do
|
107
|
+
# puts 'Hello World'
|
108
|
+
# end
|
109
|
+
def copy(path, &block) end
|
110
|
+
|
111
|
+
# Add LOCK method as a DSL for route definition
|
112
|
+
# @param [ String ] path Accepts as part of path in route definition
|
113
|
+
# @yield what to run when route matched
|
114
|
+
# @return [ nil ] nil
|
115
|
+
# @example String as router
|
116
|
+
# lock '/' do
|
117
|
+
# puts 'Hello World'
|
118
|
+
# end
|
119
|
+
def lock(path, &block) end
|
120
|
+
|
121
|
+
# Add MKCOK method as a DSL for route definition
|
122
|
+
# @param [ String ] path Accepts as part of path in route definition
|
123
|
+
# @yield what to run when route matched
|
124
|
+
# @return [ nil ] nil
|
125
|
+
# @example String as router
|
126
|
+
# mkcol '/' do
|
127
|
+
# puts 'Hello World'
|
128
|
+
# end
|
129
|
+
def mkcol(path, &block) end
|
130
|
+
|
131
|
+
# Add MOVE method as a DSL for route definition
|
132
|
+
# @param [ String ] path Accepts as part of path in route definition
|
133
|
+
# @yield what to run when route matched
|
134
|
+
# @return [ nil ] nil
|
135
|
+
# @example String as router
|
136
|
+
# move '/' do
|
137
|
+
# puts 'Hello World'
|
138
|
+
# end
|
139
|
+
def move(path, &block) end
|
140
|
+
|
141
|
+
|
142
|
+
# Add PROPFIND method as a DSL for route definition
|
143
|
+
# @param [ String ] path Accepts as part of path in route definition
|
144
|
+
# @yield what to run when route matched
|
145
|
+
# @return [ nil ] nil
|
146
|
+
# @example String as router
|
147
|
+
# propfind '/' do
|
148
|
+
# puts 'Hello World'
|
149
|
+
# end
|
150
|
+
def propfind(path, &block) end
|
151
|
+
|
152
|
+
# Add PROPPATCH method as a DSL for route definition
|
153
|
+
# @param [ String ] path Accepts as part of path in route definition
|
154
|
+
# @yield what to run when route matched
|
155
|
+
# @return [ nil ] nil
|
156
|
+
# @example String as router
|
157
|
+
# proppatch '/' do
|
158
|
+
# puts 'Hello World'
|
159
|
+
# end
|
160
|
+
def proppatch(path, &block) end
|
161
|
+
|
162
|
+
# Add UNLOCK method as a DSL for route definition
|
163
|
+
# @param [ String ] path Accepts as part of path in route definition
|
164
|
+
# @yield what to run when route matched
|
165
|
+
# @return [ nil ] nil
|
166
|
+
# @example String as router
|
167
|
+
# unlock '/' do
|
168
|
+
# puts 'Hello World'
|
169
|
+
# end
|
170
|
+
def unlock(path, &block) end
|
171
|
+
|
172
|
+
# Add REPORT method as a DSL for route definition
|
173
|
+
# @param [ String ] path Accepts as part of path in route definition
|
174
|
+
# @yield what to run when route matched
|
175
|
+
# @return [ nil ] nil
|
176
|
+
# @example String as router
|
177
|
+
# report '/' do
|
178
|
+
# puts 'Hello World'
|
179
|
+
# end
|
180
|
+
def report(path, &block) end
|
181
|
+
|
182
|
+
# Add MKACTIVITY method as a DSL for route definition
|
183
|
+
# @param [ String ] path Accepts as part of path in route definition
|
184
|
+
# @yield what to run when route matched
|
185
|
+
# @return [ nil ] nil
|
186
|
+
# @example String as router
|
187
|
+
# mkactivity '/' do
|
188
|
+
# puts 'Hello World'
|
189
|
+
# end
|
190
|
+
def mkactivity(path, &block) end
|
191
|
+
|
192
|
+
# Add CHECKOUT method as a DSL for route definition
|
193
|
+
# @param [ String ] path Accepts as part of path in route definition
|
194
|
+
# @yield what to run when route matched
|
195
|
+
# @return [ nil ] nil
|
196
|
+
# @example String as router
|
197
|
+
# checkout '/' do
|
198
|
+
# puts 'Hello World'
|
199
|
+
# end
|
200
|
+
def checkout(path, &block) end
|
201
|
+
|
202
|
+
# Add MERGE method as a DSL for route definition
|
203
|
+
# @param [ String ] path Accepts as part of path in route definition
|
204
|
+
# @yield what to run when route matched
|
205
|
+
# @return [ nil ] nil
|
206
|
+
# @example String as router
|
207
|
+
# merge '/' do
|
208
|
+
# puts 'Hello World'
|
209
|
+
# end
|
210
|
+
def merge(path, &block) end
|
211
|
+
|
212
|
+
# Add M-SEARCH method as a DSL for route definition
|
213
|
+
# @param [ String ] path Accepts as part of path in route definition
|
214
|
+
# @yield what to run when route matched
|
215
|
+
# @return [ nil ] nil
|
216
|
+
# @example String as router
|
217
|
+
# msearch '/' do
|
218
|
+
# puts 'Hello World'
|
219
|
+
# end
|
220
|
+
def msearch(path, &block)
|
221
|
+
add_route(:'M-SEARCH', path, block)
|
222
|
+
end
|
223
|
+
|
224
|
+
# Add NOTIFY method as a DSL for route definition
|
225
|
+
# @param [ String ] path Accepts as part of path in route definition
|
226
|
+
# @yield what to run when route matched
|
227
|
+
# @return [ nil ] nil
|
228
|
+
# @example String as router
|
229
|
+
# notify '/' do
|
230
|
+
# puts 'Hello World'
|
231
|
+
# end
|
232
|
+
def notify(path, &block) end
|
233
|
+
|
234
|
+
# Add SUBSCRIBE method as a DSL for route definition
|
235
|
+
# @param [ String ] path Accepts as part of path in route definition
|
236
|
+
# @yield what to run when route matched
|
237
|
+
# @return [ nil ] nil
|
238
|
+
# @example String as router
|
239
|
+
# subscribe '/' do
|
240
|
+
# puts 'Hello World'
|
241
|
+
# end
|
242
|
+
def subscribe(path, &block) end
|
243
|
+
|
244
|
+
# Add UNSUBSCRIBE method as a DSL for route definition
|
245
|
+
# @param [ String ] path Accepts as part of path in route definition
|
246
|
+
# @yield what to run when route matched
|
247
|
+
# @return [ nil ] nil
|
248
|
+
# @example String as router
|
249
|
+
# unsubscribe '/' do
|
250
|
+
# puts 'Hello World'
|
251
|
+
# end
|
252
|
+
def unsubscribe(path, &block) end
|
253
|
+
|
254
|
+
# Add PATCH method as a DSL for route definition
|
255
|
+
# @param [ String ] path Accepts as part of path in route definition
|
256
|
+
# @yield what to run when route matched
|
257
|
+
# @return [ nil ] nil
|
258
|
+
# @example String as router
|
259
|
+
# patch '/' do
|
260
|
+
# puts 'Hello World'
|
261
|
+
# end
|
262
|
+
def patch(path, &block) end
|
263
|
+
|
264
|
+
# Add PURGE method as a DSL for route definition
|
265
|
+
# @param [ String ] path Accepts as part of path in route definition
|
266
|
+
# @yield what to run when route matched
|
267
|
+
# @return [ nil ] nil
|
268
|
+
# @example String as router
|
269
|
+
# purge '/' do
|
270
|
+
# puts 'Hello World'
|
271
|
+
# end
|
272
|
+
def purge(path, &block) end
|
273
|
+
|
274
|
+
# Add LINK method as a DSL for route definition
|
275
|
+
# @param [String] path Accepts as part of path in route definition
|
276
|
+
# @yield what to run when route matched
|
277
|
+
# @return [nil] nil
|
278
|
+
# @example String as router
|
279
|
+
# link '/' do
|
280
|
+
# puts 'Hello World'
|
281
|
+
# end
|
282
|
+
def link(path, &block) end
|
283
|
+
|
284
|
+
# Add UNLINK method as a DSL for route definition
|
285
|
+
# @param [String] path Accepts as part of path in route definition
|
286
|
+
# @yield what to run when route matched
|
287
|
+
# @return [nil] nil
|
288
|
+
# @example String as router
|
289
|
+
# unlink '/' do
|
290
|
+
# puts 'Hello World'
|
291
|
+
# end
|
292
|
+
def unlink(path, &block) end
|
293
|
+
|
294
|
+
# Add WEBSOCKET method as a DSL for route definition
|
295
|
+
# @param [String] path Accepts as part of path in route definition
|
296
|
+
# @yield what to run when route matched
|
297
|
+
# @return [nil] nil
|
298
|
+
# @example String as router
|
299
|
+
# websocket '/' do
|
300
|
+
# puts 'Hello World'
|
301
|
+
# end
|
302
|
+
def websocket(path, &block) end
|
303
|
+
|
304
|
+
# Add EVENTSOURCE method as a DSL for route definition
|
305
|
+
# @param [String] path Accepts as part of path in route definition
|
306
|
+
# @yield what to run when route matched
|
307
|
+
# @return [nil] nil
|
308
|
+
# @example String as router
|
309
|
+
# eventsource '/' do
|
310
|
+
# puts 'Hello World'
|
311
|
+
# end
|
312
|
+
def eventsource(path, &block) end
|
313
|
+
|
314
|
+
# Mount a route prefix with another API defined
|
315
|
+
# @param [String] prefix prefix of the route String
|
316
|
+
# @param [Class] api inherited from Midori::API
|
317
|
+
# @return [nil] nil
|
318
|
+
def mount(prefix, api)
|
319
|
+
raise ArgumentError if prefix == '/' # Cannot mount route API
|
320
|
+
@routes[:MOUNT] << [prefix, api]
|
321
|
+
nil
|
322
|
+
end
|
323
|
+
|
324
|
+
# Definitions for global error handler
|
325
|
+
# @param [Class] error Error class, must be inherited form StandardError
|
326
|
+
# @yield what to do to deal with error
|
327
|
+
# @yieldparam [StandardError] e the detailed error
|
328
|
+
# @example Basic Usage
|
329
|
+
# capture Midori::InternalError do |e|
|
330
|
+
# Midori::Response(500, {}, e.backtrace)
|
331
|
+
# end
|
332
|
+
def capture(error, &block)
|
333
|
+
Midori::Sandbox.add_rule(error, block)
|
334
|
+
nil
|
335
|
+
end
|
336
|
+
|
337
|
+
# Implementation of route DSL
|
338
|
+
# @param [String] method HTTP method
|
339
|
+
# @param [String, Regexp] path path definition
|
340
|
+
# @param [Proc] block process to run when route matched
|
341
|
+
# @return [nil] nil
|
342
|
+
private def add_route(method, path, block)
|
343
|
+
# Argument check
|
344
|
+
raise ArgumentError unless path.is_a?String
|
345
|
+
|
346
|
+
# Insert route to routes
|
347
|
+
route = Midori::Route.new(method, path, block)
|
348
|
+
route.middlewares = @scope_middlewares + @temp_middlewares
|
349
|
+
@routes[method] << route
|
350
|
+
|
351
|
+
# Clean up temp middleware
|
352
|
+
@temp_middlewares = []
|
353
|
+
nil
|
354
|
+
end
|
355
|
+
|
356
|
+
# Use a middleware in the all routes
|
357
|
+
# @param [Class] middleware Inherited from +Midori::Middleware+
|
358
|
+
# @return [nil] nil
|
359
|
+
def use(middleware, *args)
|
360
|
+
middleware = middleware.new(*args)
|
361
|
+
@scope_middlewares << middleware
|
362
|
+
nil
|
363
|
+
end
|
364
|
+
|
365
|
+
# Use a middleware in the next route
|
366
|
+
# @param [Class] middleware Inherited from +Midori::Middleware+
|
367
|
+
# @return [nil] nil
|
368
|
+
def filter(middleware, *args)
|
369
|
+
middleware = middleware.new(*args)
|
370
|
+
@temp_middlewares << middleware
|
371
|
+
nil
|
372
|
+
end
|
373
|
+
|
374
|
+
# Helper block for defining methods in APIs
|
375
|
+
# @param [Symbol] name name of the method
|
376
|
+
# @yield define what to run in CleanRoom
|
377
|
+
def helper(name, &block)
|
378
|
+
Midori::CleanRoom.class_exec do
|
379
|
+
define_method(name, &block)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
private def inherited(subclass)
|
384
|
+
subclass.class_initialize
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
# Constants of supported methods in route definition
|
389
|
+
METHODS = %w( delete
|
390
|
+
get
|
391
|
+
head
|
392
|
+
post
|
393
|
+
put
|
394
|
+
connect
|
395
|
+
options
|
396
|
+
trace
|
397
|
+
copy
|
398
|
+
lock
|
399
|
+
mkcol
|
400
|
+
move
|
401
|
+
propfind
|
402
|
+
proppatch
|
403
|
+
unlock
|
404
|
+
report
|
405
|
+
mkactivity
|
406
|
+
checkout
|
407
|
+
merge
|
408
|
+
notify
|
409
|
+
subscribe
|
410
|
+
unsubscribe
|
411
|
+
patch
|
412
|
+
purge
|
413
|
+
websocket
|
414
|
+
eventsource
|
415
|
+
).freeze
|
416
|
+
|
417
|
+
# Magics to fill DSL methods through dynamically class method definition
|
418
|
+
METHODS.each do |method|
|
419
|
+
define_singleton_method(method) do |*args, &block|
|
420
|
+
add_route(method.upcase.to_sym, args[0], block) # args[0]: path
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
singleton_class.send :alias_method, :ws, :websocket
|
425
|
+
singleton_class.send :alias_method, :es, :eventsource
|
426
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
##
|
2
|
+
# Merge and manage all APIs.
|
3
|
+
# @attr [Hash] routes A hash of all routes merged
|
4
|
+
class Midori::APIEngine
|
5
|
+
attr_accessor :routes
|
6
|
+
|
7
|
+
# Init an API Engine
|
8
|
+
# @param [Class] root_api API inherited from [Midori::API]
|
9
|
+
# @param [Symbol] type type mustermann support
|
10
|
+
def initialize(root_api, type = :sinatra)
|
11
|
+
@routes = {}
|
12
|
+
Midori::Const::ROUTE_METHODS.map {|method| @routes[method] = []}
|
13
|
+
@root_api = root_api
|
14
|
+
@type = type
|
15
|
+
@routes = merge('', root_api, [])
|
16
|
+
@routes.delete :MOUNT
|
17
|
+
@routes.each do |method|
|
18
|
+
method[1].each do |route|
|
19
|
+
route.path = Mustermann.new(route.path, type: type)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Merge all routes with a Depth-first search
|
25
|
+
private def merge(prefix, root_api, middlewares)
|
26
|
+
root_api.routes[:MOUNT].each do |mount|
|
27
|
+
root_api.routes.merge!(merge(mount[0], mount[1], root_api.scope_middlewares)) do |_key, old_val, new_val|
|
28
|
+
old_val + new_val
|
29
|
+
end
|
30
|
+
end
|
31
|
+
root_api.routes.delete :MOUNT
|
32
|
+
root_api.routes.each do |method|
|
33
|
+
method[1].each do |route|
|
34
|
+
route.path = prefix + route.path
|
35
|
+
route.middlewares = middlewares + route.middlewares
|
36
|
+
end
|
37
|
+
end
|
38
|
+
root_api.routes
|
39
|
+
end
|
40
|
+
|
41
|
+
# Process after receive data from client
|
42
|
+
# @param request [Midori::Request] Http Raw Request
|
43
|
+
# @param connection [Midori::Connection] A connection created by EventMachine
|
44
|
+
# @return [Midori::Response] Http Response
|
45
|
+
# @raise [Midori::Error::NotFound] If no route matched
|
46
|
+
def receive(request, connection = nil)
|
47
|
+
@routes[request.method].each do |route|
|
48
|
+
params = route.path.params(request.path)
|
49
|
+
next unless params # Skip if not matched
|
50
|
+
request.params = params
|
51
|
+
clean_room = Midori::CleanRoom.new(request)
|
52
|
+
if request.websocket?
|
53
|
+
# Send 101 Switching Protocol
|
54
|
+
connection.send_data Midori::Response.new(
|
55
|
+
status: 101,
|
56
|
+
header: Midori::APIEngine.websocket_header(request.header['Sec-WebSocket-Key']),
|
57
|
+
body: '')
|
58
|
+
connection.websocket.request = request
|
59
|
+
Midori::Sandbox.run(clean_room, route.function, connection.websocket)
|
60
|
+
return Midori::Response.new
|
61
|
+
elsif request.eventsource?
|
62
|
+
connection.send_data Midori::Response.new(
|
63
|
+
status: 200,
|
64
|
+
header: Midori::Const::EVENTSOURCE_HEADER)
|
65
|
+
Midori::Sandbox.run(clean_room, route.function, connection.eventsource)
|
66
|
+
return Midori::Response.new
|
67
|
+
else
|
68
|
+
request = middleware_exec(route.middlewares, clean_room, request)
|
69
|
+
return request if request.is_a? Midori::Response # Early stop
|
70
|
+
result = Midori::Sandbox.run(clean_room, route.function)
|
71
|
+
clean_room.body = result
|
72
|
+
response = result.is_a?(Midori::Response) ? result : clean_room.raw_response
|
73
|
+
response = middleware_exec(route.middlewares, clean_room, request, response)
|
74
|
+
return response
|
75
|
+
end
|
76
|
+
end
|
77
|
+
raise Midori::Exception::NotFound
|
78
|
+
end
|
79
|
+
|
80
|
+
# Return websocket header with given key
|
81
|
+
# @param [String] key 'Sec-WebSocket-Key' in request header
|
82
|
+
# @return [Hash] header
|
83
|
+
def self.websocket_header(key)
|
84
|
+
header = Midori::Const::WEBSOCKET_HEADER.clone
|
85
|
+
header['Sec-WebSocket-Accept'] = Digest::SHA1.base64digest(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
|
86
|
+
header
|
87
|
+
end
|
88
|
+
|
89
|
+
# Exec middlewares
|
90
|
+
private def middleware_exec(middlewares, clean_room, request, response=nil)
|
91
|
+
result = response.nil? ? request : response
|
92
|
+
middlewares.each do |middleware|
|
93
|
+
if response.nil?
|
94
|
+
result = Midori::Sandbox.run(
|
95
|
+
clean_room,
|
96
|
+
proc { |req| middleware.before(req) },
|
97
|
+
result)
|
98
|
+
else
|
99
|
+
result = Midori::Sandbox.run(
|
100
|
+
clean_room,
|
101
|
+
proc { |req, resp| middleware.after(req, resp) },
|
102
|
+
request,
|
103
|
+
result)
|
104
|
+
end
|
105
|
+
return result if response.nil? && result.is_a?(Midori::Response) # Early stop
|
106
|
+
end
|
107
|
+
result
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
##
|
2
|
+
# This class is used to be sandbox of requests processing.
|
3
|
+
# @attr [Integer] status HTTP response code
|
4
|
+
# @attr [Hash] header HTTP response header
|
5
|
+
# @attr [Object] body HTTP response body. String could is accepted by default, but could leave for further process with +Midori::Middleware+
|
6
|
+
# @attr [Midori::Request] request HTTP request
|
7
|
+
class Midori::CleanRoom
|
8
|
+
attr_accessor :status, :header, :body, :request
|
9
|
+
|
10
|
+
# Init a Cleanroom for running
|
11
|
+
# @param [Midori::Request] request HTTP request
|
12
|
+
def initialize(request)
|
13
|
+
@status = 200
|
14
|
+
@header = Midori::Const::DEFAULT_HEADER.clone
|
15
|
+
@body = ''
|
16
|
+
@request = request
|
17
|
+
end
|
18
|
+
|
19
|
+
# Generate response from variables inside +Midori::CleanRoom+
|
20
|
+
# @return [Midori::Response] midori response
|
21
|
+
def raw_response
|
22
|
+
Midori::Response.new(status: @status, header: @header, body: @body)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
##
|
2
|
+
# Default configuration of Midori, extends +Configurable+
|
3
|
+
class Midori::Configure
|
4
|
+
extend Configurable
|
5
|
+
|
6
|
+
set :logger, ::Logger.new(STDOUT)
|
7
|
+
set :protocol, :http
|
8
|
+
set :bind, '127.0.0.1'
|
9
|
+
set :port, 8080
|
10
|
+
set :route_type, :sinatra
|
11
|
+
set :before, proc {}
|
12
|
+
end
|