iodine 0.4.19 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -2
  3. data/CHANGELOG.md +22 -0
  4. data/LIMITS.md +19 -9
  5. data/README.md +92 -77
  6. data/SPEC-PubSub-Draft.md +113 -0
  7. data/SPEC-Websocket-Draft.md +127 -143
  8. data/bin/http-hello +0 -1
  9. data/bin/raw-rbhttp +1 -1
  10. data/bin/raw_broadcast +8 -10
  11. data/bin/updated api +2 -2
  12. data/bin/ws-broadcast +2 -4
  13. data/bin/ws-echo +2 -2
  14. data/examples/config.ru +13 -13
  15. data/examples/echo.ru +5 -6
  16. data/examples/hello.ru +2 -3
  17. data/examples/info.md +316 -0
  18. data/examples/pubsub_engine.ru +81 -0
  19. data/examples/redis.ru +9 -9
  20. data/examples/shootout.ru +45 -11
  21. data/ext/iodine/defer.c +194 -297
  22. data/ext/iodine/defer.h +61 -53
  23. data/ext/iodine/evio.c +0 -260
  24. data/ext/iodine/evio.h +50 -22
  25. data/ext/iodine/evio_callbacks.c +26 -0
  26. data/ext/iodine/evio_epoll.c +251 -0
  27. data/ext/iodine/evio_kqueue.c +193 -0
  28. data/ext/iodine/extconf.rb +1 -1
  29. data/ext/iodine/facil.c +1420 -542
  30. data/ext/iodine/facil.h +151 -64
  31. data/ext/iodine/fio_ary.h +418 -0
  32. data/ext/iodine/{base64.c → fio_base64.c} +33 -24
  33. data/ext/iodine/{base64.h → fio_base64.h} +6 -7
  34. data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
  35. data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
  36. data/ext/iodine/fio_hashmap.h +759 -0
  37. data/ext/iodine/fio_json_parser.h +651 -0
  38. data/ext/iodine/fio_llist.h +257 -0
  39. data/ext/iodine/fio_mem.c +672 -0
  40. data/ext/iodine/fio_mem.h +140 -0
  41. data/ext/iodine/fio_random.c +248 -0
  42. data/ext/iodine/{random.h → fio_random.h} +11 -14
  43. data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
  44. data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
  45. data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
  46. data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
  47. data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
  48. data/ext/iodine/fio_siphash.h +18 -0
  49. data/ext/iodine/fio_tmpfile.h +38 -0
  50. data/ext/iodine/fiobj.h +24 -7
  51. data/ext/iodine/fiobj4sock.h +23 -0
  52. data/ext/iodine/fiobj_ary.c +143 -226
  53. data/ext/iodine/fiobj_ary.h +17 -16
  54. data/ext/iodine/fiobj_data.c +1160 -0
  55. data/ext/iodine/fiobj_data.h +164 -0
  56. data/ext/iodine/fiobj_hash.c +298 -406
  57. data/ext/iodine/fiobj_hash.h +101 -54
  58. data/ext/iodine/fiobj_json.c +478 -601
  59. data/ext/iodine/fiobj_json.h +34 -9
  60. data/ext/iodine/fiobj_numbers.c +383 -51
  61. data/ext/iodine/fiobj_numbers.h +87 -11
  62. data/ext/iodine/fiobj_str.c +423 -184
  63. data/ext/iodine/fiobj_str.h +81 -32
  64. data/ext/iodine/fiobject.c +273 -522
  65. data/ext/iodine/fiobject.h +477 -112
  66. data/ext/iodine/http.c +2243 -83
  67. data/ext/iodine/http.h +842 -121
  68. data/ext/iodine/http1.c +810 -385
  69. data/ext/iodine/http1.h +16 -39
  70. data/ext/iodine/http1_parser.c +146 -74
  71. data/ext/iodine/http1_parser.h +15 -4
  72. data/ext/iodine/http_internal.c +1258 -0
  73. data/ext/iodine/http_internal.h +226 -0
  74. data/ext/iodine/http_mime_parser.h +341 -0
  75. data/ext/iodine/iodine.c +86 -68
  76. data/ext/iodine/iodine.h +26 -11
  77. data/ext/iodine/iodine_helpers.c +8 -7
  78. data/ext/iodine/iodine_http.c +487 -324
  79. data/ext/iodine/iodine_json.c +304 -0
  80. data/ext/iodine/iodine_json.h +6 -0
  81. data/ext/iodine/iodine_protocol.c +107 -45
  82. data/ext/iodine/iodine_pubsub.c +526 -225
  83. data/ext/iodine/iodine_pubsub.h +10 -0
  84. data/ext/iodine/iodine_websockets.c +268 -510
  85. data/ext/iodine/iodine_websockets.h +2 -4
  86. data/ext/iodine/pubsub.c +726 -432
  87. data/ext/iodine/pubsub.h +85 -103
  88. data/ext/iodine/rb-call.c +4 -4
  89. data/ext/iodine/rb-defer.c +46 -22
  90. data/ext/iodine/rb-fiobj2rb.h +117 -0
  91. data/ext/iodine/rb-rack-io.c +73 -238
  92. data/ext/iodine/rb-rack-io.h +2 -2
  93. data/ext/iodine/rb-registry.c +35 -93
  94. data/ext/iodine/rb-registry.h +1 -0
  95. data/ext/iodine/redis_engine.c +742 -304
  96. data/ext/iodine/redis_engine.h +42 -39
  97. data/ext/iodine/resp_parser.h +311 -0
  98. data/ext/iodine/sock.c +627 -490
  99. data/ext/iodine/sock.h +345 -297
  100. data/ext/iodine/spnlock.inc +15 -4
  101. data/ext/iodine/websocket_parser.h +16 -20
  102. data/ext/iodine/websockets.c +188 -257
  103. data/ext/iodine/websockets.h +24 -133
  104. data/lib/iodine.rb +52 -7
  105. data/lib/iodine/cli.rb +6 -24
  106. data/lib/iodine/json.rb +40 -0
  107. data/lib/iodine/version.rb +1 -1
  108. data/lib/iodine/websocket.rb +5 -3
  109. data/lib/rack/handler/iodine.rb +58 -13
  110. metadata +38 -48
  111. data/bin/ws-shootout +0 -107
  112. data/examples/broadcast.ru +0 -56
  113. data/ext/iodine/bscrypt-common.h +0 -116
  114. data/ext/iodine/bscrypt.h +0 -49
  115. data/ext/iodine/fio2resp.c +0 -60
  116. data/ext/iodine/fio2resp.h +0 -51
  117. data/ext/iodine/fio_dict.c +0 -446
  118. data/ext/iodine/fio_dict.h +0 -99
  119. data/ext/iodine/fio_hash_table.h +0 -370
  120. data/ext/iodine/fio_list.h +0 -111
  121. data/ext/iodine/fiobj_internal.h +0 -280
  122. data/ext/iodine/fiobj_primitives.c +0 -131
  123. data/ext/iodine/fiobj_primitives.h +0 -55
  124. data/ext/iodine/fiobj_sym.c +0 -135
  125. data/ext/iodine/fiobj_sym.h +0 -60
  126. data/ext/iodine/hex.c +0 -124
  127. data/ext/iodine/hex.h +0 -70
  128. data/ext/iodine/http1_request.c +0 -81
  129. data/ext/iodine/http1_request.h +0 -58
  130. data/ext/iodine/http1_response.c +0 -417
  131. data/ext/iodine/http1_response.h +0 -95
  132. data/ext/iodine/http_request.c +0 -111
  133. data/ext/iodine/http_request.h +0 -102
  134. data/ext/iodine/http_response.c +0 -1703
  135. data/ext/iodine/http_response.h +0 -250
  136. data/ext/iodine/misc.c +0 -182
  137. data/ext/iodine/misc.h +0 -74
  138. data/ext/iodine/random.c +0 -208
  139. data/ext/iodine/redis_connection.c +0 -278
  140. data/ext/iodine/redis_connection.h +0 -86
  141. data/ext/iodine/resp.c +0 -842
  142. data/ext/iodine/resp.h +0 -261
  143. data/ext/iodine/siphash.c +0 -154
  144. data/ext/iodine/siphash.h +0 -22
  145. data/ext/iodine/xor-crypt.c +0 -193
  146. data/ext/iodine/xor-crypt.h +0 -107
