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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +235 -17
  3. data/benchmark/benchmark.rb +23 -8
  4. data/benchmark/client.rb +50 -6
  5. data/benchmark/server.rb +46 -7
  6. data/benchmark/thin_server.rb +2 -0
  7. data/ext/binary_protocol_accelerated.c +154 -42
  8. data/ext/bytes.c +14 -0
  9. data/ext/compact_protocol.c +138 -45
  10. data/ext/constants.h +12 -0
  11. data/ext/extconf.rb +17 -8
  12. data/ext/memory_buffer.c +44 -7
  13. data/ext/protocol.c +29 -0
  14. data/ext/protocol.h +35 -0
  15. data/ext/struct.c +48 -17
  16. data/ext/thrift_native.c +28 -3
  17. data/lib/thrift/bytes.rb +70 -100
  18. data/lib/thrift/client.rb +54 -13
  19. data/lib/thrift/exceptions.rb +6 -5
  20. data/lib/thrift/multiplexed_processor.rb +20 -10
  21. data/lib/thrift/processor.rb +7 -6
  22. data/lib/thrift/protocol/base_protocol.rb +52 -21
  23. data/lib/thrift/protocol/binary_protocol.rb +65 -20
  24. data/lib/thrift/protocol/binary_protocol_accelerated.rb +6 -5
  25. data/lib/thrift/protocol/compact_protocol.rb +76 -41
  26. data/lib/thrift/protocol/header_protocol.rb +321 -0
  27. data/lib/thrift/protocol/json_protocol.rb +44 -27
  28. data/lib/thrift/protocol/multiplexed_protocol.rb +6 -5
  29. data/lib/thrift/protocol/protocol_decorator.rb +13 -4
  30. data/lib/thrift/serializer/deserializer.rb +6 -5
  31. data/lib/thrift/serializer/serializer.rb +5 -5
  32. data/lib/thrift/server/base_server.rb +5 -4
  33. data/lib/thrift/server/mongrel_http_server.rb +7 -6
  34. data/lib/thrift/server/nonblocking_server.rb +35 -9
  35. data/lib/thrift/server/simple_server.rb +13 -5
  36. data/lib/thrift/server/thin_http_server.rb +4 -3
  37. data/lib/thrift/server/thread_pool_server.rb +7 -6
  38. data/lib/thrift/server/threaded_server.rb +13 -5
  39. data/lib/thrift/struct.rb +12 -11
  40. data/lib/thrift/struct_union.rb +14 -9
  41. data/lib/thrift/thrift_native.rb +3 -2
  42. data/lib/thrift/transport/base_server_transport.rb +8 -5
  43. data/lib/thrift/transport/base_transport.rb +18 -14
  44. data/lib/thrift/transport/buffered_transport.rb +7 -6
  45. data/lib/thrift/transport/framed_transport.rb +8 -7
  46. data/lib/thrift/transport/header_transport.rb +562 -0
  47. data/lib/thrift/transport/http_client_transport.rb +2 -1
  48. data/lib/thrift/transport/io_stream_transport.rb +4 -3
  49. data/lib/thrift/transport/memory_buffer_transport.rb +13 -6
  50. data/lib/thrift/transport/server_socket.rb +14 -8
  51. data/lib/thrift/transport/socket.rb +126 -60
  52. data/lib/thrift/transport/ssl_server_socket.rb +4 -3
  53. data/lib/thrift/transport/ssl_socket.rb +45 -13
  54. data/lib/thrift/transport/unix_server_socket.rb +9 -5
  55. data/lib/thrift/transport/unix_socket.rb +7 -6
  56. data/lib/thrift/types.rb +10 -6
  57. data/lib/thrift/union.rb +15 -8
  58. data/lib/thrift/uuid.rb +50 -0
  59. data/lib/thrift.rb +4 -1
  60. data/spec/ThriftSpec.thrift +21 -1
  61. data/spec/base_protocol_spec.rb +21 -2
  62. data/spec/base_transport_spec.rb +48 -8
  63. data/spec/binary_protocol_accelerated_spec.rb +1 -0
  64. data/spec/binary_protocol_spec.rb +1 -2
  65. data/spec/binary_protocol_spec_shared.rb +206 -155
  66. data/spec/bytes_spec.rb +71 -114
  67. data/spec/client_spec.rb +86 -19
  68. data/spec/compact_protocol_spec.rb +153 -16
  69. data/spec/constants_demo_spec.rb +102 -0
  70. data/spec/exception_spec.rb +1 -1
  71. data/spec/flat_spec.rb +1 -0
  72. data/spec/header_protocol_spec.rb +476 -0
  73. data/spec/header_transport_spec.rb +431 -0
  74. data/spec/http_client_spec.rb +5 -6
  75. data/spec/json_protocol_spec.rb +69 -47
  76. data/spec/multiplexed_processor_spec.rb +75 -0
  77. data/spec/namespaced_spec.rb +1 -1
  78. data/spec/nonblocking_server_spec.rb +174 -8
  79. data/spec/processor_spec.rb +1 -1
  80. data/spec/recursion_depth_spec.rb +223 -0
  81. data/spec/serializer_spec.rb +1 -1
  82. data/spec/server_socket_spec.rb +38 -1
  83. data/spec/server_spec.rb +60 -9
  84. data/spec/socket_spec.rb +119 -13
  85. data/spec/socket_spec_shared.rb +73 -9
  86. data/spec/spec_helper.rb +2 -1
  87. data/spec/ssl_server_socket_spec.rb +52 -1
  88. data/spec/ssl_socket_spec.rb +181 -11
  89. data/spec/struct_nested_containers_spec.rb +2 -2
  90. data/spec/struct_spec.rb +114 -9
  91. data/spec/support/header_protocol_helper.rb +55 -0
  92. data/spec/thin_http_server_spec.rb +4 -18
  93. data/spec/types_spec.rb +26 -26
  94. data/spec/union_spec.rb +70 -11
  95. data/spec/unix_socket_spec.rb +17 -2
  96. data/spec/uuid_validation_spec.rb +239 -0
  97. data/test/fuzz/Makefile +779 -0
  98. data/test/fuzz/Makefile.am +173 -0
  99. data/test/fuzz/Makefile.in +775 -0
  100. data/test/fuzz/README.md +149 -0
  101. data/test/fuzz/fuzz_common.rb +96 -0
  102. data/{lib/thrift/core_ext.rb → test/fuzz/fuzz_parse_binary_protocol.rb} +4 -4
  103. data/{lib/thrift/core_ext/fixnum.rb → test/fuzz/fuzz_parse_binary_protocol_accelerated.rb} +7 -13
  104. data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +23 -0
  105. data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +23 -0
  106. data/test/fuzz/fuzz_parse_compact_protocol.rb +23 -0
  107. data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +23 -0
  108. data/test/fuzz/fuzz_parse_json_protocol.rb +23 -0
  109. data/test/fuzz/fuzz_parse_json_protocol_harness.rb +23 -0
  110. data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +23 -0
  111. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +23 -0
  112. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +23 -0
  113. data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +23 -0
  114. data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +23 -0
  115. data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +23 -0
  116. data/test/fuzz/fuzz_roundtrip_json_protocol.rb +23 -0
  117. data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +23 -0
  118. data/test/fuzz/fuzz_tracer.rb +29 -0
  119. metadata +105 -70
