1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use std::net::SocketAddr;

use http::{Request, Response, StatusCode};
use hyper::{Body, Server, service::{make_service_fn, service_fn}, server::conn::AddrStream};


#[derive(Clone)]
pub struct HttpServerOpt {
  pub listen: SocketAddr,
  pub redirect: Option<String>,
}

pub async fn launch_http_server<F> (http_server_opt: HttpServerOpt, func: F) -> Result<(), Box<dyn std::error::Error>> 
where
    F: Fn()
{
  let HttpServerOpt{listen, redirect} = http_server_opt;

  // 80ポートにhttpアクセスが来た時にリダイレクトしたりするため
  if let Some(redirect) = redirect {
    println!("redirect to {}", redirect);
    let http_make_service = make_service_fn(move |_conn: &AddrStream| {
        let location = redirect.clone().to_owned();
        let service = service_fn(move |req| {
            redirect_to_https(location.clone(), req)
        });
        async move { Ok::<_, http::Error>(service) }
    });
    let http_server = Server::bind(&listen).serve(http_make_service);
    println!("Listening on http://{}", listen);
    func();
    let _ = http_server.await?;
  
  } else {
    let http_make_service = make_service_fn(move |_conn: &AddrStream| {
        let service = service_fn(move |req| {
            not_redirect_to_https(req)
        });
        async move { Ok::<_, http::Error>(service) }
    });
    let http_server = Server::bind(&listen).serve(http_make_service);
    println!("Listening on http://{}", listen);
    func();
    let _ = http_server.await?;
  
  }
  Ok(())
}

async fn redirect_to_https(
  location: String,
  _req: Request<Body>,
) -> Result<Response<Body>, http::Error> {
  let mut builder = Response::builder();
    builder = builder
        .status(StatusCode::PERMANENT_REDIRECT)
        .header("Location", location);
  // info!("location {}", location);
  builder.body(Body::empty())
}

async fn not_redirect_to_https(
  _req: Request<Body>,
) -> Result<Response<Body>, http::Error> {
  Response::builder().body(Body::empty())
}