iodine 0.7.60 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +15 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -3
  5. data/CHANGELOG.md +132 -12
  6. data/Gemfile +5 -7
  7. data/LICENSE.txt +1 -1
  8. data/README.md +147 -671
  9. data/Rakefile +9 -16
  10. data/examples/chatroom.nru +9 -0
  11. data/examples/client +74 -0
  12. data/examples/config-hello.nru +9 -0
  13. data/examples/config-hello.ru +11 -0
  14. data/examples/config-hijack.ru +13 -0
  15. data/examples/config-shootout.ru +43 -0
  16. data/examples/config.nru +120 -0
  17. data/examples/config.rb +37 -0
  18. data/examples/config.ru +42 -53
  19. data/examples/fake +24 -0
  20. data/examples/hello_neorack +137 -0
  21. data/examples/routes.nru +29 -0
  22. data/examples/routes.ru +42 -0
  23. data/exe/iodine +218 -258
  24. data/ext/iodine/extconf.rb +27 -100
  25. data/ext/iodine/fio-stl.h +128336 -0
  26. data/ext/iodine/fio-stl.md +26396 -0
  27. data/ext/iodine/iodine.c +213 -1393
  28. data/ext/iodine/iodine.h +250 -55
  29. data/ext/iodine/iodine_arg_helper.h +329 -0
  30. data/ext/iodine/iodine_caller.h +234 -25
  31. data/ext/iodine/iodine_cli.h +434 -0
  32. data/ext/iodine/iodine_compression.h +312 -0
  33. data/ext/iodine/iodine_connection.h +3484 -34
  34. data/ext/iodine/iodine_core.h +363 -0
  35. data/ext/iodine/iodine_crypto.h +1441 -0
  36. data/ext/iodine/iodine_defer.h +225 -4
  37. data/ext/iodine/iodine_json.h +738 -4
  38. data/ext/iodine/iodine_listener.h +263 -0
  39. data/ext/iodine/iodine_log.h +297 -0
  40. data/ext/iodine/iodine_minimap.h +543 -0
  41. data/ext/iodine/iodine_mustache.h +461 -4
  42. data/ext/iodine/iodine_pubsub_eng.h +729 -0
  43. data/ext/iodine/iodine_pubsub_history.h +547 -0
  44. data/ext/iodine/iodine_pubsub_msg.h +228 -0
  45. data/ext/iodine/iodine_redis.h +322 -0
  46. data/ext/iodine/iodine_store.h +418 -16
  47. data/ext/iodine/iodine_threads.h +279 -0
  48. data/ext/iodine/iodine_tls.h +515 -6
  49. data/ext/iodine/iodine_utils.h +923 -0
  50. data/iodine.gemspec +37 -42
  51. data/lib/iodine/benchmark.rb +1690 -0
  52. data/lib/iodine/documentation.rb +3085 -0
  53. data/lib/iodine/version.rb +17 -1
  54. data/lib/iodine.rb +54 -255
  55. data/logo.svg +36 -0
  56. data/mustache.md +55 -0
  57. data/sig/iodine.rbs +4 -0
  58. metadata +58 -184
  59. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  60. data/.github/workflows/ruby.yml +0 -42
  61. data/.gitignore +0 -21
  62. data/LIMITS.md +0 -41
  63. data/SPEC-PubSub-Draft.md +0 -159
  64. data/SPEC-WebSocket-Draft.md +0 -239
  65. data/bin/console +0 -22
  66. data/bin/info.md +0 -353
  67. data/bin/mustache_bench.rb +0 -100
  68. data/bin/poc/Gemfile.lock +0 -23
  69. data/bin/poc/README.md +0 -37
  70. data/bin/poc/config.ru +0 -66
  71. data/bin/poc/gemfile +0 -1
  72. data/bin/poc/www/index.html +0 -57
  73. data/examples/async_task.ru +0 -92
  74. data/examples/bates/README.md +0 -3
  75. data/examples/bates/config.ru +0 -342
  76. data/examples/bates/david+bold.pdf +0 -0
  77. data/examples/bates/public/drop-pdf.png +0 -0
  78. data/examples/bates/public/index.html +0 -600
  79. data/examples/echo.ru +0 -59
  80. data/examples/etag.ru +0 -16
  81. data/examples/hello.ru +0 -29
  82. data/examples/pubsub_engine.ru +0 -81
  83. data/examples/rack3.ru +0 -12
  84. data/examples/redis.ru +0 -70
  85. data/examples/shootout.ru +0 -73
  86. data/examples/sub-protocols.ru +0 -90
  87. data/examples/tcp_client.rb +0 -66
  88. data/examples/x-sendfile.ru +0 -14
  89. data/ext/iodine/fio.c +0 -11995
  90. data/ext/iodine/fio.h +0 -6371
  91. data/ext/iodine/fio_cli.c +0 -431
  92. data/ext/iodine/fio_cli.h +0 -189
  93. data/ext/iodine/fio_json_parser.h +0 -688
  94. data/ext/iodine/fio_siphash.c +0 -157
  95. data/ext/iodine/fio_siphash.h +0 -37
  96. data/ext/iodine/fio_tls.h +0 -129
  97. data/ext/iodine/fio_tls_missing.c +0 -649
  98. data/ext/iodine/fio_tls_openssl.c +0 -1106
  99. data/ext/iodine/fio_tmpfile.h +0 -50
  100. data/ext/iodine/fiobj.h +0 -44
  101. data/ext/iodine/fiobj4fio.h +0 -21
  102. data/ext/iodine/fiobj_ary.c +0 -333
  103. data/ext/iodine/fiobj_ary.h +0 -139
  104. data/ext/iodine/fiobj_data.c +0 -1187
  105. data/ext/iodine/fiobj_data.h +0 -167
  106. data/ext/iodine/fiobj_hash.c +0 -409
  107. data/ext/iodine/fiobj_hash.h +0 -176
  108. data/ext/iodine/fiobj_json.c +0 -622
  109. data/ext/iodine/fiobj_json.h +0 -68
  110. data/ext/iodine/fiobj_mem.h +0 -71
  111. data/ext/iodine/fiobj_mustache.c +0 -317
  112. data/ext/iodine/fiobj_mustache.h +0 -62
  113. data/ext/iodine/fiobj_numbers.c +0 -344
  114. data/ext/iodine/fiobj_numbers.h +0 -127
  115. data/ext/iodine/fiobj_str.c +0 -433
  116. data/ext/iodine/fiobj_str.h +0 -172
  117. data/ext/iodine/fiobject.c +0 -620
  118. data/ext/iodine/fiobject.h +0 -655
  119. data/ext/iodine/hpack.h +0 -1923
  120. data/ext/iodine/http.c +0 -2743
  121. data/ext/iodine/http.h +0 -1002
  122. data/ext/iodine/http1.c +0 -910
  123. data/ext/iodine/http1.h +0 -29
  124. data/ext/iodine/http1_parser.h +0 -878
  125. data/ext/iodine/http_internal.c +0 -1279
  126. data/ext/iodine/http_internal.h +0 -237
  127. data/ext/iodine/http_mime_parser.h +0 -350
  128. data/ext/iodine/iodine_caller.c +0 -230
  129. data/ext/iodine/iodine_connection.c +0 -941
  130. data/ext/iodine/iodine_defer.c +0 -420
  131. data/ext/iodine/iodine_fiobj2rb.h +0 -120
  132. data/ext/iodine/iodine_helpers.c +0 -282
  133. data/ext/iodine/iodine_helpers.h +0 -12
  134. data/ext/iodine/iodine_http.c +0 -1181
  135. data/ext/iodine/iodine_http.h +0 -23
  136. data/ext/iodine/iodine_json.c +0 -302
  137. data/ext/iodine/iodine_mustache.c +0 -567
  138. data/ext/iodine/iodine_pubsub.c +0 -580
  139. data/ext/iodine/iodine_pubsub.h +0 -26
  140. data/ext/iodine/iodine_rack_io.c +0 -273
  141. data/ext/iodine/iodine_rack_io.h +0 -20
  142. data/ext/iodine/iodine_store.c +0 -148
  143. data/ext/iodine/iodine_tcp.c +0 -346
  144. data/ext/iodine/iodine_tcp.h +0 -13
  145. data/ext/iodine/iodine_tls.c +0 -261
  146. data/ext/iodine/mustache_parser.h +0 -1546
  147. data/ext/iodine/redis_engine.c +0 -957
  148. data/ext/iodine/redis_engine.h +0 -79
  149. data/ext/iodine/resp_parser.h +0 -317
  150. data/ext/iodine/websocket_parser.h +0 -506
  151. data/ext/iodine/websockets.c +0 -743
  152. data/ext/iodine/websockets.h +0 -185
  153. data/lib/iodine/connection.rb +0 -61
  154. data/lib/iodine/json.rb +0 -42
  155. data/lib/iodine/mustache.rb +0 -113
  156. data/lib/iodine/pubsub.rb +0 -55
  157. data/lib/iodine/rack_utils.rb +0 -43
  158. data/lib/iodine/tls.rb +0 -16
  159. data/lib/rack/handler/iodine.rb +0 -33
  160. data/logo.png +0 -0
