Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OSX port scan and error handling #89

Merged
merged 5 commits into from Aug 19, 2019
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -9,7 +9,7 @@ categories = ["network-programming", "web-programming::http-server"]
license = "MIT"
build = "build.rs"
# Remember to also update in appveyor.yml
version = "1.5.1"
version = "1.5.2"
# Remember to also update in http.md
authors = ["thecoshman <rust@thecoshman.com>",
"nabijaczleweli <nabijaczleweli@gmail.com>",
@@ -1,4 +1,4 @@
version: 1.5.1-{build}
version: 1.5.2-{build}

skip_tags: false

@@ -22,21 +22,21 @@ build: off
build_script:
- git submodule update --init --recursive
- cargo build --verbose --release
- cp target\release\http.exe http-v1.5.1.exe
- strip --strip-all --remove-section=.comment --remove-section=.note http-v1.5.1.exe
- makensis -DHTTP_VERSION=v1.5.1 "/X!include \"EnvVarUpdate.nsh\"" install.nsi
- cp target\release\http.exe http-v1.5.2.exe
- strip --strip-all --remove-section=.comment --remove-section=.note http-v1.5.2.exe
- makensis -DHTTP_VERSION=v1.5.2 "/X!include \"EnvVarUpdate.nsh\"" install.nsi

test: off
test_script:
- cargo test --verbose --release

artifacts:
- path: http-v1.5.1.exe
- path: http v1.5.1 installer.exe
- path: http-v1.5.2.exe
- path: http v1.5.2 installer.exe

deploy:
provider: GitHub
artifact: /http.*v1.5.1.*\.exe/
artifact: /http.*v1.5.2.*\.exe/
auth_token:
secure: ZTXvCrv9y01s7Hd60w8W7NaouPnPoaw9YJt9WhWQ2Pep8HLvCikt9Exjkz8SGP9P
on:
@@ -1,76 +1,42 @@
use self::super::util::uppercase_first;
use std::borrow::Cow;
use std::io::Write;
use std::fmt;


/// Enum representing all possible ways the application can fail.
/// An application failure.
///
/// # Examples
///
/// ```
/// # use https::Error;
/// assert_eq!(Error {
/// desc: "network",
/// op: "write",
/// more: "full buffer".into(),
/// }.to_string(),
/// "Writing network failed: full buffer.");
/// ```
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum Error {
/// An I/O error occured.
pub struct Error {
/// The file the I/O operation regards.
pub desc: &'static str,
/// The failed operation.
///
/// This includes higher-level I/O errors like FS ones.
Io {
/// The file the I/O operation regards.
desc: &'static str,
/// The failed operation.
///
/// This should be lowercase and imperative ("create", "open").
op: &'static str,
/// Additional data.
more: Option<Cow<'static, str>>,
},
/// This should be lowercase and imperative ("create", "open").
pub op: &'static str,
/// Additional data.
pub more: Cow<'static, str>,
}

impl Error {
/// Write the error message to the specified output stream.
///
/// # Examples
///
/// ```
/// # use https::Error;
/// # use std::iter::FromIterator;
/// let mut out = Vec::new();
/// Error::Io {
/// desc: "network",
/// op: "write",
/// more: Some("full buffer"),
/// }.print_error(&mut out);
/// assert_eq!(String::from_iter(out.iter().map(|&i| i as char)),
/// "Writing network failed: full buffer.\n".to_string());
/// ```
pub fn print_error<W: Write>(&self, err_out: &mut W) {
match *self {
Error::Io { desc, op, ref more } => {
// Strip the last 'e', if any, so we get correct inflection for continuous times
let op = uppercase_first(if op.ends_with('e') {
&op[..op.len() - 1]
} else {
op
});
write!(err_out, "{}ing {} failed", op, desc).unwrap();
if let &Some(ref more) = more {
write!(err_out, ": {}", more).unwrap();
}
writeln!(err_out, ".").unwrap();
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Strip the last 'e', if any, so we get correct inflection for continuous times
let op = uppercase_first(if self.op.ends_with('e') {
&self.op[..self.op.len() - 1]
} else {
self.op
});

/// Get the executable exit value from an `Error` instance.
///
/// # Examples
///
/// ```
/// # use https::Error;
/// assert_eq!(Error::Io {
/// desc: "",
/// op: "",
/// more: None,
/// }.exit_value(), 1);
/// ```
pub fn exit_value(&self) -> i32 {
match *self {
Error::Io { .. } => 1,
}
write!(f, "{}ing {} failed: {}.", op, self.desc, self.more)
}
}
@@ -34,7 +34,6 @@ pub use error::Error;
pub use options::Options;

use iron::Iron;
use std::io::stderr;
use std::process::exit;
use std::sync::{Arc, Mutex, Condvar};
use hyper_native_tls::NativeTlsServer;
@@ -47,8 +46,8 @@ fn main() {

fn actual_main() -> i32 {
if let Err(err) = result_main() {
err.print_error(&mut stderr());
err.exit_value()
eprintln!("{}", err);
1
} else {
0
}
@@ -66,21 +65,21 @@ fn result_main() -> Result<(), Error> {
let mut responder = try!(if let Some(p) = opts.port {
if let Some(&((ref id, _), ref pw)) = opts.tls_data.as_ref() {
Iron::new(ops::HttpHandler::new(&opts)).https(("0.0.0.0", p),
try!(NativeTlsServer::new(id, pw).map_err(|_| {
Error::Io {
try!(NativeTlsServer::new(id, pw).map_err(|err| {
Error {
desc: "TLS certificate",
op: "open",
more: None,
more: err.to_string().into(),
}
})))
} else {
Iron::new(ops::HttpHandler::new(&opts)).http(("0.0.0.0", p))
}
.map_err(|_| {
Error::Io {
Error {
desc: "server",
op: "start",
more: Some("port taken".into()),
more: "port taken".into(),
}
})
} else {
@@ -1087,33 +1087,34 @@ pub fn try_ports<H: Handler + Clone>(hndlr: H, from: u16, up_to: u16, tls_data:
let ir = Iron::new(hndlr.clone());
match if let Some(&((_, ref id), ref pw)) = tls_data.as_ref() {
ir.https(("0.0.0.0", port),
try!(NativeTlsServer::new(id, pw).map_err(|_| {
Error::Io {
try!(NativeTlsServer::new(id, pw).map_err(|err| {
Error {
desc: "TLS certificate",
op: "open",
more: None,
more: err.to_string().into(),
}
})))
} else {
ir.http(("0.0.0.0", port))
} {
Ok(server) => return Ok(server),
Err(error) => {
if !error.to_string().contains("port") {
return Err(Error::Io {
let error_s = error.to_string();
if !error_s.contains("port") && !error_s.contains("in use") {
return Err(Error {
desc: "server",
op: "start",
more: None,
more: error_s.into(),
});
}
}
}
}

Err(Error::Io {
Err(Error {
desc: "server",
op: "start",
more: Some("no free ports".into()),
more: "no free ports".into(),
})
}

@@ -1130,15 +1131,15 @@ pub fn try_ports<H: Handler + Clone>(hndlr: H, from: u16, up_to: u16, tls_data:
/// assert_eq!(pass, "");
/// ```
pub fn generate_tls_data(temp_dir: &(String, PathBuf)) -> Result<((String, PathBuf), String), Error> {
fn err(which: bool, op: &'static str, more: Option<Cow<'static, str>>) -> Error {
Error::Io {
fn err<M: Into<Cow<'static, str>>>(which: bool, op: &'static str, more: M) -> Error {
Error {
desc: if which {
"TLS key generation process"
} else {
"TLS identity generation process"
},
op: op,
more: more,
more: more.into(),
}
}
fn exit_err(which: bool, process: &mut Child, exitc: &ExitStatus) -> Error {
@@ -1151,18 +1152,18 @@ pub fn generate_tls_data(temp_dir: &(String, PathBuf)) -> Result<((String, PathB
stderr = "<error getting process stderr".to_string();
}

err(which,
"exit",
Some(format!("{};\nstdout: ```\n{}```;\nstderr: ```\n{}```", exitc, stdout, stderr).into()))
err(which, "exit", format!("{};\nstdout: ```\n{}```;\nstderr: ```\n{}```", exitc, stdout, stderr))
}

let tls_dir = temp_dir.1.join("tls");
if !tls_dir.exists() && fs::create_dir_all(&tls_dir).is_err() {
return Err(Error::Io {
desc: "temporary directory",
op: "create",
more: None,
});
if !tls_dir.exists() {
if let Err(err) = fs::create_dir_all(&tls_dir) {
return Err(Error {
desc: "temporary directory",
op: "create",
more: err.to_string().into(),
});
}
}

let mut child = try!(Command::new("openssl")
@@ -1172,7 +1173,7 @@ pub fn generate_tls_data(temp_dir: &(String, PathBuf)) -> Result<((String, PathB
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.map_err(|_| err(true, "spawn", None)));
.map_err(|error| err(true, "spawn", error.to_string())));
try!(child.stdin
.as_mut()
.unwrap()
@@ -1182,8 +1183,8 @@ pub fn generate_tls_data(temp_dir: &(String, PathBuf)) -> Result<((String, PathB
env!("CARGO_PKG_VERSION"),
"\nnabijaczleweli@gmail.com\n")
.as_bytes())
.map_err(|_| err(true, "pipe", None)));
let es = try!(child.wait().map_err(|_| err(true, "wait", None)));
.map_err(|error| err(true, "pipe", error.to_string())));
let es = try!(child.wait().map_err(|error| err(true, "wait", error.to_string())));
if !es.success() {
return Err(exit_err(true, &mut child, &es));
}
@@ -1195,8 +1196,8 @@ pub fn generate_tls_data(temp_dir: &(String, PathBuf)) -> Result<((String, PathB
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.map_err(|_| err(false, "spawn", None)));
let es = try!(child.wait().map_err(|_| err(false, "wait", None)));
.map_err(|error| err(false, "spawn", error.to_string())));
let es = try!(child.wait().map_err(|error| err(false, "wait", error.to_string())));
if !es.success() {
return Err(exit_err(false, &mut child, &es));
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.