Skip to content

Commit

Permalink
Merge pull request #58 from LemmyNet/forward-backend-requests
Browse files Browse the repository at this point in the history
Forward backend requests
  • Loading branch information
Nutomic committed Nov 4, 2022
2 parents 23b7d2b + ec789fc commit 15ef721
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 65 deletions.
11 changes: 1 addition & 10 deletions docker/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,7 @@ server {

# lemmybb frontend
location / {
set $proxpass "http://0.0.0.0:8701";
# federation requests go to backend
if ($http_accept ~ "^application/.*$") {
set $proxpass "http://0.0.0.0:8703";
}
# fonts have similar accept header but need to be handled by frontend
if ($http_accept ~ "^application/font.*$") {
set $proxpass "http://0.0.0.0:8701";
}
proxy_pass $proxpass;
proxy_pass "http://0.0.0.0:8701";
rewrite ^(.+)/+$ $1 permanent;
}

Expand Down
13 changes: 7 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ use crate::{
routes::{
comment::*,
community::*,
federation::*,
post::*,
private_message::*,
redirects::*,
site::*,
user::*,
},
Expand Down Expand Up @@ -106,15 +106,16 @@ fn init_rocket() -> Result<Rocket<Build>, Error> {
private_message_editor,
do_send_private_message,
image,
redirect_apub_community,
redirect_apub_user,
redirect_apub_post,
redirect_apub_comment,
apub_community,
apub_user,
apub_post,
apub_comment,
report,
do_report,
edit_profile,
do_edit_profile,
community_list
community_list,
inboxes
],
)
.mount("/assets", FileServer::from(relative!("assets"))))
Expand Down
138 changes: 138 additions & 0 deletions src/routes/federation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
use crate::{
api::{comment::get_comment, community::get_community, user::get_person, NameOrId, CLIENT},
env::lemmy_backend,
error::ErrorPage,
rocket_uri_macro_view_forum,
rocket_uri_macro_view_profile,
rocket_uri_macro_view_topic,
routes::auth,
};
use anyhow::Error;
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
use rocket::{
http::CookieJar,
request::{FromRequest, Outcome},
response::Redirect,
Either,
};
use std::{path::PathBuf, str::FromStr};

type ReturnType = Result<Either<Redirect, String>, ErrorPage>;

#[get("/c/<name>")]
pub async fn apub_community(
name: String,
accept: AcceptHeader,
cookies: &CookieJar<'_>,
) -> ReturnType {
if accept.0.starts_with("application/") {
return foward_apub_fetch(format!("{}/c/{}", lemmy_backend(), name), accept).await;
}
let community = get_community(NameOrId::Name(name), auth(cookies)).await?;
let f = community.community_view.community.id.0;
Ok(Either::Left(Redirect::to(uri!(view_forum(
f,
Some(1),
Option::<String>::None
)))))
}

#[get("/u/<name>")]
pub async fn apub_user(name: String, accept: AcceptHeader, cookies: &CookieJar<'_>) -> ReturnType {
if accept.0.starts_with("application/") {
return foward_apub_fetch(format!("{}/u/{}", lemmy_backend(), name), accept).await;
}
let user = get_person(NameOrId::Name(name), auth(cookies)).await?;
let u = user.person_view.person.id.0;
Ok(Either::Left(Redirect::to(uri!(view_profile(u)))))
}

#[get("/post/<id>")]
pub async fn apub_post(id: i32, accept: AcceptHeader) -> ReturnType {
if accept.0.starts_with("application/") {
return foward_apub_fetch(format!("{}/post/{}", lemmy_backend(), id), accept).await;
}
Ok(Either::Left(Redirect::to(uri!(view_topic(id, Some(1))))))
}

#[get("/comment/<t>")]
pub async fn apub_comment(t: i32, accept: AcceptHeader, cookies: &CookieJar<'_>) -> ReturnType {
if accept.0.starts_with("application/") {
return foward_apub_fetch(format!("{}/comment/{}", lemmy_backend(), t), accept).await;
}
let comment = get_comment(t, auth(cookies)).await?;
// TODO: figure out actual page
Ok(Either::Left(Redirect::to(format!(
"/view_topic?t={}&page=1#p{}",
t, comment.comment_view.comment.id
))))
}

/// In case an activitypub object is being fetched, forward request to Lemmy backend
async fn foward_apub_fetch(url: String, accept: AcceptHeader) -> ReturnType {
let res = CLIENT
.get(url)
.header("accept", accept.0)
.send()
.await?
.text()
.await?;
Ok(Either::Right(res))
}

#[post("/<path..>", data = "<body>")]
pub async fn inboxes(
path: PathBuf,
body: String,
headers: Headers<'_>,
) -> Result<String, ErrorPage> {
let url = format!("{}/{}", lemmy_backend(), path.to_str().unwrap());
let headers = headers
.0
.iter()
.map(|h| {
Ok((
HeaderName::from_str(h.name.as_str())?,
HeaderValue::from_str(&h.value)?,
))
})
.collect::<Result<HeaderMap, Error>>()?;

Ok(CLIENT
.post(url)
.headers(headers)
.body(body)
.send()
.await?
.text()
.await?)
}

// Retrieve request headers
// https://github.com/SergioBenitez/Rocket/issues/178#issuecomment-953370904
pub struct Headers<'r>(&'r rocket::http::HeaderMap<'r>);

#[rocket::async_trait]
impl<'r> FromRequest<'r> for Headers<'r> {
type Error = std::convert::Infallible;

async fn from_request(req: &'r rocket::Request<'_>) -> Outcome<Self, Self::Error> {
Outcome::Success(Headers(req.headers()))
}
}

pub struct AcceptHeader(String);

#[rocket::async_trait]
impl<'r> FromRequest<'r> for AcceptHeader {
type Error = std::convert::Infallible;

async fn from_request(req: &'r rocket::Request<'_>) -> Outcome<Self, Self::Error> {
Outcome::Success(AcceptHeader(
req.headers()
.get_one("accept")
.unwrap_or_default()
.to_string(),
))
}
}
2 changes: 1 addition & 1 deletion src/routes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
pub mod comment;
pub mod community;
pub mod federation;
pub mod post;
pub mod private_message;
pub mod redirects;
pub mod site;
pub mod user;

Expand Down
48 changes: 0 additions & 48 deletions src/routes/redirects.rs

This file was deleted.

0 comments on commit 15ef721

Please sign in to comment.