apollo_router/services/
mod.rs1use std::sync::Arc;
4
5use parking_lot::Mutex;
6use schemars::JsonSchema;
7use serde::Deserialize;
8use serde::Serialize;
9use strum::Display;
10
11pub(crate) use self::execution::service::*;
12pub(crate) use self::query_planner::*;
13pub(crate) use self::subgraph_service::*;
14pub(crate) use self::supergraph::service::*;
15use crate::graphql::Request;
16use crate::http_ext;
17pub use crate::http_ext::TryIntoHeaderName;
18pub use crate::http_ext::TryIntoHeaderValue;
19pub use crate::query_planner::OperationKind;
20pub(crate) use crate::services::connect::Request as ConnectRequest;
21pub(crate) use crate::services::connect::Response as ConnectResponse;
22pub(crate) use crate::services::execution::Request as ExecutionRequest;
23pub(crate) use crate::services::execution::Response as ExecutionResponse;
24pub(crate) use crate::services::fetch::FetchRequest;
25pub(crate) use crate::services::fetch::Response as FetchResponse;
26pub(crate) use crate::services::query_planner::Request as QueryPlannerRequest;
27pub(crate) use crate::services::query_planner::Response as QueryPlannerResponse;
28pub(crate) use crate::services::router::Request as RouterRequest;
29pub(crate) use crate::services::router::Response as RouterResponse;
30pub(crate) use crate::services::subgraph::Request as SubgraphRequest;
31pub(crate) use crate::services::subgraph::Response as SubgraphResponse;
32pub(crate) use crate::services::supergraph::Request as SupergraphRequest;
33pub(crate) use crate::services::supergraph::Response as SupergraphResponse;
34pub(crate) use crate::services::supergraph::service::SupergraphCreator;
35
36pub(crate) mod connect;
37pub(crate) mod connector;
38pub(crate) mod connector_service;
39pub mod execution;
40pub(crate) mod external;
41pub(crate) mod fetch;
42pub(crate) mod fetch_service;
43pub(crate) mod header_masking;
44pub(crate) mod hickory_dns_connector;
45pub(crate) mod http;
46pub(crate) mod layers;
47pub(crate) mod new_service;
48pub(crate) mod query_planner;
49pub mod router;
50pub mod subgraph;
51pub(crate) mod subgraph_service;
52pub mod supergraph;
53
54#[derive(Clone, Debug, Display, Deserialize, PartialEq, Serialize, JsonSchema)]
56pub(crate) enum PipelineStep {
57 RouterRequest,
58 RouterResponse,
59 SupergraphRequest,
60 SupergraphResponse,
61 ExecutionRequest,
62 ExecutionResponse,
63 SubgraphRequest,
64 SubgraphResponse,
65 ConnectorRequest,
66 ConnectorResponse,
67}
68
69impl From<PipelineStep> for opentelemetry::Value {
70 fn from(val: PipelineStep) -> Self {
71 val.to_string().into()
72 }
73}
74
75impl AsRef<Request> for http_ext::Request<Request> {
76 fn as_ref(&self) -> &Request {
77 self.body()
78 }
79}
80
81impl AsRef<Request> for Arc<http_ext::Request<Request>> {
82 fn as_ref(&self) -> &Request {
83 self.body()
84 }
85}
86
87#[allow(missing_docs)]
89pub static APOLLO_KEY: Mutex<Option<String>> = Mutex::new(None);
90#[allow(missing_docs)]
91pub static APOLLO_GRAPH_REF: Mutex<Option<String>> = Mutex::new(None);
92
93pub(crate) fn apollo_key() -> Option<String> {
94 APOLLO_KEY.lock().clone()
95}
96
97pub(crate) fn apollo_graph_reference() -> Option<String> {
98 APOLLO_GRAPH_REF.lock().clone()
99}
100
101pub(crate) const MULTIPART_DEFER_SPEC_PARAMETER: &str = "deferSpec";
103pub(crate) const MULTIPART_DEFER_SPEC_VALUE: &str = "20220824";
104pub(crate) const MULTIPART_DEFER_ACCEPT: &str = "multipart/mixed;deferSpec=20220824";
105pub(crate) const MULTIPART_DEFER_CONTENT_TYPE: &str =
106 "multipart/mixed;boundary=\"graphql\";deferSpec=20220824";
107
108pub(crate) const MULTIPART_SUBSCRIPTION_ACCEPT: &str = "multipart/mixed;subscriptionSpec=1.0";
109pub(crate) const MULTIPART_SUBSCRIPTION_CONTENT_TYPE: &str =
110 "multipart/mixed;boundary=\"graphql\";subscriptionSpec=1.0";
111pub(crate) const MULTIPART_SUBSCRIPTION_SPEC_PARAMETER: &str = "subscriptionSpec";
112pub(crate) const MULTIPART_SUBSCRIPTION_SPEC_VALUE: &str = "1.0";
113
114#[cfg(unix)]
115pub(crate) const DEFAULT_SOCKET_PATH: &str = "/";
116pub(crate) const PATH_QUERY_PARAM: &str = "path=";
117
118#[cfg(unix)]
128pub(crate) fn parse_unix_socket_url(url_path: &str) -> (&str, &str) {
129 if let Some(query_start) = url_path.find('?') {
130 let socket_path = &url_path[..query_start];
131 let query = &url_path[query_start + 1..];
132
133 let http_path = query
135 .split('&')
136 .find_map(|param| param.strip_prefix(PATH_QUERY_PARAM))
137 .unwrap_or(DEFAULT_SOCKET_PATH);
138
139 (socket_path, http_path)
140 } else {
141 (url_path, DEFAULT_SOCKET_PATH)
142 }
143}
144
145#[cfg(unix)]
146#[cfg(test)]
147mod unix_socket_url_tests {
148 use rstest::rstest;
149
150 use super::parse_unix_socket_url;
151
152 #[rstest]
153 #[case::without_query("/tmp/coprocessor.sock", "/tmp/coprocessor.sock", "/")]
154 #[case::with_path_param(
155 "/tmp/coprocessor.sock?path=/api/v1",
156 "/tmp/coprocessor.sock",
157 "/api/v1"
158 )]
159 #[case::with_multiple_params(
160 "/tmp/coprocessor.sock?other=value&path=/api/v1&another=x",
161 "/tmp/coprocessor.sock",
162 "/api/v1"
163 )]
164 #[case::with_other_params_only(
165 "/tmp/coprocessor.sock?other=value",
166 "/tmp/coprocessor.sock",
167 "/"
168 )]
169 #[case::with_empty_query("/tmp/coprocessor.sock?", "/tmp/coprocessor.sock", "/")]
170 #[case::with_nested_http_path(
171 "/tmp/coprocessor.sock?path=/api/v1/coprocessor/hook",
172 "/tmp/coprocessor.sock",
173 "/api/v1/coprocessor/hook"
174 )]
175 #[case::with_empty_path_param("/tmp/coprocessor.sock?path", "/tmp/coprocessor.sock", "/")]
176 #[case::without_leading_slash(
177 "/tmp/coprocessor.sock?path=no_leading_slash",
178 "/tmp/coprocessor.sock",
179 "no_leading_slash"
180 )]
181 fn parse_socket_url(
182 #[case] input: &str,
183 #[case] expected_socket: &str,
184 #[case] expected_http_path: &str,
185 ) {
186 let (socket, http_path) = parse_unix_socket_url(input);
187 assert_eq!(socket, expected_socket);
188 assert_eq!(http_path, expected_http_path);
189 }
190}