data/ext/struct.c CHANGED
@@ -20,6 +20,7 @@
20
20
  #include "struct.h"
21
21
  #include "constants.h"
22
22
  #include "macros.h"
23
+ #include "protocol.h"
23
24
  #include "strlcpy.h"
24
25
 
25
26
  VALUE thrift_union_class;
@@ -34,6 +35,22 @@ static ID sorted_field_ids_method_id;
34
35
  #define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
35
36
  #define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
36
37
 
38
+ static void validate_container_size(int size) {
39
+ if (RB_UNLIKELY(size < 0)) {
40
+ rb_exc_raise(
41
+ get_protocol_exception(
42
+ INT2FIX(PROTOERR_NEGATIVE_SIZE),
43
+ rb_str_new2("Negative container size")
44
+ )
45
+ );
46
+ }
47
+ }
48
+
49
+ static VALUE new_container_array(int size) {
50
+ validate_container_size(size);
51
+ return rb_ary_new2(size > 1024 ? 1024 : size);
52
+ }
53
+
37
54
  //-------------------------------------------
38
55
  // Writing section
39
56
  //-------------------------------------------
@@ -75,6 +92,11 @@ VALUE default_write_string(VALUE protocol, VALUE value) {
75
92
  return Qnil;
76
93
  }
77
94
 
