diff --git a/contrib/lib/Cargo.toml b/contrib/lib/Cargo.toml index f9b2618e90..2cea1959eb 100644 --- a/contrib/lib/Cargo.toml +++ b/contrib/lib/Cargo.toml @@ -35,9 +35,7 @@ diesel_mysql_pool = ["databases", "diesel/mysql", "diesel/r2d2"] postgres_pool = ["databases", "postgres", "r2d2_postgres"] mysql_pool = ["databases", "mysql", "r2d2_mysql"] sqlite_pool = ["databases", "rusqlite", "r2d2_sqlite"] -cypher_pool = ["databases", "rusted_cypher", "r2d2_cypher"] redis_pool = ["databases", "redis", "r2d2_redis"] -mongodb_pool = ["databases", "mongodb", "r2d2-mongodb"] memcache_pool = ["databases", "memcache", "r2d2-memcache"] [dependencies] @@ -66,16 +64,12 @@ diesel = { version = "1.0", default-features = false, optional = true } postgres = { version = "0.17", optional = true } r2d2 = { version = "0.8", optional = true } r2d2_postgres = { version = "0.16", optional = true } -mysql = { version = "17.0", optional = true } -r2d2_mysql = { version = "17.0", optional = true } -rusqlite = { version = "0.16.0", optional = true } -r2d2_sqlite = { version = "0.8", optional = true } -rusted_cypher = { version = "1", optional = true } -r2d2_cypher = { version = "0.4", optional = true } -redis = { version = "0.13", optional = true } -r2d2_redis = { version = "0.12", optional = true } -mongodb = { version = "0.3.12", optional = true } -r2d2-mongodb = { version = "0.2.0", optional = true } +mysql = { version = "18.0", optional = true } +r2d2_mysql = { version = "18.0", optional = true } +rusqlite = { version = "0.23", optional = true } +r2d2_sqlite = { version = "0.16", optional = true } +redis = { version = "0.15", optional = true } +r2d2_redis = { version = "0.13", optional = true } memcache = { version = "0.14", optional = true } r2d2-memcache = { version = "0.5", optional = true } diff --git a/contrib/lib/src/databases.rs b/contrib/lib/src/databases.rs index 9ad58c52b7..86f14035bb 100644 --- a/contrib/lib/src/databases.rs +++ b/contrib/lib/src/databases.rs @@ -340,33 +340,27 @@ //! | Kind | Driver | Version | `Poolable` Type | Feature | //! |----------|-----------------------|-----------|--------------------------------|------------------------| //! | MySQL | [Diesel] | `1` | [`diesel::MysqlConnection`] | `diesel_mysql_pool` | -//! | MySQL | [`rust-mysql-simple`] | `17` | [`mysql::Conn`] | `mysql_pool` | +//! | MySQL | [`rust-mysql-simple`] | `18` | [`mysql::Conn`] | `mysql_pool` | //! | Postgres | [Diesel] | `1` | [`diesel::PgConnection`] | `diesel_postgres_pool` | //! | Postgres | [Rust-Postgres] | `0.17` | [`postgres::Client`] | `postgres_pool` | //! | Sqlite | [Diesel] | `1` | [`diesel::SqliteConnection`] | `diesel_sqlite_pool` | -//! | Sqlite | [`Rusqlite`] | `0.16` | [`rusqlite::Connection`] | `sqlite_pool` | -//! | Neo4j | [`rusted_cypher`] | `1` | [`rusted_cypher::GraphClient`] | `cypher_pool` | -//! | Redis | [`redis-rs`] | `0.13` | [`redis::Connection`] | `redis_pool` | -//! | MongoDB | [`mongodb`] | `0.3.12` | [`mongodb::db::Database`] | `mongodb_pool` | +//! | Sqlite | [`Rusqlite`] | `0.23` | [`rusqlite::Connection`] | `sqlite_pool` | +//! | Redis | [`redis-rs`] | `0.15` | [`redis::Connection`] | `redis_pool` | //! | Memcache | [`memcache`] | `0.14` | [`memcache::Client`] | `memcache_pool` | //! //! [Diesel]: https://diesel.rs -//! [`redis::Connection`]: https://docs.rs/redis/0.13.0/redis/struct.Connection.html -//! [`rusted_cypher::GraphClient`]: https://docs.rs/rusted_cypher/1.1.0/rusted_cypher/graph/struct.GraphClient.html -//! [`rusqlite::Connection`]: https://docs.rs/rusqlite/0.16.0/rusqlite/struct.Connection.html +//! [`redis::Connection`]: https://docs.rs/redis/0.15.0/redis/struct.Connection.html +//! [`rusqlite::Connection`]: https://docs.rs/rusqlite/0.23.0/rusqlite/struct.Connection.html //! [`diesel::SqliteConnection`]: http://docs.diesel.rs/diesel/prelude/struct.SqliteConnection.html //! [`postgres::Client`]: https://docs.rs/postgres/0.17/postgres/struct.Client.html //! [`diesel::PgConnection`]: http://docs.diesel.rs/diesel/pg/struct.PgConnection.html -//! [`mysql::Conn`]: https://docs.rs/mysql/17/mysql/struct.Conn.html +//! [`mysql::Conn`]: https://docs.rs/mysql/18/mysql/struct.Conn.html //! [`diesel::MysqlConnection`]: http://docs.diesel.rs/diesel/mysql/struct.MysqlConnection.html //! [`redis-rs`]: https://github.com/mitsuhiko/redis-rs -//! [`rusted_cypher`]: https://github.com/livioribeiro/rusted-cypher //! [`Rusqlite`]: https://github.com/jgallagher/rusqlite //! [Rust-Postgres]: https://github.com/sfackler/rust-postgres //! [`rust-mysql-simple`]: https://github.com/blackbeam/rust-mysql-simple //! [`diesel::PgConnection`]: http://docs.diesel.rs/diesel/pg/struct.PgConnection.html -//! [`mongodb`]: https://github.com/mongodb-labs/mongo-rust-driver-prototype -//! [`mongodb::db::Database`]: https://docs.rs/mongodb/0.3.12/mongodb/db/type.Database.html //! [`memcache`]: https://github.com/aisk/rust-memcache //! [`memcache::Client`]: https://docs.rs/memcache/0.14/memcache/struct.Client.html //! @@ -416,15 +410,9 @@ use self::r2d2::ManageConnection; #[cfg(feature = "sqlite_pool")] pub extern crate rusqlite; #[cfg(feature = "sqlite_pool")] pub extern crate r2d2_sqlite; -#[cfg(feature = "cypher_pool")] pub extern crate rusted_cypher; -#[cfg(feature = "cypher_pool")] pub extern crate r2d2_cypher; - #[cfg(feature = "redis_pool")] pub extern crate redis; #[cfg(feature = "redis_pool")] pub extern crate r2d2_redis; -#[cfg(feature = "mongodb_pool")] pub extern crate mongodb; -#[cfg(feature = "mongodb_pool")] pub extern crate r2d2_mongodb; - #[cfg(feature = "memcache_pool")] pub extern crate memcache; #[cfg(feature = "memcache_pool")] pub extern crate r2d2_memcache; @@ -626,7 +614,6 @@ impl<'a> Display for ConfigError { /// * `postgres::Connection` /// * `mysql::Conn` /// * `rusqlite::Connection` -/// * `rusted_cypher::GraphClient` /// * `redis::Connection` /// /// # Implementation Guide @@ -790,17 +777,6 @@ impl Poolable for rusqlite::Connection { } } -#[cfg(feature = "cypher_pool")] -impl Poolable for rusted_cypher::GraphClient { - type Manager = r2d2_cypher::CypherConnectionManager; - type Error = r2d2::Error; - - fn pool(config: DatabaseConfig<'_>) -> Result, Self::Error> { - let manager = r2d2_cypher::CypherConnectionManager { url: config.url.to_string() }; - r2d2::Pool::builder().max_size(config.pool_size).build(manager) - } -} - #[cfg(feature = "redis_pool")] impl Poolable for redis::Connection { type Manager = r2d2_redis::RedisConnectionManager; @@ -813,17 +789,6 @@ impl Poolable for redis::Connection { } } -#[cfg(feature = "mongodb_pool")] -impl Poolable for mongodb::db::Database { - type Manager = r2d2_mongodb::MongodbConnectionManager; - type Error = DbError; - - fn pool(config: DatabaseConfig<'_>) -> Result, Self::Error> { - let manager = r2d2_mongodb::MongodbConnectionManager::new_with_uri(config.url).map_err(DbError::Custom)?; - r2d2::Pool::builder().max_size(config.pool_size).build(manager).map_err(DbError::PoolError) - } -} - #[cfg(feature = "memcache_pool")] impl Poolable for memcache::Client { type Manager = r2d2_memcache::MemcacheConnectionManager; diff --git a/core/http/Cargo.toml b/core/http/Cargo.toml index 661dce91aa..43525ffc1c 100644 --- a/core/http/Cargo.toml +++ b/core/http/Cargo.toml @@ -21,14 +21,14 @@ private-cookies = ["cookie/private", "cookie/key-expansion"] [dependencies] smallvec = "1.0" -percent-encoding = "1" +percent-encoding = "2" hyper = { version = "0.13.0", default-features = false } http = "0.2" mime = "0.3.13" time = "0.2.11" indexmap = "1.0" state = "0.4" -tokio-rustls = { version = "0.12.0", optional = true } +tokio-rustls = { version = "0.14.0", optional = true } tokio = { version = "0.2.9", features = ["sync", "tcp", "time"] } cookie = { version = "0.14.0", features = ["percent-encode"] } pear = "0.1" diff --git a/core/http/src/parse/uri/mod.rs b/core/http/src/parse/uri/mod.rs index 19b330f9e0..735a687001 100644 --- a/core/http/src/parse/uri/mod.rs +++ b/core/http/src/parse/uri/mod.rs @@ -8,7 +8,7 @@ use crate::uri::{Uri, Origin, Absolute, Authority}; use crate::parse::indexed::IndexedInput; use self::parser::{uri, origin, authority_only, absolute_only, rocket_route_origin}; -pub use self::tables::is_pchar; +pub use self::tables::{is_pchar, PATH_SET}; pub use self::error::Error; type RawInput<'a> = IndexedInput<'a, [u8]>; diff --git a/core/http/src/parse/uri/tables.rs b/core/http/src/parse/uri/tables.rs index 7258e9e4a7..f6330d0352 100644 --- a/core/http/src/parse/uri/tables.rs +++ b/core/http/src/parse/uri/tables.rs @@ -1,3 +1,39 @@ +use percent_encoding::AsciiSet; + +// Generates an AsciiSet from a full character table: +// +// table_to_ascci_set!( ExistingAsciiSet, 0, [ 0, 1, b'x', ... ] ); +// +// A 0 or 1 token in the ith position indicates that the ASCII character i +// should be included in the set. Any other literal in the ith position +// indicates that the ASCII character with value i should not be included in the +// set. +// +// The table's last index must be 127 or earlier. All values in the original +// set, up to the end of the passed-in table, are overwritten. +macro_rules! table_to_ascii_set { + ($base:expr, $i:expr, [ 0, $($rest:tt,)* ]) => { table_to_ascii_set!($base.add($i), $i+1, [ $($rest,)* ]); }; + ($base:expr, $i:expr, [ 1, $($rest:tt,)* ]) => { table_to_ascii_set!($base.add($i), $i+1, [ $($rest,)* ]); }; + ($base:expr, $i:expr, [ $ch:literal, $($rest:tt,)* ]) => { table_to_ascii_set!($base.remove($i), $i+1, [ $($rest,)* ]); }; + ($base:expr, $i:expr, [ ]) => { $base }; +} + +// Generates an AsciiSet accompanying a character table. This is +// used to keep `PATH_CHARS` in sync with `PATH_SET`. +// +// The first block is limited to 128 entries, since it is passed +// to table_to_ascii_set! +macro_rules! table_and_asciiset { + ( + const $name:ident: [u8; $size:expr] = [ $($block1:tt)* ] [ $($block2:tt)* ]; + pub const $setname:ident: AsciiSet; + ) => { + const $name: [u8; $size] = [ $($block1)* $($block2)* ] ; + pub const $setname: AsciiSet = table_to_ascii_set!(percent_encoding::CONTROLS, 0, [ $($block1)* ]); + }; +} + +table_and_asciiset! { const PATH_CHARS: [u8; 256] = [ // 0 1 2 3 4 5 6 7 8 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // x @@ -13,7 +49,7 @@ const PATH_CHARS: [u8; 256] = [ b'Z', 0, 0, 0, 0, b'_', 0, b'a', b'b', b'c', // 9x b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', // 10x b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', // 11x - b'x', b'y', b'z', 0, 0, 0, b'~', 0, 0, 0, // 12x + b'x', b'y', b'z', 0, 0, 0, b'~', 0, ] [ 0, 0, // 12x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 13x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 14x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 15x @@ -26,8 +62,10 @@ const PATH_CHARS: [u8; 256] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 22x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 23x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 24x - 0, 0, 0, 0, 0, 0 // 25x + 0, 0, 0, 0, 0, 0, // 25x ]; +pub const PATH_SET: AsciiSet; +} #[inline(always)] pub fn is_pchar(c: u8) -> bool { diff --git a/core/http/src/uri/encoding.rs b/core/http/src/uri/encoding.rs index 3b989eb6c7..268fbfcdf3 100644 --- a/core/http/src/uri/encoding.rs +++ b/core/http/src/uri/encoding.rs @@ -1,14 +1,17 @@ use std::marker::PhantomData; use std::borrow::Cow; -use percent_encoding::{EncodeSet, utf8_percent_encode}; +use percent_encoding::{AsciiSet, utf8_percent_encode}; use crate::uri::{UriPart, Path, Query}; -use crate::parse::uri::is_pchar; +use crate::parse::uri::PATH_SET; #[derive(Clone, Copy)] #[allow(non_camel_case_types)] pub struct UNSAFE_ENCODE_SET(PhantomData

); +pub trait EncodeSet { + const SET: AsciiSet; +} impl Default for UNSAFE_ENCODE_SET

