Skip to content

RUST-870 Deserialize server response directly from raw BSON bytes #389

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1182,9 +1182,9 @@ axes:
- id: "extra-rust-versions"
values:
- id: "min"
display_name: "1.47 (minimum supported version)"
display_name: "1.48 (minimum supported version)"
variables:
RUST_VERSION: "1.47.0"
RUST_VERSION: "1.48.0"
- id: "nightly"
display_name: "nightly"
variables:
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ bson-uuid-0_8 = ["bson/uuid-0_8"]
async-trait = "0.1.42"
base64 = "0.13.0"
bitflags = "1.1.0"
bson = "2.0.0-beta.2"
bson = { git = "https://github.com/mongodb/bson-rust" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to be sure to point this back at a published release of bson before the final 2.0.0 release.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, filed RUST-901 to remind us to do that.

chrono = "0.4.7"
derivative = "2.1.1"
futures-core = "0.3.14"
Expand Down
6 changes: 1 addition & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,9 @@ This repository contains the officially supported MongoDB Rust driver, a client

## Installation
### Requirements
- Rust 1.47+
- Rust 1.48+
- MongoDB 3.6+

**Note**: A bug affecting Rust 1.46-1.47 may cause out-of-memory errors when compiling an application that uses the 1.1
version of the driver with a framework like actix-web. Upgrading Rust to 1.48+ or the driver to 1.2+ fixes this
issue. For more information, see https://github.com/rust-lang/rust/issues/75992.

### Importing
The driver is available on [crates.io](https://crates.io/crates/mongodb). To use the driver in your application, simply add it to your project's `Cargo.toml`.
```toml
Expand Down
38 changes: 0 additions & 38 deletions src/bson_util/async_encoding.rs

This file was deleted.

25 changes: 22 additions & 3 deletions src/bson_util/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
pub(crate) mod async_encoding;

use std::{convert::TryFrom, time::Duration};
use std::{convert::TryFrom, io::Read, time::Duration};

use serde::{de::Error, ser, Deserialize, Deserializer, Serialize, Serializer};

use crate::{
bson::{doc, Binary, Bson, Document, JavaScriptCodeWithScope, Regex},
error::{ErrorKind, Result},
runtime::{SyncLittleEndianRead, SyncLittleEndianWrite},
};

/// Coerce numeric types into an `i64` if it would be lossless to do so. If this Bson is not numeric
Expand Down Expand Up @@ -289,6 +288,26 @@ fn num_decimal_digits(n: usize) -> u64 {
digits
}

/// Read a document's raw BSON bytes from the provided reader.
pub(crate) fn read_document_bytes<R: Read>(mut reader: R) -> Result<Vec<u8>> {
let length = reader.read_i32()?;

let mut bytes = Vec::with_capacity(length as usize);
bytes.write_i32(length)?;

reader.take(length as u64 - 4).read_to_end(&mut bytes)?;

Ok(bytes)
}

/// Serialize the document to raw BSON and return a vec containing the bytes.
#[cfg(test)]
pub(crate) fn document_to_vec(doc: Document) -> Result<Vec<u8>> {
let mut v = Vec::new();
doc.to_writer(&mut v)?;
Ok(v)
}

#[cfg(test)]
mod test {
use crate::bson::{
Expand Down
12 changes: 7 additions & 5 deletions src/client/auth/aws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ pub(super) async fn authenticate_stream(

let server_first_response = conn.send_command(client_first, None).await?;

let server_first = ServerFirst::parse(server_first_response.raw_response)?;
let server_first =
ServerFirst::parse(server_first_response.auth_response_body("MONGODB-AWS")?)?;
server_first.validate(&nonce)?;

let aws_credential = AwsCredential::get(credential, http_client).await?;
Expand Down Expand Up @@ -96,7 +97,10 @@ pub(super) async fn authenticate_stream(
let client_second = sasl_continue.into_command();

let server_second_response = conn.send_command(client_second, None).await?;
let server_second = SaslResponse::parse("MONGODB-AWS", server_second_response.raw_response)?;
let server_second = SaslResponse::parse(
"MONGODB-AWS",
server_second_response.auth_response_body("MONGODB-AWS")?,
)?;

if server_second.conversation_id != server_first.conversation_id {
return Err(Error::invalid_authentication_response("MONGODB-AWS"));
Expand Down Expand Up @@ -373,12 +377,10 @@ impl ServerFirst {
done,
} = SaslResponse::parse("MONGODB-AWS", response)?;

let payload_document = Document::from_reader(&mut payload.as_slice())?;

let ServerFirstPayload {
server_nonce,
sts_host,
} = bson::from_bson(Bson::Document(payload_document))
} = bson::from_slice(payload.as_slice())
.map_err(|_| Error::invalid_authentication_response("MONGODB-AWS"))?;

Ok(Self {
Expand Down
2 changes: 1 addition & 1 deletion src/client/auth/plain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub(crate) async fn authenticate_stream(
.into_command();

let response = conn.send_command(sasl_start, None).await?;
let sasl_response = SaslResponse::parse("PLAIN", response.raw_response)?;
let sasl_response = SaslResponse::parse("PLAIN", response.auth_response_body("PLAIN")?)?;

if !sasl_response.done {
return Err(Error::invalid_authentication_response("PLAIN"));
Expand Down
12 changes: 6 additions & 6 deletions src/client/auth/scram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl ScramVersion {

Ok(FirstRound {
client_first,
server_first: server_first.raw_response,
server_first: server_first.auth_response_body("SCRAM")?,
})
}

Expand Down Expand Up @@ -215,7 +215,7 @@ impl ScramVersion {
let command = client_final.to_command();

let server_final_response = conn.send_command(command, None).await?;
let server_final = ServerFinal::parse(server_final_response.raw_response)?;
let server_final = ServerFinal::parse(server_final_response.auth_response_body("SCRAM")?)?;
server_final.validate(salted_password.as_slice(), &client_final, self)?;

if !server_final.done {
Expand All @@ -231,9 +231,10 @@ impl ScramVersion {
let command = noop.into_command();

let server_noop_response = conn.send_command(command, None).await?;
let server_noop_response_document: Document =
server_noop_response.auth_response_body("SCRAM")?;

if server_noop_response
.raw_response
if server_noop_response_document
.get("conversationId")
.map(|id| id == server_final.conversation_id())
!= Some(true)
Expand All @@ -244,8 +245,7 @@ impl ScramVersion {
));
};

if !server_noop_response
.raw_response
if !server_noop_response_document
.get_bool("done")
.unwrap_or(false)
{
Expand Down
12 changes: 5 additions & 7 deletions src/client/auth/x509.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
bson::{doc, Document},
client::options::ServerApi,
cmap::{Command, CommandResponse, Connection},
cmap::{Command, Connection, RawCommandResponse},
error::{Error, Result},
options::Credential,
};
Expand Down Expand Up @@ -38,7 +38,7 @@ pub(crate) async fn send_client_first(
conn: &mut Connection,
credential: &Credential,
server_api: Option<&ServerApi>,
) -> Result<CommandResponse> {
) -> Result<RawCommandResponse> {
let command = build_client_first(credential, server_api);

conn.send_command(command, None).await
Expand All @@ -53,11 +53,9 @@ pub(super) async fn authenticate_stream(
) -> Result<()> {
let server_response = match server_first.into() {
Some(server_first) => server_first,
None => {
send_client_first(conn, credential, server_api)
.await?
.raw_response
}
None => send_client_first(conn, credential, server_api)
.await?
.auth_response_body("MONGODB-X509")?,
};

if server_response.get_str("dbname") != Ok("$external") {
Expand Down
Loading