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 hickory_dns_connector;
44pub(crate) mod http;
45pub(crate) mod layers;
46pub(crate) mod new_service;
47pub(crate) mod query_planner;
48pub mod router;
49pub mod subgraph;
50pub(crate) mod subgraph_service;
51pub mod supergraph;
52
53#[derive(Clone, Debug, Display, Deserialize, PartialEq, Serialize, JsonSchema)]
55pub(crate) enum PipelineStep {
56 RouterRequest,
57 RouterResponse,
58 SupergraphRequest,
59 SupergraphResponse,
60 ExecutionRequest,
61 ExecutionResponse,
62 SubgraphRequest,
63 SubgraphResponse,
64 ConnectorRequest,
65 ConnectorResponse,
66}
67
68impl From<PipelineStep> for opentelemetry::Value {
69 fn from(val: PipelineStep) -> Self {
70 val.to_string().into()
71 }
72}
73
74impl AsRef<Request> for http_ext::Request<Request> {
75 fn as_ref(&self) -> &Request {
76 self.body()
77 }
78}
79
80impl AsRef<Request> for Arc<http_ext::Request<Request>> {
81 fn as_ref(&self) -> &Request {
82 self.body()
83 }
84}
85
86#[allow(missing_docs)]
88pub static APOLLO_KEY: Mutex<Option<String>> = Mutex::new(None);
89#[allow(missing_docs)]
90pub static APOLLO_GRAPH_REF: Mutex<Option<String>> = Mutex::new(None);
91
92pub(crate) fn apollo_key() -> Option<String> {
93 APOLLO_KEY.lock().clone()
94}
95
96pub(crate) fn apollo_graph_reference() -> Option<String> {
97 APOLLO_GRAPH_REF.lock().clone()
98}
99
100pub(crate) const MULTIPART_DEFER_SPEC_PARAMETER: &str = "deferSpec";
102pub(crate) const MULTIPART_DEFER_SPEC_VALUE: &str = "20220824";
103pub(crate) const MULTIPART_DEFER_ACCEPT: &str = "multipart/mixed;deferSpec=20220824";
104pub(crate) const MULTIPART_DEFER_CONTENT_TYPE: &str =
105 "multipart/mixed;boundary=\"graphql\";deferSpec=20220824";
106
107pub(crate) const MULTIPART_SUBSCRIPTION_ACCEPT: &str = "multipart/mixed;subscriptionSpec=1.0";
108pub(crate) const MULTIPART_SUBSCRIPTION_CONTENT_TYPE: &str =
109 "multipart/mixed;boundary=\"graphql\";subscriptionSpec=1.0";
110pub(crate) const MULTIPART_SUBSCRIPTION_SPEC_PARAMETER: &str = "subscriptionSpec";
111pub(crate) const MULTIPART_SUBSCRIPTION_SPEC_VALUE: &str = "1.0";
112
113#[cfg(unix)]
114pub(crate) const DEFAULT_SOCKET_PATH: &str = "/";
115pub(crate) const PATH_QUERY_PARAM: &str = "path=";
116
117#[cfg(unix)]
127pub(crate) fn parse_unix_socket_url(url_path: &str) -> (&str, &str) {
128 if let Some(query_start) = url_path.find('?') {
129 let socket_path = &url_path[..query_start];
130 let query = &url_path[query_start + 1..];
131
132 let http_path = query
134 .split('&')
135 .find_map(|param| param.strip_prefix(PATH_QUERY_PARAM))
136 .unwrap_or(DEFAULT_SOCKET_PATH);
137
138 (socket_path, http_path)
139 } else {
140 (url_path, DEFAULT_SOCKET_PATH)
141 }
142}
143
144#[cfg(unix)]
145#[cfg(test)]
146mod unix_socket_url_tests {
147 use rstest::rstest;
148
149 use super::parse_unix_socket_url;
150
151 #[rstest]
152 #[case::without_query("/tmp/coprocessor.sock", "/tmp/coprocessor.sock", "/")]
153 #[case::with_path_param(
154 "/tmp/coprocessor.sock?path=/api/v1",
155 "/tmp/coprocessor.sock",
156 "/api/v1"
157 )]
158 #[case::with_multiple_params(
159 "/tmp/coprocessor.sock?other=value&path=/api/v1&another=x",
160 "/tmp/coprocessor.sock",
161 "/api/v1"
162 )]
163 #[case::with_other_params_only(
164 "/tmp/coprocessor.sock?other=value",
165 "/tmp/coprocessor.sock",
166 "/"
167 )]
168 #[case::with_empty_query("/tmp/coprocessor.sock?", "/tmp/coprocessor.sock", "/")]
169 #[case::with_nested_http_path(
170 "/tmp/coprocessor.sock?path=/api/v1/coprocessor/hook",
171 "/tmp/coprocessor.sock",
172 "/api/v1/coprocessor/hook"
173 )]
174 #[case::with_empty_path_param("/tmp/coprocessor.sock?path", "/tmp/coprocessor.sock", "/")]
175 #[case::without_leading_slash(
176 "/tmp/coprocessor.sock?path=no_leading_slash",
177 "/tmp/coprocessor.sock",
178 "no_leading_slash"
179 )]
180 fn parse_socket_url(
181 #[case] input: &str,
182 #[case] expected_socket: &str,
183 #[case] expected_http_path: &str,
184 ) {
185 let (socket, http_path) = parse_unix_socket_url(input);
186 assert_eq!(socket, expected_socket);
187 assert_eq!(http_path, expected_http_path);
188 }
189}