95
+ VALUE default_write_uuid(VALUE protocol, VALUE value) {
96
+ rb_funcall(protocol, write_uuid_method_id, 1, value);
97
+ return Qnil;
98
+ }
99
+
78
100
  VALUE default_write_binary(VALUE protocol, VALUE value) {
79
101
  rb_funcall(protocol, write_binary_method_id, 1, value);
80
102
  return Qnil;
@@ -195,6 +217,10 @@ VALUE default_read_string(VALUE protocol) {
195
217
  return rb_funcall(protocol, read_string_method_id, 0);
196
218
  }
197
219
 
220
+ VALUE default_read_uuid(VALUE protocol) {
221
+ return rb_funcall(protocol, read_uuid_method_id, 0);
222
+ }
223
+
198
224
  VALUE default_read_binary(VALUE protocol) {
199
225
  return rb_funcall(protocol, read_binary_method_id, 0);
200
226
  }
@@ -229,8 +255,6 @@ static void write_container(int ttype, VALUE field_info, VALUE value, VALUE prot
229
255
 
230
256
  if (ttype == TTYPE_MAP) {
231
257
  VALUE keys;
232
- VALUE key;
233
- VALUE val;
234
258
 
235
259
  Check_Type(value, T_HASH);
236
260
 
@@ -249,8 +273,8 @@ static void write_container(int ttype, VALUE field_info, VALUE value, VALUE prot
249
273
  default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
250
274
 
251
275
  for (i = 0; i < sz; i++) {
252
- key = rb_ary_entry(keys, i);
253
- val = rb_hash_aref(value, key);
276
+ VALUE key = rb_ary_entry(keys, i);
277
+ VALUE val = rb_hash_aref(value, key);
254
278
 
255
279
  if (IS_CONTAINER(keytype)) {
256
280
  write_container(keytype, key_info, key, protocol);
@@ -342,6 +366,8 @@ static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_i
342
366
  } else {
343
367
  default_write_binary(protocol, value);
344
368
  }
369
+ } else if (ttype == TTYPE_UUID) {
370
+ default_write_uuid(protocol, value);
345
371
  } else if (IS_CONTAINER(ttype)) {
346
372
  write_container(ttype, field_info, value, protocol);
347
373
  } else if (ttype == TTYPE_STRUCT) {
@@ -452,6 +478,8 @@ static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
452
478
  }
453
479
  } else if (ttype == TTYPE_DOUBLE) {
454
480
  result = default_read_double(protocol);
481
+ } else if (ttype == TTYPE_UUID) {
482
+ result = default_read_uuid(protocol);
455
483
  } else if (ttype == TTYPE_STRUCT) {
456
484
  VALUE klass = rb_hash_aref(field_info, class_sym);
457
485
  result = rb_class_new_instance(0, NULL, klass);
@@ -462,13 +490,15 @@ static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
462
490
  rb_thrift_struct_read(result, protocol);
463
491
  }
464
492
  } else if (ttype == TTYPE_MAP) {
465
- int i;
466
-
467
493
  VALUE map_header = default_read_map_begin(protocol);
468
494
  int key_ttype = FIX2INT(rb_ary_entry(map_header, 0));
469
495
  int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
470
496
  int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
471
497
 
498
+ if (num_entries < 0) {
499
+ rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_NEGATIVE_SIZE), rb_str_new2("Negative container size")));
500
+ }
501
+
472
502
  // Check the declared key and value types against the expected ones and skip the map contents
473
503
  // if the types don't match.
474
504
  VALUE key_info = rb_hash_aref(field_info, key_sym);