@@ -1,688 +0,0 @@
1
- #ifndef H_FIO_JSON_H
2
- /* *****************************************************************************
3
- * Copyright: Boaz Segev, 2017-2019
4
- * License: MIT
5
- *
6
- * This header file is a single-file JSON naive parse.
7
- *
8
- * The code was extracted form the FIOBJ implementation in order to allow the
9
- * parser to be used independantly from the rest of the facil.io library.
10
- *
11
- * The parser ignores missing commas and other formatting errors when possible.
12
- *
13
- * The parser also extends the JSON format to allow for C and Bash style
14
- * comments as well as hex numerical formats.
15
- *****************************************************************************
16
- */
17
- #define H_FIO_JSON_H
18
-
19
- #include <ctype.h>
20
- #include <math.h>
21
- #include <stdint.h>
22
- #include <stdlib.h>
23
- #include <string.h>
24
-
25
- #if DEBUG
26
- #include <stdio.h>
27
- #endif
28
-
29
- #if !defined(__GNUC__) && !defined(__clang__) && !defined(FIO_GNUC_BYPASS)
30
- #define __attribute__(...)
31
- #define __has_include(...) 0
32
- #define __has_builtin(...) 0
33
- #define FIO_GNUC_BYPASS 1
34
- #elif !defined(__clang__) && !defined(__has_builtin)
35
- #define __has_builtin(...) 0
36
- #define FIO_GNUC_BYPASS 1
37
- #endif
38
-
39
- /* *****************************************************************************
40
- JSON API
41
- ***************************************************************************** */
42
-
43
- /* maximum allowed depth values max out at 32, since a bitmap is used */
44
- #if !defined(JSON_MAX_DEPTH) || JSON_MAX_DEPTH > 32
45
- #undef JSON_MAX_DEPTH
46
- #define JSON_MAX_DEPTH 32
47
- #endif
48
-
49
- /** The JSON parser type. Memory must be initialized to 0 before first uses. */
50
- typedef struct {
51
- /** in dictionary flag. */
52
- uint32_t dict;
53
- /** level of nesting. */
54
- uint8_t depth;
55
- /** in dictionary waiting for key. */
56
- uint8_t key;
57
- } json_parser_s;
58
-
59
- /**
60
- * Stream parsing of JSON data using a persistent parser.
61
- *
62
- * Returns the number of bytes consumed (0 being a valid value).
63
- *
64
- * Unconsumed data should be resent to the parser once more data is available.
65
- *
66
- * For security (due to numeral parsing concerns), a NUL byte should be placed
67
- * at `buffer[length]`.
68
- */
69
- static size_t __attribute__((unused))
70
- fio_json_parse(json_parser_s *parser, const char *buffer, size_t length);
71
-
72
- /**
73
- * This function allows JSON formatted strings to be converted to native
74
- * strings.
75
- */
76
- static size_t __attribute__((unused))
77
- fio_json_unescape_str(void *dest, const char *source, size_t length);
78
-
79
- /* *****************************************************************************
80
- JSON Callacks - these must be implemented in the C file that uses the parser
81
- ***************************************************************************** */
82
-
83
- /** a NULL object was detected */
84
- static void fio_json_on_null(json_parser_s *p);
85
- /** a TRUE object was detected */
86
- static void fio_json_on_true(json_parser_s *p);
87
- /** a FALSE object was detected */
88
- static void fio_json_on_false(json_parser_s *p);
89
- /** a Numberl was detected (long long). */
90
- static void fio_json_on_number(json_parser_s *p, long long i);
91
- /** a Float was detected (double). */
92
- static void fio_json_on_float(json_parser_s *p, double f);
93
- /** a String was detected (int / float). update `pos` to point at ending */
94
- static void fio_json_on_string(json_parser_s *p, void *start, size_t length);
95
- /** a dictionary object was detected, should return 0 unless error occurred. */
96
- static int fio_json_on_start_object(json_parser_s *p);
97
- /** a dictionary object closure detected */
98
- static void fio_json_on_end_object(json_parser_s *p);
99
- /** an array object was detected, should return 0 unless error occurred. */
100
- static int fio_json_on_start_array(json_parser_s *p);
101
- /** an array closure was detected */
102
- static void fio_json_on_end_array(json_parser_s *p);
103
- /** the JSON parsing is complete */
104
- static void fio_json_on_json(json_parser_s *p);
105
- /** the JSON parsing is complete */
106
- static void fio_json_on_error(json_parser_s *p);
107
-
108
- /* *****************************************************************************
109
- JSON maps (arrays used to map data to simplify `if` statements)
110
- ***************************************************************************** */
111
-
112
- /*
113
- Marks as object seperators any of the following:
114
-
115
- * White Space: [0x09, 0x0A, 0x0D, 0x20]
116
- * Comma ("," / 0x2C)
117
- * NOT Colon (":" / 0x3A)
118
- * == [0x09, 0x0A, 0x0D, 0x20, 0x2C]
119
- The rest belong to objects,
120
- */
121
- static const uint8_t JSON_SEPERATOR[] = {
122
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
124
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
129
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
130
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
132
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
133
- };
134
-
135
- /*
136
- Marks a numeral valid char (it's a permisive list):
137
- ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'e', 'E', '+', '-', 'x', 'b',
138
- '.']
139
- */
140
- static const uint8_t JSON_NUMERAL[] = {
141
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
142
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,
143
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
144
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
145
- 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
146
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
147
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
148
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
149
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
150
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
151
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
152
- };
153
-
154
- static const char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7',
155
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
156
-
157
- static const uint8_t is_hex[] = {
158
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
159
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
160
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0,
161
- 0, 0, 0, 0, 0, 11, 12, 13, 14, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0,
162
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 13,
163
- 14, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
164
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
165
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
166
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
167
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
168
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
169
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
170
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
171
-
172
- /*
173
- Stops seeking a String:
174
- ['\\', '"']
175
- */
176
- static const uint8_t string_seek_stop[] = {
177
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
178
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
179
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
180
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
181
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
182
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
183
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
184
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
185
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
186
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
187
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
188
-
189
- /* *****************************************************************************
190
- JSON String Helper - Seeking to the end of a string
191
- ***************************************************************************** */
192
-
193
- /**
194
- * finds the first occurance of either '"' or '\\'.
195
- */
196
- static inline int seek2marker(uint8_t **buffer,
197
- register const uint8_t *const limit) {
198
- if (string_seek_stop[**buffer])
199
- return 1;
200
-
201
- #if !ALLOW_UNALIGNED_MEMORY_ACCESS || (!__x86_64__ && !__aarch64__)
202
- /* too short for this mess */
203
- if ((uintptr_t)limit <= 8 + ((uintptr_t)*buffer & (~(uintptr_t)7)))
204
- goto finish;
205
- /* align memory */
206
- if (1) {
207
- {
208
- const uint8_t *alignment =
209
- (uint8_t *)(((uintptr_t)(*buffer) & (~(uintptr_t)7)) + 8);
210
- if (limit >= alignment) {
211
- while (*buffer < alignment) {
212
- if (string_seek_stop[**buffer])
213
- return 1;
214
- *buffer += 1;
215
- }
216
- }
217
- }
218
- const uint8_t *limit64 = (uint8_t *)((uintptr_t)limit & (~(uintptr_t)7));
219
- #else
220
- const uint8_t *limit64 = (uint8_t *)limit - 7;
221
- #endif
222
- uint64_t wanted1 = 0x0101010101010101ULL * '"';
223
- uint64_t wanted2 = 0x0101010101010101ULL * '\\';
224
- for (; *buffer < limit64; *buffer += 8) {
225
- const uint64_t eq1 = ~((*((uint64_t *)*buffer)) ^ wanted1);
226
- const uint64_t t1 =
227
- ((eq1 & 0x7f7f7f7f7f7f7f7fULL) + 0x0101010101010101ULL) &
228
- (eq1 & 0x8080808080808080ULL);
229
- const uint64_t eq2 = ~((*((uint64_t *)*buffer)) ^ wanted2);
230
- const uint64_t t2 =
231
- ((eq2 & 0x7f7f7f7f7f7f7f7fULL) + 0x0101010101010101ULL) &
232
- (eq2 & 0x8080808080808080ULL);
233
- if ((t1 | t2)) {
234
- break;
235
- }
236
- }
237
- }
238
- #if !ALLOW_UNALIGNED_MEMORY_ACCESS || (!__x86_64__ && !__aarch64__)
239
- finish:
240
- #endif
241
- if (*buffer + 4 <= limit) {
242
- if (string_seek_stop[(*buffer)[0]]) {
243
- // *buffer += 0;
244
- return 1;
245
- }
246
- if (string_seek_stop[(*buffer)[1]]) {
247
- *buffer += 1;
248
- return 1;
249
- }
250
- if (string_seek_stop[(*buffer)[2]]) {
251
- *buffer += 2;
252
- return 1;
253
- }
254
- if (string_seek_stop[(*buffer)[3]]) {
255
- *buffer += 3;
256
- return 1;
257
- }
258
- *buffer += 4;
259
- }
260
- while (*buffer < limit) {
261
- if (string_seek_stop[**buffer])
262
- return 1;
263
- (*buffer)++;
264
- }
265
- return 0;
266
- }
267
-
268
- static inline int seek2eos(uint8_t **buffer,
269
- register const uint8_t *const limit) {
270
- while (*buffer < limit) {
271
- if (seek2marker(buffer, limit) && **buffer == '"')
272
- return 1;
273
- (*buffer) += 2; /* consume both the escape '\\' and the escape code. */
274
- }
275
- return 0;
276
- }
277
-
278
- /* *****************************************************************************
279
- JSON String to Numeral Helpers - allowing for stand-alone mode
280
- ***************************************************************************** */
281
-
282
- #ifndef H_FACIL_IO_H /* defined in fio.h */
283
-
284
- /**
285
- * We include this in case the parser is used outside of facil.io.
286
- */
287
- int64_t __attribute__((weak)) fio_atol(char **pstr) {
288
- return strtoll((char *)*pstr, (char **)pstr, 0);
289
- }
290
- #pragma weak fio_atol
291
-
292
- /**
293
- * We include this in case the parser is used outside of facil.io.
294
- */
295
- double __attribute__((weak)) fio_atof(char **pstr) {
296
- return strtod((char *)*pstr, (char **)pstr);
297
- }
298
- #pragma weak fio_atof
299
-
300
- #endif
301
-
302
- /* *****************************************************************************
303
- JSON Consumption (astract parsing)
304
- ***************************************************************************** */
305
-
306
- /**
307
- * Returns the number of bytes consumed. Stops as close as possible to the end
308
- * of the buffer or once an object parsing was completed.
309
- */
310
- static size_t __attribute__((unused))
311
- fio_json_parse(json_parser_s *parser, const char *buffer, size_t length) {
312
- if (!length || !buffer)
313
- return 0;
314
- uint8_t *pos = (uint8_t *)buffer;
315
- const uint8_t *limit = pos + length;
316
- do {
317
- while (pos < limit && JSON_SEPERATOR[*pos])
318
- ++pos;
319
- if (pos == limit)
320
- goto stop;
321
- switch (*pos) {
322
- case '"': {
323
- uint8_t *tmp = pos + 1;
324
- if (seek2eos(&tmp, limit) == 0)
325
- goto stop;
326
- if (parser->key) {
327
- uint8_t *key = tmp + 1;
328
- while (key < limit && JSON_SEPERATOR[*key])
329
- ++key;
330
- if (key >= limit)
331
- goto stop;
332
- if (*key != ':')
333
- goto error;
334
- ++pos;
335
- fio_json_on_string(parser, pos, (uintptr_t)(tmp - pos));
336
- pos = key + 1;
337
- parser->key = 0;
338
- continue; /* skip tests */
339
- } else {
340
- ++pos;
341
- fio_json_on_string(parser, pos, (uintptr_t)(tmp - pos));
342
- pos = tmp + 1;
343
- }
344
- break;
345
- }
346
- case '{':
347
- if (parser->key) {
348
- #if DEBUG
349
- fprintf(stderr, "ERROR: JSON key can't be a Hash.\n");
350
- #endif
351
- goto error;
352
- }
353
- ++parser->depth;
354
- if (parser->depth >= JSON_MAX_DEPTH)
355
- goto error;
356
- parser->dict = (parser->dict << 1) | 1;
357
- ++pos;
358
- if (fio_json_on_start_object(parser))
359
- goto error;
360
- break;
361
- case '}':
362
- if ((parser->dict & 1) == 0) {
363
- #if DEBUG
364
- fprintf(stderr, "ERROR: JSON dictionary closure error.\n");
365
- #endif
366
- goto error;
367
- }
368
- if (!parser->key) {
369
- #if DEBUG
370
- fprintf(stderr, "ERROR: JSON dictionary closure missing key value.\n");
371
- goto error;
372
- #endif
373
- fio_json_on_null(parser); /* append NULL and recuperate from error. */
374
- }
375
- --parser->depth;
376
- ++pos;
377
- parser->dict = (parser->dict >> 1);
378
- fio_json_on_end_object(parser);
379
- break;
380
- case '[':
381
- if (parser->key) {
382
- #if DEBUG
383
- fprintf(stderr, "ERROR: JSON key can't be an array.\n");
384
- #endif
385
- goto error;
386
- }
387
- ++parser->depth;
388
- if (parser->depth >= JSON_MAX_DEPTH)
389
- goto error;
390
- ++pos;
391
- parser->dict = (parser->dict << 1);
392
- if (fio_json_on_start_array(parser))
393
- goto error;
394
- break;
395
- case ']':
396
- if ((parser->dict & 1) || !parser->depth)
397
- goto error;
398
- --parser->depth;
399
- ++pos;
400
- parser->dict = (parser->dict >> 1);
401
- fio_json_on_end_array(parser);
402
- break;
403
- case 't':
404
- if (pos + 3 >= limit)
405
- goto stop;
406
- if (pos[1] == 'r' && pos[2] == 'u' && pos[3] == 'e')
407
- fio_json_on_true(parser);
408
- else
409
- goto error;
410
- pos += 4;
411
- break;
412
- case 'N': /* overflow */
413
- case 'n':
414
- if (pos + 2 <= limit && (pos[1] | 32) == 'a' && (pos[2] | 32) == 'n')
415
- goto numeral;
416
- if (pos + 3 >= limit)
417
- goto stop;
418
- if (pos[1] == 'u' && pos[2] == 'l' && pos[3] == 'l')
419
- fio_json_on_null(parser);
420
- else
421
- goto error;
422
- pos += 4;
423
- break;
424
- case 'f':
425
- if (pos + 4 >= limit)
426
- goto stop;
427
- if (pos + 4 < limit && pos[1] == 'a' && pos[2] == 'l' && pos[3] == 's' &&
428
- pos[4] == 'e')
429
- fio_json_on_false(parser);
430
- else
431
- goto error;
432
- pos += 5;
433
- break;
434
- case '-': /* overflow */
435
- case '0': /* overflow */
436
- case '1': /* overflow */
437
- case '2': /* overflow */
438
- case '3': /* overflow */
439
- case '4': /* overflow */
440
- case '5': /* overflow */
441
- case '6': /* overflow */
442
- case '7': /* overflow */
443
- case '8': /* overflow */
444
- case '9': /* overflow */
445
- case '.': /* overflow */
446
- case 'e': /* overflow */
447
- case 'E': /* overflow */
448
- case 'x': /* overflow */
449
- case 'i': /* overflow */
450
- case 'I': /* overflow */
451
- numeral : {
452
- uint8_t *tmp = pos;
453
- long long i = fio_atol((char **)&tmp);
454
- if (tmp > limit)
455
- goto stop;
456
- if (!tmp || tmp == pos || JSON_NUMERAL[*tmp]) {
457
- tmp = pos;
458
- double f = fio_atof((char **)&tmp);
459
- if (tmp > limit)
460
- goto stop;
461
- if (!tmp || tmp == pos || JSON_NUMERAL[*tmp])
462
- goto error;
463
- fio_json_on_float(parser, f);
464
- pos = tmp;
465
- } else {
466
- fio_json_on_number(parser, i);
467
- pos = tmp;
468
- }
469
- break;
470
- }
471
- case '#': /* Ruby style comment */
472
- {
473
- uint8_t *tmp = memchr(pos, '\n', (uintptr_t)(limit - pos));
474
- if (!tmp)
475
- goto stop;
476
- pos = tmp + 1;
477
- continue; /* skip tests */
478
- ;
479
- }
480
- case '/': /* C style / Javascript style comment */
481
- if (pos[1] == '*') {
482
- if (pos + 4 > limit)
483
- goto stop;
484
- uint8_t *tmp = pos + 2; /* avoid this: /*/
485
- do {
486
- ++tmp;
487
- tmp = memchr(tmp, '/', (uintptr_t)(limit - tmp));
488
- } while (tmp && tmp[-1] != '*');
489
- if (!tmp)
490
- goto stop;
491
- pos = tmp + 1;
492
- } else if (pos[1] == '/') {
493
- uint8_t *tmp = memchr(pos, '\n', (uintptr_t)(limit - pos));
494
- if (!tmp)
495
- goto stop;
496
- pos = tmp + 1;
497
- } else
498
- goto error;
499
- continue; /* skip tests */
500
- ;
501
- default:
502
- goto error;
503
- }
504
- if (parser->depth == 0) {
505
- fio_json_on_json(parser);
506
- goto stop;
507
- }
508
- parser->key = (parser->dict & 1);
509
- } while (pos < limit);
510
- stop:
511
- return (size_t)((uintptr_t)pos - (uintptr_t)buffer);
512
- error:
513
- fio_json_on_error(parser);
514
- return 0;
515
- }
516
-
517
- /* *****************************************************************************
518
- JSON Unescape String
519
- ***************************************************************************** */
520
-
521
- #ifdef __cplusplus
522
- #define REGISTER
523
- #else
524
- #define REGISTER register
525
- #endif
526
-
527
- /* converts a uint32_t to UTF-8 and returns the number of bytes written */
528
- static inline int utf8_from_u32(uint8_t *dest, uint32_t u) {
529
- if (u <= 127) {
530
- *dest = u;
531
- return 1;
532
- } else if (u <= 2047) {
533
- *(dest++) = 192 | (u >> 6);
534
- *(dest++) = 128 | (u & 63);
535
- return 2;
536
- } else if (u <= 65535) {
537
- *(dest++) = 224 | (u >> 12);
538
- *(dest++) = 128 | ((u >> 6) & 63);
539
- *(dest++) = 128 | (u & 63);
540
- return 3;
541
- }
542
- *(dest++) = 240 | ((u >> 18) & 7);
543
- *(dest++) = 128 | ((u >> 12) & 63);
544
- *(dest++) = 128 | ((u >> 6) & 63);
545
- *(dest++) = 128 | (u & 63);
546
- return 4;
547
- }
548
-
549
- static void __attribute__((unused))
550
- fio_json_unescape_str_internal(uint8_t **dest, const uint8_t **src) {
551
- ++(*src);
552
- switch (**src) {
553
- case 'b':
554
- **dest = '\b';
555
- ++(*src);
556
- ++(*dest);
557
- return; /* from switch */
558
- case 'f':
559
- **dest = '\f';
560
- ++(*src);
561
- ++(*dest);
562
- return; /* from switch */
563
- case 'n':
564
- **dest = '\n';
565
- ++(*src);
566
- ++(*dest);
567
- return; /* from switch */
568
- case 'r':
569
- **dest = '\r';
570
- ++(*src);
571
- ++(*dest);
572
- return; /* from switch */
573
- case 't':
574
- **dest = '\t';
575
- ++(*src);
576
- ++(*dest);
577
- return; /* from switch */
578
- case 'u': { /* test for octal notation */
579
- if (is_hex[(*src)[1]] && is_hex[(*src)[2]] && is_hex[(*src)[3]] &&
580
- is_hex[(*src)[4]]) {
581
- uint32_t t =
582
- ((((is_hex[(*src)[1]] - 1) << 4) | (is_hex[(*src)[2]] - 1)) << 8) |
583
- (((is_hex[(*src)[3]] - 1) << 4) | (is_hex[(*src)[4]] - 1));
584
- if ((*src)[5] == '\\' && (*src)[6] == 'u' && is_hex[(*src)[7]] &&
585
- is_hex[(*src)[8]] && is_hex[(*src)[9]] && is_hex[(*src)[10]]) {
586
- /* Serrogate Pair */
587
- t = (t & 0x03FF) << 10;
588
- t |= ((((((is_hex[(*src)[7]] - 1) << 4) | (is_hex[(*src)[8]] - 1))
589
- << 8) |
590
- (((is_hex[(*src)[9]] - 1) << 4) | (is_hex[(*src)[10]] - 1))) &
591
- 0x03FF);
592
- t += 0x10000;
593
- (*src) += 6;
594
- }
595
- *dest += utf8_from_u32(*dest, t);
596
- *src += 5;
597
- return;
598
- } else
599
- goto invalid_escape;
600
- }
601
- case 'x': { /* test for hex notation */
602
- if (is_hex[(*src)[1]] && is_hex[(*src)[2]]) {
603
- **dest = ((is_hex[(*src)[1]] - 1) << 4) | (is_hex[(*src)[2]] - 1);
604
- ++(*dest);
605
- (*src) += 3;
606
- return;
607
- } else
608
- goto invalid_escape;
609
- }
610
- case '0':
611
- case '1':
612
- case '2':
613
- case '3':
614
- case '4':
615
- case '5':
616
- case '6':
617
- case '7': { /* test for octal notation */
618
- if ((*src)[1] >= '0' && (*src)[1] <= '7') {
619
- **dest = (((*src)[0] - '0') << 3) | ((*src)[1] - '0');
620
- ++(*dest);
621
- (*src) += 2;
622
- break; /* from switch */
623
- } else
624
- goto invalid_escape;
625
- }
626
- case '"':
627
- case '\\':
628
- case '/':
629
- /* fallthrough */
630
- default:
631
- invalid_escape:
632
- **dest = **src;
633
- ++(*src);
634
- ++(*dest);
635
- }
636
- }
637
-
638
- static size_t __attribute__((unused))
639
- fio_json_unescape_str(void *dest, const char *source, size_t length) {
640
- const uint8_t *reader = (uint8_t *)source;
641
- const uint8_t *stop = reader + length;
642
- uint8_t *writer = (uint8_t *)dest;
643
- /* copy in chuncks unless we hit an escape marker */
644
- while (reader < stop) {
645
- #if !__x86_64__ && !__aarch64__
646
- /* we can't leverage unaligned memory access, so we read the buffer twice */
647
- uint8_t *tmp = memchr(reader, '\\', (size_t)(stop - reader));
648
- if (!tmp) {
649
- memmove(writer, reader, (size_t)(stop - reader));
650
- writer += (size_t)(stop - reader);
651
- goto finish;
652
- }
653
- memmove(writer, reader, (size_t)(tmp - reader));
654
- writer += (size_t)(tmp - reader);
655
- reader = tmp;
656
- #else
657
- const uint8_t *limit64 = (uint8_t *)stop - 7;
658
- uint64_t wanted1 = 0x0101010101010101ULL * '\\';
659
- while (reader < limit64) {
660
- const uint64_t eq1 = ~((*((uint64_t *)reader)) ^ wanted1);
661
- const uint64_t t0 = (eq1 & 0x7f7f7f7f7f7f7f7fllu) + 0x0101010101010101llu;
662
- const uint64_t t1 = (eq1 & 0x8080808080808080llu);
663
- if ((t0 & t1)) {
664
- break;
665
- }
666
- *((uint64_t *)writer) = *((uint64_t *)reader);
667
- reader += 8;
668
- writer += 8;
669
- }
670
- while (reader < stop) {
671
- if (*reader == '\\')
672
- break;
673
- *writer = *reader;
674
- ++reader;
675
- ++writer;
676
- }
677
- if (reader >= stop)
678
- goto finish;
679
- #endif
680
- fio_json_unescape_str_internal(&writer, &reader);
681
- }
682
- finish:
683
- return (size_t)((uintptr_t)writer - (uintptr_t)dest);
684
- }
685
-
686
- #undef REGISTER
687
-
688
- #endif