#http #tower #axum #reverse #proxy

reverse-proxy-service

Tower service for reverse proxy

3 releases

0.1.2 Mar 7, 2023
0.1.1 Dec 27, 2022
0.1.0 Dec 27, 2022

#387 in HTTP server

Download history 36/week @ 2022-12-22 11/week @ 2022-12-29 8/week @ 2023-01-05 5/week @ 2023-01-12 2/week @ 2023-01-19 8/week @ 2023-01-26 5/week @ 2023-02-02 9/week @ 2023-02-09 10/week @ 2023-02-16 2/week @ 2023-02-23 26/week @ 2023-03-02 10/week @ 2023-03-09 10/week @ 2023-03-16

51 downloads per month

MIT/Apache

41KB
933 lines

reverse-proxy-service is tower's Services that perform reverse proxy.

These Services are implemented to be used in axum, but they can be used in a more general situation.

See the documentation.


lib.rs:

reverse-proxy-service is tower Services that performs "reverse proxy" with various rewriting rules.

Internally these services use [hyper::Client] to send an incoming request to the another server. The connector for a client can be HttpConnector, HttpsConnector, or any ones whichever you want.

Examples

There are two types of services, [OneshotService] and [ReusedService]. The [OneshotService] owns the Client, while the [ReusedService] shares the Client via Arc.

General usage

# async fn run_test() {
use reverse_proxy_service::ReusedServiceBuilder;
use reverse_proxy_service::{ReplaceAll, ReplaceN};

use hyper::body::Body;
use http::Request;
use tower_service::Service as _;

let svc_builder = reverse_proxy_service::builder_http("example.com:1234").unwrap();

let req1 = Request::builder()
    .method("GET")
    .uri("https://myserver.com/foo/bar/foo")
    .body(Body::empty())
    .unwrap();

// Clones Arc<Client>
let mut svc1 = svc_builder.build(ReplaceAll("foo", "baz"));
// http://example.com:1234/baz/bar/baz
let _res = svc1.call(req1).await.unwrap();

let req2 = Request::builder()
    .method("POST")
    .uri("https://myserver.com/foo/bar/foo")
    .header("Content-Type", "application/x-www-form-urlencoded")
    .body(Body::from("key=value"))
    .unwrap();

let mut svc2 = svc_builder.build(ReplaceN("foo", "baz", 1));
// http://example.com:1234/baz/bar/foo
let _res = svc2.call(req2).await.unwrap();
# }

In this example, the svc1 and svc2 shares the same Client, holding the Arc<Client>s inside them.

For more information of rewriting rules (ReplaceAll, ReplaceN etc.), see the documentations of [rewrite].

With axum

use reverse_proxy_service::ReusedServiceBuilder;
use reverse_proxy_service::{TrimPrefix, AppendSuffix, Static};

use axum::Router;

#[tokio::main]
async fn main() {
    let host1 = reverse_proxy_service::builder_http("example.com").unwrap();
    let host2 = reverse_proxy_service::builder_http("example.net:1234").unwrap();

    let app = Router::new()
        .route_service("/healthcheck", host1.build(Static("/")))
        .route_service("/users/*path", host1.build(TrimPrefix("/users")))
        .route_service("/posts", host2.build(AppendSuffix("/")));

    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

Return Types

The return type (Future::Output) of [ReusedService] and [OneshotService] is Result<Result<Response, Error>, Infallible>. This is because axum's Router accepts only such Services.

The [Error] type implements IntoResponse if you enable the axumfeature. It returns an empty body, with the status code INTERNAL_SERVER_ERROR. The description of this error will be logged out at error level in the into_response() method.

Features

  • http1: default on
  • http2: default off
  • https: default off
  • axum: default off

You must turn on either http1or http2. You cannot use the services if, for example, only the https feature is on.

Dependencies

~5–12MB
~221K SLoC