Skip to content

RUST-1208 Future-proof features #1062

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 5 commits into from
Apr 5, 2024
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
43 changes: 18 additions & 25 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,46 +27,37 @@ exclude = [
]

[features]
default = []
default = ["compat-3-0-0", "rustls-tls", "dns-resolver"]
compat-3-0-0 = []
sync = []
openssl-tls = ["openssl", "openssl-probe", "tokio-openssl"]

# Enable support for v0.4 of the chrono crate in the public API of the BSON library.
bson-chrono-0_4 = ["bson/chrono-0_4"]

# Enable support for the serde_with crate in the BSON library.
bson-serde_with = ["bson/serde_with"]

# Enable support for v0.8 of the uuid crate in the public API of the BSON library.
bson-uuid-0_8 = ["bson/uuid-0_8"]

# Enable support for v1.x of the uuid crate in the public API of the BSON library.
bson-uuid-1 = ["bson/uuid-1"]
rustls-tls = ["dep:rustls", "dep:rustls-pemfile", "dep:tokio-rustls"]
openssl-tls = ["dep:openssl", "dep:openssl-probe", "dep:tokio-openssl"]
dns-resolver = ["dep:trust-dns-resolver", "dep:trust-dns-proto"]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure whether giving this feature a generic name is the right way (treating the actual dependency as an internal detail) or if it should just explicitly be called "trust-dns-resolver" in case we want to add other resolver crates in the future.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, I think I'm in favor of keeping it generic. I was curious what the status of trust-dns-resolver was and it looks like they've actually "rebranded" to a different crate (see here) that we might want to switch over to at some point. Keeping the name neutral will make it easier for us to swap out the internal dep.

Worst case, if we did want to introduce more resolver crates we could treat this flag as our "default" choice and then allow users to opt into a different one if they want to.


# Enable support for MONGODB-AWS authentication.
# This can only be used with the tokio-runtime feature flag.
aws-auth = ["reqwest"]
aws-auth = ["dep:reqwest"]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Using the dep:foo format prevents the optional dependencies from automatically becoming their own feature flags.

Copy link
Contributor

Choose a reason for hiding this comment

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

nice, I think the need to do this will go away in the 2024 edition rust-lang/cargo#12826


# Enable support for on-demand Azure KMS credentials.
# This can only be used with the tokio-runtime feature flag.
azure-kms = ["reqwest"]
azure-kms = ["dep:reqwest"]

# Enable support for on-demand GCP KMS credentials.
# This can only be used with the tokio-runtime feature flag.
gcp-kms = ["reqwest"]
gcp-kms = ["dep:reqwest"]

zstd-compression = ["zstd"]
zlib-compression = ["flate2"]
snappy-compression = ["snap"]
zstd-compression = ["dep:zstd"]
zlib-compression = ["dep:flate2"]
snappy-compression = ["dep:snap"]

# Enables support for client-side field level encryption and queryable encryption.
# The In Use Encryption API is unstable and may have backwards-incompatible changes in minor version updates.
in-use-encryption-unstable = ["mongocrypt", "rayon", "num_cpus"]
in-use-encryption-unstable = ["dep:mongocrypt", "dep:rayon", "dep:num_cpus"]

# Enables support for emitting tracing events.
# The tracing API is unstable and may have backwards-incompatible changes in minor version updates.
# TODO: pending https://github.com/tokio-rs/tracing/issues/2036 stop depending directly on log.
tracing-unstable = ["tracing", "log"]
tracing-unstable = ["dep:tracing", "dep:log"]

