Skip to main content

tako_rs_core/graphql/
protocol.rs

1//! WebSocket subprotocol negotiation for `GraphQL` subscriptions:
2//! the [`GraphQLProtocol`] extractor and its rejection type.
3
4use std::str::FromStr;
5
6use async_graphql::http::WebSocketProtocols;
7use http::StatusCode;
8use http::header;
9
10use crate::extractors::FromRequest;
11use crate::extractors::FromRequestParts;
12use crate::responder::Responder;
13use crate::types::Request;
14use crate::types::Response;
15
16/// Extracted WebSocket protocol for `GraphQL` subscriptions.
17pub struct GraphQLProtocol(pub WebSocketProtocols);
18
19#[derive(Debug)]
20pub struct GraphQLProtocolRejection;
21
22impl Responder for GraphQLProtocolRejection {
23  fn into_response(self) -> Response {
24    (
25      StatusCode::BAD_REQUEST,
26      "Missing or invalid Sec-WebSocket-Protocol",
27    )
28      .into_response()
29  }
30}
31
32impl<'a> FromRequestParts<'a> for GraphQLProtocol {
33  type Error = GraphQLProtocolRejection;
34
35  fn from_request_parts(
36    parts: &'a mut http::request::Parts,
37  ) -> impl core::future::Future<Output = core::result::Result<Self, Self::Error>> + Send + 'a {
38    futures_util::future::ready(
39      parts
40        .headers
41        .get(header::SEC_WEBSOCKET_PROTOCOL)
42        .and_then(|v| v.to_str().ok())
43        .and_then(|protocols| {
44          protocols
45            .split(',')
46            .find_map(|p| WebSocketProtocols::from_str(p.trim()).ok())
47        })
48        .map(GraphQLProtocol)
49        .ok_or(GraphQLProtocolRejection),
50    )
51  }
52}
53
54impl<'a> FromRequest<'a> for GraphQLProtocol {
55  type Error = GraphQLProtocolRejection;
56
57  fn from_request(
58    req: &'a mut Request,
59  ) -> impl core::future::Future<Output = core::result::Result<Self, Self::Error>> + Send + 'a {
60    futures_util::future::ready(
61      req
62        .headers()
63        .get(header::SEC_WEBSOCKET_PROTOCOL)
64        .and_then(|v| v.to_str().ok())
65        .and_then(|protocols| {
66          protocols
67            .split(',')
68            .find_map(|p| WebSocketProtocols::from_str(p.trim()).ok())
69        })
70        .map(GraphQLProtocol)
71        .ok_or(GraphQLProtocolRejection),
72    )
73  }
74}