mongo 2.11.4 → 2.12.3

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 (357) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/README.md +2 -1
  6. data/lib/mongo.rb +3 -0
  7. data/lib/mongo/address.rb +44 -19
  8. data/lib/mongo/auth.rb +1 -0
  9. data/lib/mongo/auth/credential_cache.rb +51 -0
  10. data/lib/mongo/auth/scram/conversation.rb +20 -16
  11. data/lib/mongo/auth/user.rb +0 -8
  12. data/lib/mongo/auth/user/view.rb +4 -4
  13. data/lib/mongo/background_thread.rb +1 -1
  14. data/lib/mongo/bulk_write.rb +5 -5
  15. data/lib/mongo/client.rb +143 -14
  16. data/lib/mongo/client_encryption.rb +103 -0
  17. data/lib/mongo/cluster.rb +8 -4
  18. data/lib/mongo/cluster/reapers/cursor_reaper.rb +18 -6
  19. data/lib/mongo/cluster/sdam_flow.rb +54 -58
  20. data/lib/mongo/collection.rb +3 -3
  21. data/lib/mongo/collection/view.rb +1 -1
  22. data/lib/mongo/collection/view/aggregation.rb +1 -1
  23. data/lib/mongo/collection/view/change_stream.rb +12 -3
  24. data/lib/mongo/collection/view/iterable.rb +14 -5
  25. data/lib/mongo/collection/view/map_reduce.rb +2 -2
  26. data/lib/mongo/collection/view/readable.rb +9 -7
  27. data/lib/mongo/collection/view/writable.rb +7 -7
  28. data/lib/mongo/crypt.rb +33 -0
  29. data/lib/mongo/crypt/auto_decryption_context.rb +40 -0
  30. data/lib/mongo/crypt/auto_encrypter.rb +179 -0
  31. data/lib/mongo/crypt/auto_encryption_context.rb +44 -0
  32. data/lib/mongo/crypt/binary.rb +155 -0
  33. data/lib/mongo/crypt/binding.rb +1229 -0
  34. data/lib/mongo/crypt/context.rb +135 -0
  35. data/lib/mongo/crypt/data_key_context.rb +162 -0
  36. data/lib/mongo/crypt/encryption_io.rb +289 -0
  37. data/lib/mongo/crypt/explicit_decryption_context.rb +40 -0
  38. data/lib/mongo/crypt/explicit_encrypter.rb +117 -0
  39. data/lib/mongo/crypt/explicit_encryption_context.rb +89 -0
  40. data/lib/mongo/crypt/handle.rb +315 -0
  41. data/lib/mongo/crypt/hooks.rb +90 -0
  42. data/lib/mongo/crypt/kms_context.rb +67 -0
  43. data/lib/mongo/crypt/status.rb +131 -0
  44. data/lib/mongo/cursor.rb +64 -32
  45. data/lib/mongo/database.rb +23 -6
  46. data/lib/mongo/database/view.rb +13 -4
  47. data/lib/mongo/dbref.rb +9 -2
  48. data/lib/mongo/error.rb +5 -1
  49. data/lib/mongo/error/bulk_write_error.rb +16 -14
  50. data/lib/mongo/error/crypt_error.rb +31 -0
  51. data/lib/mongo/error/{failed_stringprep_validation.rb → failed_string_prep_validation.rb} +0 -0
  52. data/lib/mongo/error/invalid_cursor_operation.rb +27 -0
  53. data/lib/mongo/error/kms_error.rb +22 -0
  54. data/lib/mongo/error/max_bson_size.rb +14 -3
  55. data/lib/mongo/error/mongocryptd_spawn_error.rb +22 -0
  56. data/lib/mongo/error/no_server_available.rb +8 -3
  57. data/lib/mongo/error/notable.rb +0 -15
  58. data/lib/mongo/error/operation_failure.rb +1 -0
  59. data/lib/mongo/error/parser.rb +1 -1
  60. data/lib/mongo/grid/file.rb +5 -0
  61. data/lib/mongo/grid/file/chunk.rb +2 -0
  62. data/lib/mongo/grid/file/info.rb +3 -2
  63. data/lib/mongo/grid/fs_bucket.rb +15 -13
  64. data/lib/mongo/grid/stream/write.rb +9 -3
  65. data/lib/mongo/index/view.rb +3 -3
  66. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +1 -1
  67. data/lib/mongo/monitoring/event/command_started.rb +6 -1
  68. data/lib/mongo/operation/collections_info.rb +6 -3
  69. data/lib/mongo/operation/delete/op_msg.rb +1 -1
  70. data/lib/mongo/operation/find/op_msg.rb +4 -1
  71. data/lib/mongo/operation/get_more/op_msg.rb +4 -1
  72. data/lib/mongo/operation/insert/command.rb +3 -2
  73. data/lib/mongo/operation/insert/legacy.rb +3 -2
  74. data/lib/mongo/operation/insert/op_msg.rb +3 -3
  75. data/lib/mongo/operation/result.rb +36 -27
  76. data/lib/mongo/operation/shared/executable.rb +11 -9
  77. data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
  78. data/lib/mongo/operation/shared/op_msg_or_command.rb +2 -2
  79. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +2 -2
  80. data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +2 -2
  81. data/lib/mongo/operation/shared/read_preference_supported.rb +68 -19
  82. data/lib/mongo/operation/shared/response_handling.rb +1 -1
  83. data/lib/mongo/operation/shared/sessions_supported.rb +44 -3
  84. data/lib/mongo/operation/shared/write.rb +17 -10
  85. data/lib/mongo/operation/update/op_msg.rb +1 -1
  86. data/lib/mongo/protocol/bit_vector.rb +2 -1
  87. data/lib/mongo/protocol/compressed.rb +6 -5
  88. data/lib/mongo/protocol/insert.rb +3 -1
  89. data/lib/mongo/protocol/message.rb +94 -15
  90. data/lib/mongo/protocol/msg.rb +207 -37
  91. data/lib/mongo/protocol/query.rb +7 -9
  92. data/lib/mongo/protocol/serializers.rb +43 -15
  93. data/lib/mongo/retryable.rb +1 -1
  94. data/lib/mongo/server.rb +10 -4
  95. data/lib/mongo/server/connection.rb +20 -9
  96. data/lib/mongo/server/connection_base.rb +118 -18
  97. data/lib/mongo/server/connection_common.rb +61 -0
  98. data/lib/mongo/server/connection_pool.rb +37 -1
  99. data/lib/mongo/server/connection_pool/populator.rb +1 -1
  100. data/lib/mongo/server/description.rb +9 -11
  101. data/lib/mongo/server/monitor.rb +2 -0
  102. data/lib/mongo/server/monitor/connection.rb +3 -18
  103. data/lib/mongo/server/pending_connection.rb +2 -1
  104. data/lib/mongo/session.rb +3 -3
  105. data/lib/mongo/session/session_pool.rb +8 -3
  106. data/lib/mongo/socket.rb +29 -16
  107. data/lib/mongo/socket/ssl.rb +23 -8
  108. data/lib/mongo/socket/tcp.rb +12 -3
  109. data/lib/mongo/srv/monitor.rb +73 -42
  110. data/lib/mongo/srv/result.rb +0 -1
  111. data/lib/mongo/timeout.rb +49 -0
  112. data/lib/mongo/uri.rb +30 -1
  113. data/lib/mongo/uri/srv_protocol.rb +1 -1
  114. data/lib/mongo/version.rb +1 -1
  115. data/mongo.gemspec +1 -3
  116. data/spec/README.md +228 -7
  117. data/spec/integration/auth_spec.rb +53 -0
  118. data/spec/integration/bulk_write_spec.rb +19 -0
  119. data/spec/integration/{client_options_spec.rb → client_authentication_options_spec.rb} +10 -10
  120. data/spec/integration/client_construction_spec.rb +100 -1
  121. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +353 -0
  122. data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +303 -0
  123. data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +72 -0
  124. data/spec/integration/client_side_encryption/auto_encryption_old_wire_version_spec.rb +79 -0
  125. data/spec/integration/client_side_encryption/auto_encryption_reconnect_spec.rb +221 -0
  126. data/spec/integration/client_side_encryption/auto_encryption_spec.rb +601 -0
  127. data/spec/integration/client_side_encryption/bson_size_limit_spec.rb +187 -0
  128. data/spec/integration/client_side_encryption/bypass_mongocryptd_spawn_spec.rb +78 -0
  129. data/spec/integration/client_side_encryption/client_close_spec.rb +63 -0
  130. data/spec/integration/client_side_encryption/corpus_spec.rb +233 -0
  131. data/spec/integration/client_side_encryption/custom_endpoint_spec.rb +132 -0
  132. data/spec/integration/client_side_encryption/data_key_spec.rb +165 -0
  133. data/spec/integration/client_side_encryption/explicit_encryption_spec.rb +114 -0
  134. data/spec/integration/client_side_encryption/external_key_vault_spec.rb +141 -0
  135. data/spec/integration/client_side_encryption/views_spec.rb +44 -0
  136. data/spec/integration/client_update_spec.rb +154 -0
  137. data/spec/integration/command_monitoring_spec.rb +3 -1
  138. data/spec/integration/command_spec.rb +44 -10
  139. data/spec/integration/connection_spec.rb +57 -0
  140. data/spec/integration/crud_spec.rb +89 -0
  141. data/spec/integration/grid_fs_bucket_spec.rb +48 -0
  142. data/spec/integration/read_preference_spec.rb +26 -0
  143. data/spec/integration/reconnect_spec.rb +7 -6
  144. data/spec/integration/size_limit_spec.rb +111 -0
  145. data/spec/integration/srv_monitoring_spec.rb +16 -8
  146. data/spec/integration/zlib_compression_spec.rb +25 -0
  147. data/spec/kerberos/kerberos_spec.rb +87 -0
  148. data/spec/lite_spec_helper.rb +34 -29
  149. data/spec/mongo/auth/cr_spec.rb +8 -0
  150. data/spec/mongo/auth/ldap_spec.rb +5 -1
  151. data/spec/mongo/auth/scram/conversation_spec.rb +5 -6
  152. data/spec/mongo/auth/scram/negotiation_spec.rb +74 -75
  153. data/spec/mongo/auth/scram_spec.rb +45 -35
  154. data/spec/mongo/auth/user/view_spec.rb +3 -6
  155. data/spec/mongo/auth/x509_spec.rb +5 -1
  156. data/spec/mongo/bulk_write/result_spec.rb +11 -7
  157. data/spec/mongo/client_construction_spec.rb +206 -2
  158. data/spec/mongo/client_encryption_spec.rb +405 -0
  159. data/spec/mongo/cluster/cursor_reaper_spec.rb +12 -8
  160. data/spec/mongo/cluster/socket_reaper_spec.rb +14 -3
  161. data/spec/mongo/collection/view/aggregation_spec.rb +0 -2
  162. data/spec/mongo/collection/view/change_stream_spec.rb +7 -7
  163. data/spec/mongo/collection/view/map_reduce_spec.rb +3 -3
  164. data/spec/mongo/collection/view_spec.rb +1 -1
  165. data/spec/mongo/collection_spec.rb +28 -9
  166. data/spec/mongo/crypt/auto_decryption_context_spec.rb +90 -0
  167. data/spec/mongo/crypt/auto_encrypter_spec.rb +187 -0
  168. data/spec/mongo/crypt/auto_encryption_context_spec.rb +107 -0
  169. data/spec/mongo/crypt/binary_spec.rb +115 -0
  170. data/spec/mongo/crypt/binding/binary_spec.rb +56 -0
  171. data/spec/mongo/crypt/binding/context_spec.rb +257 -0
  172. data/spec/mongo/crypt/binding/helpers_spec.rb +46 -0
  173. data/spec/mongo/crypt/binding/mongocrypt_spec.rb +144 -0
  174. data/spec/mongo/crypt/binding/status_spec.rb +99 -0
  175. data/spec/mongo/crypt/binding/version_spec.rb +22 -0
  176. data/spec/mongo/crypt/binding_unloaded_spec.rb +20 -0
  177. data/spec/mongo/crypt/data_key_context_spec.rb +213 -0
  178. data/spec/mongo/crypt/encryption_io_spec.rb +136 -0
  179. data/spec/mongo/crypt/explicit_decryption_context_spec.rb +72 -0
  180. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +170 -0
  181. data/spec/mongo/crypt/handle_spec.rb +232 -0
  182. data/spec/mongo/crypt/helpers/mongo_crypt_spec_helper.rb +108 -0
  183. data/spec/mongo/crypt/status_spec.rb +152 -0
  184. data/spec/mongo/cursor_spec.rb +24 -4
  185. data/spec/mongo/database_spec.rb +20 -0
  186. data/spec/mongo/error/bulk_write_error_spec.rb +49 -0
  187. data/spec/mongo/error/crypt_error_spec.rb +26 -0
  188. data/spec/mongo/error/max_bson_size_spec.rb +35 -0
  189. data/spec/mongo/error/no_server_available_spec.rb +11 -1
  190. data/spec/mongo/error/notable_spec.rb +59 -0
  191. data/spec/mongo/error/operation_failure_spec.rb +6 -6
  192. data/spec/mongo/operation/aggregate_spec.rb +1 -1
  193. data/spec/mongo/operation/collections_info_spec.rb +1 -1
  194. data/spec/mongo/operation/command_spec.rb +3 -3
  195. data/spec/mongo/operation/create_index_spec.rb +3 -3
  196. data/spec/mongo/operation/create_user_spec.rb +3 -3
  197. data/spec/mongo/operation/delete/bulk_spec.rb +6 -6
  198. data/spec/mongo/operation/delete/op_msg_spec.rb +1 -6
  199. data/spec/mongo/operation/delete_spec.rb +7 -7
  200. data/spec/mongo/operation/drop_index_spec.rb +2 -2
  201. data/spec/mongo/operation/find/legacy_spec.rb +2 -1
  202. data/spec/mongo/operation/get_more_spec.rb +1 -1
  203. data/spec/mongo/operation/indexes_spec.rb +1 -1
  204. data/spec/mongo/operation/insert/bulk_spec.rb +7 -7
  205. data/spec/mongo/operation/insert/op_msg_spec.rb +3 -6
  206. data/spec/mongo/operation/insert_spec.rb +12 -12
  207. data/spec/mongo/operation/map_reduce_spec.rb +2 -2
  208. data/spec/mongo/operation/read_preference_legacy_spec.rb +351 -0
  209. data/spec/mongo/operation/read_preference_op_msg_spec.rb +194 -0
  210. data/spec/mongo/operation/remove_user_spec.rb +3 -3
  211. data/spec/mongo/operation/update/bulk_spec.rb +6 -6
  212. data/spec/mongo/operation/update/op_msg_spec.rb +3 -6
  213. data/spec/mongo/operation/update_spec.rb +7 -7
  214. data/spec/mongo/operation/update_user_spec.rb +1 -1
  215. data/spec/mongo/protocol/compressed_spec.rb +2 -3
  216. data/spec/mongo/protocol/delete_spec.rb +9 -8
  217. data/spec/mongo/protocol/get_more_spec.rb +9 -8
  218. data/spec/mongo/protocol/insert_spec.rb +9 -8
  219. data/spec/mongo/protocol/kill_cursors_spec.rb +6 -5
  220. data/spec/mongo/protocol/msg_spec.rb +57 -53
  221. data/spec/mongo/protocol/query_spec.rb +12 -12
  222. data/spec/mongo/protocol/registry_spec.rb +1 -1
  223. data/spec/mongo/protocol/reply_spec.rb +1 -1
  224. data/spec/mongo/protocol/update_spec.rb +10 -9
  225. data/spec/mongo/server/connection_pool_spec.rb +1 -1
  226. data/spec/mongo/server/connection_spec.rb +28 -7
  227. data/spec/mongo/socket_spec.rb +1 -1
  228. data/spec/mongo/srv/monitor_spec.rb +88 -69
  229. data/spec/mongo/timeout_spec.rb +85 -0
  230. data/spec/mongo/uri/srv_protocol_spec.rb +2 -2
  231. data/spec/mongo/uri_spec.rb +52 -5
  232. data/spec/mongo/write_concern_spec.rb +13 -1
  233. data/spec/{support → runners}/auth.rb +14 -1
  234. data/spec/{support → runners}/change_streams.rb +1 -1
  235. data/spec/{support → runners}/change_streams/operation.rb +0 -0
  236. data/spec/{support → runners}/cmap.rb +1 -1
  237. data/spec/{support → runners}/cmap/verifier.rb +0 -0
  238. data/spec/{support → runners}/command_monitoring.rb +0 -0
  239. data/spec/runners/connection_string.rb +358 -4
  240. data/spec/{support → runners}/crud.rb +9 -9
  241. data/spec/{support → runners}/crud/context.rb +0 -0
  242. data/spec/{support → runners}/crud/operation.rb +7 -3
  243. data/spec/{support → runners}/crud/outcome.rb +0 -0
  244. data/spec/{support → runners}/crud/requirement.rb +1 -1
  245. data/spec/{support → runners}/crud/spec.rb +12 -1
  246. data/spec/{support → runners}/crud/test.rb +0 -0
  247. data/spec/{support → runners}/crud/test_base.rb +0 -0
  248. data/spec/{support → runners}/crud/verifier.rb +10 -12
  249. data/spec/{support → runners}/gridfs.rb +0 -0
  250. data/spec/{support → runners}/sdam_monitoring.rb +0 -0
  251. data/spec/{support → runners}/server_discovery_and_monitoring.rb +0 -0
  252. data/spec/{support → runners}/server_selection.rb +0 -0
  253. data/spec/{support → runners}/server_selection_rtt.rb +0 -0
  254. data/spec/{support → runners}/transactions.rb +9 -11
  255. data/spec/{support → runners}/transactions/context.rb +0 -0
  256. data/spec/{support → runners}/transactions/operation.rb +0 -0
  257. data/spec/{support → runners}/transactions/spec.rb +0 -0
  258. data/spec/{support → runners}/transactions/test.rb +37 -5
  259. data/spec/spec_helper.rb +0 -5
  260. data/spec/spec_tests/auth_spec.rb +3 -3
  261. data/spec/spec_tests/client_side_encryption_spec.rb +8 -0
  262. data/spec/spec_tests/connection_string_spec.rb +1 -1
  263. data/spec/spec_tests/data/auth/connection-string.yml +13 -0
  264. data/spec/spec_tests/data/client_side_encryption/aggregate.yml +134 -0
  265. data/spec/spec_tests/data/client_side_encryption/badQueries.yml +526 -0
  266. data/spec/spec_tests/data/client_side_encryption/badSchema.yml +73 -0
  267. data/spec/spec_tests/data/client_side_encryption/basic.yml +116 -0
  268. data/spec/spec_tests/data/client_side_encryption/bulk.yml +88 -0
  269. data/spec/spec_tests/data/client_side_encryption/bypassAutoEncryption.yml +100 -0
  270. data/spec/spec_tests/data/client_side_encryption/bypassedCommand.yml +42 -0
  271. data/spec/spec_tests/data/client_side_encryption/count.yml +61 -0
  272. data/spec/spec_tests/data/client_side_encryption/countDocuments.yml +59 -0
  273. data/spec/spec_tests/data/client_side_encryption/delete.yml +105 -0
  274. data/spec/spec_tests/data/client_side_encryption/distinct.yml +73 -0
  275. data/spec/spec_tests/data/client_side_encryption/explain.yml +64 -0
  276. data/spec/spec_tests/data/client_side_encryption/find.yml +119 -0
  277. data/spec/spec_tests/data/client_side_encryption/findOneAndDelete.yml +57 -0
  278. data/spec/spec_tests/data/client_side_encryption/findOneAndReplace.yml +57 -0
  279. data/spec/spec_tests/data/client_side_encryption/findOneAndUpdate.yml +57 -0
  280. data/spec/spec_tests/data/client_side_encryption/getMore.yml +68 -0
  281. data/spec/spec_tests/data/client_side_encryption/insert.yml +102 -0
  282. data/spec/spec_tests/data/client_side_encryption/keyAltName.yml +71 -0
  283. data/spec/spec_tests/data/client_side_encryption/localKMS.yml +54 -0
  284. data/spec/spec_tests/data/client_side_encryption/localSchema.yml +72 -0
  285. data/spec/spec_tests/data/client_side_encryption/malformedCiphertext.yml +69 -0
  286. data/spec/spec_tests/data/client_side_encryption/maxWireVersion.yml +20 -0
  287. data/spec/spec_tests/data/client_side_encryption/missingKey.yml +49 -0
  288. data/spec/spec_tests/data/client_side_encryption/replaceOne.yml +64 -0
  289. data/spec/spec_tests/data/client_side_encryption/types.yml +527 -0
  290. data/spec/spec_tests/data/client_side_encryption/unsupportedCommand.yml +25 -0
  291. data/spec/spec_tests/data/client_side_encryption/updateMany.yml +77 -0
  292. data/spec/spec_tests/data/client_side_encryption/updateOne.yml +171 -0
  293. data/spec/spec_tests/data/read_write_concern/connection-string/write-concern.yml +1 -4
  294. data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +21 -0
  295. data/spec/spec_tests/data/sdam/rs/incompatible_ghost.yml +2 -4
  296. data/spec/spec_tests/data/sdam/rs/incompatible_other.yml +1 -1
  297. data/spec/spec_tests/data/sdam/rs/primary_mismatched_me_not_removed.yml +73 -0
  298. data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +1 -2
  299. data/spec/spec_tests/data/sdam/rs/repeated.yml +101 -0
  300. data/spec/spec_tests/data/sdam/rs/{primary_address_change.yml → ruby_primary_address_change.yml} +2 -0
  301. data/spec/spec_tests/data/sdam/rs/{secondary_wrong_set_name_with_primary_second.yml → ruby_secondary_wrong_set_name_with_primary_second.yml} +0 -0
  302. data/spec/spec_tests/data/sdam/sharded/ruby_discovered_single_mongos.yml +27 -0
  303. data/spec/spec_tests/data/sdam/sharded/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  304. data/spec/spec_tests/data/sdam/sharded/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  305. data/spec/spec_tests/data/sdam/single/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  306. data/spec/spec_tests/data/sdam/single/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  307. data/spec/spec_tests/data/sdam_monitoring/{replica_set_with_primary_change.yml → replica_set_primary_address_change.yml} +27 -5
  308. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +26 -74
  309. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_removal.yml +20 -16
  310. data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +73 -0
  311. data/spec/spec_tests/data/transactions/pin-mongos.yml +2 -3
  312. data/spec/spec_tests/data/uri_options/auth-options.yml +10 -0
  313. data/spec/spec_tests/data/uri_options/tls-options.yml +75 -4
  314. data/spec/spec_tests/read_write_concern_connection_string_spec.rb +1 -1
  315. data/spec/spec_tests/uri_options_spec.rb +6 -8
  316. data/spec/stress/connection_pool_timing_spec.rb +6 -3
  317. data/spec/support/certificates/README.md +4 -0
  318. data/spec/support/certificates/server-second-level-bundle.pem +77 -77
  319. data/spec/support/certificates/server-second-level.crt +52 -52
  320. data/spec/support/certificates/server-second-level.key +25 -25
  321. data/spec/support/certificates/server-second-level.pem +77 -77
  322. data/spec/support/client_registry.rb +19 -3
  323. data/spec/support/cluster_config.rb +9 -1
  324. data/spec/support/cluster_tools.rb +6 -1
  325. data/spec/support/common_shortcuts.rb +12 -0
  326. data/spec/support/constraints.rb +16 -0
  327. data/spec/support/crypt.rb +154 -0
  328. data/spec/support/crypt/corpus/corpus-key-aws.json +33 -0
  329. data/spec/support/crypt/corpus/corpus-key-local.json +31 -0
  330. data/spec/support/crypt/corpus/corpus-schema.json +2057 -0
  331. data/spec/support/crypt/corpus/corpus.json +3657 -0
  332. data/spec/support/crypt/corpus/corpus_encrypted.json +4152 -0
  333. data/spec/support/crypt/data_keys/key_document_aws.json +34 -0
  334. data/spec/support/crypt/data_keys/key_document_local.json +31 -0
  335. data/spec/support/crypt/external/external-key.json +31 -0
  336. data/spec/support/crypt/external/external-schema.json +19 -0
  337. data/spec/support/crypt/limits/limits-doc.json +102 -0
  338. data/spec/support/crypt/limits/limits-key.json +31 -0
  339. data/spec/support/crypt/limits/limits-schema.json +1405 -0
  340. data/spec/support/crypt/schema_maps/schema_map_aws.json +17 -0
  341. data/spec/support/crypt/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  342. data/spec/support/crypt/schema_maps/schema_map_local.json +18 -0
  343. data/spec/support/crypt/schema_maps/schema_map_local_key_alt_names.json +12 -0
  344. data/spec/support/lite_constraints.rb +19 -1
  345. data/spec/support/matchers.rb +19 -0
  346. data/spec/support/shared/protocol.rb +2 -0
  347. data/spec/support/spec_config.rb +53 -13
  348. data/spec/support/utils.rb +140 -10
  349. metadata +894 -687
  350. metadata.gz.sig +0 -0
  351. data/lib/mongo/cluster/srv_monitor.rb +0 -127
  352. data/lib/mongo/srv/warning_result.rb +0 -35
  353. data/spec/enterprise_auth/kerberos_spec.rb +0 -58
  354. data/spec/mongo/cluster/srv_monitor_spec.rb +0 -214
  355. data/spec/mongo/operation/read_preference_spec.rb +0 -245
  356. data/spec/spec_tests/data/sdam/sharded/single_mongos.yml +0 -33
  357. data/spec/support/connection_string.rb +0 -354
