bson 4.15.0 → 5.0.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
- checksums.yaml.gz.sig +0 -0
- data/README.md +4 -4
- data/Rakefile +5 -0
- data/ext/bson/bson-native.h +12 -4
- data/ext/bson/extconf.rb +8 -3
- data/ext/bson/init.c +11 -11
- data/ext/bson/read.c +21 -6
- data/ext/bson/util.c +168 -16
- data/ext/bson/write.c +30 -39
- data/lib/bson/active_support.rb +1 -0
- data/lib/bson/array.rb +57 -31
- data/lib/bson/big_decimal.rb +16 -6
- data/lib/bson/binary.rb +255 -128
- data/lib/bson/boolean.rb +1 -0
- data/lib/bson/code.rb +9 -11
- data/lib/bson/code_with_scope.rb +8 -10
- data/lib/bson/config.rb +1 -27
- data/lib/bson/date.rb +2 -1
- data/lib/bson/date_time.rb +2 -1
- data/lib/bson/db_pointer.rb +11 -12
- data/lib/bson/dbref.rb +11 -9
- data/lib/bson/decimal128/builder.rb +9 -8
- data/lib/bson/decimal128.rb +24 -110
- data/lib/bson/document.rb +1 -0
- data/lib/bson/environment.rb +1 -0
- data/lib/bson/error/bson_decode_error.rb +11 -0
- data/lib/bson/error/ext_json_parse_error.rb +11 -0
- data/lib/bson/error/illegal_key.rb +23 -0
- data/lib/bson/error/invalid_binary_type.rb +37 -0
- data/lib/bson/error/invalid_dbref_argument.rb +12 -0
- data/lib/bson/error/invalid_decimal128_argument.rb +25 -0
- data/lib/bson/error/invalid_decimal128_range.rb +27 -0
- data/lib/bson/error/invalid_decimal128_string.rb +26 -0
- data/lib/bson/error/invalid_key.rb +24 -0
- data/lib/bson/error/invalid_object_id.rb +11 -0
- data/lib/bson/error/invalid_regexp_pattern.rb +13 -0
- data/lib/bson/error/unrepresentable_precision.rb +19 -0
- data/lib/bson/error/unserializable_class.rb +13 -0
- data/lib/bson/error/unsupported_binary_subtype.rb +12 -0
- data/lib/bson/error/unsupported_type.rb +11 -0
- data/lib/bson/error.rb +16 -28
- data/lib/bson/ext_json.rb +1 -0
- data/lib/bson/false_class.rb +2 -1
- data/lib/bson/float.rb +2 -1
- data/lib/bson/hash.rb +127 -72
- data/lib/bson/int32.rb +16 -4
- data/lib/bson/int64.rb +16 -4
- data/lib/bson/integer.rb +3 -4
- data/lib/bson/json.rb +1 -0
- data/lib/bson/max_key.rb +7 -9
- data/lib/bson/min_key.rb +7 -9
- data/lib/bson/nil_class.rb +1 -0
- data/lib/bson/object.rb +5 -25
- data/lib/bson/object_id.rb +75 -121
- data/lib/bson/open_struct.rb +3 -2
- data/lib/bson/regexp.rb +35 -64
- data/lib/bson/registry.rb +2 -6
- data/lib/bson/specialized.rb +2 -1
- data/lib/bson/string.rb +4 -27
- data/lib/bson/symbol.rb +22 -19
- data/lib/bson/time.rb +2 -1
- data/lib/bson/time_with_zone.rb +13 -1
- data/lib/bson/timestamp.rb +2 -1
- data/lib/bson/true_class.rb +2 -1
- data/lib/bson/undefined.rb +14 -0
- data/lib/bson/version.rb +2 -1
- data/lib/bson.rb +3 -2
- data/spec/bson/array_spec.rb +19 -60
- data/spec/bson/big_decimal_spec.rb +16 -4
- data/spec/bson/binary_spec.rb +83 -74
- data/spec/bson/binary_uuid_spec.rb +1 -0
- data/spec/bson/boolean_spec.rb +1 -0
- data/spec/bson/byte_buffer_read_spec.rb +1 -0
- data/spec/bson/byte_buffer_spec.rb +1 -0
- data/spec/bson/byte_buffer_write_spec.rb +1 -0
- data/spec/bson/code_spec.rb +5 -3
- data/spec/bson/code_with_scope_spec.rb +5 -3
- data/spec/bson/config_spec.rb +1 -35
- data/spec/bson/date_spec.rb +1 -0
- data/spec/bson/date_time_spec.rb +1 -0
- data/spec/bson/dbref_legacy_spec.rb +20 -3
- data/spec/bson/dbref_spec.rb +9 -9
- data/spec/bson/decimal128_spec.rb +40 -20
- data/spec/bson/document_as_spec.rb +1 -0
- data/spec/bson/document_spec.rb +1 -1
- data/spec/bson/ext_json_parse_spec.rb +1 -0
- data/spec/bson/false_class_spec.rb +8 -0
- data/spec/bson/float_spec.rb +8 -3
- data/spec/bson/hash_as_spec.rb +1 -0
- data/spec/bson/hash_spec.rb +87 -75
- data/spec/bson/int32_spec.rb +21 -6
- data/spec/bson/int64_spec.rb +21 -6
- data/spec/bson/integer_spec.rb +45 -13
- data/spec/bson/json_spec.rb +1 -0
- data/spec/bson/max_key_spec.rb +5 -3
- data/spec/bson/min_key_spec.rb +5 -3
- data/spec/bson/nil_class_spec.rb +1 -0
- data/spec/bson/object_id_spec.rb +43 -4
- data/spec/bson/object_spec.rb +2 -1
- data/spec/bson/open_struct_spec.rb +14 -71
- data/spec/bson/raw_spec.rb +9 -15
- data/spec/bson/regexp_spec.rb +4 -3
- data/spec/bson/registry_spec.rb +2 -1
- data/spec/bson/string_spec.rb +13 -38
- data/spec/bson/symbol_raw_spec.rb +25 -0
- data/spec/bson/symbol_spec.rb +15 -18
- data/spec/bson/time_spec.rb +1 -0
- data/spec/bson/time_with_zone_spec.rb +1 -0
- data/spec/bson/timestamp_spec.rb +1 -0
- data/spec/bson/true_class_spec.rb +8 -0
- data/spec/bson/undefined_spec.rb +27 -0
- data/spec/bson_spec.rb +1 -0
- data/spec/runners/common_driver.rb +6 -5
- data/spec/runners/corpus.rb +6 -0
- data/spec/runners/corpus_legacy.rb +1 -0
- data/spec/shared/lib/mrss/constraints.rb +8 -16
- data/spec/shared/lib/mrss/docker_runner.rb +30 -3
- data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
- data/spec/shared/lib/mrss/event_subscriber.rb +15 -5
- data/spec/shared/lib/mrss/lite_constraints.rb +48 -1
- data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
- data/spec/shared/lib/mrss/session_registry.rb +69 -0
- data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
- data/spec/shared/lib/mrss/utils.rb +28 -6
- data/spec/shared/share/Dockerfile.erb +68 -85
- data/spec/shared/shlib/config.sh +27 -0
- data/spec/shared/shlib/server.sh +73 -24
- data/spec/shared/shlib/set_env.sh +39 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/spec_tests/common_driver_spec.rb +9 -4
- data/spec/spec_tests/corpus_legacy_spec.rb +1 -0
- data/spec/spec_tests/corpus_spec.rb +13 -3
- data/spec/spec_tests/data/corpus/binary.json +5 -0
- data/spec/spec_tests/data/corpus/code.json +13 -13
- data/spec/spec_tests/data/corpus/decimal128-4.json +48 -0
- data/spec/spec_tests/data/corpus/decimal128-6.json +12 -0
- data/spec/spec_tests/data/corpus/decimal128-7.json +4 -0
- data/spec/spec_tests/data/corpus/document.json +20 -0
- data/spec/spec_tests/data/corpus/symbol.json +7 -7
- data/spec/spec_tests/data/corpus/top.json +18 -3
- data/spec/support/shared_examples.rb +28 -5
- data/spec/support/spec_config.rb +1 -0
- data/spec/support/utils.rb +49 -1
- data.tar.gz.sig +0 -0
- metadata +167 -144
- metadata.gz.sig +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12132ecbf12cd3f9d72a97a4131985275206bd493afd61b38f723111e4f3d564
|
4
|
+
data.tar.gz: bbde2fa0d1b0cf9114a9c03ae971ecda873508602270d6ce4e9cc07052a73ba1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75d4fc461601cb54b33371441414a35762578c4620ebd28301649bd8ff564fe41a495055c6cda98b2b61f7ef3678f6375e3e89eebeea23cd0736f7ed4b93a525
|
7
|
+
data.tar.gz: 5a64b2fca65a1117fbac73d68144387d5f0a4bc6737f0533926f2e2af5ac02a6bf9393f0307bdf17ca085380d1b14234fad1bba3103e8f64e1868bda2840491d
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/README.md
CHANGED
@@ -10,19 +10,19 @@ An implementation of the BSON specification in Ruby.
|
|
10
10
|
Compatibility
|
11
11
|
-------------
|
12
12
|
|
13
|
-
BSON is tested against MRI (2.
|
13
|
+
BSON is tested against MRI (2.6) and JRuby (9.2+).
|
14
14
|
|
15
15
|
Documentation
|
16
16
|
-------------
|
17
17
|
|
18
18
|
Current documentation can be found
|
19
|
-
[here](
|
19
|
+
[here](https://www.mongodb.com/docs/ruby-driver/current/bson-tutorials/).
|
20
20
|
|
21
21
|
API Documentation
|
22
22
|
-----------------
|
23
23
|
|
24
|
-
The [API Documentation](https://
|
25
|
-
located at
|
24
|
+
The [API Documentation](https://www.mongodb.com/docs/ruby-driver/master/api/) is
|
25
|
+
located at mongodb.com/docs.
|
26
26
|
|
27
27
|
BSON Specification
|
28
28
|
------------------
|
data/Rakefile
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rubocop:todo all
|
3
|
+
|
1
4
|
# Copyright (C) 2009-2013 MongoDB Inc.
|
2
5
|
#
|
3
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -32,6 +35,8 @@ if jruby?
|
|
32
35
|
ext.name = "bson-ruby"
|
33
36
|
ext.ext_dir = "src"
|
34
37
|
ext.lib_dir = "lib"
|
38
|
+
ext.target_version = ENV['TARGET_VERSION'] if ENV['TARGET_VERSION']
|
39
|
+
ext.source_version = ENV['SOURCE_VERSION'] if ENV['SOURCE_VERSION']
|
35
40
|
end
|
36
41
|
else
|
37
42
|
require "rake/extensiontask"
|
data/ext/bson/bson-native.h
CHANGED
@@ -17,6 +17,7 @@
|
|
17
17
|
#include <ruby.h>
|
18
18
|
#include <stdbool.h>
|
19
19
|
#include <stdint.h>
|
20
|
+
#include <stdlib.h>
|
20
21
|
#include <unistd.h>
|
21
22
|
#include <time.h>
|
22
23
|
#include "bson-endian.h"
|
@@ -91,14 +92,16 @@ VALUE rb_bson_byte_buffer_put_uint32(VALUE self, VALUE i);
|
|
91
92
|
VALUE rb_bson_byte_buffer_put_int64(VALUE self, VALUE i);
|
92
93
|
VALUE rb_bson_byte_buffer_put_string(VALUE self, VALUE string);
|
93
94
|
VALUE rb_bson_byte_buffer_put_symbol(VALUE self, VALUE symbol);
|
94
|
-
VALUE rb_bson_byte_buffer_put_hash(VALUE self, VALUE hash
|
95
|
-
VALUE rb_bson_byte_buffer_put_array(VALUE self, VALUE array
|
95
|
+
VALUE rb_bson_byte_buffer_put_hash(VALUE self, VALUE hash);
|
96
|
+
VALUE rb_bson_byte_buffer_put_array(VALUE self, VALUE array);
|
96
97
|
VALUE rb_bson_byte_buffer_read_position(VALUE self);
|
97
98
|
VALUE rb_bson_byte_buffer_replace_int32(VALUE self, VALUE index, VALUE i);
|
98
99
|
VALUE rb_bson_byte_buffer_rewind(VALUE self);
|
99
100
|
VALUE rb_bson_byte_buffer_write_position(VALUE self);
|
100
101
|
VALUE rb_bson_byte_buffer_to_s(VALUE self);
|
102
|
+
|
101
103
|
VALUE rb_bson_object_id_generator_next(int argc, VALUE* args, VALUE self);
|
104
|
+
VALUE rb_bson_object_id_generator_reset_counter(int argc, VALUE* args, VALUE self);
|
102
105
|
|
103
106
|
size_t rb_bson_byte_buffer_memsize(const void *ptr);
|
104
107
|
void rb_bson_byte_buffer_free(void *ptr);
|
@@ -113,6 +116,13 @@ VALUE pvt_const_get_3(const char *c1, const char *c2, const char *c3);
|
|
113
116
|
|
114
117
|
int pvt_get_mode_option(int argc, VALUE *argv);
|
115
118
|
|
119
|
+
#define BSON_OBJECT_ID_RANDOM_VALUE_LENGTH ( 5 )
|
120
|
+
|
121
|
+
uint8_t* pvt_get_object_id_random_value();
|
122
|
+
void pvt_init_rand();
|
123
|
+
void pvt_rand_buf(uint8_t* bytes, int len, int pid);
|
124
|
+
int pvt_rand();
|
125
|
+
|
116
126
|
/**
|
117
127
|
* The counter for incrementing object ids.
|
118
128
|
*/
|
@@ -120,8 +130,6 @@ extern uint32_t rb_bson_object_id_counter;
|
|
120
130
|
|
121
131
|
extern VALUE rb_bson_registry;
|
122
132
|
|
123
|
-
extern VALUE rb_bson_illegal_key;
|
124
|
-
|
125
133
|
extern const rb_data_type_t rb_byte_buffer_data_type;
|
126
134
|
|
127
135
|
extern VALUE _ref_str, _id_str, _db_str;
|
data/ext/bson/extconf.rb
CHANGED
data/ext/bson/init.c
CHANGED
@@ -23,8 +23,6 @@ uint32_t rb_bson_object_id_counter;
|
|
23
23
|
|
24
24
|
VALUE rb_bson_registry;
|
25
25
|
|
26
|
-
VALUE rb_bson_illegal_key;
|
27
|
-
|
28
26
|
const rb_data_type_t rb_byte_buffer_data_type = {
|
29
27
|
"bson/byte_buffer",
|
30
28
|
{ NULL, rb_bson_byte_buffer_free, rb_bson_byte_buffer_memsize }
|
@@ -46,6 +44,8 @@ void Init_bson_native()
|
|
46
44
|
_db_str = rb_str_new_cstr("$db");
|
47
45
|
rb_gc_register_mark_object(_db_str);
|
48
46
|
|
47
|
+
rb_require("digest/md5");
|
48
|
+
|
49
49
|
VALUE rb_bson_module = rb_define_module("BSON");
|
50
50
|
|
51
51
|
/* Document-class: BSON::ByteBuffer
|
@@ -60,9 +60,6 @@ void Init_bson_native()
|
|
60
60
|
VALUE rb_digest_class = rb_const_get(rb_cObject, rb_intern("Digest"));
|
61
61
|
VALUE rb_md5_class = rb_const_get(rb_digest_class, rb_intern("MD5"));
|
62
62
|
|
63
|
-
rb_bson_illegal_key = rb_const_get(rb_const_get(rb_bson_module, rb_intern("String")),rb_intern("IllegalKey"));
|
64
|
-
rb_gc_register_mark_object(rb_bson_illegal_key);
|
65
|
-
|
66
63
|
rb_define_alloc_func(rb_byte_buffer_class, rb_bson_byte_buffer_allocate);
|
67
64
|
rb_define_method(rb_byte_buffer_class, "initialize", rb_bson_byte_buffer_initialize, -1);
|
68
65
|
|
@@ -116,7 +113,7 @@ void Init_bson_native()
|
|
116
113
|
rb_define_method(rb_byte_buffer_class, "get_array", rb_bson_byte_buffer_get_array, -1);
|
117
114
|
|
118
115
|
rb_define_method(rb_byte_buffer_class, "get_int32", rb_bson_byte_buffer_get_int32, 0);
|
119
|
-
|
116
|
+
|
120
117
|
/*
|
121
118
|
* call-seq:
|
122
119
|
* buffer.get_uint32(buffer) -> Fixnum
|
@@ -285,13 +282,13 @@ void Init_bson_native()
|
|
285
282
|
|
286
283
|
/*
|
287
284
|
* call-seq:
|
288
|
-
* buffer.put_hash(hash
|
285
|
+
* buffer.put_hash(hash) -> ByteBuffer
|
289
286
|
*
|
290
287
|
* Writes a Hash into the byte buffer.
|
291
288
|
*
|
292
289
|
* Returns the modified +self+.
|
293
290
|
*/
|
294
|
-
rb_define_method(rb_byte_buffer_class, "put_hash", rb_bson_byte_buffer_put_hash,
|
291
|
+
rb_define_method(rb_byte_buffer_class, "put_hash", rb_bson_byte_buffer_put_hash, 1);
|
295
292
|
|
296
293
|
/*
|
297
294
|
* call-seq:
|
@@ -301,7 +298,7 @@ void Init_bson_native()
|
|
301
298
|
*
|
302
299
|
* Returns the modified +self+.
|
303
300
|
*/
|
304
|
-
rb_define_method(rb_byte_buffer_class, "put_array", rb_bson_byte_buffer_put_array,
|
301
|
+
rb_define_method(rb_byte_buffer_class, "put_array", rb_bson_byte_buffer_put_array, 1);
|
305
302
|
|
306
303
|
/*
|
307
304
|
* call-seq:
|
@@ -349,6 +346,7 @@ void Init_bson_native()
|
|
349
346
|
rb_define_method(rb_byte_buffer_class, "to_s", rb_bson_byte_buffer_to_s, 0);
|
350
347
|
|
351
348
|
rb_define_method(rb_bson_object_id_generator_class, "next_object_id", rb_bson_object_id_generator_next, -1);
|
349
|
+
rb_define_method(rb_bson_object_id_generator_class, "reset_counter", rb_bson_object_id_generator_reset_counter, -1);
|
352
350
|
|
353
351
|
// Get the object id machine id and hash it.
|
354
352
|
rb_require("digest/md5");
|
@@ -356,8 +354,10 @@ void Init_bson_native()
|
|
356
354
|
rb_bson_machine_id[255] = '\0';
|
357
355
|
rb_bson_generate_machine_id(rb_md5_class, rb_bson_machine_id);
|
358
356
|
|
359
|
-
|
360
|
-
|
357
|
+
pvt_init_rand();
|
358
|
+
|
359
|
+
// Set the object id counter to a random 3-byte integer
|
360
|
+
rb_bson_object_id_counter = pvt_rand() % 0xFFFFFF;
|
361
361
|
|
362
362
|
rb_bson_registry = rb_const_get(rb_bson_module, rb_intern("Registry"));
|
363
363
|
rb_gc_register_mark_object(rb_bson_registry);
|
data/ext/bson/read.c
CHANGED
@@ -80,8 +80,23 @@ VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type, int argc,
|
|
80
80
|
case BSON_TYPE_BOOLEAN: return pvt_get_boolean(b);
|
81
81
|
default:
|
82
82
|
{
|
83
|
-
VALUE klass = rb_funcall(rb_bson_registry,rb_intern("get"),1, INT2FIX(type));
|
84
|
-
VALUE value
|
83
|
+
VALUE klass = rb_funcall(rb_bson_registry, rb_intern("get"), 1, INT2FIX(type));
|
84
|
+
VALUE value;
|
85
|
+
if (argc > 1) {
|
86
|
+
rb_raise(rb_eArgError, "At most one argument is allowed");
|
87
|
+
} else if (argc > 0) {
|
88
|
+
VALUE call_args[2];
|
89
|
+
call_args[0] = rb_buffer;
|
90
|
+
Check_Type(argv[0], T_HASH);
|
91
|
+
call_args[1] = argv[0];
|
92
|
+
#ifdef RB_PASS_KEYWORDS /* Ruby 2.7+ */
|
93
|
+
value = rb_funcallv_kw(klass, rb_intern("from_bson"), 2, call_args, RB_PASS_KEYWORDS);
|
94
|
+
#else /* Ruby 2.6 and below */
|
95
|
+
value = rb_funcallv(klass, rb_intern("from_bson"), 2, call_args);
|
96
|
+
#endif
|
97
|
+
} else {
|
98
|
+
value = rb_funcall(klass, rb_intern("from_bson"), 1, rb_buffer);
|
99
|
+
}
|
85
100
|
RB_GC_GUARD(klass);
|
86
101
|
return value;
|
87
102
|
}
|
@@ -366,17 +381,17 @@ static int pvt_is_dbref(VALUE doc) {
|
|
366
381
|
if (NIL_P(ref) || !RB_TYPE_P(ref, T_STRING)) {
|
367
382
|
return 0;
|
368
383
|
}
|
369
|
-
|
384
|
+
|
370
385
|
id = rb_hash_aref(doc, _id_str);
|
371
386
|
if (NIL_P(id)) {
|
372
387
|
return 0;
|
373
388
|
}
|
374
|
-
|
389
|
+
|
375
390
|
db = rb_hash_aref(doc, _db_str);
|
376
391
|
if (!NIL_P(db) && !RB_TYPE_P(db, T_STRING)) {
|
377
392
|
return 0;
|
378
393
|
}
|
379
|
-
|
394
|
+
|
380
395
|
return 1;
|
381
396
|
}
|
382
397
|
|
@@ -404,7 +419,7 @@ VALUE rb_bson_byte_buffer_get_hash(int argc, VALUE *argv, VALUE self){
|
|
404
419
|
if (READ_PTR(b) - start_ptr != length) {
|
405
420
|
pvt_raise_decode_error(rb_sprintf("Expected to read %d bytes for the hash but read %ld bytes", length, READ_PTR(b) - start_ptr));
|
406
421
|
}
|
407
|
-
|
422
|
+
|
408
423
|
if (pvt_is_dbref(doc)) {
|
409
424
|
VALUE cDBRef = pvt_const_get_2("BSON", "DBRef");
|
410
425
|
doc = rb_funcall(cDBRef, rb_intern("new"), 1, doc);
|
data/ext/bson/util.c
CHANGED
@@ -21,6 +21,18 @@
|
|
21
21
|
*/
|
22
22
|
static char rb_bson_machine_id_hash[HOST_NAME_HASH_MAX];
|
23
23
|
|
24
|
+
/**
|
25
|
+
* Holds a reference to the SecureRandom module, or Qnil if the modle is
|
26
|
+
* not available.
|
27
|
+
*/
|
28
|
+
static VALUE pvt_SecureRandom = Qnil;
|
29
|
+
|
30
|
+
/**
|
31
|
+
* Indicates whether or not the SecureRandom module responds to the
|
32
|
+
* `random_number` method (depends on Ruby version).
|
33
|
+
*/
|
34
|
+
static int pvt_has_random_number = 0;
|
35
|
+
|
24
36
|
void rb_bson_generate_machine_id(VALUE rb_md5_class, char *rb_bson_machine_id)
|
25
37
|
{
|
26
38
|
VALUE digest = rb_funcall(rb_md5_class, rb_intern("digest"), 1, rb_str_new2(rb_bson_machine_id));
|
@@ -29,31 +41,69 @@ void rb_bson_generate_machine_id(VALUE rb_md5_class, char *rb_bson_machine_id)
|
|
29
41
|
|
30
42
|
/**
|
31
43
|
* Generate the next object id.
|
44
|
+
*
|
45
|
+
* Specification:
|
46
|
+
* https://github.com/mongodb/specifications/blob/master/source/objectid.rst
|
47
|
+
*
|
48
|
+
* The ObjectID BSON type is a 12-byte value consisting of three different portions (fields):
|
49
|
+
* * a 4-byte value representing the seconds since the Unix epoch in the highest order bytes,
|
50
|
+
* * a 5-byte random number unique to a machine and process,
|
51
|
+
* * a 3-byte counter, starting with a random value.
|
32
52
|
*/
|
33
53
|
VALUE rb_bson_object_id_generator_next(int argc, VALUE* args, VALUE self)
|
34
54
|
{
|
35
55
|
char bytes[12];
|
36
|
-
uint32_t
|
37
|
-
|
38
|
-
|
56
|
+
uint32_t time_component;
|
57
|
+
uint8_t* random_component;
|
58
|
+
uint32_t counter_component;
|
59
|
+
VALUE timestamp;
|
60
|
+
VALUE rb_bson_object_id_class;
|
39
61
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
62
|
+
rb_bson_object_id_class = pvt_const_get_2("BSON", "ObjectId");
|
63
|
+
|
64
|
+
/* "Drivers SHOULD have an accessor method on an ObjectID class for
|
65
|
+
* obtaining the timestamp value." */
|
66
|
+
|
67
|
+
timestamp = rb_funcall(rb_bson_object_id_class, rb_intern("timestamp"), 0);
|
68
|
+
time_component = BSON_UINT32_TO_BE(NUM2INT(timestamp));
|
69
|
+
|
70
|
+
/* "A 5-byte field consisting of a random value generated once per process.
|
71
|
+
* This random value is unique to the machine and process.
|
72
|
+
*
|
73
|
+
* "Drivers MUST NOT have an accessor method on an ObjectID class for
|
74
|
+
* obtaining this value."
|
75
|
+
*/
|
46
76
|
|
47
|
-
|
77
|
+
random_component = pvt_get_object_id_random_value();
|
78
|
+
|
79
|
+
/* shift left 8 bits, so that the first three bytes of the result are
|
80
|
+
* the meaningful ones */
|
81
|
+
counter_component = BSON_UINT32_TO_BE(rb_bson_object_id_counter << 8);
|
82
|
+
|
83
|
+
memcpy(&bytes, &time_component, 4);
|
84
|
+
memcpy(&bytes[4], random_component, 5);
|
85
|
+
memcpy(&bytes[9], &counter_component, 3);
|
86
|
+
|
87
|
+
rb_bson_object_id_counter = (rb_bson_object_id_counter + 1) % 0x1000000;
|
48
88
|
|
49
|
-
memcpy(&bytes, &t, 4);
|
50
|
-
memcpy(&bytes[4], rb_bson_machine_id_hash, 3);
|
51
|
-
memcpy(&bytes[7], &pid, 2);
|
52
|
-
memcpy(&bytes[9], &c, 3);
|
53
|
-
rb_bson_object_id_counter++;
|
54
89
|
return rb_str_new(bytes, 12);
|
55
90
|
}
|
56
91
|
|
92
|
+
/**
|
93
|
+
* Reset the counter. This is purely as an aid for testing.
|
94
|
+
*
|
95
|
+
* @param [ Integer ] i the value to set the counter to (default is 0)
|
96
|
+
*/
|
97
|
+
VALUE rb_bson_object_id_generator_reset_counter(int argc, VALUE* args, VALUE self) {
|
98
|
+
switch(argc) {
|
99
|
+
case 0: rb_bson_object_id_counter = 0; break;
|
100
|
+
case 1: rb_bson_object_id_counter = FIX2INT(args[0]); break;
|
101
|
+
default: rb_raise(rb_eArgError, "Expected 0 or 1 arguments, got %d", argc);
|
102
|
+
}
|
103
|
+
|
104
|
+
return T_NIL;
|
105
|
+
}
|
106
|
+
|
57
107
|
/**
|
58
108
|
* Returns a Ruby constant nested one level, e.g. BSON::Document.
|
59
109
|
*/
|
@@ -77,7 +127,7 @@ VALUE pvt_const_get_3(const char *c1, const char *c2, const char *c3) {
|
|
77
127
|
int pvt_get_mode_option(int argc, VALUE *argv) {
|
78
128
|
VALUE opts;
|
79
129
|
VALUE mode;
|
80
|
-
|
130
|
+
|
81
131
|
rb_scan_args(argc, argv, ":", &opts);
|
82
132
|
if (NIL_P(opts)) {
|
83
133
|
return BSON_MODE_DEFAULT;
|
@@ -93,3 +143,105 @@ int pvt_get_mode_option(int argc, VALUE *argv) {
|
|
93
143
|
}
|
94
144
|
}
|
95
145
|
}
|
146
|
+
|
147
|
+
/**
|
148
|
+
* Returns the random number associated with this host and process. If the
|
149
|
+
* process ID changes (e.g. via fork), this will detect the change and
|
150
|
+
* generate another random number.
|
151
|
+
*/
|
152
|
+
uint8_t* pvt_get_object_id_random_value() {
|
153
|
+
static pid_t remembered_pid = 0;
|
154
|
+
static uint8_t remembered_value[BSON_OBJECT_ID_RANDOM_VALUE_LENGTH] = {0};
|
155
|
+
pid_t pid = getpid();
|
156
|
+
|
157
|
+
if (remembered_pid != pid) {
|
158
|
+
remembered_pid = pid;
|
159
|
+
pvt_rand_buf(remembered_value, BSON_OBJECT_ID_RANDOM_VALUE_LENGTH, pid);
|
160
|
+
}
|
161
|
+
|
162
|
+
return remembered_value;
|
163
|
+
}
|
164
|
+
|
165
|
+
/**
|
166
|
+
* Attempts to load the SecureRandom module
|
167
|
+
*/
|
168
|
+
VALUE pvt_load_secure_random(VALUE _arg) {
|
169
|
+
rb_require("securerandom");
|
170
|
+
pvt_SecureRandom = rb_const_get(rb_cObject, rb_intern("SecureRandom"));
|
171
|
+
pvt_has_random_number = rb_respond_to(pvt_SecureRandom, rb_intern("random_number"));
|
172
|
+
|
173
|
+
return Qnil;
|
174
|
+
}
|
175
|
+
|
176
|
+
/**
|
177
|
+
* The fallback, if loading `securerandom` fails.
|
178
|
+
*/
|
179
|
+
VALUE pvt_rescue_load_secure_random(VALUE _arg, VALUE _exception) {
|
180
|
+
pvt_SecureRandom = Qnil;
|
181
|
+
|
182
|
+
return Qnil;
|
183
|
+
}
|
184
|
+
|
185
|
+
/**
|
186
|
+
* Initializes the RNG.
|
187
|
+
*/
|
188
|
+
void pvt_init_rand() {
|
189
|
+
// SecureRandom may fail to load because it's not present (LoadError), or
|
190
|
+
// because it can't find a random device (NotImplementedError).
|
191
|
+
rb_rescue2(pvt_load_secure_random, Qnil, pvt_rescue_load_secure_random, Qnil,
|
192
|
+
rb_eLoadError, rb_eNotImpError, 0);
|
193
|
+
}
|
194
|
+
|
195
|
+
/**
|
196
|
+
* Fills the buffer with random bytes. It prefers to use SecureRandom for
|
197
|
+
* this, but in the very unlikely event that SecureRandom is not available,
|
198
|
+
* it will fall back to a much-less-ideal generator using srand/rand.
|
199
|
+
*
|
200
|
+
* The `pid` argument is only used by the fallback, if SecureRandom is not
|
201
|
+
* available.
|
202
|
+
*/
|
203
|
+
void pvt_rand_buf(uint8_t* bytes, int len, int pid) {
|
204
|
+
if (pvt_SecureRandom != Qnil) {
|
205
|
+
VALUE rb_bytes = rb_funcall(pvt_SecureRandom, rb_intern("bytes"), 1, INT2NUM(len));
|
206
|
+
memcpy(bytes, StringValuePtr(rb_bytes), len);
|
207
|
+
|
208
|
+
} else {
|
209
|
+
time_t t;
|
210
|
+
uint32_t seed;
|
211
|
+
int ofs = 0;
|
212
|
+
|
213
|
+
t = time(NULL);
|
214
|
+
seed = ((uint32_t)t << 16) + ((uint32_t)pid % 0xFFFF);
|
215
|
+
srand(seed);
|
216
|
+
|
217
|
+
while (ofs < len) {
|
218
|
+
int n = rand();
|
219
|
+
unsigned remaining = len - ofs;
|
220
|
+
|
221
|
+
if (remaining > sizeof(n)) remaining = sizeof(n);
|
222
|
+
memcpy(bytes+ofs, &n, remaining);
|
223
|
+
|
224
|
+
ofs += remaining;
|
225
|
+
}
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
229
|
+
/**
|
230
|
+
* Returns a random integer between 0 and INT_MAX.
|
231
|
+
*/
|
232
|
+
int pvt_rand() {
|
233
|
+
if (pvt_has_random_number) {
|
234
|
+
VALUE result = rb_funcall(pvt_SecureRandom, rb_intern("random_number"), 1, INT2NUM(INT_MAX));
|
235
|
+
return NUM2INT(result);
|
236
|
+
|
237
|
+
} else if (pvt_SecureRandom != Qnil) {
|
238
|
+
int result;
|
239
|
+
VALUE rb_result = rb_funcall(pvt_SecureRandom, rb_intern("bytes"), 1, INT2NUM(sizeof(result)));
|
240
|
+
memcpy(&result, StringValuePtr(rb_result), sizeof(result));
|
241
|
+
return result;
|
242
|
+
|
243
|
+
} else {
|
244
|
+
srand((unsigned)time(NULL));
|
245
|
+
return rand();
|
246
|
+
}
|
247
|
+
}
|