iodine 0.7.13 → 0.7.14

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 943a41860e82f16cade6bb4f0ba8eabab9d712eb620de04cfbeca7153e4e8551
4
- data.tar.gz: ef24434b749862566b869ff248089bc5f420a46b0492644096a40588766d3c3e
3
+ metadata.gz: 0d3f8b237b265c8151aa3fe966a9c863fa3c053e4fd97289cfe498b77818e564
4
+ data.tar.gz: 389b80f9feff3abf97ba7fdaf08d0a2986521093fb0365ab10c5e4b3af3b2de5
5
5
  SHA512:
6
- metadata.gz: 95c9c98a8b85201a98989e96379fbbaeb74e3d16ae9ea4b42bf3fd49d7591d7224bb406d568298b19583411f675b337110d464ad7447221ee19583d10e6a37aa
7
- data.tar.gz: 4614ca29b759b2c1c8e6329c38b565415eb69c356298a53429f0af100545fe1944e1340ccf6334e55d444d8f7659c13c3e6d1f45e6b9d384972acbaa59f7f8d4
6
+ metadata.gz: d8b220410c1ebdecf221bde09d48f64ed0c69dc50a0f0ecba69a3e530dc2b9cace643c9a1d8bc7ce73ecf9f1274ffc1162a21db6db273673de84318f9ea81cb3
7
+ data.tar.gz: 94f71023813326cb0edfabecbbd862e566ec37882de35ca6b6f14a2759088b54ed52df9bb943888b3c58f3441881c67a4c82197550272593050eaca6fc66b3e8
@@ -6,6 +6,16 @@ Please notice that this change log contains changes for upcoming releases as wel
6
6
 
7
7
  ## Changes:
8
8
 
9
+ #### Change log v.0.7.14
10
+
11
+ **Fix**: (`facil.io`) fixed superfluous ping event.
12
+
13
+ **Fix**: (`iodine_tcp`) fixed responsiveness to the argument name `timeout` (a spelling mistake was testing for `timout`).
14
+
15
+ **Fix**: (`iodine_store`) fixed missing EOL marker in DEBUG messages when reporting iodine's GC guard activity.
16
+
17
+ **Update**: (`iodine`) added support for dynamic (hot) connection callback switching.
18
+
9
19
  #### Change log v.0.7.13
10
20
 
11
21
  **Fix**: (`mustache`) added support for padding in template partials.
data/README.md CHANGED
@@ -427,6 +427,8 @@ Iodine is written in C and allows some compile-time customizations, such as:
427
427
 
428
428
  * `FIO_ENGINE_POLL` - prefer the `poll` system call over `epoll` or `kqueue` (not recommended).
429
429
 
430
+ * `FIO_LOG_LENGTH_LIMIT` - sets the limit on iodine's logging messages (uses stack memory, so limits must be reasonable. Defaults to 2048.
431
+
430
432
  These options can be used, for example, like so:
431
433
 
432
434
  ```bash
@@ -501,35 +503,99 @@ Iodine allows custom TCP/IP server authoring, for those cases where we need raw
501
503
  Here's a short and sweet echo server - No HTTP, just use `telnet`:
502
504
 
503
505
  ```ruby
504
-
505
506
  require 'iodine'
506
507
 
507
508
  # an echo protocol with asynchronous notifications.
508
509
  class EchoProtocol
509
510
  # `on_message` is an optional alternative to the `on_data` callback.
510
511
  # `on_message` has a 1Kb buffer that recycles itself for memory optimization.
511
- def on_message buffer
512
+ def on_message client, buffer
512
513
  # writing will never block and will use a buffer written in C when needed.
513
- write buffer
514
+ client.write buffer
514
515
  # close will be performed only once all the data in the write buffer
515
516
  # was sent. use `force_close` to close early.
516
- close if buffer =~ /^bye[\r\n]/i
517
- # use buffer.dup to save the data from being recycled once we return.
518
- data = buffer.dup
519
- # run asynchronous tasks with ease
520
- run do
517
+ client.close if buffer =~ /^bye[\r\n]/i
518
+ # run asynchronous tasks using the thread pool
519
+ Iodine.run do
521
520
  sleep 1
522
- puts "Echoed data: #{data}"
521
+ puts "Echoed data: #{buffer}"
523
522
  end
524
523
  end
525
524
  end
526
525
 
527
526
  # listen on port 3000 for the echo protocol.