@@ -480,7 +510,7 @@ static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
480
510
  if (num_entries == 0 || (specified_key_type == key_ttype && specified_value_type == value_ttype)) {
481
511
  result = rb_hash_new();
482
512
 
483
- for (i = 0; i < num_entries; ++i) {
513
+ for (int i = 0; i < num_entries; ++i) {
484
514
  VALUE key, val;
485
515
 
486
516
  key = read_anything(protocol, key_ttype, key_info);
@@ -497,8 +527,6 @@ static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
497
527
 
498
528
  default_read_map_end(protocol);
499
529
  } else if (ttype == TTYPE_LIST) {
500
- int i;
501
-
502
530
  VALUE list_header = default_read_list_begin(protocol);
503
531
  int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
504
532
  int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
@@ -509,22 +537,23 @@ static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
509
537
  if (!NIL_P(element_info)) {
510
538
  int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
511
539
  if (specified_element_type == element_ttype) {
512
- result = rb_ary_new2(num_elements);
540
+ result = new_container_array(num_elements);
513
541
 
514
- for (i = 0; i < num_elements; ++i) {
542
+ for (int i = 0; i < num_elements; ++i) {
515
543
  rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
516
544
  }
517
545
  } else {
546
+ validate_container_size(num_elements);
518
547
  skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
519
548
  }
520
549
  } else {
550
+ validate_container_size(num_elements);
521
551
  skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
522
552
  }
523
553
 
524
554
  default_read_list_end(protocol);
525
555
  } else if (ttype == TTYPE_SET) {
526
556
  VALUE items;
527
- int i;
528
557
 
529
558
  VALUE set_header = default_read_set_begin(protocol);
530
559
  int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
@@ -536,17 +565,19 @@ static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
536
565
  if (!NIL_P(element_info)) {
537
566
  int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
538
567
  if (specified_element_type == element_ttype) {
539
- items = rb_ary_new2(num_elements);
568
+ items = new_container_array(num_elements);
540
569
 
541
- for (i = 0; i < num_elements; ++i) {
570
+ for (int i = 0; i < num_elements; ++i) {
542
571
  rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
543
572
  }
544
573
 
545
574
  result = rb_class_new_instance(1, &items, rb_cSet);
546
575
  } else {
576
+ validate_container_size(num_elements);
547
577
  skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
548
578
  }
549
579
  } else {
580
+ validate_container_size(num_elements);
550
581
  skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
551
582
  }
552
583
 
@@ -643,7 +674,7 @@ static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
643
674
  field_type = FIX2INT(field_type_value);
644
675
 
645
676
  if (field_type != TTYPE_STOP) {
646
- rb_raise(rb_eRuntimeError, "too many fields in union!");
677
+ rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("too many fields in union!")));
647
678
  }
648
679
 
649
680
  // read struct end
@@ -671,7 +702,7 @@ static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) {
671
702
  VALUE field_info = rb_hash_aref(struct_fields, field_id);
672
703
 
673
704
  if(NIL_P(field_info)) {
674
- rb_raise(rb_eRuntimeError, "set_field is not valid for this union!");
705
+ rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("set_field is not valid for this union!")));
675
706
  }
676
707
 
677
708
  VALUE ttype_value = rb_hash_aref(field_info, type_sym);
@@ -691,7 +722,7 @@ static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) {
691
722
  return Qnil;
692
723
  }
693
724
 