@@ -1,11 +1,11 @@
1
1
  /*
2
- copyright: Boaz segev, 2016-2017
2
+ copyright: Boaz Segev, 2016-2018
3
3
  license: MIT
4
4
 
5
5
  Feel free to copy, use and enjoy according to the license provided.
6
6
  */
7
- #ifndef WEBSOCKETS_H
8
- #define WEBSOCKETS_H
7
+ #ifndef H_WEBSOCKETS_H
8
+ #define H_WEBSOCKETS_H
9
9
 
10
10
  #include "http.h"
11
11
 
@@ -14,109 +14,14 @@ Feel free to copy, use and enjoy according to the license provided.
14
14
  extern "C" {
15
15
  #endif
16
16
 
17
- /* *****************************************************************************
18
- Upgrading from HTTP to Websockets
19
- ***************************************************************************** */
20
-
21
- /**
22
- The Websocket type is an opaque type used by the websocket API to provide
23
- identify a specific Websocket connection and manage it's internal state.
24
- */
25
- typedef struct Websocket ws_s;
26
-
27
17
  /**
28
- The protocol / service identifier for `libserver`.
18
+ The protocol / service identifier.
29
19
  */
30
20
  extern char *WEBSOCKET_ID_STR;
31
- /**
32
- The Websocket Handler contains all the settings required for new websocket
33
- connections.
34
21
 
35
- This struct is used for the named agruments in the `websocket_upgrade`
36
- macro.
37
- */
38
- typedef struct {
39
- /**
40
- The (optional) on_message callback will be called whenever a websocket message
41
- is
42
- received for this connection.
43
-
44
- The data received points to the websocket's message buffer and it will be
45
- overwritten once the function exits (it cannot be saved for later, but it can
46
- be copied).
47
- */
48
- void (*on_message)(ws_s *ws, char *data, size_t size, uint8_t is_text);
49
- /**
50
- The (optional) on_open callback will be called once the websocket connection
51
- is established and before is is registered with `facil`, so no `on_message`
52
- events are raised before `on_open` returns.
53
- */
54
- void (*on_open)(ws_s *ws);
55
- /**
56
- The (optional) on_ready callback will be after a the underlying socket's
57
- buffer changes it's state from full to available.
58
-
59
- If the socket's buffer is never full, the callback is never called.
60
-
61
- It should be noted that `libsock` manages the socket's buffer overflow and
62
- implements and augmenting user-land buffer, allowing data to be safely written
63
- to the websocket without worrying over the socket's buffer.
64
- */
65
- void (*on_ready)(ws_s *ws);
66
- /**
67
- The (optional) on_shutdown callback will be called if a websocket connection
68
- is still open while the server is shutting down (called before `on_close`).
69
- */
70
- void (*on_shutdown)(ws_s *ws);
71
- /**
72
- The (optional) on_close callback will be called once a websocket connection is
73
- terminated or failed to be established.
74
- */
75
- void (*on_close)(ws_s *ws);
76
- /** The `http_request_s` to be converted ("upgraded") to a websocket
77
- * connection. Either a request or a response object is required.*/
78
- http_request_s *request;
79
- /**
80
- The (optional) HttpResponse to be used for sending the upgrade response.
81
-
82
- Using this object allows cookies to be set before "upgrading" the connection.
83
-
84
- The ownership of the response object will remain unchanged - so if you have
85
- created the response object, you should free it.
86
- */
87
- http_response_s *response;
88
- /**
89
- The maximum websocket message size/buffer (in bytes) for this connection.
90
- */
91
- size_t max_msg_size;
92
- /** Opaque user data. */
93
- void *udata;
94
- /**
95
- Timeout for the websocket connections, a ping will be sent
96
- whenever the timeout is reached. Connections are only closed when a ping
97
- cannot be sent (the network layer fails). Pongs aren't reviewed.
98
- */
99
- uint8_t timeout;
100
- } websocket_settings_s;
101
-
102
- /** This macro allows easy access to the `websocket_upgrade` function. The macro
103
- * allows the use of named arguments, using the `websocket_settings_s` struct
104
- * members. i.e.:
105
- *
106
- * on_message(ws_s * ws, char * data, size_t size, int is_text) {
107
- * ; // ... this is the websocket on_message callback
108
- * websocket_write(ws, data, size, is_text); // a simple echo example
109
- * }
110
- *
111
- * on_request(http_request_s* request) {
112
- * websocket_upgrade( .request = request, .on_message = on_message);
113
- * }
114
- *
115
- * Returns 0 on sucess and -1 on failure. A response is always sent.
116
- */
117
- ssize_t websocket_upgrade(websocket_settings_s settings);
118
- #define websocket_upgrade(...) \
119
- websocket_upgrade((websocket_settings_s){__VA_ARGS__})
22
+ /** used internally: attaches the Websocket protocol to the socket. */
23
+ void websocket_attach(intptr_t uuid, http_settings_s *http_settings,
24
+ websocket_settings_s *args, void *data, size_t length);
120
25
 
121
26
  /* *****************************************************************************
122
27
  Websocket information
@@ -177,22 +82,12 @@ typedef struct pubsub_engine_s pubsub_engine_s;
177
82
  typedef struct {
178
83
  /** the websocket receiving the message. */
179
84
  ws_s *ws;
180
- /** the pub/sub engine from which where the message originated. */
181
- struct pubsub_engine_s *engine;
182
85
  /** the Websocket pub/sub subscription ID. */
183
86
  uintptr_t subscription_id;
184
87
  /** the channel where the message was published. */
185
- struct {
186
- const char *name;
187
- size_t len;
188
- } channel;
88
+ FIOBJ channel;
189
89
  /** the published message. */
190
- struct {
191
- const char *data;
192
- size_t len;
193
- } msg;
194
- /** Pattern matching was used for channel subscription. */
195
- unsigned use_pattern : 1;
90
+ FIOBJ message;
196
91
  /** user opaque data. */
197
92
  void *udata;
198
93
  } websocket_pubsub_notification_s;
