apollo-router 3.0.0-alpha.2

A configurable, high-performance routing runtime for Apollo Federation 🚀
Documentation
use std::task::Context;
use std::task::Poll;

use futures::future::BoxFuture;
use http::HeaderName;
use http::HeaderValue;
use http::header::CONTENT_TYPE;
use tower::BoxError;
use tower::Layer;
use tower::Service;

use super::multipart_form_data::MultipartFormData;
use crate::services::http::HttpRequest;
use crate::services::http::HttpResponse;
use crate::services::router;

pub(super) static APOLLO_REQUIRE_PREFLIGHT: HeaderName =
    HeaderName::from_static("apollo-require-preflight");
pub(super) static TRUE: HeaderValue = HeaderValue::from_static("true");

pub(super) struct FileUploadLayer;

#[derive(Clone)]
pub(super) struct FileUploadService<S> {
    inner: S,
}

impl<S> Layer<S> for FileUploadLayer {
    type Service = FileUploadService<S>;

    fn layer(&self, inner: S) -> Self::Service {
        FileUploadService { inner }
    }
}

impl<S> Service<HttpRequest> for FileUploadService<S>
where
    S: Service<HttpRequest, Response = HttpResponse, Error = BoxError> + Clone + Send + 'static,
    S::Future: Send + 'static,
{
    type Response = HttpResponse;
    type Error = BoxError;
    type Future = BoxFuture<'static, Result<HttpResponse, BoxError>>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), BoxError>> {
        self.inner.poll_ready(cx)
    }

    fn call(&mut self, mut req: HttpRequest) -> Self::Future {
        let service = self.inner.clone();
        let mut inner = std::mem::replace(&mut self.inner, service);
        Box::pin(async move {
            let form = req
                .http_request
                .extensions_mut()
                .remove::<MultipartFormData>();
            if let Some(form) = form {
                let (mut parts, operations) = req.http_request.into_parts();
                parts
                    .headers
                    .insert(APOLLO_REQUIRE_PREFLIGHT.clone(), TRUE.clone());
                parts.headers.insert(CONTENT_TYPE, form.content_type());
                let body = router::body::from_result_stream(form.into_stream(operations).await);
                req.http_request = http::Request::from_parts(parts, body);
            }
            inner.call(req).await
        })
    }
}