Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a basic Url rewrite modifier. #82

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions source/river/assets/test-config.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ services {
upstream-request {
filter kind="remove-header-key-regex" pattern=".*(secret|SECRET).*"
filter kind="upsert-header" key="x-proxy-friend" value="river"
filter kind="url-rewrite" regex="^/rewrite/(.*)$" rewrite="/${1}"
}
upstream-response {
filter kind="remove-header-key-regex" pattern=".*ETag.*"
Expand Down
2 changes: 2 additions & 0 deletions source/river/assets/test-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ name = "Example1"
# Filters are applied in the order they are specified. Multiple instances of
# each filter may be provided.
upstream-request-filters = [
# Url rewrite to
{ kind = "url-rewrite", regex = "^/rewrite/(.*)$", rewrite = "/${1}" },
# Remove any headers with keys matching `pattern`
{ kind = "remove-header-key-regex", pattern = ".*(secret|SECRET).*" },
# Add or replace (e.g. "Upsert") a fixed header with the given key and value
Expand Down
3 changes: 3 additions & 0 deletions source/river/src/proxy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ impl Modifiers {
"upsert-header" => {
Box::new(request_modifiers::UpsertHeader::from_settings(filter).unwrap())
}
"url-rewrite" => {
Box::new(request_modifiers::PathRewrite::from_settings(filter).unwrap())
}
other => {
tracing::warn!("Unknown upstream request filter: '{other}'");
return Err(Error::new(ErrorType::Custom("Bad configuration")));
Expand Down
49 changes: 48 additions & 1 deletion source/river/src/proxy/request_modifiers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::collections::BTreeMap;
use std::{collections::BTreeMap, str::FromStr};

use async_trait::async_trait;
use http::{uri::PathAndQuery, Uri};
use log::info;
use pingora_core::{Error, Result};
use pingora_http::RequestHeader;
use pingora_proxy::Session;
Expand Down Expand Up @@ -112,3 +114,48 @@ impl RequestModifyMod for UpsertHeader {
Ok(())
}
}

pub struct PathRewrite {
regex: Regex,
rewrite: String,
}

impl PathRewrite {
// Create from settings
pub fn from_settings(mut settings: BTreeMap<String, String>) -> Result<Self> {
let regex = extract_val("regex", &mut settings)?;
let regex = Regex::from_str(regex.as_str()).expect("Unable to parse regex for rewrite.");
let rewrite = extract_val("rewrite", &mut settings)?;

Ok(Self {
regex,
rewrite: rewrite.clone(),
})
}
}

#[async_trait]
impl RequestModifyMod for PathRewrite {
async fn upstream_request_filter(
&self,
_session: &mut Session,
header: &mut RequestHeader,
_ctx: &mut RiverContext,
) -> Result<()> {
let path = header.uri.path();
match self.regex.is_match(path) {
false => Ok(()),
true => {
let rewrite = self.regex.replace(path, self.rewrite.as_str());

let rewritten_uri = Uri::builder()
.path_and_query(PathAndQuery::from_str(&rewrite.to_string()).unwrap())
.build();

header.set_uri(rewritten_uri.unwrap());

Ok(())
}
}
}
}