528
- Iodine.listen 3000, EchoProtocol
529
- Iodine.threads = 1
530
- Iodine.processes = 1
527
+ Iodine.listen(port: "3000") { EchoProtocol.new }
528
+ Iodine.threads = 4
529
+ Iodine.workers = 1
531
530
  Iodine.start
531
+ ```
532
+
533
+ Or a nice plain text chat room (connect using `telnet` or `nc` ):
534
+
535
+ ```ruby
536
+ require 'iodine'
532
537
 
538
+ # a chat protocol with asynchronous notifications.
539
+ class ChatProtocol
540
+ def initialize nickname = "guest"
541
+ @nickname = nickname
542
+ end
543
+ def on_open client
544
+ client.subscribe :chat
545
+ client.publish :chat, "#{@nickname} joined chat.\n"
546
+ client.timeout = 40
547
+ end
548
+ def on_close client
549
+ client.publish :chat, "#{@nickname} left chat.\n"
550
+ end
551
+ def on_shutdown client
552
+ client.write "Server is shutting down... try reconnecting later.\n"
553
+ end
554
+ def on_message client, buffer
555
+ if(buffer[-1] == "\n")
556
+ client.publish :chat, "#{@nickname}: #{buffer}"
557
+ else
558
+ client.publish :chat, "#{@nickname}: #{buffer}\n"
559
+ end
560
+ # close will be performed only once all the data in the outgoing buffer
561
+ client.close if buffer =~ /^bye[\r\n]/i
562
+ end
563
+ def ping client
564
+ client.write "(ping) Are you there, #{@nickname}...?\n"
565
+ end
566
+ end
567
+
568
+ #an initial login protocol
569
+ class LoginProtocol
570
+ def on_open client
571
+ client.write "Enter nickname to log in to chat room:\n"
572
+ client.timeout = 10
573
+ end
574
+ def ping client
575
+ client.write "Time's up... goodbye.\n"
576
+ client.close
577
+ end
578
+ def on_message client, buffer
579
+ # validate nickname and switch connection callback to ChatProtocol
580
+ nickname = buffer.split("\n")[0]
581
+ while (nickname && nickname.length() > 0 && (nickname[-1] == '\n' || nickname[-1] == '\r'))
582
+ nickname = nickname.slice(0, nickname.length() -1)
583
+ end
584
+ if(nickname && nickname.length() > 0 && buffer.split("\n").length() == 1)
585
+ chat = ChatProtocol.new(nickname)
586
+ client.handler = chat
587
+ else
588
+ client.write "Nickname error, try again.\n"
589
+ on_open client
590
+ end
591
+ end
592
+ end
593
+
594
+ # listen on port 3000
595
+ Iodine.listen(port: 3000) { LoginProtocol.new }
596
+ Iodine.threads = 1
597
+ Iodine.workers = 1
598
+ Iodine.start
533
599
  ```
534
600
 
535
601
  ### Why not EventMachine?
@@ -2009,7 +2009,7 @@ static void mock_ping(intptr_t uuid, fio_protocol_s *protocol) {
2009
2009
  static void mock_ping2(intptr_t uuid, fio_protocol_s *protocol) {
2010
2010
  (void)protocol;
2011
2011
 
2012
- uuid_data(uuid).active = fio_last_tick().tv_sec;
2012
+ touchfd(fio_uuid2fd(uuid));
2013
2013
  if (uuid_data(uuid).timeout == 255)
2014
2014
  return;
2015
2015
  protocol->ping = mock_ping;
@@ -2046,7 +2046,7 @@ static void deferred_on_shutdown(void *arg, void *arg2) {
2046
2046
  return;
2047
2047
  goto postpone;
2048
2048
  }
2049
- uuid_data(arg).active = fio_data->last_cycle.tv_sec;
2049
+ touchfd(fio_uuid2fd(arg));
2050
2050
  uint8_t r = pr->on_shutdown ? pr->on_shutdown((intptr_t)arg, pr) : 0;
2051
2051
  if (r) {
2052
2052
  if (r == 255) {
@@ -2733,6 +2733,7 @@ ssize_t fio_write2_fn(intptr_t uuid, fio_write_args_s options) {
2733
2733
  fio_unlock(&uuid_data(uuid).sock_lock);
2734
2734
 
2735
2735
  if (was_empty) {
2736
+ touchfd(fio_uuid2fd(uuid));
2736
2737
  fio_defer_push_urgent(deferred_on_ready, (void *)uuid, NULL);
2737
2738
  }
2738
2739
  return 0;
@@ -2893,6 +2894,7 @@ test_errno:
2893
2894
 
2894
2895
  return -1;
2895
2896
  flushed:
2897
+ touchfd(fio_uuid2fd(uuid));
2896
2898
  fio_unlock(&uuid_data(uuid).sock_lock);
2897
2899
  return 1;
2898
2900
  }
@@ -3045,7 +3047,7 @@ static int fio_attach__internal(void *uuid_, void *protocol_) {
3045
3047
  fio_protocol_s *old_pr = uuid_data(uuid).protocol;
3046
3048
  uuid_data(uuid).open = 1;
3047
3049
  uuid_data(uuid).protocol = protocol;
3048
- uuid_data(uuid).active = fio_data->last_cycle.tv_sec;
3050
+ touchfd(fio_uuid2fd(uuid));
3049
3051
  fio_unlock(&uuid_data(uuid).protocol_lock);
3050
3052
  if (old_pr) {
3051
3053
  fio_defer_push_task(deferred_on_close, (void *)uuid, old_pr);
@@ -3082,7 +3084,7 @@ void fio_attach_fd(int fd, fio_protocol_s *protocol) {
3082
3084
  /** Sets a timeout for a specific connection (only when running and valid). */
3083
3085
  void fio_timeout_set(intptr_t uuid, uint8_t timeout) {
3084
3086
  if (uuid_is_valid(uuid)) {
3085
- uuid_data(uuid).active = fio_data->last_cycle.tv_sec;
3087
+ touchfd(fio_uuid2fd(uuid));
3086
3088
  uuid_data(uuid).timeout = timeout;
3087
3089
  } else {
3088
3090
  FIO_LOG_DEBUG("Called fio_timeout_set for invalid uuid %p", (void *)uuid);
@@ -180,6 +180,15 @@ Version and helper macros
180
180
  #define FIO_PUBSUB_SUPPORT 1
181
181
  #endif
182
182
 
183
+ #ifndef FIO_LOG_LENGTH_LIMIT
184
+ /**
185
+ * Since logging uses stack memory rather than dynamic allocation, it's memory
186
+ * usage must be limited to avoid exploding the stack. The following sets the
187
+ * memory used for a logging event.
188
+ */
189
+ #define FIO_LOG_LENGTH_LIMIT 2048
190
+ #endif
191
+
183
192
  #ifndef FIO_IGNORE_MACRO
184
193
  /**
185
194
  * This is used internally to ignore macros that shadow functions (avoiding
@@ -427,9 +436,10 @@ extern int FIO_LOG_LEVEL;
427
436
  #define FIO_LOG_PRINT(level, ...) \
428
437
  do { \
429
438
  if (level <= FIO_LOG_LEVEL) { \
430
- char tmp___log[1024]; \
431
- int len___log = snprintf(tmp___log, 1000, __VA_ARGS__); \
432
- if (len___log <= 0 || len___log > 1000) { \
439
+ char tmp___log[FIO_LOG_LENGTH_LIMIT]; \
440
+ int len___log = \
441
+ snprintf(tmp___log, FIO_LOG_LENGTH_LIMIT - 2, __VA_ARGS__); \
442
+ if (len___log <= 0 || len___log >= FIO_LOG_LENGTH_LIMIT - 2) { \
433
443
  fwrite("ERROR: log line output too long (can't write).", 46, 1, \
434
444
  stderr); \
435
445
  break; \
@@ -319,6 +319,63 @@ static VALUE iodine_connection_env(VALUE self) {
319
319
  return Qnil;
320
320
  }
321
321
 
322
+ /**
323
+ * Returns the client's current callback object.
324
+ */
325
+ static VALUE iodine_connection_handler_get(VALUE self) {
326
+ iodine_connection_data_s *data = iodine_connection_validate_data(self);
327
+ if (!data) {
328
+ FIO_LOG_DEBUG("(iodine) requested connection handler for "
329
+ "an invalid connection: %p",
330
+ (void *)self);
331
+ return Qnil;
332
+ }
333
+ return data->info.handler;
334
+ }
335
+
336
+ // clang-format off
337
+ /**
338
+ * Sets the client's callback object, so future events will use the new object's callbacks.
339
+ *
340
+ * @Note this will fire the `on_close` callback in the old handler and the `on_open` callback on the new handler. However, existing subscriptions will remain intact.
341
+ */
342
+ static VALUE iodine_connection_handler_set(VALUE self, VALUE handler) {
343
+ // clang-format on
344
+ iodine_connection_data_s *data = iodine_connection_validate_data(self);
345
+ if (!data) {
346
+ FIO_LOG_DEBUG("(iodine) attempted to set a connection handler for "
347
+ "an invalid connection: %p",
348
+ (void *)self);
349
+ return Qnil;
350
+ }
351
+ if (handler == Qnil || handler == Qfalse) {
352
+ FIO_LOG_DEBUG(
353
+ "(iodine) called client.handler = nil, closing connection: %p",
354
+ (void *)self);
355
+ iodine_connection_close(self);
356
+ return Qnil;
357
+ }
358
+ if (data->info.handler != handler) {
359
+ uint8_t answers_on_open = (rb_respond_to(handler, on_open_id) != 0);
360
+ if(data->answers_on_close)
361
+ IodineCaller.call2(data->info.handler, on_close_id, 1, &self);
362
+ fio_lock(&data->lock);
363
+ data->info.handler = handler;
364
+ data->answers_on_open = answers_on_open,
365
+ data->answers_on_message = (rb_respond_to(handler, on_message_id) != 0),
366
+ data->answers_ping = (rb_respond_to(handler, ping_id) != 0),
367
+ data->answers_on_drained = (rb_respond_to(handler, on_drained_id) != 0),
368
+ data->answers_on_shutdown = (rb_respond_to(handler, on_shutdown_id) != 0),
369
+ data->answers_on_close = (rb_respond_to(handler, on_close_id) != 0),
370
+ fio_unlock(&data->lock);
371
+ if (answers_on_open) {
372
+ iodine_connection_fire_event(self, IODINE_CONNECTION_ON_OPEN, Qnil);
373
+ }
374
+ FIO_LOG_DEBUG("(iodine) switched handlers for connection: %p",
375
+ (void *)self);
376
+ }
377
+ return handler;
378
+ }
322
379
  /* *****************************************************************************
323
380
  Pub/Sub Callbacks (internal implementation)
324
381
  ***************************************************************************** */
@@ -837,6 +894,10 @@ void iodine_connection_init(void) {
837
894
  1);
838
895
  rb_define_method(ConnectionKlass, "env", iodine_connection_env, 0);
839
896
 
897
+ rb_define_method(ConnectionKlass, "handler", iodine_connection_handler_get,
898
+ 0);
899
+ rb_define_method(ConnectionKlass, "handler=", iodine_connection_handler_set,
900
+ 1);
840
901
  rb_define_method(ConnectionKlass, "subscribe", iodine_pubsub_subscribe, -1);
841
902
  rb_define_method(ConnectionKlass, "unsubscribe", iodine_pubsub_unsubscribe,
842
903
  1);
@@ -65,7 +65,7 @@ static void storage_print(void) {
65
65
  fprintf(stderr, "Total of %" PRIuPTR " objects protected form GC\n", index);
66
66
  fprintf(stderr,
67
67
  "Storage uses %" PRIuPTR " Hash bins for %" PRIuPTR " objects\n"
68
- "The largest collection was %zu objects.",
68
+ "The largest collection was %zu objects.\n",
69
69
  iodine_storage.capa, iodine_storage.count, iodine_storage_count_max);
70
70
  fio_unlock(&iodine_storage_lock);
71
71
  }
@@ -2,6 +2,7 @@
2
2
  #include <ruby/encoding.h>
3
3
  #include <ruby/io.h>
4
4
 
5
+ #define FIO_INCLUDE_STR
5
6
  #include "fio.h"
6
7
 
7
8
  /* *****************************************************************************
@@ -40,6 +41,7 @@ static void *iodine_tcp_on_data_in_GIL(void *b_) {
40
41
  iodine_buffer_s *b = b_;
41
42
  if (!b) {
42
43
  FIO_LOG_FATAL("(iodine->tcp/ip->on_data->GIL) WTF?!\n");
44
+ exit(-1);
43
45
  }
44
46
  VALUE data = IodineStore.add(rb_str_new(b->buffer, b->len));
45
47
  rb_enc_associate(data, IodineBinaryEncoding);
@@ -148,7 +150,7 @@ The {listen} method instructs iodine to listen to incoming connections using eit
148
150
 
149
151
  The method accepts a single Hash argument with the following optional keys:
150
152
 
151
- :port :: The port to listen to, deafults to 0 (using a Unix socket)
153
+ :port :: The port to listen to, deafults to nil (using a Unix socket)
152
154
  :address :: The address to listen to, which could be a Unix Socket path as well as an IPv4 / IPv6 address. Deafults to 0.0.0.0 (or the IPv6 equivelant).
153
155
  :handler :: An object that answers the `call` method (i.e., a Proc).
154
156
 
@@ -217,6 +219,7 @@ static VALUE iodine_tcp_listen(VALUE self, VALUE args) {
217
219
  VALUE rb_port = rb_hash_aref(args, port_id);
218
220
  VALUE rb_address = rb_hash_aref(args, address_id);
219
221
  VALUE rb_handler = rb_hash_aref(args, handler_id);
222
+ fio_str_s port = FIO_STR_INIT;
220
223
  if (rb_handler == Qnil || rb_handler == Qfalse || rb_handler == Qtrue) {
221
224
  rb_need_block();
222
225
  rb_handler = rb_block_proc();
@@ -225,10 +228,19 @@ static VALUE iodine_tcp_listen(VALUE self, VALUE args) {
225
228
  if (rb_address != Qnil) {
226
229
  Check_Type(rb_address, T_STRING);
227
230
  }
231
+
228
232
  if (rb_port != Qnil) {
229
- Check_Type(rb_port, T_STRING);
233
+ if (rb_port == Qfalse) {
234
+ fio_str_write_i(&port, 0);
235
+ } else if (RB_TYPE_P(rb_port, T_STRING))
236
+ fio_str_write(&port, RSTRING_PTR(rb_port), RSTRING_LEN(rb_port));
237
+ else if (RB_TYPE_P(rb_port, T_FIXNUM))
238
+ fio_str_write_i(&port, FIX2LONG(rb_port));
239
+ else
240
+ rb_raise(rb_eTypeError,
241
+ "The `port` property MUST be either a String or a Number");
230
242
  }
231
- if (fio_listen(.port = (rb_port == Qnil ? NULL : StringValueCStr(rb_port)),
243
+ if (fio_listen(.port = fio_str_info(&port).data,
232
244
  .address =
233
245
  (rb_address == Qnil ? NULL : StringValueCStr(rb_address)),
234
246
  .on_open = iodine_tcp_on_open,
@@ -269,6 +281,7 @@ static VALUE iodine_tcp_connect(VALUE self, VALUE args) {
269
281
  VALUE rb_handler = rb_hash_aref(args, handler_id);
270
282
  VALUE rb_timeout = rb_hash_aref(args, timeout_id);
271
283
  uint8_t timeout = 0;
284
+ fio_str_s port = FIO_STR_INIT;
272
285
  if (rb_handler == Qnil || rb_handler == Qfalse || rb_handler == Qtrue) {
273
286
  rb_raise(rb_eArgError, "A callback object (:handler) must be provided.");
274
287
  }
@@ -277,13 +290,21 @@ static VALUE iodine_tcp_connect(VALUE self, VALUE args) {
277
290
  Check_Type(rb_address, T_STRING);
278
291
  }
279
292
  if (rb_port != Qnil) {
280
- Check_Type(rb_port, T_STRING);
293
+ if (rb_port == Qfalse) {
294
+ fio_str_write_i(&port, 0);
295
+ } else if (RB_TYPE_P(rb_port, T_STRING))
296
+ fio_str_write(&port, RSTRING_PTR(rb_port), RSTRING_LEN(rb_port));
297
+ else if (RB_TYPE_P(rb_port, T_FIXNUM))
298
+ fio_str_write_i(&port, FIX2LONG(rb_port));
299
+ else
300
+ rb_raise(rb_eTypeError,
301
+ "The `port` property MUST be either a String or a Number");
281
302
  }
282
303
  if (rb_timeout != Qnil) {
283
304
  Check_Type(rb_timeout, T_FIXNUM);
284
305
  timeout = NUM2USHORT(rb_timeout);
285
306
  }
286
- fio_connect(.port = (rb_port == Qnil ? NULL : StringValueCStr(rb_port)),
307
+ fio_connect(.port = fio_str_info(&port).data,
287
308
  .address =
288
309
  (rb_address == Qnil ? NULL : StringValueCStr(rb_address)),
289
310
  .on_connect = iodine_tcp_on_connect,
@@ -332,7 +353,7 @@ void iodine_init_tcp_connections(void) {
332
353
  port_id = IodineStore.add(rb_id2sym(rb_intern("port")));
333
354
  address_id = IodineStore.add(rb_id2sym(rb_intern("address")));
334
355
  handler_id = IodineStore.add(rb_id2sym(rb_intern("handler")));
335
- timeout_id = IodineStore.add(rb_id2sym(rb_intern("timout")));
356
+ timeout_id = IodineStore.add(rb_id2sym(rb_intern("timeout")));
336
357
  on_closed_id = rb_intern("on_closed");
337
358
 
338
359
  IodineBinaryEncoding = rb_enc_find("binary");
@@ -8,47 +8,6 @@ Feel free to copy, use and enjoy according to the license provided.
8
8
  /**
9
9
  * A mustache parser using a callback systems that allows this implementation to
10
10
  * be framework agnostic (i.e., can be used with any JSON library).
11
- *
12
- * When including the mustache parser within an iumplementation file,
13
- * `INCLUDE_MUSTACHE_IMPLEMENTATION` must be defined as 1. This allows the
14
- * header's types to be exposed within a containing header.
15
- *
16
- * The API has three functions:
17
- *
18
- * 1. `mustache_load` loads a template file, converting it to instruction data.
19
- * 2. `mustache_build` calls any callbacks according to the loaded instructions.
20
- * 3. `mustache_free` frees the instruction and data memory (the template).
21
- *
22
- * The template is loaded and converted to an instruction array using
23
- * `mustache_load`. This loads any nested templates / partials as well.
24
- *
25
- * The resulting instruction array (`mustache_s *`) is composed of three memory
26
- * segments: header segment, instruction array segment and data segment.
27
- *
28
- * The instruction array (`mustache_s *`) can be used to build actual output
29
- * data using the `mustache_build` function.
30
- *
31
- * The `mustache_build` function accepts two opaque pointers for user data
32
- * (`udata1` and `udata2`) that can be used by the callbacks for data input and
33
- * data output.
34
- *
35
- * The `mustache_build` function is thread safe and many threads can build
36
- * content based on the same template.
37
- *
38
- * While the build function is performed, the following callback might be
39
- * called:
40
- *
41
- * * `mustache_on_arg` - called to output an argument's value .
42
- * * `mustache_on_text` - called to output raw text.
43
- * * `mustache_on_section_test` - called when a section is tested for validity.
44
- * * `mustache_on_section_start` - called when entering a named section.
45
- * * `mustache_on_formatting_error` - called when a formatting error occurred.
46
- *
47
- * Once the template is no longer needed, it's easy to free the template using
48
- * the `mustache_free` function (which, at the moment, simply calls `free`).
49
- *
50
- * For details about mustache templating scheme, see: https://mustache.github.io
51
- *
52
11
  */
53
12
  #define H_MUSTACHE_LOADR_H
54
13
 
@@ -524,26 +483,28 @@ static inline int mustache__write_padding(mustache__builder_stack_s *s) {
524
483
  */
525
484
  static int mustache__write_escaped(mustache__builder_stack_s *s, char *text,
526
485
  uint32_t len) {
486
+ #define MUSTACHE_ESCAPE_BUFFER_SIZE 4096
527
487
  /** HTML ecape table, created using the following Ruby Script:
528
488
 
529
- a = (0..255).to_a.map {|i| i.chr }
530
- # 100.times {|i| a[i] = "&\#x#{ i < 16 ? "0#{i.to_s(16)}" : i.to_s(16)};"}
531
- 100.times {|i| a[i] = "&\##{i.to_s(10)};"}
532
- ('a'.ord..'z'.ord).each {|i| a[i] = i.chr }
533
- ('A'.ord..'Z'.ord).each {|i| a[i] = i.chr }
534
- ('0'.ord..'9'.ord).each {|i| a[i] = i.chr }
535
- a['<'.ord] = "&lt;"
536
- a['>'.ord] = "&gt;"
537
- a['&'.ord] = "&amp;"
538
- a['"'.ord] = "&quot;"
539
- a["\'".ord] = "&apos;"
540
- a['|'.ord] = "&\##{'|'.ord.to_s(10)};"
541
-
542
- b = a.map {|s| s.length }
543
- puts "static char *html_escape_strs[] = {", a.to_s.slice(1..-2) ,"};",
544
- "static uint8_t html_escape_len[] = {", b.to_s.slice(1..-2),"};"
489
+ a = (0..255).to_a.map {|i| i.chr }
490
+ 100.times {|i| a[i] = "&\##{i.to_s(10)};"}
491
+ ('a'.ord..'z'.ord).each {|i| a[i] = i.chr }
492
+ ('A'.ord..'Z'.ord).each {|i| a[i] = i.chr }
493
+ ('0'.ord..'9'.ord).each {|i| a[i] = i.chr }
494
+ a['<'.ord] = "&lt;"
495
+ a['>'.ord] = "&gt;"
496
+ a['&'.ord] = "&amp;"
497
+ a['"'.ord] = "&quot;"
498
+ a["\'".ord] = "&apos;"
499
+ a['|'.ord] = "&\##{'|'.ord.to_s(10)};"
500
+
501
+ b = a.map {|s| s.length }
502
+ puts "static char *html_escape_strs[] = {",
503
+ a.to_s.slice(1..-2) ,"};",
504
+ "static uint8_t html_escape_len[] = {",
505
+ b.to_s.slice(1..-2),"};"
545
506
  */
546
- static char *html_escape_strs[] = {
507
+ static const char *html_escape_strs[] = {
547
508
  "&#0;", "&#1;", "&#2;", "&#3;", "&#4;", "&#5;", "&#6;", "&#7;",
548
509
  "&#8;", "&#9;", "&#10;", "&#11;", "&#12;", "&#13;", "&#14;", "&#15;",
549
510
  "&#16;", "&#17;", "&#18;", "&#19;", "&#20;", "&#21;", "&#22;", "&#23;",
@@ -576,7 +537,7 @@ puts "static char *html_escape_strs[] = {", a.to_s.slice(1..-2) ,"};",
576
537
  "\xE8", "\xE9", "\xEA", "\xEB", "\xEC", "\xED", "\xEE", "\xEF",
577
538
  "\xF0", "\xF1", "\xF2", "\xF3", "\xF4", "\xF5", "\xF6", "\xF7",
578
539
  "\xF8", "\xF9", "\xFA", "\xFB", "\xFC", "\xFD", "\xFE", "\xFF"};
579
- static uint8_t html_escape_len[] = {
540
+ static const uint8_t html_escape_len[] = {
580
541
  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
581
542
  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5,
582
543
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 4, 5, 4, 5, 5, 1, 1, 1, 1, 1, 1, 1,
@@ -588,7 +549,7 @@ puts "static char *html_escape_strs[] = {", a.to_s.slice(1..-2) ,"};",
588
549
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
589
550
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
590
551
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
591
- char buffer[4096];
552
+ char buffer[MUSTACHE_ESCAPE_BUFFER_SIZE];
592
553
  size_t pos = 0;
593
554
  const char *end = text + len;
594
555
  while (text < end) {
@@ -604,7 +565,7 @@ puts "static char *html_escape_strs[] = {", a.to_s.slice(1..-2) ,"};",
604
565
  memcpy(buffer + pos, html_escape_strs[(uint8_t)text[0]],
605
566
  html_escape_len[(uint8_t)text[0]]);
606
567
  pos += html_escape_len[(uint8_t)text[0]];
607
- if (pos >= 4090) {
568
+ if (pos >= (MUSTACHE_ESCAPE_BUFFER_SIZE - 6)) {
608
569
  buffer[pos] = 0;
609
570
  if (mustache_on_text(&s->stack[s->index].sec, buffer, pos) == -1)
610
571
  return -1;
@@ -619,6 +580,7 @@ puts "static char *html_escape_strs[] = {", a.to_s.slice(1..-2) ,"};",
619
580
  return -1;
620
581
  }
621
582
  return 0;
583
+ #undef MUSTACHE_ESCAPE_BUFFER_SIZE
622
584
  }
623
585
  /**
624
586
  * This helper function should be used to write text to the output
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = '0.7.13'.freeze
2
+ VERSION = '0.7.14'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iodine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.13
4
+ version: 0.7.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-12-07 00:00:00.000000000 Z
11
+ date: 2018-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -210,7 +210,7 @@ licenses:
210
210
  - MIT
211
211
  metadata:
212
212
  allowed_push_host: https://rubygems.org
213
- post_install_message: 'Thank you for installing Iodine 0.7.13.
213
+ post_install_message: 'Thank you for installing Iodine 0.7.14.
214
214
 
215
215
  '
216
216
  rdoc_options: []