Skip to content
This repository has been archived by the owner on Aug 3, 2023. It is now read-only.

Commit

Permalink
Added https to edge
Browse files Browse the repository at this point in the history
  • Loading branch information
jspspike committed Aug 6, 2020
1 parent e1206c2 commit 1f5881f
Show file tree
Hide file tree
Showing 9 changed files with 231 additions and 88 deletions.
55 changes: 43 additions & 12 deletions src/commands/dev/edge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ mod server;
mod setup;
mod watch;

use server::serve;
use setup::{upload, Session};
use watch::watch_for_changes;

Expand All @@ -20,6 +19,7 @@ pub fn dev(
user: GlobalUser,
server_config: ServerConfig,
deploy_config: DeployConfig,
http: bool,
verbose: bool,
) -> Result<(), failure::Error> {
let session = Session::new(&target, &user, &deploy_config)?;
Expand Down Expand Up @@ -53,17 +53,48 @@ pub fn dev(

let mut runtime = TokioRuntime::new()?;
runtime.block_on(async {
let devtools_listener = tokio::spawn(socket::listen(session.websocket_url));
let server = tokio::spawn(serve(
server_config,
Arc::clone(&preview_token),
session.host,
));
let res = tokio::try_join!(async { devtools_listener.await? }, async { server.await? });

match res {
Ok(_) => Ok(()),
Err(e) => Err(e),
let devtools_listener = tokio::spawn(socket::listen(session.clone().websocket_url));
if http {
start_http(server_config, preview_token, session.clone()).await?;
} else {
start_https(server_config, preview_token, session.clone()).await;
}

//let res = tokio::try_join!(async { devtools_listener.await? }, async { server.await? });
devtools_listener.await?
})
}

async fn start_http(
server_config: ServerConfig,
preview_token: Arc<Mutex<String>>,
session: Session,
) -> Result<(), failure::Error> {
let server = tokio::spawn(server::http(
server_config,
Arc::clone(&preview_token),
session.host,
));

server.await?
}

async fn start_https(
server_config: ServerConfig,
preview_token: Arc<Mutex<String>>,
session: Session,
) {
let mut server = tokio::spawn(server::https(
server_config.clone(),
Arc::clone(&preview_token),
session.host.clone(),
));

while server.await.is_ok() {
server = tokio::spawn(server::https(
server_config.clone(),
Arc::clone(&preview_token),
session.host.clone(),
));
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use super::preview_request;
use crate::commands::dev::server_config::ServerConfig;
use crate::commands::dev::utils::get_path_as_str;
use crate::terminal::emoji;

use std::sync::{Arc, Mutex};

use chrono::prelude::*;
use hyper::client::{HttpConnector, ResponseFuture};
use hyper::header::{HeaderName, HeaderValue};
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Client as HyperClient, Request, Server};
use hyper_rustls::HttpsConnector;

pub(super) async fn serve(
pub async fn http(
server_config: ServerConfig,
preview_token: Arc<Mutex<String>>,
host: String,
Expand Down Expand Up @@ -44,6 +43,7 @@ pub(super) async fn serve(
client,
preview_token.to_owned(),
host.clone(),
true,
)
.await?;

Expand All @@ -64,38 +64,10 @@ pub(super) async fn serve(

let server = Server::bind(&listening_address).serve(make_service);
println!("{} Listening on http://{}", emoji::EAR, listening_address);

if let Err(e) = server.await {
eprintln!("server error: {}", e)
eprintln!("{}", e);
}
Ok(())
}

fn preview_request(
req: Request<Body>,
client: HyperClient<HttpsConnector<HttpConnector>>,
preview_token: String,
host: String,
) -> ResponseFuture {
let (mut parts, body) = req.into_parts();

let path = get_path_as_str(&parts.uri);

parts.headers.insert(
HeaderName::from_static("host"),
HeaderValue::from_str(&host).expect("Could not create host header"),
);

parts.headers.insert(
HeaderName::from_static("cf-workers-preview-token"),
HeaderValue::from_str(&preview_token).expect("Could not create token header"),
);

// TODO: figure out how to http _or_ https
parts.uri = format!("https://{}{}", host, path)
.parse()
.expect("Could not construct preview url");

let req = Request::from_parts(parts, body);

client.request(req)
Ok(())
}
98 changes: 98 additions & 0 deletions src/commands/dev/edge/server/https.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use super::preview_request;
use crate::commands::dev::server_config::ServerConfig;
use crate::commands::dev::tls;
use crate::commands::dev::utils::get_path_as_str;
use crate::terminal::{emoji, message};

use std::sync::{Arc, Mutex};

use chrono::prelude::*;
use futures_util::{
future::TryFutureExt,
stream::{StreamExt, TryStreamExt},
};
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Client as HyperClient, Request, Server};
use hyper_rustls::HttpsConnector;
use tokio::net::TcpListener;

pub async fn https(
server_config: ServerConfig,
preview_token: Arc<Mutex<String>>,
host: String,
) -> Result<(), failure::Error> {
tls::generate_cert()?;

// set up https client to connect to the preview service
let https = HttpsConnector::new();
let client = HyperClient::builder().build::<_, Body>(https);

// create a closure that hyper will use later to handle HTTP requests
let service = make_service_fn(move |_| {
let client = client.to_owned();
let preview_token = preview_token.to_owned();
let host = host.to_owned();

async move {
Ok::<_, failure::Error>(service_fn(move |req| {
let client = client.to_owned();
let preview_token = preview_token.lock().unwrap().to_owned();
let host = host.to_owned();
let version = req.version();
let (parts, body) = req.into_parts();
let req_method = parts.method.to_string();
let now: DateTime<Local> = Local::now();
let path = get_path_as_str(&parts.uri);
async move {
let resp = preview_request(
Request::from_parts(parts, body),
client,
preview_token.to_owned(),
host.clone(),
false,
)
.await?;

println!(
"[{}] {} {}{} {:?} {}",
now.format("%Y-%m-%d %H:%M:%S"),
req_method,
host,
path,
version,
resp.status()
);
Ok::<_, failure::Error>(resp)
}
}))
}
});

let listening_address = server_config.listening_address;

let mut tcp = TcpListener::bind(&listening_address).await?;
let tls_acceptor = tls::get_tls_acceptor()?;
let incoming_tls_stream = tcp
.incoming()
.map_err(|e| tls::io_error(format!("Incoming connection failed: {:?}", e)))
.and_then(move |s| {
tls_acceptor
.accept(s)
.map_err(|e| tls::io_error(format!("Incoming connection failed: {:?}", e)))
})
.boxed();

let server = Server::builder(tls::HyperAcceptor {
acceptor: incoming_tls_stream,
})
.serve(service);

println!("{} Listening on https://{}", emoji::EAR, listening_address);
message::info("Generated certifiacte is not verified, browsers will give a warning and curl will require `--inscure`");

if let Err(e) = server.await {
eprintln!("{}", e);
}

Ok(())
}
46 changes: 46 additions & 0 deletions src/commands/dev/edge/server/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
mod http;
mod https;

pub use self::http::http;
pub use self::https::https;

use crate::commands::dev::utils::get_path_as_str;

use hyper::client::{HttpConnector, ResponseFuture};
use hyper::header::{HeaderName, HeaderValue};
use hyper::{Body, Client as HyperClient, Request};
use hyper_rustls::HttpsConnector;

fn preview_request(
req: Request<Body>,
client: HyperClient<HttpsConnector<HttpConnector>>,
preview_token: String,
host: String,
http: bool,
) -> ResponseFuture {
let (mut parts, body) = req.into_parts();

let path = get_path_as_str(&parts.uri);

parts.headers.insert(
HeaderName::from_static("host"),
HeaderValue::from_str(&host).expect("Could not create host header"),
);

parts.headers.insert(
HeaderName::from_static("cf-workers-preview-token"),
HeaderValue::from_str(&preview_token).expect("Could not create token header"),
);

parts.uri = if http {
format!("http://{}{}", host, path)
} else {
format!("https://{}{}", host, path)
}
.parse()
.expect("Could not construct preview url");

let req = Request::from_parts(parts, body);

client.request(req)
}
13 changes: 3 additions & 10 deletions src/commands/dev/gcs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,11 @@ pub fn dev(
// and we must block the main thread on the completion of
// said futures
runtime.block_on(async {
let mut running = true;
let devtools_listener = tokio::spawn(socket::listen(socket_url.clone()));
let mut server = tokio::spawn(serve(server_config.clone(), Arc::clone(&preview_id)));

while running {
let server = tokio::spawn(serve(server_config.clone(), Arc::clone(&preview_id)));

//let res = tokio::try_join!(async { devtools_listener.await? }, async { server.await? });
let res = server.await;
running = match res {
Ok(_) => false,
Err(_) => true,
}
while server.await.is_ok() {
server = tokio::spawn(serve(server_config.clone(), Arc::clone(&preview_id)));
}

devtools_listener.await?
Expand Down
Loading

0 comments on commit 1f5881f

Please sign in to comment.