694
- void Init_struct() {
725
+ void Init_struct(void) {
695
726
  VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
696
727
 
697
728
  rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
data/ext/thrift_native.c CHANGED
@@ -43,6 +43,7 @@ int TTYPE_MAP;
43
43
  int TTYPE_SET;
44
44
  int TTYPE_LIST;
45
45
  int TTYPE_STRUCT;
46
+ int TTYPE_UUID;
46
47
 
47
48
  // method ids
48
49
  ID validate_method_id;
@@ -57,6 +58,7 @@ ID write_i32_method_id;
57
58
  ID write_i64_method_id;
58
59
  ID write_double_method_id;
59
60
  ID write_string_method_id;
61
+ ID write_uuid_method_id;
60
62
  ID write_binary_method_id;
61
63
  ID write_map_begin_method_id;
62
64
  ID write_map_end_method_id;
@@ -70,6 +72,7 @@ ID read_i16_method_id;
70
72
  ID read_i32_method_id;
71
73
  ID read_i64_method_id;
72
74
  ID read_string_method_id;
75
+ ID read_uuid_method_id;
73
76
  ID read_binary_method_id;
74
77
  ID read_double_method_id;
75
78
  ID read_map_begin_method_id;
@@ -109,7 +112,17 @@ VALUE class_sym;
109
112
  VALUE binary_sym;
110
113
  VALUE protocol_exception_class;
111
114
 
112
- void Init_thrift_native() {
115
+ // protocol errors
116
+ int PROTOERR_UNKNOWN;
117
+ int PROTOERR_INVALID_DATA;
118
+ int PROTOERR_NEGATIVE_SIZE;
119
+ int PROTOERR_SIZE_LIMIT;
120
+ int PROTOERR_BAD_VERSION;
121
+ int PROTOERR_NOT_IMPLEMENTED;
122
+ int PROTOERR_DEPTH_LIMIT;
123
+
124
+ // cppcheck-suppress unusedFunction
125
+ RUBY_FUNC_EXPORTED void Init_thrift_native(void) {
113
126
  // cached classes
114
127
  thrift_module = rb_const_get(rb_cObject, rb_intern("Thrift"));
115
128
  rb_global_variable(&thrift_module);
@@ -138,6 +151,7 @@ void Init_thrift_native() {
138
151
  TTYPE_SET = FIX2INT(rb_const_get(thrift_types_module, rb_intern("SET")));
139
152
  TTYPE_LIST = FIX2INT(rb_const_get(thrift_types_module, rb_intern("LIST")));
140
153
  TTYPE_STRUCT = FIX2INT(rb_const_get(thrift_types_module, rb_intern("STRUCT")));
154
+ TTYPE_UUID = FIX2INT(rb_const_get(thrift_types_module, rb_intern("UUID")));
141
155
 
142
156
  // method ids
143
157
  validate_method_id = rb_intern("validate");
@@ -152,6 +166,7 @@ void Init_thrift_native() {
152
166
  write_i64_method_id = rb_intern("write_i64");
153
167
  write_double_method_id = rb_intern("write_double");
154
168
  write_string_method_id = rb_intern("write_string");
169
+ write_uuid_method_id = rb_intern("write_uuid");
155
170
  write_binary_method_id = rb_intern("write_binary");
156
171
  write_map_begin_method_id = rb_intern("write_map_begin");
157
172
  write_map_end_method_id = rb_intern("write_map_end");
@@ -165,10 +180,11 @@ void Init_thrift_native() {
165
180
  read_i32_method_id = rb_intern("read_i32");
166
181
  read_i64_method_id = rb_intern("read_i64");
167
182
  read_string_method_id = rb_intern("read_string");
183
+ read_uuid_method_id = rb_intern("read_uuid");
168
184
  read_binary_method_id = rb_intern("read_binary");
169
185
  read_double_method_id = rb_intern("read_double");
170
186
  read_map_begin_method_id = rb_intern("read_map_begin");
171
- read_map_end_method_id = rb_intern("read_map_end");
187
+ read_map_end_method_id = rb_intern("read_map_end");
172
188
  read_list_begin_method_id = rb_intern("read_list_begin");
173
189
  read_list_end_method_id = rb_intern("read_list_end");
174
190
  read_set_begin_method_id = rb_intern("read_set_begin");
@@ -192,7 +208,7 @@ void Init_thrift_native() {
192
208
  fields_const_id = rb_intern("FIELDS");
193
209
  transport_ivar_id = rb_intern("@trans");
194
210
  strict_read_ivar_id = rb_intern("@strict_read");
195
- strict_write_ivar_id = rb_intern("@strict_write");
211
+ strict_write_ivar_id = rb_intern("@strict_write");
196
212
 
197
213
  // cached symbols
198
214
  type_sym = ID2SYM(rb_intern("type"));
@@ -203,6 +219,15 @@ void Init_thrift_native() {
203
219
  class_sym = ID2SYM(rb_intern("class"));
204
220
  binary_sym = ID2SYM(rb_intern("binary"));
205
221
 
222
+ // protocol errors
223
+ PROTOERR_UNKNOWN = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("UNKNOWN")));
224
+ PROTOERR_INVALID_DATA = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("INVALID_DATA")));
225
+ PROTOERR_NEGATIVE_SIZE = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("NEGATIVE_SIZE")));
226
+ PROTOERR_SIZE_LIMIT = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("SIZE_LIMIT")));
227
+ PROTOERR_BAD_VERSION = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("BAD_VERSION")));
228
+ PROTOERR_NOT_IMPLEMENTED = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("NOT_IMPLEMENTED")));
229
+ PROTOERR_DEPTH_LIMIT = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("DEPTH_LIMIT")));
230
+
206
231
  rb_global_variable(&type_sym);
