midori.rb 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
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