@@ -239,7 +239,7 @@ module Mongo
239
239
  server = cluster.next_primary(nil, session)
240
240
  end
241
241
  validate_collation!(server)
242
- initial_query_op(session).execute(server)
242
+ initial_query_op(session).execute(server, client: client)
243
243
  end
244
244
 
245
245
  def fetch_query_spec
@@ -259,7 +259,7 @@ module Mongo
259
259
  end
260
260
 
261
261
  def send_fetch_query(server, session)
262
- fetch_query_op(server, session).execute(server)
262
+ fetch_query_op(server, session).execute(server, client: client)
263
263
  end
264
264
 
265
265
  def validate_collation!(server)
@@ -155,7 +155,7 @@ module Mongo
155
155
  :options => {:limit => -1},
156
156
  :read => read_pref,
157
157
  :session => session
158
- ).execute(server)
158
+ ).execute(server, client: client)
159
159
  end.n.to_i
160
160
  end
161
161
  end
@@ -185,7 +185,9 @@ module Mongo
185
185
  pipeline << { :'$limit' => opts[:limit] } if opts[:limit]
186
186
  pipeline << { :'$group' => { _id: 1, n: { :'$sum' => 1 } } }
187
187
 
188
- opts.select! { |k, _| [:hint, :max_time_ms, :read, :collation, :session].include?(k) }
188
+ opts = opts.select { |k, _| [:hint, :max_time_ms, :read, :collation, :session].include?(k) }
189
+ opts[:collation] ||= collation
190
+
189
191
  first = aggregate(pipeline, opts).first