207
232
  rb_global_variable(&name_sym);
208
233
  rb_global_variable(&key_sym);
data/lib/thrift/bytes.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # encoding: ascii-8bit
2
- #
2
+ # frozen_string_literal: true
3
+ #
3
4
  # Licensed to the Apache Software Foundation (ASF) under one
4
5
  # or more contributor license agreements. See the NOTICE file
5
6
  # distributed with this work for additional information
@@ -7,9 +8,9 @@
7
8
  # to you under the Apache License, Version 2.0 (the
8
9
  # "License"); you may not use this file except in compliance
9
10
  # with the License. You may obtain a copy of the License at
10
- #
11
+ #
11
12
  # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
+ #
13
14
  # Unless required by applicable law or agreed to in writing,
14
15
  # software distributed under the License is distributed on an
15
16
  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -21,111 +22,80 @@
21
22
  module Thrift
22
23
  # A collection of utilities for working with bytes and byte buffers.
23
24
  module Bytes
24
- if RUBY_VERSION >= '1.9'
25
- # Creates and empty byte buffer (String with BINARY encoding)
26
- #
27
- # size - The Integer size of the buffer (default: nil) to create
28
- #
29
- # Returns a String with BINARY encoding, filled with null characters
30
- # if size is greater than zero
31
- def self.empty_byte_buffer(size = nil)
32
- if (size && size > 0)
33
- "\0".force_encoding(Encoding::BINARY) * size
34
- else
35
- ''.force_encoding(Encoding::BINARY)
36
- end
37
- end
38
-
39
- # Forces the encoding of the buffer to BINARY. If the buffer
40
- # passed is frozen, then it will be duplicated.
41
- #
42
- # buffer - The String to force the encoding of.
43
- #
44
- # Returns the String passed with an encoding of BINARY; returned
45
- # String may be a duplicate.
46
- def self.force_binary_encoding(buffer)
47
- buffer = buffer.dup if buffer.frozen?
48
- buffer.force_encoding(Encoding::BINARY)
49
- end
50
-
51
- # Gets the byte value of a given position in a String.
52
- #
53
- # string - The String to retrive the byte value from.
54
- # index - The Integer location of the byte value to retrieve.
55
- #
56
- # Returns an Integer value between 0 and 255.
57
- def self.get_string_byte(string, index)
58
- string.getbyte(index)
59
- end
60
-
61
- # Sets the byte value given to a given index in a String.
62
- #
63
- # string - The String to set the byte value in.
64
- # index - The Integer location to set the byte value at.
65
- # byte - The Integer value (0 to 255) to set in the string.
66
- #
67
- # Returns an Integer value of the byte value to set.
68
- def self.set_string_byte(string, index, byte)
69
- string.setbyte(index, byte)
70
- end
71
-
72
- # Converts the given String to a UTF-8 byte buffer.
73
- #
74
- # string - The String to convert.
75
- #
76
- # Returns a new String with BINARY encoding, containing the UTF-8
77
- # bytes of the original string.
78
- def self.convert_to_utf8_byte_buffer(string)
79
- if string.encoding != Encoding::UTF_8
80
- # transcode to UTF-8
81
- string = string.encode(Encoding::UTF_8)
82
- else
83
- # encoding is already UTF-8, but a duplicate is needed
84
- string = string.dup
85
- end
86
- string.force_encoding(Encoding::BINARY)
25
+ # Creates and empty byte buffer (String with BINARY encoding)
26
+ #
27
+ # size - The Integer size of the buffer (default: nil) to create
28
+ #
29
+ # Returns a String with BINARY encoding, filled with null characters
30
+ # if size is greater than zero
31
+ def self.empty_byte_buffer(size = nil)
32
+ if (size && size > 0)
33
+ "\0".b * size
34
+ else
35
+ ''.b
87
36
  end
