diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e15c9b..f415552 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# 0.12.0 +* Upgrade libmongoc to 1.8.2 +* Update bson dependency to 0.11 +* Parse MongoDB server responses with lossy UTF-8 decoding to work + around https://jira.mongodb.org/browse/SERVER-24007 + +# 0.11.0 +* Update bson dependency to 0.10 +* Use installed libmongoc if it right version is present on the system (thanks to Matrix-Zhang) + # 0.10.0 * Initial upgrade to mongo c driver 1.8.0, no support for new features yet diff --git a/Cargo.toml b/Cargo.toml index 9616294..99fb54b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mongo_driver" -version = "0.10.0" +version = "0.12.0" authors = ["Thijs Cadier "] description = "Mongo Rust driver built on top of the Mongo C driver" readme = "README.md" @@ -21,11 +21,11 @@ name = "tests" [dependencies] libc = "^0.2" log = "^0.3" -bson = "^0.10" +bson = "^0.11" [dependencies.mongoc-sys] path = "mongoc-sys" -version = "1.8.0" +version = "1.8.2-0" [dev-dependencies] chrono = "^0.4" diff --git a/mongoc-sys/Cargo.toml b/mongoc-sys/Cargo.toml index c28f6fa..4a04fe4 100644 --- a/mongoc-sys/Cargo.toml +++ b/mongoc-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mongoc-sys" -version = "1.8.0" +version = "1.8.2-0" description = "Sys package with installer and bindings for mongoc" authors = ["Thijs Cadier "] build = "build.rs" diff --git a/mongoc-sys/build.rs b/mongoc-sys/build.rs index c11dfda..a57ccae 100644 --- a/mongoc-sys/build.rs +++ b/mongoc-sys/build.rs @@ -4,26 +4,30 @@ use std::env; use std::path::Path; use std::process::Command; -static VERSION: &'static str = "1.8.0"; // Should be the same major version as in the manifest fn main() { + let mongoc_version = env!("CARGO_PKG_VERSION") + .split('-') + .next() + .expect("Crate version is not valid"); + if pkg_config::Config::new() - .atleast_version(VERSION) + .atleast_version(mongoc_version) .statik(true) .probe("libmongoc-1.0") .is_err() { let out_dir_var = env::var("OUT_DIR").expect("No out dir"); - let out_dir = format!("{}/{}", out_dir_var, VERSION); - let driver_src_path = format!("mongo-c-driver-{}", VERSION); + let out_dir = format!("{}/{}", out_dir_var, mongoc_version); + let driver_src_path = format!("mongo-c-driver-{}", mongoc_version); let libmongoc_path = Path::new(&out_dir).join("lib/libmongoc-1.0.a"); if !libmongoc_path.exists() { // Download and extract driver archive let url = format!( "https://github.com/mongodb/mongo-c-driver/releases/download/{}/mongo-c-driver-{}.tar.gz", - VERSION, - VERSION + mongoc_version, + mongoc_version ); assert!( Command::new("curl").arg("-O") // Save to disk @@ -34,7 +38,7 @@ fn main() { .success() ); - let archive_name = format!("mongo-c-driver-{}.tar.gz", VERSION); + let archive_name = format!("mongo-c-driver-{}.tar.gz", mongoc_version); assert!( Command::new("tar") .arg("xzf") diff --git a/src/bsonc.rs b/src/bsonc.rs index c033141..45bf2d6 100644 --- a/src/bsonc.rs +++ b/src/bsonc.rs @@ -42,6 +42,7 @@ impl Bsonc { Ok(Bsonc{ inner: inner }) } + /// Decode a bson from the C side to a document pub fn as_document(&self) -> Result { assert!(!self.inner.is_null()); @@ -63,6 +64,28 @@ impl Bsonc { Ok(document) } + /// Decode a bson from the C side to a document with lossy UTF-8 decoding + pub fn as_document_utf8_lossy(&self) -> Result { + assert!(!self.inner.is_null()); + + // This pointer should not be modified or freed + // See: http://mongoc.org/libbson/current/bson_get_data.html + let data_ptr = unsafe { bindings::bson_get_data(self.inner) }; + assert!(!data_ptr.is_null()); + + let data_len = unsafe { + let bson = *self.inner; + bson.len + } as usize; + + let mut slice = unsafe { + slice::from_raw_parts(data_ptr, data_len) + }; + + let document = try!(bson::decode_document_utf8_lossy(&mut slice)); + Ok(document) + } + pub fn as_json(&self) -> String { assert!(!self.inner.is_null()); let json_ptr = unsafe { bindings::bson_as_json(self.inner, ptr::null_mut()) }; @@ -106,7 +129,18 @@ mod tests { let bsonc = super::Bsonc::from_document(&document).unwrap(); let decoded = bsonc.as_document().unwrap(); - assert!(decoded.contains_key("key")); + assert_eq!(decoded.get_str("key").unwrap(), "value"); + } + + #[test] + fn test_bsonc_from_and_as_document_invalid_utf8() { + let bytes = b"\x80\xae".to_vec(); + let value = unsafe { String::from_utf8_unchecked(bytes) }; + let document = doc! { "key" => value }; + let bsonc = super::Bsonc::from_document(&document).unwrap(); + + let decoded = bsonc.as_document_utf8_lossy().unwrap(); + assert_eq!(decoded.get_str("key").unwrap(), "��"); } #[test] diff --git a/src/client.rs b/src/client.rs index 3d65629..2fe78aa 100644 --- a/src/client.rs +++ b/src/client.rs @@ -305,7 +305,7 @@ impl<'a> Client<'a> { }; if success == 1 { - match reply.as_document() { + match reply.as_document_utf8_lossy() { Ok(document) => return Ok(document), Err(error) => return Err(error.into()) } diff --git a/src/collection.rs b/src/collection.rs index 72a50df..729551f 100644 --- a/src/collection.rs +++ b/src/collection.rs @@ -342,7 +342,7 @@ impl<'a> Collection<'a> { }; if success == 1 { - match reply.as_document() { + match reply.as_document_utf8_lossy() { Ok(document) => return Ok(document), Err(error) => return Err(error.into()) } @@ -547,7 +547,7 @@ impl<'a> Collection<'a> { }; if success == 1 { - match reply.as_document() { + match reply.as_document_utf8_lossy() { Ok(document) => return Ok(document), Err(error) => return Err(error.into()) } @@ -884,7 +884,7 @@ impl<'a>BulkOperation<'a> { ) }; - let document = match reply.as_document() { + let document = match reply.as_document_utf8_lossy() { Ok(document) => document, Err(error) => return Err(BulkOperationError{error: error.into(), reply: doc!{}}) }; diff --git a/src/database.rs b/src/database.rs index bf97f31..6cb05af 100644 --- a/src/database.rs +++ b/src/database.rs @@ -116,7 +116,7 @@ impl<'a> Database<'a> { }; if success == 1 { - match reply.as_document() { + match reply.as_document_utf8_lossy() { Ok(document) => return Ok(document), Err(error) => return Err(error.into()) } diff --git a/tests/bulk_operation.rs b/tests/bulk_operation.rs index d6acabe..7a8c115 100644 --- a/tests/bulk_operation.rs +++ b/tests/bulk_operation.rs @@ -9,7 +9,9 @@ fn test_execute_error() { let uri = Uri::new("mongodb://localhost:27017/").unwrap(); let pool = ClientPool::new(uri, None); let client = pool.pop(); - let collection = client.get_collection("rust_driver_test", "bulk_operation_error"); + let mut collection = client.get_collection("rust_driver_test", "bulk_operation_error"); + collection.drop().unwrap_or(()); + let bulk_operation = collection.create_bulk_operation(None); let result = bulk_operation.execute(); @@ -24,11 +26,13 @@ fn test_basics() { let uri = Uri::new("mongodb://localhost:27017/").unwrap(); let pool = ClientPool::new(uri, None); let client = pool.pop(); - let collection = client.get_collection("rust_driver_test", "bulk_operation_basics"); + let mut collection = client.get_collection("rust_driver_test", "bulk_operation_basics"); + collection.drop().unwrap_or(()); + let bulk_operation = collection.create_bulk_operation(None); let document = doc! {"key_1" => "Value 1"}; - bulk_operation.insert(&document).unwrap(); + bulk_operation.insert(&document).expect("Could not insert"); assert!(bulk_operation.execute().is_ok()); let first_document = collection.find(&doc!{}, None).unwrap().next().unwrap().unwrap(); @@ -43,11 +47,13 @@ fn test_utf8() { let uri = Uri::new("mongodb://localhost:27017/").unwrap(); let pool = ClientPool::new(uri, None); let client = pool.pop(); - let collection = client.get_collection("rust_driver_test", "bulk_operation_utf8"); + let mut collection = client.get_collection("rust_driver_test", "bulk_operation_utf8"); + collection.drop().unwrap_or(()); + let bulk_operation = collection.create_bulk_operation(None); let document = doc! {"key_1" => "kācaṃ śaknomyattum; nopahinasti mām."}; - bulk_operation.insert(&document).unwrap(); + bulk_operation.insert(&document).expect("Could not insert"); assert!(bulk_operation.execute().is_ok()); let first_document = collection.find(&doc!{}, None).unwrap().next().unwrap().unwrap();