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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +9 -0
  3. data/LICENSE +21 -0
  4. data/ext/midori/extconf.rb +4 -0
  5. data/ext/midori/websocket.c +32 -0
  6. data/lib/midori/api.rb +426 -0
  7. data/lib/midori/api_engine.rb +109 -0
  8. data/lib/midori/clean_room.rb +24 -0
  9. data/lib/midori/configure.rb +12 -0
  10. data/lib/midori/connection.rb +59 -0
  11. data/lib/midori/const.rb +118 -0
  12. data/lib/midori/core_ext/configurable.rb +33 -0
  13. data/lib/midori/core_ext/define_class.rb +29 -0
  14. data/lib/midori/core_ext/proc.rb +13 -0
  15. data/lib/midori/core_ext/string.rb +29 -0
  16. data/lib/midori/env.rb +18 -0
  17. data/lib/midori/eventsource.rb +20 -0
  18. data/lib/midori/exception.rb +22 -0
  19. data/lib/midori/logger.rb +15 -0
  20. data/lib/midori/middleware.rb +31 -0
  21. data/lib/midori/request.rb +115 -0
  22. data/lib/midori/response.rb +34 -0
  23. data/lib/midori/route.rb +20 -0
  24. data/lib/midori/runner.rb +63 -0
  25. data/lib/midori/sandbox.rb +46 -0
  26. data/lib/midori/server.rb +106 -0
  27. data/lib/midori/version.rb +5 -0
  28. data/lib/midori/websocket.rb +105 -0
  29. data/lib/midori.rb +37 -0
  30. data/midori.sublime-project +16 -0
  31. data/tutorial/README.md +11 -0
  32. data/tutorial/SUMMARY.md +28 -0
  33. data/tutorial/advanced/custom_extensions.md +0 -0
  34. data/tutorial/advanced/deploying_for_production.md +0 -0
  35. data/tutorial/advanced/error_handling.md +0 -0
  36. data/tutorial/advanced/rerl.md +0 -0
  37. data/tutorial/advanced/scaling_project.md +0 -0
  38. data/tutorial/advanced/unit_testing.md +0 -0
  39. data/tutorial/essentials/extensions.md +31 -0
  40. data/tutorial/essentials/getting_started.md +27 -0
  41. data/tutorial/essentials/installation.md +93 -0
  42. data/tutorial/essentials/middlewares.md +88 -0
  43. data/tutorial/essentials/request_handling.md +74 -0
  44. data/tutorial/essentials/routing.md +136 -0
  45. data/tutorial/essentials/runner.md +59 -0
  46. data/tutorial/meta/comparison_with_other_frameworks.md +0 -0
  47. data/tutorial/meta/join_the_midori_community.md +0 -0
  48. data/tutorial/meta/next_steps.md +0 -0
  49. 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
@@ -0,0 +1,9 @@
1
+ root = true
2
+
3
+ [*]
4
+ end_of_line = lf
5
+ insert_final_newline = true
6
+
7
+ [*.rb]
8
+ indent_style = space
9
+ indent_size = 2
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,4 @@
1
+ require 'mkmf'
2
+ extension_name = 'midori_ext'
3
+ dir_config(extension_name)
4
+ create_makefile(extension_name)
@@ -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