37
+ end
88
38
 
89
- # Converts the given UTF-8 byte buffer into a String
90
- #
91
- # utf8_buffer - A String, with BINARY encoding, containing UTF-8 bytes
92
- #
93
- # Returns a new String with UTF-8 encoding,
94
- def self.convert_to_string(utf8_buffer)
95
- # duplicate the buffer, force encoding to UTF-8
96
- utf8_buffer.dup.force_encoding(Encoding::UTF_8)
97
- end
98
- else
99
- def self.empty_byte_buffer(size = nil)
100
- if (size && size > 0)
101
- "\0" * size
102
- else
103
- ''
104
- end
105
- end
39
+ # Forces the encoding of the buffer to BINARY. If the buffer
40
+ # passed is frozen and not already BINARY, then it will be duplicated.
41
+ #
42
+ # buffer - The String to force the encoding of.
43
+ #
44
+ # Returns the String passed with an encoding of BINARY; returned
45
+ # String may be a duplicate.
46
+ def self.force_binary_encoding(buffer)
47
+ return buffer if buffer.encoding == Encoding::BINARY
106
48
 
107
- def self.force_binary_encoding(buffer)
108
- buffer
109
- end
49
+ buffer = buffer.dup if buffer.frozen?
50
+ buffer.force_encoding(Encoding::BINARY)
51
+ end
110
52
 
111
- def self.get_string_byte(string, index)
112
- string[index]
113
- end
53
+ # Gets the byte value of a given position in a String.
54
+ #
55
+ # string - The String to retrive the byte value from.
56
+ # index - The Integer location of the byte value to retrieve.
57
+ #
58
+ # Returns an Integer value between 0 and 255.
59
+ def self.get_string_byte(string, index)
60
+ string.getbyte(index)
61
+ end
114
62
 
115
- def self.set_string_byte(string, index, byte)
116
- string[index] = byte
117
- end
63
+ # Sets the byte value given to a given index in a String.
64
+ #
65
+ # string - The String to set the byte value in.
66
+ # index - The Integer location to set the byte value at.
67
+ # byte - The Integer value (0 to 255) to set in the string.
68
+ #
69
+ # Returns an Integer value of the byte value to set.
70
+ def self.set_string_byte(string, index, byte)
71
+ string.setbyte(index, byte)
72
+ end
118
73
 
119
- def self.convert_to_utf8_byte_buffer(string)
120
- # This assumes $KCODE is 'UTF8'/'U', which would mean the String is already a UTF-8 byte buffer
121
- # TODO consider handling other $KCODE values and transcoding with iconv
122
- string
74
+ # Converts the given String to a UTF-8 byte buffer.
75
+ #
76
+ # string - The String to convert.
77
+ #
78
+ # Returns a new String with BINARY encoding, containing the UTF-8
79
+ # bytes of the original string.
80
+ def self.convert_to_utf8_byte_buffer(string)
81
+ if string.encoding != Encoding::UTF_8
82
+ # transcode to UTF-8
83
+ string = string.encode(Encoding::UTF_8)
84
+ else
85
+ # encoding is already UTF-8, but a duplicate is needed
86
+ string = string.dup
123
87
  end
88
+ string.force_encoding(Encoding::BINARY)
89
+ end
124
90
 
125
- def self.convert_to_string(utf8_buffer)
126
- # See comment in 'convert_to_utf8_byte_buffer' for relevant assumptions.
127
- utf8_buffer
128
- end
91
+ # Converts the given UTF-8 byte buffer into a String
92
+ #
93
+ # utf8_buffer - A String, with BINARY encoding, containing UTF-8 bytes
94
+ #
95
+ # Returns a new String with UTF-8 encoding,
96
+ def self.convert_to_string(utf8_buffer)
97
+ # duplicate the buffer, force encoding to UTF-8
98
+ utf8_buffer.dup.force_encoding(Encoding::UTF_8)
129
99
  end
