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

[rc] [dev] Dev Server Feature Branch #883

Merged
merged 113 commits into from
Feb 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
2d99521
Proxy proof of concept
EverlastingBugstopper Nov 13, 2019
4e5036d
Proxy the preview service
EverlastingBugstopper Nov 14, 2019
534fcdc
Add formatted output to proxy
EverlastingBugstopper Nov 14, 2019
f273570
Adds host argument to proxy
EverlastingBugstopper Nov 14, 2019
db2cb46
Build before proxying
EverlastingBugstopper Nov 14, 2019
be767a1
Refactor proxy and add IP argument
EverlastingBugstopper Nov 14, 2019
d984b0c
Async proxy
EverlastingBugstopper Nov 19, 2019
6aa6f1f
Sends modified headers to preview
EverlastingBugstopper Nov 19, 2019
7f5c8dd
proxy: Improves code style
EverlastingBugstopper Nov 20, 2019
3f87f03
Merge branch 'avery/a-time-sync' into avery/look-ma-real-headers
EverlastingBugstopper Nov 20, 2019
03e4323
proxy: Handle response headers
EverlastingBugstopper Nov 20, 2019
a7bc973
proxy: Build before proxying
EverlastingBugstopper Nov 20, 2019
c63f9f0
Merge branch 'avery/a-time-sync' into avery/look-ma-real-headers
EverlastingBugstopper Nov 20, 2019
7a63a52
Merge branch 'avery/look-ma-real-headers' into avery/response-headers
EverlastingBugstopper Nov 20, 2019
afac21f
Rename proxy to dev
EverlastingBugstopper Nov 20, 2019
de3fbe8
Merge pull request #890 from cloudflare/avery/proxy-to-dev
EverlastingBugstopper Nov 20, 2019
1c194a2
dev: re-order listening address reference
EverlastingBugstopper Nov 20, 2019
04c4f25
Merge branch 'avery/a-time-sync' into avery/look-ma-real-headers
EverlastingBugstopper Nov 20, 2019
90f41fb
Merge branch 'avery/look-ma-real-headers' into avery/response-headers
EverlastingBugstopper Nov 20, 2019
9095a13
Merge branch 'master' into avery/a-time-sync
EverlastingBugstopper Nov 20, 2019
1cbc145
Merge branch 'avery/a-time-sync' into avery/look-ma-real-headers
EverlastingBugstopper Nov 20, 2019
9540ad3
Merge branch 'avery/look-ma-real-headers' into avery/response-headers
EverlastingBugstopper Nov 20, 2019
0f53a9c
Merge branch 'master' into avery/a-time-sync
EverlastingBugstopper Nov 21, 2019
56087f6
Merge branch 'master' into avery/a-time-sync
EverlastingBugstopper Nov 21, 2019
6a5a226
Merge branch 'avery/a-time-sync' into avery/look-ma-real-headers
EverlastingBugstopper Nov 21, 2019
e1a1ee1
Merge branch 'avery/look-ma-real-headers' into avery/response-headers
EverlastingBugstopper Nov 21, 2019
1840222
Merge branch 'master' into avery/a-time-sync
EverlastingBugstopper Nov 27, 2019
9605937
Refactor wrangler dev
EverlastingBugstopper Nov 27, 2019
f1e4c2d
Adds comments in Host struct
EverlastingBugstopper Nov 27, 2019
594314a
Merge pull request #917 from cloudflare/avery/refactor-dev
EverlastingBugstopper Dec 2, 2019
138ddab
Merge branch 'avery/a-time-sync' into avery/look-ma-real-headers
EverlastingBugstopper Dec 2, 2019
5c7547e
Merge branch 'avery/look-ma-real-headers' into avery/response-headers
EverlastingBugstopper Dec 2, 2019
f931c03
dev: log proof of concept
EverlastingBugstopper Dec 3, 2019
2b2c36d
Merge branch 'master' into avery/a-time-sync
EverlastingBugstopper Dec 9, 2019
b901048
Merge branch 'avery/a-time-sync' into avery/look-ma-real-headers
EverlastingBugstopper Dec 9, 2019
a1c8efd
Merge branch 'avery/look-ma-real-headers' into avery/response-headers
EverlastingBugstopper Dec 9, 2019
79a9dad
Merge branch 'avery/response-headers' into avery/websockets
EverlastingBugstopper Dec 9, 2019
d630000
Update to stable hyper and tokio
EverlastingBugstopper Dec 10, 2019
7125520
Merge branch 'avery/a-time-sync' into avery/look-ma-real-headers
EverlastingBugstopper Dec 10, 2019
010abf9
Merge branch 'avery/look-ma-real-headers' into avery/response-headers
EverlastingBugstopper Dec 10, 2019
fd2ae36
Merge branch 'avery/response-headers' into avery/websockets
EverlastingBugstopper Dec 10, 2019
7ac61f6
use devtools crate for log messages
EverlastingBugstopper Dec 11, 2019
8083946
Merge pull request #947 from cloudflare/avery/devtools-crate
EverlastingBugstopper Dec 11, 2019
f38979c
Use latest devtools-rs commit sha
EverlastingBugstopper Dec 12, 2019
9502afa
Merge pull request #951 from cloudflare/avery/devtools-crate
EverlastingBugstopper Dec 12, 2019
c98907d
Merge branch 'master' into avery/a-time-sync
EverlastingBugstopper Dec 12, 2019
0ed4c55
Remove accidental changelog snippet
EverlastingBugstopper Dec 12, 2019
c0dc4c5
Merge branch 'avery/a-time-sync' into avery/look-ma-real-headers
EverlastingBugstopper Dec 12, 2019
fa24b2f
Merge branch 'avery/look-ma-real-headers' into avery/response-headers
EverlastingBugstopper Dec 12, 2019
25dff43
Remove an unwrap
EverlastingBugstopper Dec 12, 2019
605972a
Split out response header munging to separate function
EverlastingBugstopper Dec 12, 2019
0e3b39d
Merge pull request #886 from cloudflare/avery/response-headers
EverlastingBugstopper Dec 12, 2019
0ad23dc
Merge branch 'avery/look-ma-real-headers' into avery/websockets
EverlastingBugstopper Dec 12, 2019
3ce09c8
Merge branch 'master' into avery/a-time-sync
EverlastingBugstopper Dec 16, 2019
2270767
Replace unwraps with expects
EverlastingBugstopper Dec 16, 2019
5e31a69
Merge branch 'avery/a-time-sync' into avery/look-ma-real-headers
EverlastingBugstopper Dec 16, 2019
3030190
Replace unwrap with expect
EverlastingBugstopper Dec 16, 2019
8f563d0
Merge branch 'avery/look-ma-real-headers' into avery/websockets
EverlastingBugstopper Dec 16, 2019
4b5f367
Replace unwraps with expects
EverlastingBugstopper Dec 16, 2019
6da69bd
Merge branch 'avery/a-time-sync' into avery/look-ma-real-headers
EverlastingBugstopper Dec 16, 2019
0f855be
Merge branch 'avery/look-ma-real-headers' into avery/websockets
EverlastingBugstopper Dec 16, 2019
3533db0
Refactor header munging
EverlastingBugstopper Dec 16, 2019
542c428
Replace clones with to_owneds
EverlastingBugstopper Dec 16, 2019
52808ca
Merge pull request #884 from cloudflare/avery/look-ma-real-headers
EverlastingBugstopper Dec 16, 2019
303012f
Bump hyper version
EverlastingBugstopper Dec 16, 2019
4976fb6
Merge branch 'avery/a-time-sync' into avery/websockets
EverlastingBugstopper Dec 16, 2019
80bf6d9
Color devtools output
EverlastingBugstopper Dec 16, 2019
71f9bb1
Use default port 8787 for wrangler dev
EverlastingBugstopper Dec 16, 2019
2d99489
Merge branch 'avery/a-time-sync' into avery/websockets
EverlastingBugstopper Dec 16, 2019
2bb09c9
Address clippy warnings
EverlastingBugstopper Dec 16, 2019
12d5c3f
Merge branch 'avery/a-time-sync' into avery/websockets
EverlastingBugstopper Dec 16, 2019
116f362
Remove extern crate statements
EverlastingBugstopper Dec 17, 2019
af09338
Rename runtime to tokioruntime
EverlastingBugstopper Dec 17, 2019
64cfff3
rt -> runtime
EverlastingBugstopper Dec 17, 2019
c6df5ee
Handle HTTP response codes
EverlastingBugstopper Dec 17, 2019
b3b5ea7
Merge pull request #968 from cloudflare/avery/show-response-code
EverlastingBugstopper Dec 17, 2019
be9e571
Merge branch 'avery/a-time-sync' into avery/websockets
EverlastingBugstopper Dec 17, 2019
8ab9777
Add extra info in log message about parsing devtools event
EverlastingBugstopper Dec 17, 2019
c885557
Merge pull request #923 from cloudflare/avery/websockets
EverlastingBugstopper Dec 17, 2019
8a701d5
Remove response code println
EverlastingBugstopper Dec 17, 2019
7e0e683
Merge branch 'master' into avery/a-time-sync
EverlastingBugstopper Jan 6, 2020
5e139fe
Fixup clippy warnings
EverlastingBugstopper Jan 6, 2020
528029c
Adds environment support to dev server
EverlastingBugstopper Jan 6, 2020
e3b6c96
Fixup clippy warnings
EverlastingBugstopper Jan 6, 2020
6032be1
Merge branch 'master' into avery/a-time-sync
EverlastingBugstopper Jan 8, 2020
423a84d
Switch from ws-rs to tungstenite-rs
EverlastingBugstopper Jan 8, 2020
6aa8b0e
wip: Add keepalive timer
EverlastingBugstopper Jan 8, 2020
942b3c6
Switch from tungstenite-rs to tokio-tungstenite
EverlastingBugstopper Jan 9, 2020
37eb258
Adds support for live reload to wrangler dev
EverlastingBugstopper Jan 14, 2020
1433607
uses latest chrome-devtools-rs
EverlastingBugstopper Jan 15, 2020
3e9681f
Use one runtime
EverlastingBugstopper Jan 21, 2020
6f79676
Merge pull request #984 from cloudflare/avery/denv
EverlastingBugstopper Jan 22, 2020
37f40bb
Merge branch 'avery/a-time-sync' into avery/totally-metal
EverlastingBugstopper Jan 22, 2020
64d2c59
Merge branch 'avery/totally-metal' into avery/dev-dev
EverlastingBugstopper Jan 22, 2020
030ce2e
Merge pull request #1002 from cloudflare/avery/dev-dev
EverlastingBugstopper Jan 22, 2020
8808cdf
cargo fmt
EverlastingBugstopper Jan 22, 2020
fe8c0bb
Merge branch 'avery/totally-metal' into avery/new-reload
EverlastingBugstopper Jan 22, 2020
c9e03ec
cargo fmt
EverlastingBugstopper Jan 22, 2020
3c24b39
Merge branch 'avery/totally-metal' into avery/new-reload
EverlastingBugstopper Jan 22, 2020
4a9f8f3
cargo fmt
EverlastingBugstopper Jan 22, 2020
24c44e8
Merge branch 'avery/totally-metal' into avery/new-reload
EverlastingBugstopper Jan 22, 2020
d5e535d
Dont suppress errors and return ! from keep_alive
EverlastingBugstopper Jan 22, 2020
b4b8bd0
Merge branch 'avery/totally-metal' into avery/new-reload
EverlastingBugstopper Jan 22, 2020
e585c20
Merge pull request #991 from cloudflare/avery/totally-metal
EverlastingBugstopper Jan 29, 2020
c639c1e
move color handling to chrome-devtools-rs
EverlastingBugstopper Jan 30, 2020
a6f2305
Merge pull request #1019 from cloudflare/avery/devtools-cleanup
EverlastingBugstopper Jan 30, 2020
ed5cffb
Merge branch 'master' into avery/a-time-sync
EverlastingBugstopper Feb 6, 2020
ea481c5
Merge branch 'avery/a-time-sync' into avery/new-reload
EverlastingBugstopper Feb 6, 2020
2b7a556
Use published packages
EverlastingBugstopper Feb 6, 2020
19d8328
Merge branch 'avery/a-time-sync' into avery/new-reload
EverlastingBugstopper Feb 6, 2020
834918d
Rename variables and remove std::mem
EverlastingBugstopper Feb 6, 2020
a45df49
Merge pull request #999 from cloudflare/avery/new-reload
EverlastingBugstopper Feb 6, 2020
b5c8ad1
Merge branch 'master' into avery/a-time-sync
EverlastingBugstopper Feb 6, 2020
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
2,089 changes: 1,087 additions & 1,002 deletions Cargo.lock