190
192
  return 0 unless first
191
193
  first['n'].to_i
@@ -222,7 +224,7 @@ module Mongo
222
224
  db_name: database.name,
223
225
  read: read_pref,
224
226
  session: session
225
- ).execute(server)
227
+ ).execute(server, client: client)
226
228
  end.n.to_i
227
229
  end
228
230
  end
@@ -267,7 +269,7 @@ module Mongo
267
269
  :options => {:limit => -1},
268
270
  :read => read_pref,
269
271
  :session => session
270
- }).execute(server)
272
+ }).execute(server, client: client)
271
273
  end.first['values']
272
274
  end
273
275
  end
@@ -602,21 +604,21 @@ module Mongo
602
604
  :read_concern => read_concern,
603
605
  :session => session,
604
606
  }.merge!(options))
605
- cmd.execute(server).cursor_ids.map do |cursor_id|
607
+ cmd.execute(server, client: client).cursor_ids.map do |cursor_id|
606
608
  result = if server.features.find_command_enabled?
607
609
  Operation::GetMore.new({
608
610
  :selector => {:getMore => BSON::Int64.new(cursor_id),
609
611
  :collection => collection.name},
610
612
  :db_name => database.name,
611
613
  :session => session,
612
- }).execute(server)
614
+ }).execute(server, client: client)
613
615
  else