130
100
  end
131
101
  end
data/lib/thrift/client.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # Licensed to the Apache Software Foundation (ASF) under one
3
4
  # or more contributor license agreements. See the NOTICE file
@@ -19,19 +20,25 @@
19
20
 
20
21
  module Thrift
21
22
  module Client
22
- def initialize(iprot, oprot=nil)
23
+ MIN_SEQUENCE_ID = -(2**31)
24
+ MAX_SEQUENCE_ID = (2**31) - 1
25
+
26
+ def initialize(iprot, oprot = nil)
23
27
  @iprot = iprot
24
28
  @oprot = oprot || iprot
25
29
  @seqid = 0
30
+ @pending_seqids = []
26
31
  end
27
32
 
28
33
  def send_message(name, args_class, args = {})
29
- @oprot.write_message_begin(name, MessageTypes::CALL, @seqid)
34
+ seqid = next_seqid!
35
+ @oprot.write_message_begin(name, MessageTypes::CALL, seqid)
30
36
  send_message_args(args_class, args)
37
+ @pending_seqids << seqid
31
38
  end
32
39
 
33
40
  def send_oneway_message(name, args_class, args = {})
34
- @oprot.write_message_begin(name, MessageTypes::ONEWAY, @seqid)
41
+ @oprot.write_message_begin(name, MessageTypes::ONEWAY, next_seqid!)
35
42
  send_message_args(args_class, args)
36
43
  end
37
44
 
@@ -55,9 +62,33 @@ module Thrift
55
62
  [fname, mtype, rseqid]
56
63
  end
57
64
 
58
- def reply_seqid(rseqid)
59
- result = (rseqid==@seqid)?true:false
60
- result
65
+ def validate_message_begin(fname, mtype, rseqid, expected_name)
66
+ expected_seqid = dequeue_pending_seqid
67
+
68
+ if mtype == MessageTypes::EXCEPTION
69
+ raise_application_exception
70
+ end
71
+
72
+ if mtype != MessageTypes::REPLY
73
+ raise ApplicationException.new(
74
+ ApplicationException::INVALID_MESSAGE_TYPE,
75
+ "#{expected_name} failed: invalid message type"
76
+ )
77
+ end
78
+
79
+ if fname != expected_name
80
+ raise ApplicationException.new(
81
+ ApplicationException::WRONG_METHOD_NAME,
82
+ "#{expected_name} failed: wrong method name"
83
+ )
84
+ end
85
+
86
+ return if !expected_seqid.nil? && rseqid == expected_seqid
87
+
88
+ raise ApplicationException.new(
89
+ ApplicationException::BAD_SEQUENCE_ID,
90
+ "#{expected_name} failed: out of sequence response"
91
+ )
61
92
  end
62
93
 
63
94
  def receive_message(result_klass)
@@ -67,13 +98,23 @@ module Thrift
67
98
  result
68
99
  end
69
100
 
70
- def handle_exception(mtype)
71
- if mtype == MessageTypes::EXCEPTION
72
- x = ApplicationException.new
73
- x.read(@iprot)
74
- @iprot.read_message_end
75
- raise x
76
- end
101
+ private
102
+
103
+ def next_seqid!
104
+ seqid = @seqid
105
+ @seqid = (seqid == MAX_SEQUENCE_ID) ? MIN_SEQUENCE_ID : seqid + 1
106
+ seqid
107
+ end
108
+
109
+ def dequeue_pending_seqid
110
+ @pending_seqids.shift
111
+ end
112
+
113
+ def raise_application_exception
114
+ x = ApplicationException.new
115
+ x.read(@iprot)
116
+ @iprot.read_message_end
117
+ raise x
77
118
  end
78
119
  end
79
120
  end
@@ -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,16 +7,16 @@
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
  module Thrift
21
22
  class Exception < StandardError
@@ -43,7 +44,7 @@ module Thrift
43
44
 
44
45
  attr_reader :type
45
46
 
46
- def initialize(type=UNKNOWN, message=nil)
47
+ def initialize(type = UNKNOWN, message = nil)
47
48
  super(message)
48
49
  @type = type
49
50
  end