[dependencies]
action_macro = { path = "action_macro" }
Expand Down Expand Up @@ -95,7 +86,7 @@ percent-encoding = "2.0.0"
rand = { version = "0.8.3", features = ["small_rng"] }
rayon = { version = "1.5.3", optional = true }
rustc_version_runtime = "0.2.1"
rustls-pemfile = "1.0.1"
rustls-pemfile = { version = "1.0.1", optional = true }
serde_with = "1.3.1"
sha-1 = "0.10.0"
sha2 = "0.10.2"
Expand All @@ -107,8 +98,8 @@ take_mut = "0.2.2"
thiserror = "1.0.24"
tokio-openssl = { version = "0.6.3", optional = true }
tracing = { version = "0.1.36", optional = true }
trust-dns-proto = "0.21.2"
trust-dns-resolver = "0.21.2"
trust-dns-proto = { version = "0.21.2", optional = true }
trust-dns-resolver = { version = "0.21.2", optional = true }
typed-builder = "0.10.0"
webpki-roots = "0.25.2"
zstd = { version = "0.11.2", optional = true }
Expand All @@ -125,6 +116,7 @@ features = ["json", "rustls-tls"]

[dependencies.rustls]
version = "0.21.6"
optional = true
features = ["dangerous_configuration"]

[dependencies.serde]
Expand All @@ -140,6 +132,7 @@ features = ["io-util", "sync", "macros", "net", "process", "rt", "time"]

[dependencies.tokio-rustls]
version = "0.24.1"
optional = true
features = ["dangerous_configuration"]

