~nickbp/tokio-scgi

cc53b9afe29ced7a9d81be431b5c10dea4704861 — Nick Parker 3 years ago 79d639b
Bump version, run rustfmt
4 files changed, 38 insertions(+), 20 deletions(-)

M Cargo.lock
M Cargo.toml
M examples/client.rs
M examples/server.rs
M Cargo.lock => Cargo.lock +1 -1
@@ 649,7 649,7 @@ dependencies = [

[[package]]
name = "tokio-scgi"
version = "0.1.0"
version = "0.2.0"
dependencies = [
 "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
 "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",

M Cargo.toml => Cargo.toml +2 -2
@@ 1,6 1,6 @@
[package]
name = "tokio-scgi"
version = "0.1.0"
version = "0.2.0"
authors = ["Nick Parker <nick@nickbp.com>"]
license = "MIT"
edition = "2018"


@@ 9,9 9,9 @@ description = "Tokio codec for building and parsing SCGI requests"
repository = "https://github.com/nickbp/tokio-scgi"

[dependencies]
bytes = "0.4.12"
tokio = "=0.2.0-alpha.1"
tokio-codec = "=0.2.0-alpha.1"
bytes = "0.4.12"

[dev-dependencies]
proptest = "0.9.4"

M examples/client.rs => examples/client.rs +12 -5
@@ 50,7 50,9 @@ async fn main() -> Result<(), Error> {

/// Runs the client: Sends a request and prints the responses via the provided UDS or TCP connection.
async fn run_client<C>(conn: &mut C) -> Result<(), Error>
where C: AsyncRead + AsyncWrite + std::marker::Send + std::marker::Unpin + std::fmt::Debug {
where
    C: AsyncRead + AsyncWrite + std::marker::Send + std::marker::Unpin + std::fmt::Debug,
{
    let (mut tx_scgi, mut rx_scgi) = Framed::new(conn, SCGICodec::new()).split();

    // Send request


@@ 64,14 66,14 @@ where C: AsyncRead + AsyncWrite + std::marker::Send + std::marker::Unpin + std::
                // Shouldn't happen for response data, but this is how it would work...
                println!("Response data is incomplete, resuming read");
                rx_scgi = new_rx;
            },
            }
            (Some(Err(e)), _new_rx) => {
                // RX error: return error and abort
                return Err(Error::new(
                    ErrorKind::Other,
                    format!("Error when waiting for response: {}", e),
                ));
            },
            }
            (Some(Ok(response)), new_rx) => {
                // Got SCGI response: if empty, treat as end of response.
                if response.len() == 0 {


@@ 81,9 83,14 @@ where C: AsyncRead + AsyncWrite + std::marker::Send + std::marker::Unpin + std::
                rx_scgi = new_rx;
                match String::from_utf8(response.to_vec()) {
                    Ok(s) => println!("Got {} bytes:\n{}", response.len(), s),
                    Err(e) => println!("{} byte response is not UTF8 ({}):\n{:?}", response.len(), e, response)
                    Err(e) => println!(
                        "{} byte response is not UTF8 ({}):\n{:?}",
                        response.len(),
                        e,
                        response
                    ),
                }
            },
            }
        }
    }
}

M examples/server.rs => examples/server.rs +23 -12
@@ 40,8 40,12 @@ async fn main() -> Result<(), std::io::Error> {
            let (conn, _addr) = bind.accept().await?;
            tokio::spawn(async move {
                match serve(conn).await {
                    Err(e) =>{ println!("Error serving UDS session: {:?}", e); }
                    Ok(()) => { println!("Served UDS request"); }
                    Err(e) => {
                        println!("Error serving UDS session: {:?}", e);
                    }
                    Ok(()) => {
                        println!("Served UDS request");
                    }
                };
            });
        }


@@ 52,8 56,12 @@ async fn main() -> Result<(), std::io::Error> {
            let (conn, addr) = bind.accept().await?;
            tokio::spawn(async move {
                match serve(conn).await {
                    Err(e) => { println!("Error when serving TCP session from {:?}: {:?}", addr, e); }
                    Ok(()) => { println!("Served TCP request from {:?}", addr); }
                    Err(e) => {
                        println!("Error when serving TCP session from {:?}: {:?}", addr, e);
                    }
                    Ok(()) => {
                        println!("Served TCP request from {:?}", addr);
                    }
                };
            });
        }


@@ 117,7 125,9 @@ macro_rules! http_response {
}

async fn serve<C>(conn: C) -> Result<(), Error>
where C: AsyncRead + AsyncWrite + std::marker::Send + std::marker::Unpin + std::fmt::Debug {
where
    C: AsyncRead + AsyncWrite + std::marker::Send + std::marker::Unpin + std::fmt::Debug,
{
    let mut handler = SampleHandler::new();
    let (mut tx_scgi, mut rx_scgi) = Framed::new(conn, SCGICodec::new()).split();



@@ 127,31 137,32 @@ where C: AsyncRead + AsyncWrite + std::marker::Send + std::marker::Unpin + std::
                // SCGI request not ready: loop for more rx data
                println!("Request read returned None, resuming read");
                rx_scgi = new_rx;
            },
            }
            (Some(Err(e)), _new_rx) => {
                // RX error: return error and abort
                return Err(Error::new(
                    ErrorKind::Other,
                    format!("Error when waiting for request: {}", e),
                ));
            },
            (Some(Ok(request)), new_rx) =>
            }
            (Some(Ok(request)), new_rx) => {
                // Got SCGI request: pass to handler
                match handler.handle(request) {
                    Ok(Some(r)) => {
                        // Response ready: send and exit
                        return tx_scgi.send(r).await;
                    },
                    }
                    Ok(None) => {
                        // Response not ready: loop for more rx data
                        println!("Request data is incomplete, resuming read");
                        rx_scgi = new_rx;
                    },
                    }
                    Err(e) => {
                        // Handler error: respond with formatted error message
                        return tx_scgi.send(handle_error(e)).await;
                    }
                },
                }
            }
        }
    }
}


@@ 281,7 292,7 @@ fn build_response(headers: &Vec<(String, String)>, body: &BytesMut) -> Vec<u8> {
        // Printable content with minimal effort at avoiding HTML injection:
        Ok(s) => format!("{}", s.replace('<', "&lt;").replace('>', "&gt;")),
        // Not printable content, fall back to printing as list of dec codes:
        Err(_e) => format!("{:?}", body.to_vec())
        Err(_e) => format!("{:?}", body.to_vec()),
    };
    let content = format!(
        "<html><head><title>scgi-sample-server</title></head><body>