Large diffs are not rendered by default.

54 changes: 31 additions & 23 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,43 +12,51 @@ build = "build.rs"

[dependencies]
atty = "0.2.11"
base64 = "0.10.1"
binary-install = "0.0.3-alpha"
chrome-devtools-rs = "0.0.0-alpha.0"
chrono = "0.4.9"
clap = "2.32.0"
cloudflare = "0.6.2"
config = "0.9.2"
console = "0.7.5"
console = "0.9.1"
data-encoding = "2.1.2"
dirs = "1.0.5"
cloudflare = "0.6.2"
env_logger = "0.6.1"
exitfailure = "0.5.1"
failure = "0.1.5"
flate2 = "1.0.7"
fs2 = "0.4.3"
futures = "0.3"
futures-util = "0.3"
http = "0.2.0"
hyper = "0.13.1"
hyper-tls = "0.4.0"
ignore = "0.4.10"
indicatif = "0.13.0"
lazy_static = "1.3.0"
log = "0.4.6"
openssl = { version = '0.10.11', optional = true }
notify = "4.0.12"
number_prefix = "0.3.0"
openssl = { version = '0.10.26', optional = true }
percent-encoding = "1.0.1"
prettytable-rs = "0.8.0"
rand = "0.6.5"
regex = "1"
reqwest = { version = "0.10.1", features = ["blocking", "json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.39"
serde_with = "1.3.1"
sha2 = "0.8.0"
tempfile = "3.1.0"
text_io = "0.1.7"
tokio = { version = "0.2", default-features = false, features = ["io-std", "time"] }
tokio-tungstenite = { version = "0.10.1", features = ["tls"] }
toml = "0.5.5"
url = "2.1.0"
uuid = { version = "0.8", features = ["v4"] }
which = "2.0.1"
rand = "0.6.5"
fs2 = "0.4.3"
number_prefix = "0.3.0"
flate2 = "1.0.7"
base64 = "0.10.1"
lazy_static = "1.3.0"
text_io = "0.1.7"
exitfailure = "0.5.1"
prettytable-rs = "0.8.0"
notify = "4.0.12"
ws = "0.9.0"
url = "2.1.0"
percent-encoding = "1.0.1"
http = "0.2.0"
regex = "1"
sha2 = "0.8.0"
data-encoding = "2.1.2"
ignore = "0.4.10"
tempfile = "3.1.0"
indicatif = "0.13.0"
serde_with = "1.3.1"

[dev-dependencies]
assert_cmd = "0.11.1"
Expand Down
Empty file added logs/connection.log
Empty file.
58 changes: 58 additions & 0 deletions src/commands/dev/headers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const HEADER_PREFIX: &str = "cf-ew-raw-";

use std::str::FromStr;

use hyper::header::{HeaderMap, HeaderName};
use hyper::http::request::Parts as RequestParts;
use hyper::http::response::Parts as ResponseParts;
use hyper::http::status::StatusCode;

pub fn structure_request(parts: &mut RequestParts) {
prepend_request_headers_prefix(parts)
}

pub fn destructure_response(parts: &mut ResponseParts) -> Result<(), failure::Error> {
set_response_status(parts)?;
strip_response_headers_prefix(parts)
}

fn prepend_request_headers_prefix(parts: &mut RequestParts) {
let mut headers: HeaderMap = HeaderMap::new();

for header in &parts.headers {
let (name, value) = header;
let forward_header = format!("{}{}", HEADER_PREFIX, name);
let header_name = HeaderName::from_bytes(forward_header.as_bytes())
.unwrap_or_else(|_| panic!("Could not create header name for {}", name));
headers.insert(header_name, value.clone());
}
parts.headers = headers;
}

fn strip_response_headers_prefix(parts: &mut ResponseParts) -> Result<(), failure::Error> {
let mut headers = HeaderMap::new();

for header in &parts.headers {
let (name, value) = header;
let name = name.as_str();
if name.starts_with(HEADER_PREFIX) {
let header_name = &name[HEADER_PREFIX.len()..];
let header_name = HeaderName::from_bytes(header_name.as_bytes())?;
headers.insert(header_name, value.clone());
}
}
parts.headers = headers;
Ok(())
}

fn set_response_status(parts: &mut ResponseParts) -> Result<(), failure::Error> {
let status = parts
.headers
.get("cf-ew-status")
.expect("Could not determine status code of response");
// status will be "404 not found" or "200 ok"
// we need to split that string to create hyper's status code
let status_vec: Vec<&str> = status.to_str()?.split(' ').collect();
parts.status = StatusCode::from_str(status_vec[0])?;
Ok(())
}
198 changes: 198 additions & 0 deletions src/commands/dev/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
mod server_config;
mod socket;
use server_config::ServerConfig;
mod headers;
use headers::{destructure_response, structure_request};
mod watch;
use watch::watch_for_changes;

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

use chrono::prelude::*;

use hyper::client::{HttpConnector, ResponseFuture};
use hyper::header::{HeaderName, HeaderValue};

use hyper::http::uri::InvalidUri;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Client as HyperClient, Request, Response, Server, Uri};

use hyper_tls::HttpsConnector;

use tokio::runtime::Runtime as TokioRuntime;

use uuid::Uuid;

use crate::commands;
use crate::commands::preview::upload;

use crate::settings::global_user::GlobalUser;
use crate::settings::toml::Target;

use crate::terminal::emoji;

const PREVIEW_HOST: &str = "rawhttp.cloudflareworkers.com";

pub fn dev(
target: Target,
user: Option<GlobalUser>,
host: Option<&str>,
port: Option<&str>,
ip: Option<&str>,
verbose: bool,
) -> Result<(), failure::Error> {
commands::build(&target)?;
let server_config = ServerConfig::new(host, ip, port)?;
let session_id = get_session_id()?;
let preview_id = get_preview_id(
target.clone(),
user.clone(),
&server_config,
&session_id.clone(),
verbose,
)?;
let preview_id = Arc::new(Mutex::new(preview_id));

{
let session_id = session_id.clone();
let preview_id = preview_id.clone();
let server_config = server_config.clone();
thread::spawn(move || {
watch_for_changes(
target,
user,
&server_config,
Arc::clone(&preview_id),
&session_id,
verbose,
)
});
}

let mut runtime = TokioRuntime::new()?;

let devtools_listener = socket::listen(&session_id);
let server = serve(server_config, Arc::clone(&preview_id));

let runners = futures::future::join(devtools_listener, server);

runtime.block_on(async {
let (devtools_listener, server) = runners.await;
devtools_listener?;
server
})
}

async fn serve(
server_config: ServerConfig,
preview_id: Arc<Mutex<String>>,
) -> Result<(), failure::Error> {
// set up https client to connect to the preview service
let https = HttpsConnector::new();
let client = HyperClient::builder().build::<_, Body>(https);

let listening_address = server_config.listening_address.clone();
// create a closure that hyper will use later to handle HTTP requests
let make_service = make_service_fn(move |_| {
let client = client.to_owned();
let preview_id = preview_id.lock().unwrap().to_owned();
let server_config = server_config.to_owned();
async move {
Ok::<_, failure::Error>(service_fn(move |req| {
let client = client.to_owned();
let preview_id = preview_id.to_owned();
let server_config = server_config.to_owned();
async move {
let resp =
preview_request(req, client, preview_id.to_owned(), server_config).await?;
let (mut parts, body) = resp.into_parts();

destructure_response(&mut parts)?;
let resp = Response::from_parts(parts, body);
Ok::<_, failure::Error>(resp)
}
}))
}
});

let server = Server::bind(&listening_address.address).serve(make_service);
println!("{} Listening on http://{}", emoji::EAR, listening_address);
if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
Ok(())
}

fn get_preview_url(path_string: &str) -> Result<Uri, InvalidUri> {
format!("https://{}{}", PREVIEW_HOST, path_string).parse()
}

fn get_path_as_str(uri: &Uri) -> String {
uri.path_and_query()
.map(|x| x.as_str())
.unwrap_or("")
.to_string()
}

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

let path = get_path_as_str(&parts.uri);
let method = parts.method.to_string();
let now: DateTime<Local> = Local::now();
let preview_id = &preview_id;

structure_request(&mut parts);

parts.headers.insert(
HeaderName::from_static("host"),
HeaderValue::from_static(PREVIEW_HOST),
);

parts.headers.insert(
HeaderName::from_static("cf-ew-preview"),
HeaderValue::from_str(preview_id).expect("Could not create header for preview id"),
);

parts.uri = get_preview_url(&path).expect("Could not get preview url");

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

println!(
"[{}] \"{} {}{} {:?}\"",
now.format("%Y-%m-%d %H:%M:%S"),
method,
server_config.host,
path,
req.version()
);
client.request(req)
}