614
616
  Operation::GetMore.new({
615
617
  :to_return => 0,
616
618
  :cursor_id => BSON::Int64.new(cursor_id),
617
619
  :db_name => database.name,
618
620
  :coll_name => collection.name
619
- }).execute(server)
621
+ }).execute(server, client: client)
620
622
  end
621
623
  Cursor.new(self, result, server, session: session)
622
624
  end
@@ -63,7 +63,7 @@ module Mongo
63
63
  :db_name => database.name,
64
64
  :session => session,
65
65
  :txn_num => txn_num
66
- ).execute(server)
66
+ ).execute(server, client: client)
67
67
  end
68
68
  end.first['value']
69
69
  end
@@ -144,7 +144,7 @@ module Mongo
144
144
  :db_name => database.name,
145
145
  :session => session,
146
146
  :txn_num => txn_num
147
- ).execute(server)
147
+ ).execute(server, client: client)
148
148
  end
149
149
  end.first['value']
150
150
  value unless value.nil? || value.empty?
@@ -175,7 +175,7 @@ module Mongo
175
175
  :coll_name => collection.name,
176
176
  :write_concern => write_concern,
177
177
  :session => session
178
- ).execute(server)
178
+ ).execute(server, client: client)
179
179
  end
180
180
  end
181
181
  end
