hyperium / hyper-tls

Apache License 2.0
190 stars 96 forks source link

Making HTTPS call from Daemonize daemon #35

Closed grantgumina closed 5 years ago

grantgumina commented 5 years ago

I'm using Hyper + Hyper-TLS with the Daemonize crate to make the following HTTPS call from within a Daemon my subprocess runs. Interestingly, if I make a HTTP call things work fine and the request gets POST'ed to my server. However, if I change the BASE_URL to be HTTPS, then I get the following error printed out:

Error {
    kind: Connect,
    cause: Custom {
        kind: Other,
        error: Error {
            code: -909

I can't find any documentation as to what this might be. Also what's disturbing is that after I print this error, no other print statements are executed because the process seems to have died. Any help would be appreciated. Code using hyper/hyper-tls is below.

    let url: hyper::Uri = format!("{}/logs/new", BASE_URL).parse().unwrap();
    let https_connector = HttpsConnector::new(4).unwrap();
    let client = Client::builder().build(https_connector);
    let method = hyper::Method::POST;
    let mut headers = HeaderMap::new();

    let json_payload = json!({
        "jobName": job_name,
        "line": line,
    });

    let mut req = Request::new(Body::from(json_payload.to_string()));

    headers.insert("x-access-token", HeaderValue::from_str(&token).unwrap());
    headers.insert(
        hyper::header::CONTENT_TYPE,
        HeaderValue::from_static("application/json")
    );

    *req.method_mut() = method;
    *req.uri_mut() = url;
    *req.headers_mut() = headers;

    client.request(req).and_then(|res| {
        Ok(res.status())
    }).from_err::<kraken_utils::FetchError>().from_err()
seanmonstar commented 5 years ago

I'm not too familiar with Daemonize, and that errno seems to not turn up anything. Got anything more about how you call Daemonize, or execute the futures?

grantgumina commented 5 years ago

My daemon is created and run from inside the main file of my program:

fn main() {
                let job_daemon = Daemonize::new()
                .pid_file(job_daemon_pid_file_path) // Every method except `new` and `start`
                .chown_pid_file(true)      // is optional, see `Daemonize` documentation
                .stdout(job_stdout)
                .stderr(job_stderr)
                .working_directory("/tmp") // for default behaviour.
                .privileged_action(move || {
                    krephis::new_log(&ujn, &s); // This executes the HTTPS POST request shown above
                });

            match job_daemon.start() {
                Ok(_) => {
                },
                Err(e) => eprintln!("{}", e),
            }
}

That krephis::new_log function calls another function which returns a future:

pub fn new_log(job_id: &str, line: &str) {
            let fut = make_https_request()&token, job_id, line.map(|_response| {
            }).map_err(|e| {

                // An error occurs when sending HTTPS calls in a daemon... why?

                match e {
                    kraken_utils::FetchError::Http(e) => {
                        eprintln!("\n============");                        
                        eprintln!("error:     {:#?}", e); // nothing gets printed after this... wtf?
                        eprintln!("============\n");

                        eprintln!("http error: {}", e);
                    },
                    kraken_utils::FetchError::Json(e) => {
                        eprintln!("json parsing error: {}", e);
                    },
                    kraken_utils::FetchError::KrakenServerError(e) => {
                        eprintln!("Server error: {}", e.message);
                    },                    
                    kraken_utils::FetchError::Other(e) => {
                        eprintln!("Error: {}", e);
                    },
                }

            });

            rt::run(fut);
}

make_https_request has the code shown above:

fn make_https_request(token: &str, job_name: &str, line: &str) -> impl Future<Item = StatusCode, Error = kraken_utils::FetchError> {
    let url: hyper::Uri = format!("{}/logs/new", BASE_URL).parse().unwrap();
    let https_connector = HttpsConnector::new(4).unwrap();
    let client = Client::builder().build(https_connector);
    let method = hyper::Method::POST;
    let mut headers = HeaderMap::new();

    let json_payload = json!({
        "jobName": job_name,
        "line": line,
    });

    let mut req = Request::new(Body::from(json_payload.to_string()));

    headers.insert("x-access-token", HeaderValue::from_str(&token).unwrap());
    headers.insert(
        hyper::header::CONTENT_TYPE,
        HeaderValue::from_static("application/json")
    );

    *req.method_mut() = method;
    *req.uri_mut() = url;
    *req.headers_mut() = headers;

    client.request(req).and_then(|res| {
        Ok(res.status())
    }).from_err::<kraken_utils::FetchError>().from_err()
}
seanmonstar commented 5 years ago

Thanks! Also, do you have the OS, relevant crate versions (hyper, native-tls, OS specific TLS sub crate)?

grantgumina commented 5 years ago

OS: MacOS 10.14.2 Crates: hyper = "0.12" hyper-tls = "0.3.1"

I'm not actually using native-tls in this project.

seanmonstar commented 5 years ago

hyper-tls depends on native-tls, which on macOS means it will use the security-framework crate. You can see all the resolved dependencies in your Cargo.lock file that is generated.

Also, to be clear, the request works if not combined with Daemonize?

seanmonstar commented 5 years ago

Is there any additional output for the error? Besides code, it should hopefully have a message...

grantgumina commented 5 years ago

Ok that makes more sense. And yes, the HTTPS request code works just fine when not using Daemonize (I'm going to go bother those folks next haha). Unfortunately no other error message is printed. It's almost as if as soon as I print out that error, it cuts out half way through just based on how it's formatted. Also, after printing that error, no other print statements show up - I believe the program exits.

Here's the full dependency list:

[[package]]
name = "hyper"
version = "0.12.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
 "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
 "h2 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
 "http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
 "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
 "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
 "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
 "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
 "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
 "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
 "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "hyper-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
 "hyper 0.12.19 (registry+https://github.com/rust-lang/crates.io-index)",
 "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
seanmonstar commented 5 years ago

A search for "security-framework error 909" brought up this page, looks relevant: https://developer.apple.com/documentation/security/1542001-security_framework_result_codes/errsecbadreq

I don't recall exactly how security-framework works, but I believe it interacts with Keychain. Could it not have permissions because of being Daemonize?

grantgumina commented 5 years ago

I think that's the most likely problem here. I'm not sure how to proceed, but this seems to not be an issue with hyper-tls. I'm going to do some digging and possibly commend on the Daemonize page to see what's going on. Thanks so much for your help!

NyxCode commented 4 years ago

I think I've struck a similar issue. I'm using warp with Daemonize and TLS. I don't get any error, but the server is not responding (chrome fails with ERR_TIMED_OUT). However, I'm not on macos, but on arch linux (5.4.18-1-MANJARO).

robphilipp-tiggee commented 4 years ago

I have the same issue with a simple tcp server. Once I daemonize, the server no longer responds.