{ #[inline(always)] @@ -16,17 +19,15 @@ impl Default for UNSAFE_ENCODE_SET

{ } impl EncodeSet for UNSAFE_ENCODE_SET { - #[inline(always)] - fn contains(&self, byte: u8) -> bool { - !is_pchar(byte) || byte == b'%' - } + const SET: AsciiSet = PATH_SET + .add(b'%'); } impl EncodeSet for UNSAFE_ENCODE_SET { - #[inline(always)] - fn contains(&self, byte: u8) -> bool { - (!is_pchar(byte) && (byte != b'?')) || byte == b'%' || byte == b'+' - } + const SET: AsciiSet = PATH_SET + .remove(b'?') + .add(b'%') + .add(b'+'); } #[derive(Clone, Copy)] @@ -34,20 +35,14 @@ impl EncodeSet for UNSAFE_ENCODE_SET { pub struct ENCODE_SET(PhantomData

); impl EncodeSet for ENCODE_SET { - #[inline(always)] - fn contains(&self, byte: u8) -> bool { - >::default().contains(byte) || byte == b'/' - } + const SET: AsciiSet = >::SET + .add(b'/'); } impl EncodeSet for ENCODE_SET { - #[inline(always)] - fn contains(&self, byte: u8) -> bool { - >::default().contains(byte) || match byte { - b'&' | b'=' => true, - _ => false - } - } + const SET: AsciiSet = >::SET + .add(b'&') + .add(b'='); } #[derive(Default, Clone, Copy)] @@ -55,11 +50,15 @@ impl EncodeSet for ENCODE_SET { pub struct DEFAULT_ENCODE_SET; impl EncodeSet for DEFAULT_ENCODE_SET { - #[inline(always)] - fn contains(&self, byte: u8) -> bool { - ENCODE_SET::(PhantomData).contains(byte) || - ENCODE_SET::(PhantomData).contains(byte) - } + // DEFAULT_ENCODE_SET Includes: + // * ENCODE_SET (and UNSAFE_ENCODE_SET) + const SET: AsciiSet = >::SET + // * UNSAFE_ENCODE_SET + .add(b'%') + .add(b'+') + // * ENCODE_SET + .add(b'&') + .add(b'='); } pub fn unsafe_percent_encode(string: &str) -> Cow<'_, str> { @@ -71,5 +70,5 @@ pub fn unsafe_percent_encode(string: &str) -> Cow<'_, str> { } pub fn percent_encode(string: &str) -> Cow<'_, str> { - utf8_percent_encode(string, S::default()).into() + utf8_percent_encode(string, &S::SET).into() } diff --git a/examples/raw_sqlite/Cargo.toml b/examples/raw_sqlite/Cargo.toml index 1b09d9af6b..6797794176 100644 --- a/examples/raw_sqlite/Cargo.toml +++ b/examples/raw_sqlite/Cargo.toml @@ -7,4 +7,4 @@ publish = false [dependencies] rocket = { path = "../../core/lib" } -rusqlite = "0.16" +rusqlite = "0.23" diff --git a/examples/todo/Cargo.toml b/examples/todo/Cargo.toml index 2478841f2b..4fddee3ef1 100644 --- a/examples/todo/Cargo.toml +++ b/examples/todo/Cargo.toml @@ -15,7 +15,7 @@ diesel_migrations = "1.3" log = "0.4" [dev-dependencies] -parking_lot = { version = "0.10", features = ["nightly"] } +parking_lot = "0.11" rand = "0.7" [dependencies.rocket_contrib] diff --git a/examples/todo/src/tests.rs b/examples/todo/src/tests.rs index 1c4b2dc9fd..f4f72f3a12 100644 --- a/examples/todo/src/tests.rs +++ b/examples/todo/src/tests.rs @@ -9,7 +9,7 @@ use rocket::http::{Status, ContentType}; // We use a lock to synchronize between tests so DB operations don't collide. // For now. In the future, we'll have a nice way to run each test in a DB // transaction so we can regain concurrency. -static DB_LOCK: Mutex<()> = Mutex::new(()); +static DB_LOCK: Mutex<()> = parking_lot::const_mutex(()); macro_rules! run_test { (|$client:ident, $conn:ident| $block:expr) => ({ diff --git a/scripts/test.sh b/scripts/test.sh index 45c66fd912..5ee3f49bd0 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -75,9 +75,7 @@ if [ "$1" = "--contrib" ]; then postgres_pool mysql_pool sqlite_pool - cypher_pool redis_pool - mongodb_pool memcache_pool brotli_compression gzip_compression diff --git a/site/guide/6-state.md b/site/guide/6-state.md index c5638118c5..bbac0716e6 100644 --- a/site/guide/6-state.md +++ b/site/guide/6-state.md @@ -230,34 +230,28 @@ Presently, Rocket provides built-in support for the following databases: | Kind | Driver | Version | `Poolable` Type | Feature | |----------|-----------------------|-----------|--------------------------------|------------------------| | MySQL | [Diesel] | `1` | [`diesel::MysqlConnection`] | `diesel_mysql_pool` | -| MySQL | [`rust-mysql-simple`] | `17` | [`mysql::Conn`] | `mysql_pool` | +| MySQL | [`rust-mysql-simple`] | `18` | [`mysql::Conn`] | `mysql_pool` | | Postgres | [Diesel] | `1` | [`diesel::PgConnection`] | `diesel_postgres_pool` | | Postgres | [Rust-Postgres] | `0.17` | [`postgres::Client`] | `postgres_pool` | | Sqlite | [Diesel] | `1` | [`diesel::SqliteConnection`] | `diesel_sqlite_pool` | -| Sqlite | [`Rusqlite`] | `0.16` | [`rusqlite::Connection`] | `sqlite_pool` | -| Neo4j | [`rusted_cypher`] | `1` | [`rusted_cypher::GraphClient`] | `cypher_pool` | -| Redis | [`redis-rs`] | `0.13` | [`redis::Connection`] | `redis_pool` | -| MongoDB | [`mongodb`] | `0.3.12` | [`mongodb::db::Database`] | `mongodb_pool` | +| Sqlite | [`Rusqlite`] | `0.23` | [`rusqlite::Connection`] | `sqlite_pool` | +| Redis | [`redis-rs`] | `0.15` | [`redis::Connection`] | `redis_pool` | | Memcache | [`memcache`] | `0.14` | [`memcache::Client`] | `memcache_pool` | [`r2d2`]: https://crates.io/crates/r2d2 [Diesel]: https://diesel.rs -[`redis::Connection`]: https://docs.rs/redis/0.13.0/redis/struct.Connection.html -[`rusted_cypher::GraphClient`]: https://docs.rs/rusted_cypher/1.1.0/rusted_cypher/graph/struct.GraphClient.html -[`rusqlite::Connection`]: https://docs.rs/rusqlite/0.16.0/rusqlite/struct.Connection.html +[`redis::Connection`]: https://docs.rs/redis/0.15.0/redis/struct.Connection.html +[`rusqlite::Connection`]: https://docs.rs/rusqlite/0.23.0/rusqlite/struct.Connection.html [`diesel::SqliteConnection`]: http://docs.diesel.rs/diesel/prelude/struct.SqliteConnection.html [`postgres::Client`]: https://docs.rs/postgres/0.17/postgres/struct.Client.html [`diesel::PgConnection`]: http://docs.diesel.rs/diesel/pg/struct.PgConnection.html -[`mysql::Conn`]: https://docs.rs/mysql/17/mysql/struct.Conn.html +[`mysql::Conn`]: https://docs.rs/mysql/18/mysql/struct.Conn.html [`diesel::MysqlConnection`]: http://docs.diesel.rs/diesel/mysql/struct.MysqlConnection.html [`redis-rs`]: https://github.com/mitsuhiko/redis-rs -[`rusted_cypher`]: https://github.com/livioribeiro/rusted-cypher [`Rusqlite`]: https://github.com/jgallagher/rusqlite [Rust-Postgres]: https://github.com/sfackler/rust-postgres [`rust-mysql-simple`]: https://github.com/blackbeam/rust-mysql-simple [`diesel::PgConnection`]: http://docs.diesel.rs/diesel/pg/struct.PgConnection.html -[`mongodb`]: https://github.com/mongodb-labs/mongo-rust-driver-prototype -[`mongodb::db::Database`]: https://docs.rs/mongodb/0.3.12/mongodb/db/type.Database.html [`memcache`]: https://github.com/aisk/rust-memcache [`memcache::Client`]: https://docs.rs/memcache/0.14/memcache/struct.Client.html