@@ -206,7 +206,7 @@ module Mongo
206
206
  :write_concern => write_concern,
207
207
  :session => session,
208
208
  :txn_num => txn_num
209
- ).execute(server)
209
+ ).execute(server, client: client)
210
210
  end
211
211
  end
212
212
  end
@@ -250,7 +250,7 @@ module Mongo
250
250
  :bypass_document_validation => !!opts[:bypass_document_validation],
251
251
  :session => session,
252
252
  :txn_num => txn_num
253
- ).execute(server)
253
+ ).execute(server, client: client)
254
254
  end
255
255
  end
256
256
  end
@@ -295,7 +295,7 @@ module Mongo
295
295
  :write_concern => write_concern,
296
296
  :bypass_document_validation => !!opts[:bypass_document_validation],
297
297
  :session => session
298
- ).execute(server)
298
+ ).execute(server, client: client)
299
299
  end
300
300
  end
301
301
  end
@@ -341,7 +341,7 @@ module Mongo
341
341
  :bypass_document_validation => !!opts[:bypass_document_validation],
342
342
  :session => session,
343
343
  :txn_num => txn_num
344
- ).execute(server)
344
+ ).execute(server, client: client)
345
345
  end
346
346
  end
347
347
  end
@@ -0,0 +1,33 @@
1
+ # Copyright (C) 2019 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ module Crypt
17
+ autoload(:Binding, 'mongo/crypt/binding')
18
+ autoload(:Binary, 'mongo/crypt/binary')
19
+ autoload(:Status, 'mongo/crypt/status')
20
+ autoload(:Hooks, 'mongo/crypt/hooks')
21
+ autoload(:Handle, 'mongo/crypt/handle')
22
+ autoload(:KmsContext, 'mongo/crypt/kms_context')
23
+ autoload(:Context, 'mongo/crypt/context')
24
+ autoload(:DataKeyContext, 'mongo/crypt/data_key_context')
25
+ autoload(:ExplicitEncryptionContext, 'mongo/crypt/explicit_encryption_context')
26
+ autoload(:AutoEncryptionContext, 'mongo/crypt/auto_encryption_context')
27
+ autoload(:ExplicitDecryptionContext, 'mongo/crypt/explicit_decryption_context')
28
+ autoload(:AutoDecryptionContext, 'mongo/crypt/auto_decryption_context')
29
+ autoload(:EncryptionIO, 'mongo/crypt/encryption_io')
30
+ autoload(:ExplicitEncrypter, 'mongo/crypt/explicit_encrypter')
31
+ autoload(:AutoEncrypter, 'mongo/crypt/auto_encrypter')
32
+ end
33
+ end
@@ -0,0 +1,40 @@
1
+ # Copyright (C) 2019 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ module Crypt
17
+
18
+ # A Context object initialized for auto decryption
19
+ #
20
+ # @api private
21
+ class AutoDecryptionContext < Context
22
+
23
+ # Create a new AutoEncryptionContext object
24
+ #
25
+ # @param [ Mongo::Crypt::Handle ] mongocrypt a Handle that
26
+ # wraps a mongocrypt_t object used to create a new mongocrypt_ctx_t.
27
+ # @param [ ClientEncryption::IO ] io A instance of the IO class
28
+ # that implements driver I/O methods required to run the
29
+ # state machine.
30
+ # @param [ Hash ] command The command to be decrypted.
31
+ def initialize(mongocrypt, io, command)
32
+ super(mongocrypt, io)
33
+
34
+ @command = command
35
+
36
+ Binding.ctx_decrypt_init(self, @command)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,179 @@
1
+ # Copyright (C) 2019 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ module Crypt
17
+
18
+ # An AutoEcnrypter is an object that encapsulates the behavior of
19
+ # automatic encryption. It controls all resources associated with
20
+ # auto-encryption, including the libmongocrypt handle, key vault client
21
+ # object, mongocryptd client object, and encryption I/O.
22
+ #
23
+ # The AutoEncrypter is kept as an instance on a Mongo::Client. Client
24
+ # objects with the same auto_encryption_options Hash may share
25
+ # AutoEncrypters.
26
+ #
27
+ # @api private
28
+ class AutoEncrypter
29
+
30
+ attr_reader :mongocryptd_client
31
+ attr_reader :key_vault_client
32
+ attr_reader :options
33
+
34
+ # A Hash of default values for the :extra_options option
35
+ DEFAULT_EXTRA_OPTIONS = Options::Redacted.new({
36
+ mongocryptd_uri: 'mongodb://localhost:27020',
37
+ mongocryptd_bypass_spawn: false,
38
+ mongocryptd_spawn_path: 'mongocryptd',
39
+ mongocryptd_spawn_args: ['--idleShutdownTimeoutSecs=60'],
40
+ })
41
+
42
+ # Set up encryption-related options and instance variables
43
+ # on the class that includes this module. Calls the same method
44
+ # on the Mongo::Crypt::Encrypter module.
45
+ #
46
+ # @param [ Hash ] options
47
+ #
48
+ # @option options [ Mongo::Client ] :client A client connected to the
49
+ # encrypted collection.
50
+ # @option options [ Mongo::Client | nil ] :key_vault_client A client connected
51
+ # to the MongoDB instance containing the encryption key vault; optional.
52
+ # If not provided, will default to :client option.
53
+ # @option options [ String ] :key_vault_namespace The namespace of the key
54
+ # vault in the format database.collection.
55
+ # @option options [ Hash | nil ] :schema_map The JSONSchema of the collection(s)
56
+ # with encrypted fields.
57
+ # @option options [ Boolean | nil ] :bypass_auto_encryption When true, disables
58
+ # auto-encryption. Default is false.
59
+ # @option options [ Hash | nil ] :extra_options Options related to spawning
60
+ # mongocryptd. These are set to default values if no option is passed in.
61
+ #
62
+ # @raise [ ArgumentError ] If required options are missing or incorrectly
63
+ # formatted.
64
+ def initialize(options)
65
+ @options = set_default_options(options).freeze
66
+
67
+ @crypt_handle = Crypt::Handle.new(
68
+ @options[:kms_providers],
69
+ schema_map: @options[:schema_map]
70
+ )
71
+
72
+ @key_vault_client = @options[:key_vault_client]
73
+
74
+ # Set server selection timeout to 1 to prevent the client waiting for a
75
+ # long timeout before spawning mongocryptd
76
+ @mongocryptd_client = Client.new(
77
+ @options[:extra_options][:mongocryptd_uri],
78
+ monitoring_io: @options[:client].options[:monitoring_io],
79
+ server_selection_timeout: 1,
80
+ )
81
+
82
+ begin
83
+ @encryption_io = EncryptionIO.new(
84
+ client: @options[:client],
85
+ mongocryptd_client: @mongocryptd_client,
86
+ key_vault_namespace: @options[:key_vault_namespace],
87
+ key_vault_client: @key_vault_client,
88
+ mongocryptd_options: @options[:extra_options]
89
+ )
90
+ rescue
91
+ begin
92
+ @mongocryptd_client.close
93
+ rescue => e
94
+ log_warn("Eror closing mongocryptd client in auto encrypter's constructor: #{e.class}: #{e}")
95
+ # Drop this exception so that the original exception is raised
96
+ end
97
+ raise
98
+ end
99
+ end
100
+
101
+ # Whether this encrypter should perform encryption (returns false if
102
+ # the :bypass_auto_encryption option is set to true).
103
+ #
104
+ # @return [ Boolean ] Whether to perform encryption.
105
+ def encrypt?
106
+ !@options[:bypass_auto_encryption]
107
+ end
108
+
109
+ # Encrypt a database command.
110
+ #
111
+ # @param [ String ] database_name The name of the database on which the
112
+ # command is being run.
113
+ # @param [ Hash ] command The command to be encrypted.
114
+ #
115
+ # @return [ BSON::Document ] The encrypted command.
116
+ def encrypt(database_name, command)
117
+ AutoEncryptionContext.new(
118
+ @crypt_handle,
119
+ @encryption_io,
120
+ database_name,
121
+ command
122
+ ).run_state_machine
123
+ end
124
+
125
+ # Decrypt a database command.
126
+ #
127
+ # @param [ Hash ] command The command with encrypted fields.
128
+ #
129
+ # @return [ BSON::Document ] The decrypted command.
130
+ def decrypt(command)
131
+ AutoDecryptionContext.new(
132
+ @crypt_handle,
133
+ @encryption_io,
134
+ command
135
+ ).run_state_machine
136
+ end
137
+
138
+ # Close the resources created by the AutoEncrypter.
139
+ #
140
+ # @return [ true ] Always true.
141
+ def close
142
+ @mongocryptd_client.close if @mongocryptd_client
143
+
144
+ true
145
+ end
146
+
147
+ private
148
+
149
+ # Returns a new set of options with the following changes:
150
+ # - sets default values for all extra_options
151
+ # - adds --idleShtudownTimeoutSecs=60 to extra_options[:mongocryptd_spawn_args]
152
+ # if not already present
153
+ # - sets bypass_auto_encryption to false
154
+ # - sets default key vault client
155
+ def set_default_options(options)
156
+ opts = options.dup
157
+
158
+ extra_options = opts.delete(:extra_options) || Options::Redacted.new
159
+ extra_options = DEFAULT_EXTRA_OPTIONS.merge(extra_options)
160
+
161
+ has_timeout_string_arg = extra_options[:mongocryptd_spawn_args].any? do |elem|
162
+ elem.is_a?(String) && elem.match(/\A--idleShutdownTimeoutSecs=\d+\z/)
163
+ end
164
+
165
+ timeout_int_arg_idx = extra_options[:mongocryptd_spawn_args].index('--idleShutdownTimeoutSecs')
166
+ has_timeout_int_arg = timeout_int_arg_idx && extra_options[:mongocryptd_spawn_args][timeout_int_arg_idx + 1].is_a?(Integer)
167
+
168
+ unless has_timeout_string_arg || has_timeout_int_arg
169
+ extra_options[:mongocryptd_spawn_args] << '--idleShutdownTimeoutSecs=60'
170
+ end
171
+
172
+ opts[:bypass_auto_encryption] ||= false
173
+ opts[:key_vault_client] ||= opts[:client]
174
+
175
+ Options::Redacted.new(opts).merge(extra_options: extra_options)
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,44 @@
1
+ # Copyright (C) 2019 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ module Crypt
17
+
18
+ # A Context object initialized for auto encryption
19
+ #
20
+ # @api private
21
+ class AutoEncryptionContext < Context
22
+
23
+ # Create a new AutoEncryptionContext object
24
+ #
25
+ # @param [ Mongo::Crypt::Handle ] mongocrypt a Handle that
26
+ # wraps a mongocrypt_t object used to create a new mongocrypt_ctx_t
27
+ # @param [ ClientEncryption::IO ] io A instance of the IO class
28
+ # that implements driver I/O methods required to run the
29
+ # state machine
30
+ # @param [ String ] db_name The name of the database against which
31
+ # the command is being made
32
+ # @param [ Hash ] command The command to be encrypted
33
+ def initialize(mongocrypt, io, db_name, command)
34
+ super(mongocrypt, io)
35
+
36
+ @db_name = db_name
37
+ @command = command
38
+
39
+ # Initialize the ctx object for auto encryption
40
+ Binding.ctx_encrypt_init(self, @db_name, @command)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,155 @@
1
+ # Copyright (C) 2019 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'ffi'
16
+
17
+ module Mongo
18
+ module Crypt
19
+
20
+ # A wrapper around mongocrypt_binary_t, a non-owning buffer of
21
+ # uint-8 byte data. Each Binary instance keeps a copy of the data
22
+ # passed to it in order to keep that data alive.
23
+ #
24
+ # @api private
25
+ class Binary
26
+ # Create a new Binary object that wraps a byte string
27
+ #
28
+ # @param [ String ] data The data string wrapped by the
29
+ # byte buffer (optional)
30
+ # @param [ FFI::Pointer ] pointer A pointer to an existing
31
+ # mongocrypt_binary_t object
32
+ #
33
+ # @note When initializing a Binary object with a string or a pointer,
34
+ # it is recommended that you use #self.from_pointer or #self.from_data
35
+ # methods
36
+ def initialize(data: nil, pointer: nil)
37
+ if data
38
+ # Represent data string as array of uint-8 bytes
39
+ bytes = data.unpack('C*')
40
+
41
+ # FFI::MemoryPointer automatically frees memory when it goes out of scope
42
+ @data_p = FFI::MemoryPointer.new(bytes.length)
43
+ .write_array_of_uint8(bytes)
44
+
45
+ # FFI::AutoPointer uses a custom release strategy to automatically free
46
+ # the pointer once this object goes out of scope
47
+ @bin = FFI::AutoPointer.new(
48
+ Binding.mongocrypt_binary_new_from_data(@data_p, bytes.length),
49
+ Binding.method(:mongocrypt_binary_destroy)
50
+ )
51
+ elsif pointer
52
+ # If the Binary class is used this way, it means that the pointer
53
+ # for the underlying mongocrypt_binary_t object is allocated somewhere
54
+ # else. It is not the responsibility of this class to de-allocate data.
55
+ @bin = pointer
56
+ else
57
+ # FFI::AutoPointer uses a custom release strategy to automatically free
58
+ # the pointer once this object goes out of scope
59
+ @bin = FFI::AutoPointer.new(
60
+ Binding.mongocrypt_binary_new,
61
+ Binding.method(:mongocrypt_binary_destroy)
62
+ )
63
+ end
64
+ end
65
+
66
+ # Initialize a Binary object from an existing pointer to a mongocrypt_binary_t
67
+ # object.
68
+ #
69
+ # @param [ FFI::Pointer ] pointer A pointer to an existing
70
+ # mongocrypt_binary_t object
71
+ #
72
+ # @return [ Mongo::Crypt::Binary ] A new binary object
73
+ def self.from_pointer(pointer)
74
+ self.new(pointer: pointer)
75
+ end
76
+
77
+ # Initialize a Binary object with a string. The Binary object will store a
78
+ # copy of the specified string and destroy the allocated memory when
79
+ # it goes out of scope.
80
+ #
81
+ # @param [ String ] data A string to be wrapped by the Binary object
82
+ #
83
+ # @return [ Mongo::Crypt::Binary ] A new binary object
84
+ def self.from_data(data)
85
+ self.new(data: data)
86
+ end
87
+
88
+ # Overwrite the existing data wrapped by this Binary object
89
+ #
90
+ # @note The data passed in must not take up more memory than the
91
+ # original memory allocated to the underlying mongocrypt_binary_t
92
+ # object. Do NOT use this method unless required to do so by libmongocrypt.
93
+ #
94
+ # @param [ String ] data The new string data to be wrapped by this binary object
95
+ #
96
+ # @return [ true ] Always true
97
+ #
98
+ # @raise [ ArgumentError ] Raises when trying to write more data
99
+ # than was originally allocated or when writing to an object that
100
+ # already owns data.
101
+ def write(data)
102
+ if @data
103
+ raise ArgumentError, 'Cannot write to an owned Binary'
104
+ end
105
+
106
+ # Cannot write a string that's longer than the space currently allocated
107
+ # by the mongocrypt_binary_t object
108
+ str_p = Binding.mongocrypt_binary_data(ref)
109
+ len = Binding.mongocrypt_binary_len(ref)
110
+
111
+ if len < data.bytesize
112
+ raise ArgumentError.new(
113
+ "Cannot write #{data.bytesize} bytes of data to a Binary object " +
114
+ "that was initialized with #{Binding.mongocrypt_binary_len(@bin)} bytes."
115
+ )
116
+ end
117
+
118
+ str_p.put_bytes(0, data)
119
+
120
+ true
121
+ end
122
+
123
+ # Returns the data stored as a string
124
+ #
125
+ # @return [ String ] Data stored in the mongocrypt_binary_t as a string
126
+ def to_s
127
+ str_p = Binding.mongocrypt_binary_data(ref)
128
+ len = Binding.mongocrypt_binary_len(ref)
129
+ str_p.read_string(len)
130
+ end
131
+
132
+ # Returns the reference to the underlying mongocrypt_binary_t
133
+ # object
134
+ #
135
+ # @return [ FFI::Pointer ] The underlying mongocrypt_binary_t object
136
+ def ref
137
+ @bin
138
+ end
139
+
140
+ # Wraps a String with a mongocrypt_binary_t, yielding an FFI::Pointer
141
+ # to the wrapped struct.
142
+ def self.wrap_string(str)
143
+ binary_p = Binding.mongocrypt_binary_new_from_data(
144
+ FFI::MemoryPointer.from_string(str),
145
+ str.bytesize,
146
+ )
147
+ begin
148
+ yield binary_p
149
+ ensure
150
+ Binding.mongocrypt_binary_destroy(binary_p)
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end