I want to execute a GET request in an actix-web
extractor, in order obtain additional information from a header.
Cannot drop a runtime in a context where blocking is not allowed
. (This may very well be my fault, but it led me to believe it is not possible)Box::pin
to handle the asynchronous part. That's what I am currently trying.impl FromRequest for AuthorizedHttpRequest {
type Error = CustomError;
type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
#[inline]
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
let path: Path<Url> = Path::new(Url::new(req.path().parse::<Uri>().unwrap().clone()));
let head: RequestHead = req.head().clone();
let date_header: Option<&HeaderValue> = req.headers().get(header::DATE).clone();
Box::pin(async move {
match date_header {
Some(date_header_value) => {
let date_header_str_res: Result<&str, ToStrError> = date_header_value.to_str();
match date_header_str_res {
Ok(date_header_str) => {
let service_client: CustomServiceClient = CustomServiceClient::new(Env::new().custom_service_url);
let additional_data: Result<Data, CustomError> = service_client.get_additonal_data(date_header_str.parse().unwrap()).await.map_err(CustomError::from);
Ok(AuthorizedHttpRequest::new(path, head, user))
}
Err(_) => Ok(AuthorizedHttpRequest::new(
path.clone(), head.clone(),
Err(CustomError::from(InvalidHeaderError))
))
}
},
None => Ok(AuthorizedHttpRequest::new(
path.clone(), head.clone(),
Err(CustomError::from(InvalidHeaderError))
))
}
})
}
}
impl CustomServiceClient {
pub async fn get_additonal_data(&self, date_str: String) -> Result<Data, UnavailableDataError> {
let client: Client = Client::builder()
.danger_accept_invalid_certs(true) // necessary as I have self-signed certificates
.build().unwrap();
let response: Response = client
.get(format!("{}", self.url))
.header(header::DATE, format!("Date {}", date_str))
.send().await.unwrap();
let additional_data: Data = response.json().await.unwrap();
Ok(additional_data)
}
}
It seems my implementation (which mirrors the one in the answer of the mentioned question) raises a lifetime error, that I am not able to fix. The error is as follows:
error: lifetime may not live long enough
--> src/<path>/authorized_http_request.rs:61:9
|
56 | fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
| - let's call the lifetime of this reference `'1`
...
61 | / Box::pin(async move {
62 | | match date_header {
63 | | Some(date_header_value) => {
64 | | let date_header_str_res: Result<&str, ToStrError> = date_header_value.to_str();
... |
96 | | })
| |__________^ returning this value requires that `'1` must outlive `'static`
How can I fix this lifetime issue? Should I have done things another way entirely?
Have you tried .cloned()
instead of .clone()
?
let date_header: Option<HeaderValue> = req.headers().get(header::DATE).cloned();
Which gives you an owned Option<HeaderValue>
instead of referenced Option<&HeaderValue>