[dependencies.tokio-util]
Expand Down
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,6 @@ features = ["sync"]
|:---------------------|:--------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------|:--------|
| `sync` | Expose the synchronous API (`mongodb::sync`). | n/a | no |
| `aws-auth` | Enable support for the MONGODB-AWS authentication mechanism. | `reqwest` | no |
| `bson-uuid-0_8` | Enable support for v0.8 of the [`uuid`](docs.rs/uuid/0.8) crate in the public API of the re-exported `bson` crate. | n/a | no |
| `bson-uuid-1` | Enable support for v1.x of the [`uuid`](docs.rs/uuid/1.0) crate in the public API of the re-exported `bson` crate. | n/a | no |
| `bson-chrono-0_4` | Enable support for v0.4 of the [`chrono`](docs.rs/chrono/0.4) crate in the public API of the re-exported `bson` crate. | n/a | no |
| `bson-serde_with` | Enable support for the [`serde_with`](docs.rs/serde_with/latest) crate in the public API of the re-exported `bson` crate. | `serde_with` | no |
| `zlib-compression` | Enable support for compressing messages with [`zlib`](https://zlib.net/) | `flate2` | no |
| `zstd-compression` | Enable support for compressing messages with [`zstd`](http://facebook.github.io/zstd/). | `zstd` | no |
| `snappy-compression` | Enable support for compressing messages with [`snappy`](http://google.github.io/snappy/) | `snap` | no |
Expand Down
4 changes: 0 additions & 4 deletions manual/src/installation_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ features = ["sync"]
|:---------------------|:--------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------|:--------|
| `sync` | Expose the synchronous API (`mongodb::sync`). | n/a | no |
| `aws-auth` | Enable support for the MONGODB-AWS authentication mechanism. | `reqwest` 0.11 | no |
| `bson-uuid-0_8` | Enable support for v0.8 of the [`uuid`](docs.rs/uuid/0.8) crate in the public API of the re-exported `bson` crate. | n/a | no |
| `bson-uuid-1` | Enable support for v1.x of the [`uuid`](docs.rs/uuid/1.0) crate in the public API of the re-exported `bson` crate. | n/a | no |
| `bson-chrono-0_4` | Enable support for v0.4 of the [`chrono`](docs.rs/chrono/0.4) crate in the public API of the re-exported `bson` crate. | n/a | no |
| `bson-serde_with` | Enable support for the [`serde_with`](docs.rs/serde_with/latest) crate in the public API of the re-exported `bson` crate. | `serde_with` 1.0 | no |
| `zlib-compression` | Enable support for compressing messages with [`zlib`](https://zlib.net/) | `flate2` 1.0 | no |
| `zstd-compression` | Enable support for compressing messages with [`zstd`](http://facebook.github.io/zstd/). This flag requires Rust version 1.54. | `zstd` 0.9.0 | no |
| `snappy-compression` | Enable support for compressing messages with [`snappy`](http://google.github.io/snappy/) | `snap` 1.0.5 | no |
Expand Down
1 change: 1 addition & 0 deletions src/action/client_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ pub struct ParseConnectionString {
impl ParseConnectionString {
/// In the case that "mongodb+srv" is used, SRV and TXT record lookups will be done using the
/// provided `ResolverConfig` as part of this method.
#[cfg(feature = "dns-resolver")]
pub fn resolver_config(mut self, value: ResolverConfig) -> Self {
self.resolver_config = Some(value);
self
Expand Down
2 changes: 1 addition & 1 deletion src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ impl Client {
}
}

#[cfg(test)]
#[cfg(all(test, feature = "dns-resolver"))]
pub(crate) fn get_hosts(&self) -> Vec<String> {
let watcher = self.inner.topology.watch();
let state = watcher.peek_latest();
Expand Down
32 changes: 27 additions & 5 deletions src/client/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ mod parse;
mod resolver_config;

use std::{
borrow::Cow,
cmp::Ordering,
collections::HashSet,
convert::TryFrom,
Expand Down Expand Up @@ -45,7 +44,10 @@ use crate::{
srv::{OriginalSrvInfo, SrvResolver},
};

#[cfg(feature = "dns-resolver")]
pub use resolver_config::ResolverConfig;
#[cfg(not(feature = "dns-resolver"))]
pub(crate) use resolver_config::ResolverConfig;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Use of DNS resolution is ... not neatly encapsulated in the codebase, so to keep this from being a giant refactor PR I made the various machinery crate-internal when the feature is disabled rather than being feature-gated entirely.


pub(crate) const DEFAULT_PORT: u16 = 27017;

Expand Down Expand Up @@ -253,14 +255,16 @@ impl ServerAddress {
})
}

pub(crate) fn host(&self) -> Cow<'_, str> {
#[cfg(feature = "dns-resolver")]
pub(crate) fn host(&self) -> std::borrow::Cow<'_, str> {
match self {
Self::Tcp { host, .. } => Cow::Borrowed(host.as_str()),
Self::Tcp { host, .. } => std::borrow::Cow::Borrowed(host.as_str()),
#[cfg(unix)]
Self::Unix { path } => path.to_string_lossy(),
}
}

#[cfg(feature = "dns-resolver")]
pub(crate) fn port(&self) -> Option<u16> {
match self {
Self::Tcp { port, .. } => *port,
Expand Down Expand Up @@ -597,6 +601,7 @@ pub struct ClientOptions {
#[builder(default, setter(skip))]
#[serde(skip)]
#[derivative(Debug = "ignore")]
#[cfg(feature = "dns-resolver")]
pub(crate) resolver_config: Option<ResolverConfig>,

/// Control test behavior of the client.
Expand Down Expand Up @@ -932,8 +937,7 @@ impl HostInfo {
Ok(match self {
Self::HostIdentifiers(hosts) => ResolvedHostInfo::HostIdentifiers(hosts),
Self::DnsRecord(hostname) => {
let mut resolver =
SrvResolver::new(resolver_config.clone().map(|config| config.inner)).await?;
let mut resolver = SrvResolver::new(resolver_config.clone()).await?;
let config = resolver.resolve_client_options(&hostname).await?;
ResolvedHostInfo::DnsRecord { hostname, config }
}
Expand Down Expand Up @@ -1264,6 +1268,17 @@ impl ClientOptions {
MIN_HEARTBEAT_FREQUENCY
}
}

pub(crate) fn resolver_config(&self) -> Option<&ResolverConfig> {
#[cfg(feature = "dns-resolver")]
{
self.resolver_config.as_ref()
}
#[cfg(not(feature = "dns-resolver"))]
{
None
}
}
}

/// Splits a string into a section before a given index and a section exclusively after the index.
Expand Down Expand Up @@ -1359,6 +1374,13 @@ impl ConnectionString {
.into())
}
};
#[cfg(not(feature = "dns-resolver"))]
if srv {
return Err(Error::invalid_argument(
"mongodb+srv connection strings cannot be used when the 'dns-resolver' feature is \
disabled",
));
}

let after_scheme = &s[end_of_scheme + 3..];

Expand Down
6 changes: 5 additions & 1 deletion src/client/options/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ impl Action for ParseConnectionString {
.is_some();
let host_info = std::mem::take(&mut conn_str.host_info);
let mut options = ClientOptions::from_connection_string(conn_str);
options.resolver_config = self.resolver_config.clone();
#[cfg(feature = "dns-resolver")]
{
options.resolver_config = self.resolver_config.clone();
}

let resolved = host_info.resolve(self.resolver_config).await?;
options.hosts = match resolved {
Expand Down Expand Up @@ -146,6 +149,7 @@ impl ClientOptions {
original_srv_info: None,
#[cfg(test)]
original_uri: Some(conn_str.original_uri),
#[cfg(feature = "dns-resolver")]
resolver_config: None,
server_api: None,
load_balanced: conn_str.load_balanced,
Expand Down
3 changes: 3 additions & 0 deletions src/client/options/resolver_config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[cfg(feature = "dns-resolver")]
use trust_dns_resolver::config::ResolverConfig as TrustDnsResolverConfig;

/// Configuration for the upstream nameservers to use for resolution.
Expand All @@ -6,9 +7,11 @@ use trust_dns_resolver::config::ResolverConfig as TrustDnsResolverConfig;
/// API stability.
#[derive(Clone, Debug, PartialEq)]
pub struct ResolverConfig {
#[cfg(feature = "dns-resolver")]
pub(crate) inner: TrustDnsResolverConfig,
}

#[cfg(feature = "dns-resolver")]
impl ResolverConfig {
/// Creates a default configuration, using 1.1.1.1, 1.0.0.1 and 2606:4700:4700::1111,
/// 2606:4700:4700::1001 (thank you, Cloudflare).
Expand Down
1 change: 1 addition & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ impl Error {
self.labels.insert(label);
}

#[cfg(feature = "dns-resolver")]
pub(crate) fn from_resolve_error(error: trust_dns_resolver::error::ResolveError) -> Self {
ErrorKind::DnsResolve {
message: error.to_string(),
Expand Down
45 changes: 25 additions & 20 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@
//! |:-----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|
//! | `sync` | Expose the synchronous API (`mongodb::sync`). | no |
//! | `aws-auth` | Enable support for the MONGODB-AWS authentication mechanism. | no |
//! | `bson-uuid-0_8` | Enable support for v0.8 of the [`uuid`](docs.rs/uuid/0.8) crate in the public API of the re-exported `bson` crate. | no |
//! | `bson-uuid-1` | Enable support for v1.x of the [`uuid`](docs.rs/uuid/1.0) crate in the public API of the re-exported `bson` crate. | no |
//! | `bson-chrono-0_4` | Enable support for v0.4 of the [`chrono`](docs.rs/chrono/0.4) crate in the public API of the re-exported `bson` crate. | no |
//! | `bson-serde_with` | Enable support for the [`serde_with`](docs.rs/serde_with/latest) crate in the public API of the re-exported `bson` crate. | no |
//! | `zlib-compression` | Enable support for compressing messages with [`zlib`](https://zlib.net/). | no |
//! | `zstd-compression` | Enable support for compressing messages with [`zstd`](http://facebook.github.io/zstd/). | no |
//! | `snappy-compression` | Enable support for compressing messages with [`snappy`](http://google.github.io/snappy/). | no |
Expand Down Expand Up @@ -142,9 +138,9 @@
//! ```
//!
//! ### Finding documents in a collection
//! Results from queries are generally returned via [`Cursor`](struct.Cursor.html), a struct which streams
//! the results back from the server as requested. The [`Cursor`](struct.Cursor.html) type implements the
//! [`Stream`](https://docs.rs/futures/latest/futures/stream/trait.Stream.html) trait from
//! Results from queries are generally returned via [`Cursor`](struct.Cursor.html), a struct which
//! streams the results back from the server as requested. The [`Cursor`](struct.Cursor.html) type
//! implements the [`Stream`](https://docs.rs/futures/latest/futures/stream/trait.Stream.html) trait from
//! the [`futures`](https://crates.io/crates/futures) crate, and in order to access its streaming
//! functionality you need to import at least one of the
//! [`StreamExt`](https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html) or
Expand Down Expand Up @@ -236,14 +232,14 @@
//! In async Rust, it is common to implement cancellation and timeouts by dropping a future after a
//! certain period of time instead of polling it to completion. This is how
//! [`tokio::time::timeout`](https://docs.rs/tokio/1.10.1/tokio/time/fn.timeout.html) works, for
//! example. However, doing this with futures returned by the driver can leave the driver's internals in
//! an inconsistent state, which may lead to unpredictable or incorrect behavior (see RUST-937 for more
//! details). As such, it is **_highly_** recommended to poll all futures returned from the driver to
//! completion. In order to still use timeout mechanisms like `tokio::time::timeout` with the driver,
//! one option is to spawn tasks and time out on their
//! example. However, doing this with futures returned by the driver can leave the driver's
//! internals in an inconsistent state, which may lead to unpredictable or incorrect behavior (see
//! RUST-937 for more details). As such, it is **_highly_** recommended to poll all futures returned
//! from the driver to completion. In order to still use timeout mechanisms like
//! `tokio::time::timeout` with the driver, one option is to spawn tasks and time out on their
//! [`JoinHandle`](https://docs.rs/tokio/1.10.1/tokio/task/struct.JoinHandle.html) futures instead of on
//! the driver's futures directly. This will ensure the driver's futures will always be completely polled
//! while also allowing the application to continue in the event of a timeout.
//! the driver's futures directly. This will ensure the driver's futures will always be completely
//! polled while also allowing the application to continue in the event of a timeout.
//!
//! e.g.
//! ``` rust
Expand All @@ -268,8 +264,8 @@
//!
//! ## Minimum supported Rust version (MSRV)
//!
//! The MSRV for this crate is currently 1.64.0. This will be rarely be increased, and if it ever is,
//! it will only happen in a minor or major version release.
//! The MSRV for this crate is currently 1.64.0. This will be rarely be increased, and if it ever
//! is, it will only happen in a minor or major version release.

#![warn(missing_docs)]
#![warn(rustdoc::missing_crate_level_docs)]
Expand All @@ -289,7 +285,6 @@
#![cfg_attr(test, type_length_limit = "80000000")]
#![doc(html_root_url = "https://docs.rs/mongodb/2.8.0")]


#[macro_use]
pub mod options;

Expand Down Expand Up @@ -318,8 +313,8 @@ mod index;
mod operation;
pub mod results;
pub(crate) mod runtime;
mod search_index;
mod sdam;
mod search_index;
mod selection_criteria;
mod serde_util;
mod srv;
Expand All @@ -344,7 +339,17 @@ pub use crate::{
gridfs::{GridFsBucket, GridFsDownloadStream, GridFsUploadStream},
};

pub use {client::session::ClusterTime, coll::Namespace, index::IndexModel, sdam::public::*, search_index::SearchIndexModel};
pub use client::session::ClusterTime;
pub use coll::Namespace;
pub use index::IndexModel;
pub use sdam::public::*;
pub use search_index::SearchIndexModel;

/// A boxed future.
pub type BoxFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + Send + 'a>>;
pub type BoxFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + Send + 'a>>;

#[cfg(not(feature = "compat-3-0-0"))]
compile_error!(
"The feature 'compat-3-0-0' must be enabled to ensure forward compatibility with future \
versions of this crate."
);
Loading