From 3b9fa765ade7780a2fa3c1414ec10fbd0fe80458 Mon Sep 17 00:00:00 2001 From: Sunli Date: Thu, 2 Sep 2021 19:39:45 +0800 Subject: [PATCH] Add feature gate `cbor`. --- Cargo.toml | 7 +++++-- README.md | 1 + src/http/mod.rs | 41 +++++++++++++++++++++++++++++++---------- src/lib.rs | 1 + 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f8d4b8b0..177a52de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ string_number = ["num-traits"] dataloader = ["futures-timer", "futures-channel", "lru"] tracing = ["tracinglib", "tracing-futures"] decimal = ["rust_decimal"] +cbor = ["serde_cbor"] [dependencies] async-graphql-derive = { path = "derive", version = "2.9.8" } @@ -37,13 +38,14 @@ pin-project-lite = "0.2.6" regex = "1.4.5" serde = { version = "1.0.125", features = ["derive"] } serde_json = "1.0.64" -serde_cbor = "0.11.1" thiserror = "1.0.24" static_assertions = "1.1.0" http = "0.2.3" multer = "2.0.0" tempfile = "3.2.0" bytes = { version = "1.0.1", features = ["serde"] } +mime = "0.3.15" + # Feature optional dependencies bson = { version = "2.0.0-beta.1", optional = true, features = ["chrono-0_4"] } chrono = { version = "0.4.19", optional = true } @@ -56,7 +58,7 @@ opentelemetry = { version = "0.13.0", optional = true } url = { version = "2.2.1", optional = true } uuid = { version = "0.8.2", optional = true, features = ["v4", "serde"] } rust_decimal = { version = "1.14.3", optional = true } -mime = "0.3.15" + # Non-feature optional dependencies blocking = { version = "1.0.2", optional = true } lru = { version = "0.6.5", optional = true } @@ -64,6 +66,7 @@ num-traits = { version = "0.2.14", optional = true } sha2 = { version = "0.9.3", optional = true } futures-timer = { version = "3.0.2", optional = true } futures-channel = { version = "0.3.13", optional = true } +serde_cbor = { version = "0.11.1", optional = true } [dev-dependencies] tokio = { version = "1.4.0", features = ["macros", "rt-multi-thread", "sync", "time"] } diff --git a/README.md b/README.md index 52364ed5..e144fa38 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ This crate offers the following features, all of which are not activated by defa - `dataloader`: Support [DataLoader](dataloader/struct.DataLoader.html). - `secrecy`: Integrate with the [`secrecy` crate](https://crates.io/crates/secrecy). - `decimal`: Integrate with the [`rust_decimal` crate](https://crates.io/crates/rust_decimal). +- `cbor`: Support for [serde_cbor](https://crates.io/crates/serde_cbor). ## Apollo Studio diff --git a/src/http/mod.rs b/src/http/mod.rs index de2e8fc6..1ce8cd0a 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -4,16 +4,17 @@ mod graphiql_source; mod multipart; mod playground_source; mod websocket; -use mime::{self}; -use futures_util::io::{AsyncRead, AsyncReadExt}; - -use crate::{BatchRequest, ParseRequestError, Request}; pub use graphiql_source::graphiql_source; pub use multipart::MultipartOptions; pub use playground_source::{playground_source, GraphQLPlaygroundConfig}; pub use websocket::{ClientMessage, Protocols as WebSocketProtocols, WebSocket, WsMessage}; +use futures_util::io::{AsyncRead, AsyncReadExt}; +use mime; + +use crate::{BatchRequest, ParseRequestError, Request}; + /// Receive a GraphQL request from a content type and body. pub async fn receive_body( content_type: Option>, @@ -32,26 +33,37 @@ pub async fn receive_batch_body( opts: MultipartOptions, ) -> Result { // if no content-type header is set, we default to json - let content_type = content_type.as_ref().map(AsRef::as_ref).unwrap_or("application/json"); - + let content_type = content_type + .as_ref() + .map(AsRef::as_ref) + .unwrap_or("application/json"); + let content_type: mime::Mime = content_type.parse()?; + match (content_type.type_(), content_type.subtype()) { // application/json -> try json (mime::APPLICATION, mime::JSON) => receive_batch_json(body).await, + // cbor is in application/octet-stream. // TODO: wait for mime to add application/cbor and match against that too - (mime::OCTET_STREAM, _) | (mime::APPLICATION, mime::OCTET_STREAM) => receive_batch_cbor(body).await, + #[cfg(feature = "cbor")] + (mime::OCTET_STREAM, _) | (mime::APPLICATION, mime::OCTET_STREAM) => { + receive_batch_cbor(body).await + } + // try to use multipart (mime::MULTIPART, _) => { if let Some(boundary) = content_type.get_param("boundary") { multipart::receive_batch_multipart(body, boundary.to_string(), opts).await } else { - Err(ParseRequestError::InvalidMultipart(multer::Error::NoBoundary)) + Err(ParseRequestError::InvalidMultipart( + multer::Error::NoBoundary, + )) } } // default to json and try that - _ => receive_batch_json(body).await + _ => receive_batch_json(body).await, } } @@ -71,7 +83,16 @@ pub async fn receive_batch_json(body: impl AsyncRead) -> Result Result { + receive_batch_cbor(body).await?.into_single() +} + +/// Receive a GraphQL batch request from a body as CBOR +#[cfg(feature = "cbor")] +#[cfg_attr(docsrs, doc(cfg(feature = "cbor")))] pub async fn receive_batch_cbor(body: impl AsyncRead) -> Result { let mut data = Vec::new(); futures_util::pin_mut!(body); diff --git a/src/lib.rs b/src/lib.rs index 963d658c..06802b7a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,6 +72,7 @@ //! - `string_number`: Enable the [StringNumber](types/struct.StringNumber.html). //! - `dataloader`: Support [DataLoader](dataloader/struct.DataLoader.html). //! - `decimal`: Integrate with the [`rust_decimal` crate](https://crates.io/crates/rust_decimal). +//! - `cbor`: Support for [serde_cbor](https://crates.io/crates/serde_cbor). //! //! ## Integrations //!