isomorfeus-iodine 0.7.44

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  3. data/.gitignore +20 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +32 -0
  6. data/.yardopts +8 -0
  7. data/CHANGELOG.md +1038 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE.txt +21 -0
  10. data/LIMITS.md +41 -0
  11. data/README.md +782 -0
  12. data/Rakefile +44 -0
  13. data/SPEC-PubSub-Draft.md +159 -0
  14. data/SPEC-WebSocket-Draft.md +239 -0
  15. data/bin/console +22 -0
  16. data/bin/info.md +353 -0
  17. data/bin/mustache_bench.rb +100 -0
  18. data/bin/poc/Gemfile.lock +23 -0
  19. data/bin/poc/README.md +37 -0
  20. data/bin/poc/config.ru +66 -0
  21. data/bin/poc/gemfile +1 -0
  22. data/bin/poc/www/index.html +57 -0
  23. data/examples/async_task.ru +92 -0
  24. data/examples/config.ru +56 -0
  25. data/examples/echo.ru +59 -0
  26. data/examples/hello.ru +29 -0
  27. data/examples/pubsub_engine.ru +81 -0
  28. data/examples/redis.ru +70 -0
  29. data/examples/shootout.ru +73 -0
  30. data/examples/sub-protocols.ru +90 -0
  31. data/examples/tcp_client.rb +66 -0
  32. data/examples/x-sendfile.ru +14 -0
  33. data/exe/iodine +277 -0
  34. data/ext/iodine/extconf.rb +109 -0
  35. data/ext/iodine/fio.c +11985 -0
  36. data/ext/iodine/fio.h +6373 -0
  37. data/ext/iodine/fio_cli.c +431 -0
  38. data/ext/iodine/fio_cli.h +189 -0
  39. data/ext/iodine/fio_json_parser.h +687 -0
  40. data/ext/iodine/fio_siphash.c +157 -0
  41. data/ext/iodine/fio_siphash.h +37 -0
  42. data/ext/iodine/fio_tls.h +129 -0
  43. data/ext/iodine/fio_tls_missing.c +649 -0
  44. data/ext/iodine/fio_tls_openssl.c +1056 -0
  45. data/ext/iodine/fio_tmpfile.h +50 -0
  46. data/ext/iodine/fiobj.h +44 -0
  47. data/ext/iodine/fiobj4fio.h +21 -0
  48. data/ext/iodine/fiobj_ary.c +333 -0
  49. data/ext/iodine/fiobj_ary.h +139 -0
  50. data/ext/iodine/fiobj_data.c +1185 -0
  51. data/ext/iodine/fiobj_data.h +167 -0
  52. data/ext/iodine/fiobj_hash.c +409 -0
  53. data/ext/iodine/fiobj_hash.h +176 -0
  54. data/ext/iodine/fiobj_json.c +622 -0
  55. data/ext/iodine/fiobj_json.h +68 -0
  56. data/ext/iodine/fiobj_mem.h +71 -0
  57. data/ext/iodine/fiobj_mustache.c +317 -0
  58. data/ext/iodine/fiobj_mustache.h +62 -0
  59. data/ext/iodine/fiobj_numbers.c +344 -0
  60. data/ext/iodine/fiobj_numbers.h +127 -0
  61. data/ext/iodine/fiobj_str.c +433 -0
  62. data/ext/iodine/fiobj_str.h +172 -0
  63. data/ext/iodine/fiobject.c +620 -0
  64. data/ext/iodine/fiobject.h +654 -0
  65. data/ext/iodine/hpack.h +1923 -0
  66. data/ext/iodine/http.c +2754 -0
  67. data/ext/iodine/http.h +1002 -0
  68. data/ext/iodine/http1.c +912 -0
  69. data/ext/iodine/http1.h +29 -0
  70. data/ext/iodine/http1_parser.h +873 -0
  71. data/ext/iodine/http_internal.c +1278 -0
  72. data/ext/iodine/http_internal.h +237 -0
  73. data/ext/iodine/http_mime_parser.h +350 -0
  74. data/ext/iodine/iodine.c +1430 -0
  75. data/ext/iodine/iodine.h +63 -0
  76. data/ext/iodine/iodine_caller.c +218 -0
  77. data/ext/iodine/iodine_caller.h +27 -0
  78. data/ext/iodine/iodine_connection.c +933 -0
  79. data/ext/iodine/iodine_connection.h +55 -0
  80. data/ext/iodine/iodine_defer.c +420 -0
  81. data/ext/iodine/iodine_defer.h +6 -0
  82. data/ext/iodine/iodine_fiobj2rb.h +120 -0
  83. data/ext/iodine/iodine_helpers.c +282 -0
  84. data/ext/iodine/iodine_helpers.h +12 -0
  85. data/ext/iodine/iodine_http.c +1171 -0
  86. data/ext/iodine/iodine_http.h +23 -0
  87. data/ext/iodine/iodine_json.c +302 -0
  88. data/ext/iodine/iodine_json.h +6 -0
  89. data/ext/iodine/iodine_mustache.c +567 -0
  90. data/ext/iodine/iodine_mustache.h +6 -0
  91. data/ext/iodine/iodine_pubsub.c +580 -0
  92. data/ext/iodine/iodine_pubsub.h +26 -0
  93. data/ext/iodine/iodine_rack_io.c +281 -0
  94. data/ext/iodine/iodine_rack_io.h +20 -0
  95. data/ext/iodine/iodine_store.c +142 -0
  96. data/ext/iodine/iodine_store.h +20 -0
  97. data/ext/iodine/iodine_tcp.c +346 -0
  98. data/ext/iodine/iodine_tcp.h +13 -0
  99. data/ext/iodine/iodine_tls.c +261 -0
  100. data/ext/iodine/iodine_tls.h +13 -0
  101. data/ext/iodine/mustache_parser.h +1546 -0
  102. data/ext/iodine/redis_engine.c +957 -0
  103. data/ext/iodine/redis_engine.h +79 -0
  104. data/ext/iodine/resp_parser.h +317 -0
  105. data/ext/iodine/websocket_parser.h +505 -0
  106. data/ext/iodine/websockets.c +735 -0
  107. data/ext/iodine/websockets.h +185 -0
  108. data/isomorfeus-iodine.gemspec +42 -0
  109. data/lib/iodine/connection.rb +61 -0
  110. data/lib/iodine/json.rb +42 -0
  111. data/lib/iodine/mustache.rb +113 -0
  112. data/lib/iodine/pubsub.rb +55 -0
  113. data/lib/iodine/rack_utils.rb +43 -0
  114. data/lib/iodine/tls.rb +16 -0
  115. data/lib/iodine/version.rb +3 -0
  116. data/lib/iodine.rb +274 -0
  117. data/lib/rack/handler/iodine.rb +33 -0
  118. data/logo.png +0 -0
  119. metadata +271 -0