fn get_session_id() -> Result<String, failure::Error> {
Ok(Uuid::new_v4().to_simple().to_string())
}

pub fn get_preview_id(
mut target: Target,
user: Option<GlobalUser>,
server_config: &ServerConfig,
session_id: &str,
verbose: bool,
) -> Result<String, failure::Error> {
let sites_preview = false;
let script_id = upload(&mut target, user.as_ref(), sites_preview, verbose)?;
Ok(format!(
"{}{}{}{}",
&script_id,
session_id,
server_config.host.is_https() as u8,
server_config.host
))
}
51 changes: 51 additions & 0 deletions src/commands/dev/server_config/host.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use std::fmt;

use failure::format_err;
use url::Url;

#[derive(Clone)]
pub struct Host {
url: Url,
}

impl Host {
pub fn new(host: &str) -> Result<Self, failure::Error> {
// try to create a url from host
let url = match Url::parse(&host) {
Ok(host) => Ok(host),
// if it doesn't work, it might be because there was no scheme
// default to https
Err(_) => Url::parse(&format!("https://{}", host)),
}?;

// validate scheme
let scheme = url.scheme();
if scheme != "http" && scheme != "https" {
failure::bail!("Your host scheme must be either http or https")
}

// validate host
let host = url.host_str().ok_or_else(|| format_err!("Invalid host, accepted formats are example.com, http://example.com, or https://example.com"))?;

// recreate url without any trailing path
let url = Url::parse(&format!("{}://{}", scheme, host))?;
Ok(Host { url })
}

pub fn is_https(&self) -> bool {
self.url.scheme() == "https"
}
}

impl fmt::Display for Host {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
self.url
.host_str()
.expect("could not parse host")
.to_string()
)
}
}
Loading