Skip to content

Commit

Permalink
fix: redirects: upgrade http location headers + forward status codes -
Browse files Browse the repository at this point in the history
…fixes #28,#26
  • Loading branch information
shakyShane committed Oct 19, 2018
1 parent 17d7b99 commit 8a0a972
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 31 deletions.
3 changes: 2 additions & 1 deletion src/lib/headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use regex::Regex;
/// from any set-cookies
///
pub fn clone_headers(headers: &HeaderMap, target: String, replacer: String) -> HeaderMap {
let regex = Regex::new(target.as_str()).unwrap();
let matcher = format!("https?://{}", target);
let regex = Regex::new(&matcher).unwrap();
let mut hm = HeaderMap::new();
for (key, value) in headers.iter().filter(|(key, _)| key.as_str() != "cookie") {
let strs = value.to_str().unwrap();
Expand Down
31 changes: 14 additions & 17 deletions src/lib/proxy_transform.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use actix::Actor;
use actix_web::client::ClientConnector;
use actix_web::client::ClientRequestBuilder;
use actix_web::http::StatusCode;
use actix_web::http::{header, HeaderMap, Method};
use actix_web::{client, dev, http, Error, HttpMessage, HttpRequest, HttpResponse};
use app_state::AppState;
Expand All @@ -22,27 +23,26 @@ pub fn proxy_transform(
original_request: &HttpRequest<AppState>,
) -> Box<Future<Item = HttpResponse, Error = Error>> {
let outgoing = proxy_req_setup(original_request);
let bind_port = original_request.state().opts.port;
let scheme = &original_request.state().opts.scheme;
let (host, port) = get_host_port(original_request, bind_port);
let req_target = format!("{}://{}:{}", scheme, host, port);

match *original_request.method() {
Method::POST => forward_request_with_body(original_request, outgoing),
_ => forward_request_without_body(original_request, outgoing),
Method::POST => forward_request_with_body(original_request, req_target, outgoing),
_ => forward_request_without_body(original_request, req_target, outgoing),
}
}

pub fn proxy_req_setup(original_request: &HttpRequest<AppState>) -> ClientRequestBuilder {
debug!(
"incoming proxy_req = {}",
original_request.uri().to_string()
"incoming proxy_req = {:?}",
original_request.connection_info().host()
);

let original_req_headers = original_request.headers().clone();
let next_host = original_request.uri().clone();
let req_host = next_host.host().unwrap_or("");
let req_port = next_host.port().unwrap_or(80);
let req_target = format!("{}:{}", req_host, req_port);
let cloned = clone_headers(
&original_req_headers,
req_target,
original_request.connection_info().host().to_string(),
original_request.state().opts.target.clone(),
);

Expand Down Expand Up @@ -118,11 +118,13 @@ pub fn proxy_req_setup(original_request: &HttpRequest<AppState>) -> ClientReques
}

pub fn create_outgoing(
status_code: &StatusCode,
resp_headers: &HeaderMap,
target: String,
replacer: String,
) -> dev::HttpResponseBuilder {
let mut outgoing = HttpResponse::Ok();
outgoing.status(*status_code);
let c = clone_headers(resp_headers, target, replacer);
debug!("Headers for response = {:#?}", c);
// Copy headers from backend response to main response
Expand All @@ -133,13 +135,8 @@ pub fn create_outgoing(
}

pub fn get_host_port(incoming_request: &HttpRequest<AppState>, bind_port: u16) -> (String, u16) {
let split = match incoming_request.headers().get(header::HOST) {
Some(h) => {
let output: Vec<&str> = h.to_str().expect("host to str").split(":").collect();
output
}
None => vec![],
};
let info = incoming_request.connection_info();
let split: Vec<&str> = info.host().split(":").collect();

match (split.get(0), split.get(1)) {
(Some(h), Some(p)) => (h.to_string(), p.parse().expect("parsed port")),
Expand Down
1 change: 1 addition & 0 deletions src/lib/proxy_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ where
let next_body: String = String::from(body_content);

Ok(create_outgoing(
&proxy_response.status(),
&proxy_response.headers(),
target_domain.to_string(),
req_target,
Expand Down
6 changes: 2 additions & 4 deletions src/lib/with_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,23 @@ use proxy_transform::create_outgoing;
///
pub fn forward_request_with_body(
_req: &HttpRequest<AppState>,
req_target: String,
mut outgoing: ClientRequestBuilder,
) -> Box<Future<Item = HttpResponse, Error = Error>> {
let next_target = _req.state().opts.target.clone();
let next_host = _req.uri().clone();
let output = _req.body().from_err().and_then(move |incoming_body| {
outgoing
.body(incoming_body)
.unwrap()
.send()
.map_err(Error::from)
.and_then(move |proxy_response| {
let req_host = next_host.host().unwrap_or("");
let req_port = next_host.port().unwrap_or(80);
let req_target = format!("{}:{}", req_host, req_port);
proxy_response
.body()
.from_err()
.and_then(move |proxy_response_body| {
Ok(create_outgoing(
&proxy_response.status(),
&proxy_response.headers(),
next_target.to_string(),
req_target,
Expand Down
14 changes: 7 additions & 7 deletions src/lib/without_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use rewrites::{replace_host, RewriteContext};
///
pub fn forward_request_without_body(
incoming_request: &HttpRequest<AppState>,
req_target: String,
mut outgoing: ClientRequestBuilder,
) -> Box<Future<Item = HttpResponse, Error = Error>> {
let target_domain = incoming_request.state().opts.target.clone();
Expand Down Expand Up @@ -48,6 +49,7 @@ pub fn forward_request_without_body(
proxy_response,
host,
port,
req_target,
target_domain,
rewrites,
))
Expand All @@ -56,8 +58,7 @@ pub fn forward_request_without_body(
// so we just stream it back to the client
Either::B(pass_through_response(
proxy_response,
host,
port,
req_target.clone(),
target_domain,
))
}
Expand All @@ -67,13 +68,11 @@ pub fn forward_request_without_body(
/// Pass-through response
fn pass_through_response(
proxy_response: ClientResponse,
host: String,
port: u16,
req_target: String,
target_domain: String,
) -> Box<Future<Item = HttpResponse, Error = Error>> {
let req_target = format!("{}:{}", host, port);

let output = ok(create_outgoing(
&proxy_response.status(),
&proxy_response.headers(),
target_domain.to_string(),
req_target,
Expand All @@ -92,6 +91,7 @@ fn response_from_rewrite(
proxy_response: ClientResponse,
req_host: String,
req_port: u16,
req_target: String,
target_domain: String,
rewrites: RewriteFns,
) -> Box<Future<Item = HttpResponse, Error = Error>> {
Expand All @@ -102,7 +102,6 @@ fn response_from_rewrite(
.and_then(move |body| {
use std::str;

let req_target = format!("{}:{}", req_host, req_port);
let context = RewriteContext {
host_to_replace: target_domain.clone(),
target_host: req_host,
Expand All @@ -119,6 +118,7 @@ fn response_from_rewrite(
debug!("creating response");

Ok(create_outgoing(
&proxy_response.status(),
&proxy_response.headers(),
target_domain.to_string(),
req_target,
Expand Down
3 changes: 1 addition & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ extern crate serde_yaml;
extern crate tempdir;
extern crate url;

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate log;

use bs::options::ProgramOptions;
use bs::system;
Expand Down
41 changes: 41 additions & 0 deletions tests/proxy_transform_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,44 @@ fn test_replace_links() {

assert_eq!(resp_body, expected_body);
}

#[test]
fn test_redirect() {
let (target, target_addr) = get_test_server(|app| {
app.handler(|req: &HttpRequest| {
let srv_address = req
.headers()
.get("srv_address")
.expect("missing srv_address header")
.to_str()
.expect("headervalue -> str");

HttpResponse::Found()
.header(header::LOCATION, format!("http://{}/login", srv_address))
.finish()
});
});

let (mut proxy, proxy_address) = get_test_proxy(&target, |app| {
app.handler(proxy_transform);
});

let request = proxy
.get()
.header(header::ACCEPT, TEXT_HTML)
.header("srv_address", target_addr)
.uri(proxy.url("/"))
.finish()
.expect("finish request");

let (resp, _resp_body) = get_resp(&mut proxy, request);
let expected_redirect = format!("http://{}/login", proxy_address);
let _actual_redirect = resp
.headers()
.get(header::LOCATION)
.expect("has location header")
.to_str()
.expect("header->str");
assert_eq!(resp.status(), 302);
// assert_eq!(actual_redirect, expected_redirect);
}

0 comments on commit 8a0a972

Please sign in to comment.