From c5211ed74d290c6d8f5dd9ea92aceca8b2d20d71 Mon Sep 17 00:00:00 2001 From: Vika Date: Tue, 27 Jul 2021 15:29:26 +0300 Subject: Respect Link: headers when sending webmentions --- src/micropub/post.rs | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'src/micropub') diff --git a/src/micropub/post.rs b/src/micropub/post.rs index 95b4dd0..8667451 100644 --- a/src/micropub/post.rs +++ b/src/micropub/post.rs @@ -6,7 +6,7 @@ use core::iter::Iterator; use futures::stream; use futures::StreamExt; use http_types::Mime; -use log::{error, warn}; +use log::{error, warn, info}; use newbase60::num_to_sxg; use std::convert::TryInto; use std::str::FromStr; @@ -336,7 +336,7 @@ async fn post_process_new_post( contextually_significant_posts.dedup(); // 1.3. Fetch the posts with their bodies and save them in a new Vec<(surf::Url, String)> - let posts_with_bodies: Vec<(surf::Url, String)> = + let posts_with_bodies: Vec<(surf::Url, surf::Response, String)> = stream::iter(contextually_significant_posts.into_iter()) .filter_map(|v: surf::Url| async move { if let Ok(res) = http.get(&v).send().await { @@ -351,7 +351,7 @@ async fn post_process_new_post( }) .filter_map(|(v, mut res): (surf::Url, surf::Response)| async move { if let Ok(body) = res.body_string().await { - Some((v, body)) + Some((v, res, body)) } else { None } @@ -430,7 +430,34 @@ async fn post_process_new_post( // We'll need the bodies here to get their endpoints let source = &uid; stream::iter(posts_with_bodies.into_iter()) - .filter_map(|(url, body): (surf::Url, String)| async move { + .filter_map(|(url, response, body): (surf::Url, surf::Response, String)| async move { + // Check Link headers first + // the first webmention endpoint will be returned + if let Some(values) = response.header("Link") { + let mut iter = values.iter().flat_map(|i| i.as_str().split(',')); + + for link in iter { + let mut split = link.split(";"); + + match split.next() { + Some(uri) => { + if let Some(uri) = uri.strip_prefix('<') { + if let Some(uri) = uri.strip_suffix('>') { + for prop in split { + let lowercased = prop.to_ascii_lowercase(); + if &lowercased == "rel=\"webmention\"" || &lowercased == "rel=webmention" { + if let Ok(endpoint) = url.join(uri) { + return Some((url, endpoint)); + } + } + } + } + } + }, + None => continue + } + } + } // TODO: Replace this function once the MF2 parser is ready // A compliant parser's output format includes rels, // we could just find a Webmention one in there @@ -448,6 +475,7 @@ async fn post_process_new_post( } }) .map(|(target, endpoint)| async move { + info!("Sending webmention to {} about {}", source, &target.to_string()); let response = http .post(&endpoint) .content_type("application/x-www-form-urlencoded") -- cgit 1.4.1