@@ -201,17 +96,8 @@ typedef struct {
201
96
  struct websocket_subscribe_s {
202
97
  /** the websocket receiving the message. REQUIRED. */
203
98
  ws_s *ws;
204
- /**
205
- * The pub/sub engine to use.
206
- *
207
- * Default: engine will publish messages throughout the facil process cluster.
208
- */
209
- struct pubsub_engine_s *engine;
210
99
  /** the channel where the message was published. */
211
- struct {
212
- const char *name;
213
- size_t len;
214
- } channel;
100
+ FIOBJ channel;
215
101
  /**
216
102
  * The callback that handles pub/sub notifications.
217
103
  *
@@ -288,8 +174,7 @@ void websocket_unsubscribe(ws_s *ws, uintptr_t subscription_id);
288
174
 
289
175
  /* *****************************************************************************
290
176
  Websocket Tasks - within a single process scope, NOT and entire cluster
291
- *****************************************************************************
292
- */
177
+ ***************************************************************************** */
293
178
 
294
179
  /** The named arguments for `websocket_each` */
295
180
  struct websocket_each_args_s {
@@ -303,17 +188,22 @@ struct websocket_each_args_s {
303
188
  void (*on_finish)(ws_s *origin, void *arg);
304
189
  };
305
190
  /**
306
- Performs a task on each websocket connection that shares the same process
307
- (except the originating `ws_s` connection which is allowed to be NULL).
191
+ * DEPRECATION NOTICE: this function will be removed in favor of pub/sub logic.
192
+ *
193
+ * Performs a task on each websocket connection that shares the same process
194
+ * (except the originating `ws_s` connection which is allowed to be NULL).
308
195
  */
309
- void websocket_each(struct websocket_each_args_s args);
196
+ void __attribute__((deprecated))
197
+ websocket_each(struct websocket_each_args_s args);
310
198
  #define websocket_each(...) \
311
199
  websocket_each((struct websocket_each_args_s){__VA_ARGS__})
312
200
 
313
201
  /**
314
- The Arguments passed to the `websocket_write_each` function / macro are defined
315
- here, for convinience of calling the function.
316
- */
202
+ * DEPRECATION NOTICE: this function will be removed in favor of pub/sub logic.
203
+ *
204
+ * The Arguments passed to the `websocket_write_each` function / macro are
205
+ * defined here, for convinience of calling the function.
206
+ */
317
207
  struct websocket_write_each_args_s {
318
208
  /** The originating websocket client will be excluded from the `write`.
319
209
  * Can be NULL. */
@@ -343,7 +233,8 @@ Writes data to each websocket connection that shares the same process
343
233
  Accepts a sing `struct websocket_write_each_args_s` argument. See the struct
344
234
  details for possible arguments.
345
235
  */
346
- int websocket_write_each(struct websocket_write_each_args_s args);
236
+ int __attribute__((deprecated))
237
+ websocket_write_each(struct websocket_write_each_args_s args);
347
238
  #define websocket_write_each(...) \
348
239
  websocket_write_each((struct websocket_write_each_args_s){__VA_ARGS__})
349
240
 
data/lib/iodine.rb CHANGED
@@ -59,8 +59,6 @@ require 'iodine/iodine'
59
59
  # * {Iodine.listen2http} listens to new TCP/IP connections using the buildin HTTP / Websocket Protocol.
60
60
  # * {Iodine.warmup} warms up any HTTP Rack applications.
61
61
  # * {Iodine.count} counts the number of connections (including HTTP / Websocket connections).
62
- # * {Iodine::Protocol.each} runs a code of block for every connection sharing the process (except HTTP / Websocket connections).
63
- # * {Iodine::Websocket.each} runs a code of block for every existing websocket sharing the process.
64
62
  #
65
63
  # In addition to the top level API, there's also the connection class and connection instance API, as specified in the {Iodine::Protocol} and {Iodine::Websocket} documentation.
66
64
  #
@@ -70,12 +68,14 @@ require 'iodine/iodine'
70
68
  #
71
69
  # The following methods offect server side Pub/Sub that allows the server code to react to channel event.
72
70
  #
73
- # * {Iodine.subscribe}, {Iodine.unsubscribe} manages a process's subscription to a channel (which is different than a connection's subscription, such as employed by {Iodine::Websocket}).
74
- # * {Iodine.publish} publishes a message to a Pub/Sub channel. The message will be sent to all subscribers - connections, other processes in the cluster and even other machines (when using the {Iodine::PubSub::RedisEngine}).
75
- # * {Iodine.default_pubsub=}, {Iodine.default_pubsub} sets or gets the default Pub/Sub {Iodine::PubSub::Engine}. i.e., when set to a new {Iodine::PubSub::RedisEngine} instance, all Pub/Sub method calls will use the Redis engine (unless explicitly requiring a different engine).
71
+ # * {Iodine.subscribe} subscribes the process to a channel (which might be different than a connection's subscription, see {Iodine::Websocket}).
72
+ # * {Iodine.publish} publishes a message to a Pub/Sub channel. The message will be sent to all subscribers - connections, other processes in the cluster and possibly other machines (when using an engine such as {Iodine::PubSub::RedisEngine}).
73
+ # * {Iodine::PubSub.default_engine=}, {Iodine::PubSub.default_engine} sets or gets the default Pub/Sub {Iodine::PubSub::Engine}. i.e., when set to a new {Iodine::PubSub::RedisEngine} instance, all Pub/Sub method calls will use the Redis engine (unless explicitly requiring a different engine).
76
74
  #
77
75
  # {Iodine::Websocket} objects have a seperate Pub/Sub implementation that manages the subscription's lifetime to match the connection's lifetime and allows direct client Pub/Sub (forwards the message to the client directly without invoking the Ruby interpreter).
78
76
  #
77
+ # Note that {Iodine.subscribe} returns an {Iodine::PubSub::Subscription} object that can be used for closing the subscription.
78
+ #
79
79
  # == Patching Rack
80
80
  #
81
81
  # Although Iodine offers Rack::Utils optimizations using monkey patching, Iodine does NOT monkey patch Rack automatically.
@@ -170,7 +170,8 @@ module Iodine
170
170
  end
171
171
  end
172
172
 
173
- def self.patch_rack
173
+ # Will monkey patch some Rack methods to increase their performance.
174
+ def self.patch_rack
174
175
  ::Rack::Utils.class_eval do
175
176
  Iodine::Base::MonkeyPatch::RackUtils.methods(false).each do |m|
176
177
  ::Rack::Utils.define_singleton_method(m,
@@ -179,7 +180,51 @@ module Iodine
179
180
  end
180
181
  end
181
182
 
182
- self.default_pubsub = ::Iodine::PubSub::CLUSTER
183
+ # Will monkey patch the default JSON parser to replace the default `JSON.parse` with {Iodine::JSON.parse}.
184
+ def self.patch_json
185
+ ::JSON.class_eval do
186
+ ::JSON.define_singleton_method(:parse,
187
+ Iodine::JSON.instance_method(:parse) )
188
+ end
189
+ end
190
+
191
+
192
+ @after_fork_blocks = []
193
+ def self.after_fork(*args, &block)
194
+ if(block)
195
+ @after_fork_blocks << [args, block]
196
+ else
197
+ @after_fork_blocks.each {|b| b[1].call(b[0]) }
198
+ end
199
+ end
200
+
201
+ @before_fork_blocks = []
202
+ def self.before_fork(*args, &block)
203
+ if(block)
204
+ @before_fork_blocks << [args, block]
205
+ else
206
+ @before_fork_blocks.each {|b| b[1].call(b[0]) }
207
+ end
208
+ end
209
+
210
+ ::Iodine::PubSub.default_engine = ::Iodine::PubSub::CLUSTER
183
211
  end
184
212
 
213
+ if(!defined?(after_fork))
214
+ def after_fork(*args, &block)
215
+ Iodine.after_fork(*args, &block)
216
+ end
217
+ end
218
+ if(!defined?(on_worker_boot))
219
+ def on_worker_boot(*args, &block)
220
+ Iodine.after_fork(*args, &block)
221
+ end
222
+ end
223
+ if(!defined?(before_fork))
224
+ def before_fork(*args, &block)
225
+ Iodine.before_fork(*args, &block)
226
+ end
227
+ end
228
+
229
+
185
230
  require 'rack/handler/iodine' unless defined? ::Iodine::Rack::IODINE_RACK_LOADED
data/lib/iodine/cli.rb CHANGED
@@ -19,15 +19,17 @@ Use:
19
19
  Both <options> and <filename> are optional.
20
20
 
21
21
  Available options:
22
+ -b Binding address. Default: nil (same as 0.0.0.0).
22
23
  -p Port number. Default: 3000.
23
24
  -t Number of threads. Default: CPU core count.
24
25
  -w Number of worker processes. Default: CPU core count.
25
26
  -www Public folder for static file serving. Default: nil (none).
26
27
  -v Log responses. Default: never log responses.
27
28
  -warmup Warmup invokes autoloading (lazy loading) during server startup.
28
- -tout HTTP inactivity connection timeout. Default: 5 seconds.
29
- -maxbd Maximum Mb per HTTP message (max body size). Default: 50Mib.
30
- -maxms Maximum Bytes per Websocket message. Default: 250Kib.
29
+ -tout HTTP inactivity connection timeout. Default: 40 seconds.
30
+ -maxhead Maximum total headers length per HTTP request. Default: 32Kb.
31
+ -maxbd Maximum Mb per HTTP message (max body size). Default: 50Mb.
32
+ -maxms Maximum Bytes per Websocket message. Default: 250Kb.
31
33
  -ping Websocket ping interval in seconds. Default: 40 seconds.
32
34
  <filename> Defaults to: config.ru
33
35
 
@@ -48,15 +50,13 @@ EOS
48
50
  return ::Rack::Builder.parse_file filename
49
51
  end
50
52
 
51
-
52
-
53
53
  def call
54
54
  if ARGV[0] =~ /(\-\?)|(help)|(\?)|(h)|(\-h)$/
55
55
  return print_help
56
56
  end
57
57
 
58
58
  app, opt = nil, nil
59
- filename = ((ARGV[-2].to_s[0] != '-' || ARGV[-2].to_s == '-warmup') && ARGV[-1].to_s[0] != '-' && ARGV[-1])
59
+ filename = ((ARGV[-2].to_s[0] != '-' || ARGV[-2].to_s == '-warmup' || ARGV[-2].to_s == '-v' || ARGV[-2].to_s == '-q') && ARGV[-1].to_s[0] != '-' && ARGV[-1])
60
60
  if filename
61
61
  app, opt = try_file filename;
62
62
  unless opt
@@ -79,24 +79,6 @@ EOS
79
79
  end
80
80
  end
81
81
 
82
- if ARGV.index('-maxbd') && ARGV[ARGV.index('-maxbd') + 1]
83
- Iodine::Rack.max_body_size = ARGV[ARGV.index('-maxbd') + 1].to_i
84
- end
85
- if ARGV.index('-maxms') && ARGV[ARGV.index('-maxms') + 1]
86
- Iodine::Rack.max_msg_size = ARGV[ARGV.index('-maxms') + 1].to_i
87
- end
88
- if ARGV.index('-ping') && ARGV[ARGV.index('-ping') + 1]
89
- Iodine::Rack.ws_timeout = ARGV[ARGV.index('-ping') + 1].to_i
90
- end
91
- if ARGV.index('-www') && ARGV[ARGV.index('-www') + 1]
92
- Iodine::Rack.public = ARGV[ARGV.index('-www') + 1]
93
- end
94
- if ARGV.index('-tout') && ARGV[ARGV.index('-tout') + 1]
95
- Iodine::Rack.timeout = ARGV[ARGV.index('-tout') + 1].to_i
96
- puts "WARNNING: Iodine::Rack.timeout set to 0 (ignored, timeout will be ~5 seconds)."
97
- end
98
- Iodine::Rack.log = true if ARGV.index('-v')
99
- Iodine::Rack.log = false if ARGV.index('-q')
100
82
  Iodine.warmup(app) if ARGV.index('-warmup')
101
83
  Iodine::Rack.run(app, opt)
102
84
  end
@@ -0,0 +1,40 @@
1
+ module Iodine
2
+ # Iodine includes a lenient JSON parser that attempts to ignore JSON errors when possible and adds some extensions such as Hex numerical representations and comments.
3
+ #
4
+ # On my system, the Iodine JSON parser is more than 40% faster than the native Ruby parser. When using symbols the speed increase is even higher.
5
+ #
6
+ # It's easy to monkey-patch the system's `JSON.parse` method (not the `JSON.parse!` method) by using `Iodine.patch_json`.
7
+ #
8
+ # You can benchmark the Iodine JSON performance and decide if you wish to monkey-patch the Ruby implementation.
9
+ #
10
+ # JSON_FILENAME="foo.json"
11
+ #
12
+ # require 'json'
13
+ # require 'iodine'
14
+ # TIMES = 100
15
+ # STR = IO.binread(JSON_FILENAME); nil
16
+ #
17
+ # JSON.parse(STR) == Iodine::JSON.parse(STR) # => true
18
+ # JSON.parse!(STR) == Iodine::JSON.parse!(STR) # => undefined, maybe true maybe false
19
+ #
20
+ # # warm-up
21
+ # TIMES.times { JSON.parse STR }
22
+ # TIMES.times { Iodine::JSON.parse STR }
23
+ #
24
+ # puts ""; Benchmark.bm do |b|
25
+ # sys = b.report("system") { TIMES.times { JSON.parse STR } }
26
+ # sys_sym = b.report("system-sym") { TIMES.times { JSON.parse STR, symbolize_names: true } }
27
+ # iodine = b.report("iodine") { TIMES.times { Iodine::JSON.parse STR } }
28
+ # iodine_sym = b.report("iodine-sym") { TIMES.times { Iodine::JSON.parse STR, symbolize_names: true } }
29
+ #
30
+ # puts "----------------------------"
31
+ # puts "Iodine::JSON speed as percent of Ruby's native JSON:"
32
+ # puts "normal: #{sys/iodine}"
33
+ # puts "symolized: #{sys_sym/iodine_sym}"
34
+ # end; nil
35
+ #
36
+ # Note that the bang(!) method should NOT be used for monkey-patching the default JSON parser, since some important features are unsupported by the Iodine parser.
37
+ #
38
+ module JSON
39
+ end
40
+ end
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = '0.4.19'.freeze
2
+ VERSION = '0.5.0'.freeze
3
3
  end
@@ -1,11 +1,13 @@
1
1
  module Iodine
2
- # This module lists the available API for Websocket connections and classes.
2
+ # This module lists the available API for WebSocket and EventSource (SSE) connections.
3
3
  #
4
- # This module is mixed in (using `extend` and `include`) with the Websocket Callback Object (as specified by the {file:SPEC-Websocket-Draft.md proposed Rack specification}.
4
+ # This module is mixed in (using `extend` and `include`) with the WebSocket Callback Object (as specified by the {file:SPEC-Websocket-Draft.md proposed Rack specification}.
5
+ #
6
+ # The server performs `extend` to allow the application to be namespace agnostic (so the server can be replaced without effecting the application).
5
7
  #
6
8
  # The websocket API is divided into three main groups:
7
9
  # * Server <=> Client relations ({Iodine::Websocket#write}, {Iodine::Websocket#close} etc')
8
- # * Client <=> Server <=> Client relations ({Iodine::Websocket#subscribe}, {Iodine::Websocket#publish}, etc').
10
+ # * Client <=> Server <=> Pub/Sub relations ({Iodine::Websocket#subscribe}, {Iodine::Websocket#publish}.
9
11
  # * Task scheduling ({Iodine::Websocket.defer}, {Iodine::Websocket#defer}, {Iodine::Websocket.each}).
10
12
  #
11
13
  # Notice that Websocket callback objects (as specified by the {file:SPEC-Websocket-Draft.md proposed Rack specification} *MUST* provide an `on_message(data)` callback.
@@ -1,9 +1,7 @@
1
1
  require 'iodine' unless defined?(::Iodine::VERSION)
2
2
 
3
3
  module Iodine
4
- # {Iodine::Rack} provides a Rack complient interface (connecting Iodine to Rack) for an HTTP and Websocket Server.
5
- #
6
- # {Iodine::Rack} also provides convinient access to the {Iodine::HTTP.listen} function, which powers the {Iodine::Rack} server.
4
+ # Iodine's {Iodine::Rack} module provides a Rack complient interface (connecting Iodine to Rack) for an HTTP and Websocket Server.
7
5
  module Rack
8
6
  # get/set the Rack application.
9
7
  def self.app=(val)
@@ -14,16 +12,18 @@ module Iodine
14
12
  def self.app
15
13
  @app
16
14
  end
15
+ @app = nil
17
16
 
18
- # get/set the HTTP connection timeout property. Defaults to 5. Limited to a maximum of 255. 0 values are silently ignored.
17
+ # get/set the HTTP connection timeout property. Defaults to 40. Limited to a maximum of 255. 0 values are silently ignored.
19
18
  def self.timeout=(t)
20
19
  @timeout = t
21
20
  end
22
21
 
23
- # get/set the HTTP connection timeout property. Defaults to 5.
22
+ # get/set the HTTP connection timeout property. Defaults to 40 seconds.
24
23
  def self.timeout
25
24
  @timeout
26
25
  end
26
+ @timeout = 0
27
27
 
28
28
  # get/set the Websocket connection timeout property. Defaults to 40 seconds. Limited to a maximum of 255. 0 values are silently ignored.
29
29
  def self.ws_timeout=(t)
@@ -34,14 +34,15 @@ module Iodine
34
34
  def self.ws_timeout
35
35
  @ws_timeout
36
36
  end
37
+ @ws_timeout = 0
37
38
 
38
- # get/set the HTTP public folder property. Defaults to 5. Defaults to the incoming argumrnts or `nil`.
39
+ # get/set the HTTP public folder property. Defaults to the incoming arguments or `nil`.
39
40
  def self.public=(val)
40
41
  @public = val
41
42
  end
42
- @public = ARGV[ARGV.index('-www') + 1] if ARGV.index('-www')
43
+ @public = nil
43
44
 
44
- # get/set the HTTP public folder property. Defaults to 5.
45
+ # get/set the HTTP public folder property. Defaults to `nil`.
45
46
  def self.public
46
47
  @public
47
48
  end
@@ -55,7 +56,6 @@ module Iodine
55
56
  def self.max_body_size
56
57
  @max_body
57
58
  end
58
-
59
59
  # get/set the maximum HTTP body size for incoming data. Defaults to ~50Mb. 0 values are silently ignored.
60
60
  def self.max_body=(val)
61
61
  @max_body = val
@@ -65,6 +65,19 @@ module Iodine
65
65
  def self.max_body
66
66
  @max_body
67
67
  end
68
+ @max_body = 0
69
+
70
+ # get/set the maximum HTTP header length for incoming requests. Defaults to ~32Kb. 0 values are silently ignored.
71
+ def self.max_headers=(val)
72
+ @max_headers = val
73
+ end
74
+
75
+ # get/set the maximum HTTP header length for incoming requests. Defaults to ~32Kb.
76
+ def self.max_headers
77
+ @max_headers
78
+ end
79
+ @max_headers = 0
80
+
68
81
 
69
82
  # get/set the maximum Websocket body size for incoming data. Defaults to defaults to ~250KB. 0 values are silently ignored.
70
83
  def self.max_msg_size=(val)
@@ -85,6 +98,7 @@ module Iodine
85
98
  def self.max_msg
86
99
  @max_msg
87
100
  end
101
+ @max_msg = 0
88
102
 
89
103
  # get/set the HTTP logging value (true / false). Defaults to the incoming argumrnts or `false`.
90
104
  def self.log=(val)
@@ -95,8 +109,7 @@ module Iodine
95
109
  def self.log
96
110
  @log
97
111
  end
98
- @log = true if ARGV.index('-v')
99
- @log = false if ARGV.index('-q')
112
+ @log = false
100
113
 
101
114
  # get/set the HTTP listening port. Defaults to 3000.
102
115
  def self.port=(val)
@@ -107,8 +120,7 @@ module Iodine
107
120
  def self.port
108
121
  @port
109
122
  end
110
- @port = ARGV[ARGV.index('-p') + 1] if ARGV.index('-p')
111
- @port ||= 3000.to_s
123
+ @port = 3000.to_s
112
124
 
113
125
  # get/set the HTTP socket binding address. Defaults to `nil` (usually best).
114
126
  def self.address=(val)
@@ -153,6 +165,38 @@ module Iodine
153
165
  end
154
166
  end
155
167
 
168
+ if ARGV.index('-b') && ARGV[ARGV.index('-b') + 1]
169
+ Iodine::Rack.address = ARGV[ARGV.index('-b') + 1]
170
+ end
171
+ if ARGV.index('-p') && ARGV[ARGV.index('-p') + 1]
172
+ Iodine::Rack.port = ARGV[ARGV.index('-p') + 1]
173
+ end
174
+
175
+ if ARGV.index('-maxbd') && ARGV[ARGV.index('-maxbd') + 1]
176
+ Iodine::Rack.max_body_size = ARGV[ARGV.index('-maxbd') + 1].to_i
177
+ end
178
+ if ARGV.index('-maxms') && ARGV[ARGV.index('-maxms') + 1]
179
+ Iodine::Rack.max_msg_size = ARGV[ARGV.index('-maxms') + 1].to_i
180
+ end
181
+ if ARGV.index('-ping') && ARGV[ARGV.index('-ping') + 1]
182
+ Iodine::Rack.ws_timeout = ARGV[ARGV.index('-ping') + 1].to_i
183
+ end
184
+ if ARGV.index('-www') && ARGV[ARGV.index('-www') + 1]
185
+ Iodine::Rack.public = ARGV[ARGV.index('-www') + 1]
186
+ end
187
+ if ARGV.index('-maxhead') && ARGV[ARGV.index('-maxhead') + 1]
188
+ Iodine::Rack.max_headers = ARGV[ARGV.index('-maxhead') + 1].to_i
189
+ end
190
+ if ARGV.index('-tout') && ARGV[ARGV.index('-tout') + 1]
191
+ Iodine::Rack.timeout = ARGV[ARGV.index('-tout') + 1].to_i
192
+ puts "WARNNING: Iodine::Rack.timeout set to 0 (ignored, timeout will be ~5 seconds)."
193
+ end
194
+ Iodine::Rack.log = true if ARGV.index('-v')
195
+ Iodine::Rack.log = false if ARGV.index('-q')
196
+
197
+
198
+
199
+
156
200
  # Iodine::Rack.app = proc { |env| p env; puts env['rack.input'].read(1024).tap { |s| puts "Got data #{s.length} long, #{s[0].ord}, #{s[1].ord} ... #{s[s.length - 2].ord}, #{s[s.length - 1].ord}:" if s }; env['rack.input'].rewind; [404, {}, []] }
157
201
 
158
202
  ENV['RACK_HANDLER'] = 'iodine'
@@ -167,6 +211,7 @@ end
167
211
 
168
212
  begin
169
213
  ::Rack::Handler.register('iodine', 'Iodine::Rack') if defined?(::Rack::Handler)
214
+ ::Rack::Handler.register('Iodine', 'Iodine::Rack') if defined?(::Rack::Handler)
170
215
  rescue Exception
171
216
 
172
217
  end