thrift 0.22.0 → 0.24.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.
- checksums.yaml +4 -4
- data/README.md +235 -17
- data/benchmark/benchmark.rb +23 -8
- data/benchmark/client.rb +50 -6
- data/benchmark/server.rb +46 -7
- data/benchmark/thin_server.rb +2 -0
- data/ext/binary_protocol_accelerated.c +154 -42
- data/ext/bytes.c +14 -0
- data/ext/compact_protocol.c +138 -45
- data/ext/constants.h +12 -0
- data/ext/extconf.rb +17 -8
- data/ext/memory_buffer.c +44 -7
- data/ext/protocol.c +29 -0
- data/ext/protocol.h +35 -0
- data/ext/struct.c +48 -17
- data/ext/thrift_native.c +28 -3
- data/lib/thrift/bytes.rb +70 -100
- data/lib/thrift/client.rb +54 -13
- data/lib/thrift/exceptions.rb +6 -5
- data/lib/thrift/multiplexed_processor.rb +20 -10
- data/lib/thrift/processor.rb +7 -6
- data/lib/thrift/protocol/base_protocol.rb +52 -21
- data/lib/thrift/protocol/binary_protocol.rb +65 -20
- data/lib/thrift/protocol/binary_protocol_accelerated.rb +6 -5
- data/lib/thrift/protocol/compact_protocol.rb +76 -41
- data/lib/thrift/protocol/header_protocol.rb +321 -0
- data/lib/thrift/protocol/json_protocol.rb +44 -27
- data/lib/thrift/protocol/multiplexed_protocol.rb +6 -5
- data/lib/thrift/protocol/protocol_decorator.rb +13 -4
- data/lib/thrift/serializer/deserializer.rb +6 -5
- data/lib/thrift/serializer/serializer.rb +5 -5
- data/lib/thrift/server/base_server.rb +5 -4
- data/lib/thrift/server/mongrel_http_server.rb +7 -6
- data/lib/thrift/server/nonblocking_server.rb +35 -9
- data/lib/thrift/server/simple_server.rb +13 -5
- data/lib/thrift/server/thin_http_server.rb +4 -3
- data/lib/thrift/server/thread_pool_server.rb +7 -6
- data/lib/thrift/server/threaded_server.rb +13 -5
- data/lib/thrift/struct.rb +12 -11
- data/lib/thrift/struct_union.rb +14 -9
- data/lib/thrift/thrift_native.rb +3 -2
- data/lib/thrift/transport/base_server_transport.rb +8 -5
- data/lib/thrift/transport/base_transport.rb +18 -14
- data/lib/thrift/transport/buffered_transport.rb +7 -6
- data/lib/thrift/transport/framed_transport.rb +8 -7
- data/lib/thrift/transport/header_transport.rb +562 -0
- data/lib/thrift/transport/http_client_transport.rb +2 -1
- data/lib/thrift/transport/io_stream_transport.rb +4 -3
- data/lib/thrift/transport/memory_buffer_transport.rb +13 -6
- data/lib/thrift/transport/server_socket.rb +14 -8
- data/lib/thrift/transport/socket.rb +126 -60
- data/lib/thrift/transport/ssl_server_socket.rb +4 -3
- data/lib/thrift/transport/ssl_socket.rb +45 -13
- data/lib/thrift/transport/unix_server_socket.rb +9 -5
- data/lib/thrift/transport/unix_socket.rb +7 -6
- data/lib/thrift/types.rb +10 -6
- data/lib/thrift/union.rb +15 -8
- data/lib/thrift/uuid.rb +50 -0
- data/lib/thrift.rb +4 -1
- data/spec/ThriftSpec.thrift +21 -1
- data/spec/base_protocol_spec.rb +21 -2
- data/spec/base_transport_spec.rb +48 -8
- data/spec/binary_protocol_accelerated_spec.rb +1 -0
- data/spec/binary_protocol_spec.rb +1 -2
- data/spec/binary_protocol_spec_shared.rb +206 -155
- data/spec/bytes_spec.rb +71 -114
- data/spec/client_spec.rb +86 -19
- data/spec/compact_protocol_spec.rb +153 -16
- data/spec/constants_demo_spec.rb +102 -0
- data/spec/exception_spec.rb +1 -1
- data/spec/flat_spec.rb +1 -0
- data/spec/header_protocol_spec.rb +476 -0
- data/spec/header_transport_spec.rb +431 -0
- data/spec/http_client_spec.rb +5 -6
- data/spec/json_protocol_spec.rb +69 -47
- data/spec/multiplexed_processor_spec.rb +75 -0
- data/spec/namespaced_spec.rb +1 -1
- data/spec/nonblocking_server_spec.rb +174 -8
- data/spec/processor_spec.rb +1 -1
- data/spec/recursion_depth_spec.rb +223 -0
- data/spec/serializer_spec.rb +1 -1
- data/spec/server_socket_spec.rb +38 -1
- data/spec/server_spec.rb +60 -9
- data/spec/socket_spec.rb +119 -13
- data/spec/socket_spec_shared.rb +73 -9
- data/spec/spec_helper.rb +2 -1
- data/spec/ssl_server_socket_spec.rb +52 -1
- data/spec/ssl_socket_spec.rb +181 -11
- data/spec/struct_nested_containers_spec.rb +2 -2
- data/spec/struct_spec.rb +114 -9
- data/spec/support/header_protocol_helper.rb +55 -0
- data/spec/thin_http_server_spec.rb +4 -18
- data/spec/types_spec.rb +26 -26
- data/spec/union_spec.rb +70 -11
- data/spec/unix_socket_spec.rb +17 -2
- data/spec/uuid_validation_spec.rb +239 -0
- data/test/fuzz/Makefile +779 -0
- data/test/fuzz/Makefile.am +173 -0
- data/test/fuzz/Makefile.in +775 -0
- data/test/fuzz/README.md +149 -0
- data/test/fuzz/fuzz_common.rb +96 -0
- data/{lib/thrift/core_ext.rb → test/fuzz/fuzz_parse_binary_protocol.rb} +4 -4
- data/{lib/thrift/core_ext/fixnum.rb → test/fuzz/fuzz_parse_binary_protocol_accelerated.rb} +7 -13
- data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +23 -0
- data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_parse_compact_protocol.rb +23 -0
- data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_parse_json_protocol.rb +23 -0
- data/test/fuzz/fuzz_parse_json_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_json_protocol.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_tracer.rb +29 -0
- metadata +105 -70
data/ext/compact_protocol.c
CHANGED
|
@@ -20,10 +20,12 @@
|
|
|
20
20
|
#include <ruby.h>
|
|
21
21
|
#include <stdbool.h>
|
|
22
22
|
#include <stdint.h>
|
|
23
|
+
#include <string.h>
|
|
23
24
|
#include <constants.h>
|
|
24
25
|
#include <struct.h>
|
|
25
26
|
#include <macros.h>
|
|
26
27
|
#include <bytes.h>
|
|
28
|
+
#include <protocol.h>
|
|
27
29
|
|
|
28
30
|
#define LAST_ID(obj) FIX2INT(rb_ary_pop(rb_ivar_get(obj, last_field_id)))
|
|
29
31
|
#define SET_LAST_ID(obj, val) rb_ary_push(rb_ivar_get(obj, last_field_id), val)
|
|
@@ -58,6 +60,7 @@ static int CTYPE_LIST = 0x09;
|
|
|
58
60
|
static int CTYPE_SET = 0x0A;
|
|
59
61
|
static int CTYPE_MAP = 0x0B;
|
|
60
62
|
static int CTYPE_STRUCT = 0x0C;
|
|
63
|
+
static int CTYPE_UUID = 0x0D;
|
|
61
64
|
|
|
62
65
|
VALUE rb_thrift_compact_proto_write_i16(VALUE self, VALUE i16);
|
|
63
66
|
|
|
@@ -86,6 +89,8 @@ static int get_compact_type(VALUE type_value) {
|
|
|
86
89
|
return CTYPE_MAP;
|
|
87
90
|
} else if (type == TTYPE_STRUCT) {
|
|
88
91
|
return CTYPE_STRUCT;
|
|
92
|
+
} else if (type == TTYPE_UUID) {
|
|
93
|
+
return CTYPE_UUID;
|
|
89
94
|
} else {
|
|
90
95
|
char str[50];
|
|
91
96
|
sprintf(str, "don't know what type: %d", type);
|
|
@@ -102,7 +107,7 @@ static void write_field_begin_internal(VALUE self, VALUE type, VALUE id_value, V
|
|
|
102
107
|
int id = FIX2INT(id_value);
|
|
103
108
|
int last_id = LAST_ID(self);
|
|
104
109
|
VALUE transport = GET_TRANSPORT(self);
|
|
105
|
-
|
|
110
|
+
|
|
106
111
|
// if there's a type override, use that.
|
|
107
112
|
int8_t type_to_write = RTEST(type_override) ? FIX2INT(type_override) : get_compact_type(type);
|
|
108
113
|
// check if we can use delta encoding for the field id
|
|
@@ -119,21 +124,29 @@ static void write_field_begin_internal(VALUE self, VALUE type, VALUE id_value, V
|
|
|
119
124
|
SET_LAST_ID(self, id_value);
|
|
120
125
|
}
|
|
121
126
|
|
|
122
|
-
static
|
|
123
|
-
return (n << 1) ^ (n
|
|
127
|
+
static uint32_t int_to_zig_zag(int32_t n) {
|
|
128
|
+
return (((uint32_t)n) << 1) ^ (0U - (uint32_t)(n < 0));
|
|
124
129
|
}
|
|
125
130
|
|
|
126
131
|
static uint64_t ll_to_zig_zag(int64_t n) {
|
|
127
|
-
return (n << 1) ^ (n
|
|
132
|
+
return (((uint64_t)n) << 1) ^ (0ULL - (uint64_t)(n < 0));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static uint32_t message_seqid_to_varint32(int32_t seqid) {
|
|
136
|
+
return seqid < 0 ? (uint32_t)((int64_t)seqid + (INT64_C(1) << 32)) : (uint32_t)seqid;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
static int32_t message_seqid_from_varint32(uint32_t seqid) {
|
|
140
|
+
return seqid > INT32_MAX ? (int32_t)((int64_t)seqid - (INT64_C(1) << 32)) : (int32_t)seqid;
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
static void write_varint32(VALUE transport, uint32_t n) {
|
|
131
144
|
while (true) {
|
|
132
|
-
if ((n & ~
|
|
133
|
-
write_byte_direct(transport, n &
|
|
145
|
+
if ((n & ~0x7FU) == 0U) {
|
|
146
|
+
write_byte_direct(transport, n & 0x7FU);
|
|
134
147
|
break;
|
|
135
148
|
} else {
|
|
136
|
-
write_byte_direct(transport, (n &
|
|
149
|
+
write_byte_direct(transport, (n & 0x7FU) | 0x80U);
|
|
137
150
|
n = n >> 7;
|
|
138
151
|
}
|
|
139
152
|
}
|
|
@@ -141,11 +154,11 @@ static void write_varint32(VALUE transport, uint32_t n) {
|
|
|
141
154
|
|
|
142
155
|
static void write_varint64(VALUE transport, uint64_t n) {
|
|
143
156
|
while (true) {
|
|
144
|
-
if ((n & ~
|
|
145
|
-
write_byte_direct(transport, n &
|
|
157
|
+
if ((n & ~0x7FULL) == 0ULL) {
|
|
158
|
+
write_byte_direct(transport, n & 0x7FULL);
|
|
146
159
|
break;
|
|
147
160
|
} else {
|
|
148
|
-
write_byte_direct(transport, (n &
|
|
161
|
+
write_byte_direct(transport, (n & 0x7FULL) | 0x80ULL);
|
|
149
162
|
n = n >> 7;
|
|
150
163
|
}
|
|
151
164
|
}
|
|
@@ -169,6 +182,7 @@ static void write_collection_begin(VALUE transport, VALUE elem_type, VALUE size_
|
|
|
169
182
|
VALUE rb_thrift_compact_proto_write_i32(VALUE self, VALUE i32);
|
|
170
183
|
VALUE rb_thrift_compact_proto_write_string(VALUE self, VALUE str);
|
|
171
184
|
VALUE rb_thrift_compact_proto_write_binary(VALUE self, VALUE buf);
|
|
185
|
+
VALUE rb_thrift_compact_proto_write_uuid(VALUE self, VALUE uuid);
|
|
172
186
|
|
|
173
187
|
VALUE rb_thrift_compact_proto_write_message_end(VALUE self) {
|
|
174
188
|
return Qnil;
|
|
@@ -202,11 +216,12 @@ VALUE rb_thrift_compact_proto_write_set_end(VALUE self) {
|
|
|
202
216
|
|
|
203
217
|
VALUE rb_thrift_compact_proto_write_message_begin(VALUE self, VALUE name, VALUE type, VALUE seqid) {
|
|
204
218
|
VALUE transport = GET_TRANSPORT(self);
|
|
219
|
+
int32_t seqid_value = FIX2INT(seqid);
|
|
205
220
|
write_byte_direct(transport, PROTOCOL_ID);
|
|
206
221
|
write_byte_direct(transport, (VERSION & VERSION_MASK) | ((FIX2INT(type) << TYPE_SHIFT_AMOUNT) & TYPE_MASK));
|
|
207
|
-
write_varint32(transport,
|
|
222
|
+
write_varint32(transport, message_seqid_to_varint32(seqid_value));
|
|
208
223
|
rb_thrift_compact_proto_write_string(self, name);
|
|
209
|
-
|
|
224
|
+
|
|
210
225
|
return Qnil;
|
|
211
226
|
}
|
|
212
227
|
|
|
@@ -320,6 +335,46 @@ VALUE rb_thrift_compact_proto_write_binary(VALUE self, VALUE buf) {
|
|
|
320
335
|
return Qnil;
|
|
321
336
|
}
|
|
322
337
|
|
|
338
|
+
VALUE rb_thrift_compact_proto_write_uuid(VALUE self, VALUE uuid) {
|
|
339
|
+
if (NIL_P(uuid) || TYPE(uuid) != T_STRING) {
|
|
340
|
+
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("UUID must be a string")));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
VALUE transport = GET_TRANSPORT(self);
|
|
344
|
+
char bytes[16];
|
|
345
|
+
const char* str = RSTRING_PTR(uuid);
|
|
346
|
+
long len = RSTRING_LEN(uuid);
|
|
347
|
+
|
|
348
|
+
// Parse UUID string (format: "550e8400-e29b-41d4-a716-446655440000")
|
|
349
|
+
// Expected length: 36 characters (32 hex + 4 hyphens)
|
|
350
|
+
if (len != 36 || str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-') {
|
|
351
|
+
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("Invalid UUID format")));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Parse hex string to bytes using direct conversion, skipping hyphens
|
|
355
|
+
int byte_idx = 0;
|
|
356
|
+
for (int i = 0; i < len && byte_idx < 16; i++) {
|
|
357
|
+
if (str[i] == '-') continue;
|
|
358
|
+
if (i + 1 >= len || str[i + 1] == '-') break;
|
|
359
|
+
|
|
360
|
+
// Convert two hex characters to one byte
|
|
361
|
+
int high = hex_char_to_int(str[i]);
|
|
362
|
+
int low = hex_char_to_int(str[i + 1]);
|
|
363
|
+
|
|
364
|
+
if (high < 0 || low < 0) break;
|
|
365
|
+
|
|
366
|
+
bytes[byte_idx++] = (unsigned char)((high << 4) | low);
|
|
367
|
+
i++; // skip next char since we processed two
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (byte_idx != 16) {
|
|
371
|
+
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("Invalid UUID format")));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
WRITE(transport, bytes, 16);
|
|
375
|
+
return Qnil;
|
|
376
|
+
}
|
|
377
|
+
|
|
323
378
|
//---------------------------------------
|
|
324
379
|
// interface reading methods
|
|
325
380
|
//---------------------------------------
|
|
@@ -331,6 +386,7 @@ VALUE rb_thrift_compact_proto_read_binary(VALUE self);
|
|
|
331
386
|
VALUE rb_thrift_compact_proto_read_byte(VALUE self);
|
|
332
387
|
VALUE rb_thrift_compact_proto_read_i32(VALUE self);
|
|
333
388
|
VALUE rb_thrift_compact_proto_read_i16(VALUE self);
|
|
389
|
+
VALUE rb_thrift_compact_proto_read_uuid(VALUE self);
|
|
334
390
|
|
|
335
391
|
static int8_t get_ttype(int8_t ctype) {
|
|
336
392
|
if (ctype == TTYPE_STOP) {
|
|
@@ -357,6 +413,8 @@ static int8_t get_ttype(int8_t ctype) {
|
|
|
357
413
|
return TTYPE_MAP;
|
|
358
414
|
} else if (ctype == CTYPE_STRUCT) {
|
|
359
415
|
return TTYPE_STRUCT;
|
|
416
|
+
} else if (ctype == CTYPE_UUID) {
|
|
417
|
+
return TTYPE_UUID;
|
|
360
418
|
} else {
|
|
361
419
|
char str[50];
|
|
362
420
|
sprintf(str, "don't know what type: %d", ctype);
|
|
@@ -370,37 +428,49 @@ static char read_byte_direct(VALUE self) {
|
|
|
370
428
|
return (char)(FIX2INT(byte));
|
|
371
429
|
}
|
|
372
430
|
|
|
373
|
-
static int64_t zig_zag_to_ll(
|
|
374
|
-
return (((
|
|
431
|
+
static int64_t zig_zag_to_ll(uint64_t n) {
|
|
432
|
+
return (int64_t)((n >> 1) ^ (0ULL - (n & 1ULL)));
|
|
375
433
|
}
|
|
376
434
|
|
|
377
|
-
static int32_t zig_zag_to_int(
|
|
378
|
-
return (((
|
|
435
|
+
static int32_t zig_zag_to_int(uint32_t n) {
|
|
436
|
+
return (int32_t)((n >> 1) ^ (0U - (n & 1U)));
|
|
379
437
|
}
|
|
380
438
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
439
|
+
#define MAX_VARINT32_BYTES 5 /* ceil(32/7); matches protobuf wire format */
|
|
440
|
+
#define MAX_VARINT64_BYTES 10 /* ceil(64/7); matches protobuf wire format */
|
|
441
|
+
|
|
442
|
+
static uint64_t read_varint64(VALUE self) {
|
|
443
|
+
int i, shift = 0;
|
|
444
|
+
uint64_t result = 0;
|
|
445
|
+
for (i = 0; i < MAX_VARINT64_BYTES; i++) {
|
|
385
446
|
int8_t b = read_byte_direct(self);
|
|
386
|
-
result
|
|
447
|
+
result |= ((uint64_t)(b & 0x7f) << shift);
|
|
387
448
|
if ((b & 0x80) != 0x80) {
|
|
388
|
-
|
|
449
|
+
return result;
|
|
389
450
|
}
|
|
390
451
|
shift += 7;
|
|
391
452
|
}
|
|
392
|
-
|
|
453
|
+
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("Variable-length int over 10 bytes.")));
|
|
454
|
+
return 0; /* unreachable */
|
|
393
455
|
}
|
|
394
456
|
|
|
395
|
-
static
|
|
396
|
-
|
|
457
|
+
static uint32_t read_varint32(VALUE self) {
|
|
458
|
+
int i, shift = 0;
|
|
459
|
+
uint32_t result = 0;
|
|
460
|
+
for (i = 0; i < MAX_VARINT32_BYTES; i++) {
|
|
461
|
+
int8_t b = read_byte_direct(self);
|
|
462
|
+
result |= ((uint32_t)(b & 0x7f) << shift);
|
|
463
|
+
if ((b & 0x80) != 0x80) {
|
|
464
|
+
return result;
|
|
465
|
+
}
|
|
466
|
+
shift += 7;
|
|
467
|
+
}
|
|
468
|
+
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("Variable-length int over 5 bytes.")));
|
|
469
|
+
return 0; /* unreachable */
|
|
397
470
|
}
|
|
398
471
|
|
|
399
|
-
static
|
|
400
|
-
|
|
401
|
-
args[0] = code;
|
|
402
|
-
args[1] = message;
|
|
403
|
-
return rb_class_new_instance(2, (VALUE*)&args, protocol_exception_class);
|
|
472
|
+
static int16_t read_i16(VALUE self) {
|
|
473
|
+
return (int16_t)zig_zag_to_int(read_varint32(self));
|
|
404
474
|
}
|
|
405
475
|
|
|
406
476
|
VALUE rb_thrift_compact_proto_read_message_end(VALUE self) {
|
|
@@ -441,7 +511,7 @@ VALUE rb_thrift_compact_proto_read_message_begin(VALUE self) {
|
|
|
441
511
|
buf[len] = 0;
|
|
442
512
|
rb_exc_raise(get_protocol_exception(INT2FIX(-1), rb_str_new2(buf)));
|
|
443
513
|
}
|
|
444
|
-
|
|
514
|
+
|
|
445
515
|
int8_t version_and_type = read_byte_direct(self);
|
|
446
516
|
int8_t version = version_and_type & VERSION_MASK;
|
|
447
517
|
if (version != VERSION) {
|
|
@@ -450,9 +520,9 @@ VALUE rb_thrift_compact_proto_read_message_begin(VALUE self) {
|
|
|
450
520
|
buf[len] = 0;
|
|
451
521
|
rb_exc_raise(get_protocol_exception(INT2FIX(-1), rb_str_new2(buf)));
|
|
452
522
|
}
|
|
453
|
-
|
|
523
|
+
|
|
454
524
|
int8_t type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS;
|
|
455
|
-
int32_t seqid = (
|
|
525
|
+
int32_t seqid = message_seqid_from_varint32(read_varint32(self));
|
|
456
526
|
VALUE messageName = rb_thrift_compact_proto_read_string(self);
|
|
457
527
|
return rb_ary_new3(3, messageName, INT2FIX(type), INT2NUM(seqid));
|
|
458
528
|
}
|
|
@@ -467,7 +537,7 @@ VALUE rb_thrift_compact_proto_read_field_begin(VALUE self) {
|
|
|
467
537
|
|
|
468
538
|
// mask off the 4 MSB of the type header. it could contain a field id delta.
|
|
469
539
|
uint8_t modifier = ((type & 0xf0) >> 4);
|
|
470
|
-
|
|
540
|
+
|
|
471
541
|
if (modifier == 0) {
|
|
472
542
|
// not a delta. look ahead for the zigzag varint field id.
|
|
473
543
|
(void) LAST_ID(self);
|
|
@@ -490,19 +560,19 @@ VALUE rb_thrift_compact_proto_read_field_begin(VALUE self) {
|
|
|
490
560
|
}
|
|
491
561
|
|
|
492
562
|
VALUE rb_thrift_compact_proto_read_map_begin(VALUE self) {
|
|
493
|
-
|
|
563
|
+
uint32_t size = read_varint32(self);
|
|
494
564
|
uint8_t key_and_value_type = size == 0 ? 0 : read_byte_direct(self);
|
|
495
|
-
return rb_ary_new3(3, INT2FIX(get_ttype(key_and_value_type >> 4)), INT2FIX(get_ttype(key_and_value_type & 0xf)),
|
|
565
|
+
return rb_ary_new3(3, INT2FIX(get_ttype(key_and_value_type >> 4)), INT2FIX(get_ttype(key_and_value_type & 0xf)), UINT2NUM(size));
|
|
496
566
|
}
|
|
497
567
|
|
|
498
568
|
VALUE rb_thrift_compact_proto_read_list_begin(VALUE self) {
|
|
499
569
|
uint8_t size_and_type = read_byte_direct(self);
|
|
500
|
-
|
|
570
|
+
uint32_t size = (size_and_type >> 4) & 0x0f;
|
|
501
571
|
if (size == 15) {
|
|
502
|
-
size = (
|
|
572
|
+
size = read_varint32(self);
|
|
503
573
|
}
|
|
504
574
|
uint8_t type = get_ttype(size_and_type & 0x0f);
|
|
505
|
-
return rb_ary_new3(2, INT2FIX(type),
|
|
575
|
+
return rb_ary_new3(2, INT2FIX(type), UINT2NUM(size));
|
|
506
576
|
}
|
|
507
577
|
|
|
508
578
|
VALUE rb_thrift_compact_proto_read_set_begin(VALUE self) {
|
|
@@ -528,7 +598,7 @@ VALUE rb_thrift_compact_proto_read_i16(VALUE self) {
|
|
|
528
598
|
}
|
|
529
599
|
|
|
530
600
|
VALUE rb_thrift_compact_proto_read_i32(VALUE self) {
|
|
531
|
-
return INT2NUM(zig_zag_to_int((
|
|
601
|
+
return INT2NUM(zig_zag_to_int(read_varint32(self)));
|
|
532
602
|
}
|
|
533
603
|
|
|
534
604
|
VALUE rb_thrift_compact_proto_read_i64(VALUE self) {
|
|
@@ -561,11 +631,32 @@ VALUE rb_thrift_compact_proto_read_string(VALUE self) {
|
|
|
561
631
|
}
|
|
562
632
|
|
|
563
633
|
VALUE rb_thrift_compact_proto_read_binary(VALUE self) {
|
|
564
|
-
|
|
565
|
-
return
|
|
634
|
+
uint32_t size = read_varint32(self);
|
|
635
|
+
return rb_funcall(GET_TRANSPORT(self), read_all_method_id, 1, UINT2NUM(size));
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
VALUE rb_thrift_compact_proto_read_uuid(VALUE self) {
|
|
639
|
+
VALUE data = READ(self, 16);
|
|
640
|
+
const unsigned char* bytes = (const unsigned char*)RSTRING_PTR(data);
|
|
641
|
+
|
|
642
|
+
// Format as UUID string: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
|
643
|
+
char uuid_str[37];
|
|
644
|
+
char* p = uuid_str;
|
|
645
|
+
|
|
646
|
+
for (int i = 0; i < 16; i++) {
|
|
647
|
+
*p++ = int_to_hex_char((bytes[i] >> 4) & 0x0F);
|
|
648
|
+
*p++ = int_to_hex_char(bytes[i] & 0x0F);
|
|
649
|
+
if (i == 3 || i == 5 || i == 7 || i == 9) {
|
|
650
|
+
*p++ = '-';
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
*p = '\0';
|
|
655
|
+
|
|
656
|
+
return rb_str_new(uuid_str, 36);
|
|
566
657
|
}
|
|
567
658
|
|
|
568
|
-
static void Init_constants() {
|
|
659
|
+
static void Init_constants(void) {
|
|
569
660
|
thrift_compact_protocol_class = rb_const_get(thrift_module, rb_intern("CompactProtocol"));
|
|
570
661
|
rb_global_variable(&thrift_compact_protocol_class);
|
|
571
662
|
|
|
@@ -582,7 +673,7 @@ static void Init_constants() {
|
|
|
582
673
|
rbuf_ivar_id = rb_intern("@rbuf");
|
|
583
674
|
}
|
|
584
675
|
|
|
585
|
-
static void Init_rb_methods() {
|
|
676
|
+
static void Init_rb_methods(void) {
|
|
586
677
|
rb_define_method(thrift_compact_protocol_class, "native?", rb_thrift_compact_proto_native_qmark, 0);
|
|
587
678
|
|
|
588
679
|
rb_define_method(thrift_compact_protocol_class, "write_message_begin", rb_thrift_compact_proto_write_message_begin, 3);
|
|
@@ -599,6 +690,7 @@ static void Init_rb_methods() {
|
|
|
599
690
|
rb_define_method(thrift_compact_protocol_class, "write_double", rb_thrift_compact_proto_write_double, 1);
|
|
600
691
|
rb_define_method(thrift_compact_protocol_class, "write_string", rb_thrift_compact_proto_write_string, 1);
|
|
601
692
|
rb_define_method(thrift_compact_protocol_class, "write_binary", rb_thrift_compact_proto_write_binary, 1);
|
|
693
|
+
rb_define_method(thrift_compact_protocol_class, "write_uuid", rb_thrift_compact_proto_write_uuid, 1);
|
|
602
694
|
|
|
603
695
|
rb_define_method(thrift_compact_protocol_class, "write_message_end", rb_thrift_compact_proto_write_message_end, 0);
|
|
604
696
|
rb_define_method(thrift_compact_protocol_class, "write_struct_begin", rb_thrift_compact_proto_write_struct_begin, 1);
|
|
@@ -622,6 +714,7 @@ static void Init_rb_methods() {
|
|
|
622
714
|
rb_define_method(thrift_compact_protocol_class, "read_double", rb_thrift_compact_proto_read_double, 0);
|
|
623
715
|
rb_define_method(thrift_compact_protocol_class, "read_string", rb_thrift_compact_proto_read_string, 0);
|
|
624
716
|
rb_define_method(thrift_compact_protocol_class, "read_binary", rb_thrift_compact_proto_read_binary, 0);
|
|
717
|
+
rb_define_method(thrift_compact_protocol_class, "read_uuid", rb_thrift_compact_proto_read_uuid, 0);
|
|
625
718
|
|
|
626
719
|
rb_define_method(thrift_compact_protocol_class, "read_message_end", rb_thrift_compact_proto_read_message_end, 0);
|
|
627
720
|
rb_define_method(thrift_compact_protocol_class, "read_struct_begin", rb_thrift_compact_proto_read_struct_begin, 0);
|
|
@@ -632,7 +725,7 @@ static void Init_rb_methods() {
|
|
|
632
725
|
rb_define_method(thrift_compact_protocol_class, "read_set_end", rb_thrift_compact_proto_read_set_end, 0);
|
|
633
726
|
}
|
|
634
727
|
|
|
635
|
-
void Init_compact_protocol() {
|
|
728
|
+
void Init_compact_protocol(void) {
|
|
636
729
|
Init_constants();
|
|
637
730
|
Init_rb_methods();
|
|
638
731
|
}
|
data/ext/constants.h
CHANGED
|
@@ -29,6 +29,7 @@ extern int TTYPE_MAP;
|
|
|
29
29
|
extern int TTYPE_SET;
|
|
30
30
|
extern int TTYPE_LIST;
|
|
31
31
|
extern int TTYPE_STRUCT;
|
|
32
|
+
extern int TTYPE_UUID;
|
|
32
33
|
|
|
33
34
|
extern ID validate_method_id;
|
|
34
35
|
extern ID write_struct_begin_method_id;
|
|
@@ -49,6 +50,7 @@ extern ID write_list_begin_method_id;
|
|
|
49
50
|
extern ID write_list_end_method_id;
|
|
50
51
|
extern ID write_set_begin_method_id;
|
|
51
52
|
extern ID write_set_end_method_id;
|
|
53
|
+
extern ID write_uuid_method_id;
|
|
52
54
|
extern ID read_bool_method_id;
|
|
53
55
|
extern ID read_byte_method_id;
|
|
54
56
|
extern ID read_i16_method_id;
|
|
@@ -63,6 +65,7 @@ extern ID read_list_begin_method_id;
|
|
|
63
65
|
extern ID read_list_end_method_id;
|
|
64
66
|
extern ID read_set_begin_method_id;
|
|
65
67
|
extern ID read_set_end_method_id;
|
|
68
|
+
extern ID read_uuid_method_id;
|
|
66
69
|
extern ID read_struct_begin_method_id;
|
|
67
70
|
extern ID read_struct_end_method_id;
|
|
68
71
|
extern ID read_field_begin_method_id;
|
|
@@ -97,3 +100,12 @@ extern VALUE thrift_types_module;
|
|
|
97
100
|
extern VALUE thrift_bytes_module;
|
|
98
101
|
extern VALUE class_thrift_protocol;
|
|
99
102
|
extern VALUE protocol_exception_class;
|
|
103
|
+
|
|
104
|
+
// protocol errors
|
|
105
|
+
extern int PROTOERR_UNKNOWN;
|
|
106
|
+
extern int PROTOERR_INVALID_DATA;
|
|
107
|
+
extern int PROTOERR_NEGATIVE_SIZE;
|
|
108
|
+
extern int PROTOERR_SIZE_LIMIT;
|
|
109
|
+
extern int PROTOERR_BAD_VERSION;
|
|
110
|
+
extern int PROTOERR_NOT_IMPLEMENTED;
|
|
111
|
+
extern int PROTOERR_DEPTH_LIMIT;
|
data/ext/extconf.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
2
3
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
3
4
|
# or more contributor license agreements. See the NOTICE file
|
|
4
5
|
# distributed with this work for additional information
|
|
@@ -6,27 +7,35 @@
|
|
|
6
7
|
# to you under the Apache License, Version 2.0 (the
|
|
7
8
|
# "License"); you may not use this file except in compliance
|
|
8
9
|
# with the License. You may obtain a copy of the License at
|
|
9
|
-
#
|
|
10
|
+
#
|
|
10
11
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
-
#
|
|
12
|
+
#
|
|
12
13
|
# Unless required by applicable law or agreed to in writing,
|
|
13
14
|
# software distributed under the License is distributed on an
|
|
14
15
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
16
|
# KIND, either express or implied. See the License for the
|
|
16
17
|
# specific language governing permissions and limitations
|
|
17
18
|
# under the License.
|
|
18
|
-
#
|
|
19
|
+
#
|
|
19
20
|
|
|
20
21
|
if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
|
|
21
|
-
File.open('Makefile', 'w'){|f| f.puts "all:\n\ninstall:\n" }
|
|
22
|
+
File.open('Makefile', 'w'){ |f| f.puts "all:\n\ninstall:\n" }
|
|
22
23
|
else
|
|
23
24
|
require 'mkmf'
|
|
24
|
-
require 'rbconfig'
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
append_cflags(["-fsigned-char", "-g", "-O2", "-Wall", "-Werror", "-Werror=old-style-definition"])
|
|
27
27
|
|
|
28
|
+
# clang 21+ introduced -Wdefault-const-init-field-unsafe, which fires on
|
|
29
|
+
# Ruby 3.2's rstring.h (struct RString has a const field via RBasic).
|
|
30
|
+
# This is a Ruby header issue, not a Thrift bug, so suppress the warning here.
|
|
31
|
+
# append_cflags silently ignores flags unsupported by the compiler, so this
|
|
32
|
+
# is safe across all clang versions.
|
|
33
|
+
append_cflags("-Wno-default-const-init-field-unsafe")
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
# Makes all symbols private by default to avoid unintended conflict
|
|
36
|
+
# with other gems. To explicitly export symbols you can use RUBY_FUNC_EXPORTED
|
|
37
|
+
# selectively, or entirely remove this flag.
|
|
38
|
+
append_cflags("-fvisibility=hidden")
|
|
30
39
|
|
|
31
40
|
have_func("strlcpy", "string.h")
|
|
32
41
|
|
data/ext/memory_buffer.c
CHANGED
|
@@ -28,11 +28,15 @@ ID index_ivar_id;
|
|
|
28
28
|
ID slice_method_id;
|
|
29
29
|
|
|
30
30
|
int GARBAGE_BUFFER_SIZE;
|
|
31
|
+
static VALUE transport_exception_class;
|
|
32
|
+
static VALUE transport_negative_size;
|
|
33
|
+
static ID new_method_id;
|
|
31
34
|
|
|
32
35
|
#define GET_BUF(self) rb_ivar_get(self, buf_ivar_id)
|
|
33
36
|
|
|
34
37
|
VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str);
|
|
35
38
|
VALUE rb_thrift_memory_buffer_read(VALUE self, VALUE length_value);
|
|
39
|
+
VALUE rb_thrift_memory_buffer_read_all(VALUE self, VALUE length_value);
|
|
36
40
|
VALUE rb_thrift_memory_buffer_read_byte(VALUE self);
|
|
37
41
|
VALUE rb_thrift_memory_buffer_read_into_buffer(VALUE self, VALUE buffer_value, VALUE size_value);
|
|
38
42
|
|
|
@@ -45,13 +49,13 @@ VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str) {
|
|
|
45
49
|
|
|
46
50
|
VALUE rb_thrift_memory_buffer_read(VALUE self, VALUE length_value) {
|
|
47
51
|
int length = FIX2INT(length_value);
|
|
48
|
-
|
|
52
|
+
|
|
49
53
|
VALUE index_value = rb_ivar_get(self, index_ivar_id);
|
|
50
54
|
int index = FIX2INT(index_value);
|
|
51
|
-
|
|
55
|
+
|
|
52
56
|
VALUE buf = GET_BUF(self);
|
|
53
57
|
VALUE data = rb_funcall(buf, slice_method_id, 2, index_value, length_value);
|
|
54
|
-
|
|
58
|
+
|
|
55
59
|
index += length;
|
|
56
60
|
if (index > RSTRING_LEN(buf)) {
|
|
57
61
|
index = (int)RSTRING_LEN(buf);
|
|
@@ -69,6 +73,33 @@ VALUE rb_thrift_memory_buffer_read(VALUE self, VALUE length_value) {
|
|
|
69
73
|
return data;
|
|
70
74
|
}
|
|
71
75
|
|
|
76
|
+
VALUE rb_thrift_memory_buffer_read_all(VALUE self, VALUE length_value) {
|
|
77
|
+
int length = FIX2INT(length_value);
|
|
78
|
+
|
|
79
|
+
if (RB_UNLIKELY(length < 0)) {
|
|
80
|
+
rb_exc_raise(rb_funcall(transport_exception_class, new_method_id, 2, transport_negative_size, rb_str_new2("Negative size")));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
VALUE index_value = rb_ivar_get(self, index_ivar_id);
|
|
84
|
+
int index = FIX2INT(index_value);
|
|
85
|
+
VALUE buf = GET_BUF(self);
|
|
86
|
+
|
|
87
|
+
if (RB_UNLIKELY(length > RSTRING_LEN(buf) - index)) {
|
|
88
|
+
rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
VALUE data = rb_str_subseq(buf, index, length);
|
|
92
|
+
|
|
93
|
+
index += length;
|
|
94
|
+
if (index >= GARBAGE_BUFFER_SIZE) {
|
|
95
|
+
rb_ivar_set(self, buf_ivar_id, rb_str_subseq(buf, index, RSTRING_LEN(buf) - index));
|
|
96
|
+
index = 0;
|
|
97
|
+
}
|
|
98
|
+
rb_ivar_set(self, index_ivar_id, INT2FIX(index));
|
|
99
|
+
|
|
100
|
+
return data;
|
|
101
|
+
}
|
|
102
|
+
|
|
72
103
|
VALUE rb_thrift_memory_buffer_read_byte(VALUE self) {
|
|
73
104
|
VALUE index_value = rb_ivar_get(self, index_ivar_id);
|
|
74
105
|
int index = FIX2INT(index_value);
|
|
@@ -118,17 +149,23 @@ VALUE rb_thrift_memory_buffer_read_into_buffer(VALUE self, VALUE buffer_value, V
|
|
|
118
149
|
return INT2FIX(i);
|
|
119
150
|
}
|
|
120
151
|
|
|
121
|
-
void Init_memory_buffer() {
|
|
152
|
+
void Init_memory_buffer(void) {
|
|
122
153
|
VALUE thrift_memory_buffer_class = rb_const_get(thrift_module, rb_intern("MemoryBufferTransport"));
|
|
123
154
|
rb_define_method(thrift_memory_buffer_class, "write", rb_thrift_memory_buffer_write, 1);
|
|
124
155
|
rb_define_method(thrift_memory_buffer_class, "read", rb_thrift_memory_buffer_read, 1);
|
|
156
|
+
rb_define_method(thrift_memory_buffer_class, "read_all", rb_thrift_memory_buffer_read_all, 1);
|
|
125
157
|
rb_define_method(thrift_memory_buffer_class, "read_byte", rb_thrift_memory_buffer_read_byte, 0);
|
|
126
158
|
rb_define_method(thrift_memory_buffer_class, "read_into_buffer", rb_thrift_memory_buffer_read_into_buffer, 2);
|
|
127
|
-
|
|
159
|
+
|
|
128
160
|
buf_ivar_id = rb_intern("@buf");
|
|
129
161
|
index_ivar_id = rb_intern("@index");
|
|
130
|
-
|
|
162
|
+
|
|
131
163
|
slice_method_id = rb_intern("slice");
|
|
132
|
-
|
|
164
|
+
new_method_id = rb_intern("new");
|
|
165
|
+
|
|
133
166
|
GARBAGE_BUFFER_SIZE = FIX2INT(rb_const_get(thrift_memory_buffer_class, rb_intern("GARBAGE_BUFFER_SIZE")));
|
|
167
|
+
transport_exception_class = rb_const_get(thrift_module, rb_intern("TransportException"));
|
|
168
|
+
transport_negative_size = rb_const_get(transport_exception_class, rb_intern("NEGATIVE_SIZE"));
|
|
169
|
+
rb_global_variable(&transport_exception_class);
|
|
170
|
+
rb_global_variable(&transport_negative_size);
|
|
134
171
|
}
|
data/ext/protocol.c
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
* or more contributor license agreements. See the NOTICE file
|
|
4
|
+
* distributed with this work for additional information
|
|
5
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
* to you under the Apache License, Version 2.0 (the
|
|
7
|
+
* "License"); you may not use this file except in compliance
|
|
8
|
+
* with the License. You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing,
|
|
13
|
+
* software distributed under the License is distributed on an
|
|
14
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
+
* KIND, either express or implied. See the License for the
|
|
16
|
+
* specific language governing permissions and limitations
|
|
17
|
+
* under the License.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
#include <ruby.h>
|
|
21
|
+
#include <constants.h>
|
|
22
|
+
#include <protocol.h>
|
|
23
|
+
|
|
24
|
+
VALUE get_protocol_exception(VALUE code, VALUE message) {
|
|
25
|
+
VALUE args[2];
|
|
26
|
+
args[0] = code;
|
|
27
|
+
args[1] = message;
|
|
28
|
+
return rb_class_new_instance(2, (VALUE*)&args, protocol_exception_class);
|
|
29
|
+
}
|
data/ext/protocol.h
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
* or more contributor license agreements. See the NOTICE file
|
|
4
|
+
* distributed with this work for additional information
|
|
5
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
* to you under the Apache License, Version 2.0 (the
|
|
7
|
+
* "License"); you may not use this file except in compliance
|
|
8
|
+
* with the License. You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing,
|
|
13
|
+
* software distributed under the License is distributed on an
|
|
14
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
+
* KIND, either express or implied. See the License for the
|
|
16
|
+
* specific language governing permissions and limitations
|
|
17
|
+
* under the License.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
#include <ruby.h>
|
|
21
|
+
|
|
22
|
+
VALUE get_protocol_exception(VALUE code, VALUE message);
|
|
23
|
+
|
|
24
|
+
// Efficient hex character to integer conversion
|
|
25
|
+
static inline int hex_char_to_int(char c) {
|
|
26
|
+
if (c >= '0' && c <= '9') return c - '0';
|
|
27
|
+
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
|
28
|
+
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
|
29
|
+
return -1; // invalid hex character
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Efficient integer to hex character conversion
|
|
33
|
+
static inline char int_to_hex_char(int val) {
|
|
34
|
+
return val < 10 ? ('0' + val) : ('a' + val - 10);
|
|
35
|
+
}
|