data/exe/iodine ADDED
@@ -0,0 +1,277 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ IODINE_PARSE_CLI = true
4
+ require 'iodine'
5
+
6
+ # Load Rack if available (assume it will be used).
7
+ #
8
+ # Remember, code costs memory. Duplicating the Rack::Builder module and functions can be avoided.
9
+ begin
10
+ require 'rack'
11
+ module Iodine
12
+ module Base
13
+ module Rack
14
+ Builder = ::Rack::Builder
15
+ end
16
+ end
17
+ end
18
+ rescue LoadError
19
+ module Iodine
20
+ module Base
21
+ module Rack
22
+ # The Rack::Builder code is used when Rack isn't available.
23
+ #
24
+ # The code was copied (with minor adjustments) from the Rack source code and is licensed under the MIT license.
25
+ # Copyright (C) 2007-2019 Leah Neukirchen <http://leahneukirchen.org/infopage.html>
26
+ #
27
+ # ====
28
+ #
29
+ # Rack::Builder implements a small DSL to iteratively construct Rack
30
+ # applications.
31
+ #
32
+ # Example:
33
+ #
34
+ # require 'rack/lobster'
35
+ # app = Rack::Builder.new do
36
+ # use Rack::CommonLogger
37
+ # use Rack::ShowExceptions
38
+ # map "/lobster" do
39
+ # use Rack::Lint
40
+ # run Rack::Lobster.new
41
+ # end
42
+ # end
43
+ #
44
+ # run app
45
+ #
46
+ # Or
47
+ #
48
+ # app = Rack::Builder.app do
49
+ # use Rack::CommonLogger
50
+ # run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['OK']] }
51
+ # end
52
+ #
53
+ # run app
54
+ #
55
+ # +use+ adds middleware to the stack, +run+ dispatches to an application.
56
+ # You can use +map+ to construct a Rack::URLMap in a convenient way.
57
+ class Builder
58
+ # https://stackoverflow.com/questions/2223882/whats-the-difference-between-utf-8-and-utf-8-without-bom
59
+ UTF_8_BOM = '\xef\xbb\xbf'
60
+
61
+ def self.parse_file(config, opts = Hash.new)
62
+ if config =~ /\.ru$/
63
+ return self.load_file(config, opts)
64
+ else
65
+ require config
66
+ app = Object.const_get(::File.basename(config, '.rb').split('_').map(&:capitalize).join(''))
67
+ return app, {}
68
+ end
69
+ end
70
+
71
+ def self.load_file(path, options = Hash.new)
72
+ cfgfile = ::File.read(path)
73
+ cfgfile.slice!(/\A#{UTF_8_BOM}/) if cfgfile.encoding == Encoding::UTF_8
74
+
75
+ cfgfile.sub!(/^__END__\n.*\Z/m, '')
76
+ app = new_from_string cfgfile, path
77
+
78
+ return app, options
79
+ end
80
+
81
+ def self.new_from_string(builder_script, file = "(rackup)")
82
+ eval "Iodine::Base::Rack::Builder.new {\n" + builder_script + "\n}.to_app",
83
+ TOPLEVEL_BINDING, file, 0
84
+ end
85
+
86
+ def initialize(default_app = nil, &block)
87
+ @use, @map, @run, @warmup, @freeze_app = [], nil, default_app, nil, false
88
+ instance_eval(&block) if block_given?
89
+ end
90
+
91
+ def self.app(default_app = nil, &block)
92
+ self.new(default_app, &block).to_app
93
+ end
94
+
95
+ # Specifies middleware to use in a stack.
96
+ #
97
+ # class Middleware
98
+ # def initialize(app)
99
+ # @app = app
100
+ # end
101
+ #
102
+ # def call(env)
103
+ # env["rack.some_header"] = "setting an example"
104
+ # @app.call(env)
105
+ # end
106
+ # end
107
+ #
108
+ # use Middleware
109
+ # run lambda { |env| [200, { "Content-Type" => "text/plain" }, ["OK"]] }
110
+ #
111
+ # All requests through to this application will first be processed by the middleware class.
112
+ # The +call+ method in this example sets an additional environment key which then can be
113
+ # referenced in the application if required.
114
+ def use(middleware, *args, &block)
115
+ if @map
116
+ mapping, @map = @map, nil
117
+ @use << proc { |app| generate_map(app, mapping) }
118
+ end
119
+ @use << proc { |app| middleware.new(app, *args, &block) }
120
+ end
121
+
122
+ # Takes an argument that is an object that responds to #call and returns a Rack response.
123
+ # The simplest form of this is a lambda object:
124
+ #
125
+ # run lambda { |env| [200, { "Content-Type" => "text/plain" }, ["OK"]] }
126
+ #
127
+ # However this could also be a class:
128
+ #
129
+ # class Heartbeat
130
+ # def self.call(env)
131
+ # [200, { "Content-Type" => "text/plain" }, ["OK"]]
132
+ # end
133
+ # end
134
+ #
135
+ # run Heartbeat
136
+ def run(app)
137
+ @run = app
138
+ end
139
+
140
+ # Takes a lambda or block that is used to warm-up the application.
141
+ #
142
+ # warmup do |app|
143
+ # client = Rack::MockRequest.new(app)
144
+ # client.get('/')
145
+ # end
146
+ #
147
+ # use SomeMiddleware
148
+ # run MyApp
149
+ def warmup(prc = nil, &block)
150
+ @warmup = prc || block
151
+ end
152
+
153
+ # Creates a route within the application.
154
+ #
155
+ # Rack::Builder.app do
156
+ # map '/' do
157
+ # run Heartbeat
158
+ # end
159
+ # end
160
+ #
161
+ # The +use+ method can also be used here to specify middleware to run under a specific path:
162
+ #
163
+ # Rack::Builder.app do
164
+ # map '/' do
165
+ # use Middleware
166
+ # run Heartbeat
167
+ # end
168
+ # end
169
+ #
170
+ # This example includes a piece of middleware which will run before requests hit +Heartbeat+.
171
+ #
172
+ def map(path, &block)
173
+ @map ||= {}
174
+ @map[path] = block
175
+ end
176
+
177
+ # Freeze the app (set using run) and all middleware instances when building the application
178
+ # in to_app.
179
+ def freeze_app
180
+ @freeze_app = true
181
+ end
182
+
183
+ def to_app
184
+ app = @map ? generate_map(@run, @map) : @run
185
+ fail "missing run or map statement" unless app
186
+ app.freeze if @freeze_app
187
+ app = @use.reverse.inject(app) { |a, e| e[a].tap { |x| x.freeze if @freeze_app } }
188
+ @warmup.call(app) if @warmup
189
+ app
190
+ end
191
+
192
+ def call(env)
193
+ to_app.call(env)
194
+ end
195
+
196
+ private
197
+
198
+ def generate_map(default_app, mapping)
199
+ mapped = default_app ? { '/' => default_app } : {}
200
+ mapping.each { |r, b| mapped[r] = self.class.new(default_app, &b).to_app }
201
+ URLMap.new(mapped)
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ module Iodine
210
+ # The Iodine::Base namespace is reserved for internal use and is NOT part of the public API.
211
+ module Base
212
+ # Command line interface. The Ruby CLI might be changed in future versions.
213
+ module CLI
214
+
215
+ def self.try_file filename
216
+ return nil unless File.exist? filename
217
+ return Iodine::Base::Rack::Builder.parse_file filename
218
+ end
219
+
220
+ def self.get_app_opts
221
+ app, opt = nil, nil
222
+ filename = Iodine::DEFAULT_SETTINGS[:filename_]
223
+ if filename
224
+ app, opt = try_file filename
225
+ app, opt = try_file "#{filename}.ru" unless opt
226
+ unless opt
227
+ puts "* Couldn't find #{filename}\n testing for config.ru\n"
228
+ app, opt = try_file "config.ru"
229
+ end
230
+ else
231
+ app, opt = try_file "config.ru";
232
+ end
233
+
234
+ unless opt
235
+ puts "WARNING: Ruby application not found#{ filename ? " - missing both #{filename} and config.ru" : " - missing config.ru"}."
236
+ if Iodine::DEFAULT_SETTINGS[:public]
237
+ puts " Running only static file service."
238
+ opt = Hash.new
239
+ app = Proc.new { [404, {}, "Not Found!"] }
240
+ else
241
+ puts "\nERROR: Couldn't run Ruby application, check command line arguments."
242
+ ARGV << "-?"
243
+ Iodine::Base::CLI.parse
244
+ exit(0);
245
+ end
246
+ end
247
+ return app, opt
248
+ end
249
+
250
+ def self.perform_warmup(app)
251
+ # load anything marked with `autoload`, since autoload is niether thread safe nor fork friendly.
252
+ Iodine.on_state(:on_start) do
253
+ Module.constants.each do |n|
254
+ begin
255
+ Object.const_get(n)
256
+ rescue StandardError => _e
257
+ end
258
+ end
259
+ Iodine::Base::Rack::Builder.new(app) do |r|
260
+ r.warmup do |a|
261
+ client = ::Rack::MockRequest.new(a)
262
+ client.get('/')
263
+ end
264
+ end
265
+ end
266
+ end
267
+
268
+ def self.call
269
+ app, opt = get_app_opts
270
+ perform_warmup(app) if Iodine::DEFAULT_SETTINGS[:warmup_]
271
+ Iodine::Rack.run(app, opt)
272
+ end
273
+ end
274
+ end
275
+ end
276
+
277
+ Iodine::Base::CLI.call
@@ -0,0 +1,109 @@
1
+ require 'mkmf'
2
+
3
+ # Test polling
4
+ def iodine_test_polling_support
5
+ iodine_poll_test_kqueue = <<EOS
6
+ \#define _GNU_SOURCE
7
+ \#include <stdlib.h>
8
+ \#include <sys/event.h>
9
+ int main(void) {
10
+ int fd = kqueue();
11
+ }
12
+ EOS
13
+
14
+ iodine_poll_test_epoll = <<EOS
15
+ \#define _GNU_SOURCE
16
+ \#include <stdlib.h>
17
+ \#include <stdio.h>
18
+ \#include <sys/types.h>
19
+ \#include <sys/stat.h>
20
+ \#include <fcntl.h>
21
+ \#include <sys/epoll.h>
22
+ int main(void) {
23
+ int fd = epoll_create1(EPOLL_CLOEXEC);
24
+ }
25
+ EOS
26
+
27
+ iodine_poll_test_poll = <<EOS
28
+ \#define _GNU_SOURCE
29
+ \#include <stdlib.h>
30
+ \#include <poll.h>
31
+ int main(void) {
32
+ struct pollfd plist[18];
33
+ memset(plist, 0, sizeof(plist[0]) * 18);
34
+ poll(plist, 1, 1);
35
+ }
36
+ EOS
37
+
38
+ # Test for manual selection and then TRY_COMPILE with each polling engine
39
+ if Gem.win_platform?
40
+ puts "skipping polling tests, using WSAPOLL on Windows"
41
+ $defs << "-DFIO_ENGINE_WSAPOLL"
42
+ elsif ENV['FIO_POLL']
43
+ puts "skipping polling tests, enforcing manual selection of: poll"
44
+ $defs << "-DFIO_ENGINE_POLL"
45
+ elsif ENV['FIO_FORCE_POLL']
46
+ puts "skipping polling tests, enforcing manual selection of: poll"
47
+ $defs << "-DFIO_ENGINE_POLL"
48
+ elsif ENV['FIO_FORCE_EPOLL']
49
+ puts "skipping polling tests, enforcing manual selection of: epoll"
50
+ $defs << "-DFIO_ENGINE_EPOLL"
51
+ elsif ENV['FIO_FORCE_KQUEUE']
52
+ puts "* Skipping polling tests, enforcing manual selection of: kqueue"
53
+ $defs << "-DFIO_ENGINE_KQUEUE"
54
+ elsif try_compile(iodine_poll_test_epoll)
55
+ puts "detected `epoll`"
56
+ $defs << "-DFIO_ENGINE_EPOLL"
57
+ elsif try_compile(iodine_poll_test_kqueue)
58
+ puts "detected `kqueue`"
59
+ $defs << "-DFIO_ENGINE_KQUEUE"
60
+ elsif try_compile(iodine_poll_test_poll)
61
+ puts "detected `poll` - this is suboptimal fallback!"
62
+ $defs << "-DFIO_ENGINE_POLL"
63
+ else
64
+ puts "* WARNING: No supported polling engine! expecting compilation to fail."
65
+ end
66
+ end
67
+
68
+ iodine_test_polling_support()
69
+
70
+ unless Gem.win_platform?
71
+ # Test for OpenSSL version equal to 1.0.0 or greater.
72
+ unless ENV['NO_SSL'] || ENV['NO_TLS'] || ENV["DISABLE_SSL"]
73
+ OPENSSL_TEST_CODE = <<EOS
74
+ \#include <openssl/bio.h>
75
+ \#include <openssl/err.h>
76
+ \#include <openssl/ssl.h>
77
+ \#if OPENSSL_VERSION_NUMBER < 0x10100000L
78
+ \#error "OpenSSL version too small"
79
+ \#endif
80
+ int main(void) {
81
+ SSL_library_init();
82
+ SSL_CTX *ctx = SSL_CTX_new(TLS_method());
83
+ SSL *ssl = SSL_new(ctx);
84
+ BIO *bio = BIO_new_socket(3, 0);
85
+ BIO_up_ref(bio);
86
+ SSL_set0_rbio(ssl, bio);
87
+ SSL_set0_wbio(ssl, bio);
88
+ }
89
+ EOS
90
+
91
+ dir_config("openssl")
92
+ begin
93
+ require 'openssl'
94
+ rescue LoadError
95
+ else
96
+ if have_library('crypto') && have_library('ssl')
97
+ puts "detected OpenSSL library, testing for version and required functions."
98
+ if try_compile(OPENSSL_TEST_CODE)
99
+ $defs << "-DHAVE_OPENSSL"
100
+ puts "confirmed OpenSSL to be version 1.1.0 or above (#{OpenSSL::OPENSSL_LIBRARY_VERSION})...\n* compiling with HAVE_OPENSSL."
101
+ else
102
+ puts "FAILED: OpenSSL version not supported (#{OpenSSL::OPENSSL_LIBRARY_VERSION} is too old)."
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ create_makefile 'iodine/iodine'