digest-headers 0.1.1

A simple library to hash a request's body in the headers
docs.rs failed to build digest-headers-0.1.1
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: digest-headers-0.2.1

Digest Headers

A library to aid in the creation and verification of Digest Headers, Sha Digests of HTTP Request Bodies

Getting started

Add the following to your Cargo.toml

[dependencies.digest-headers]
default-features = false

If you want the hyper types, add features = ["use_hyper"] to the digest-headers section. If you want the rocket types, add features = ["use_rocket"].

Building requests with Hyper

use digest_headers::Digest;
use digest_headers::use_hyper::DigestHeader;

let mut req = Request::new(Method::Post, uri);

req.headers_mut().set(ContentType::json());
req.headers_mut().set(ContentLength(json.len() as u64));
req.headers_mut().set(DigestHeader(Digest::new(
    json.as_bytes(),
    ShaSize::TwoFiftySix,
)));
req.set_body(json);

Handling requests with Hyper

use digest_headers::use_hyper::DigestHeader;
use futures::{Future, IntoFuture, Stream};
use hyper::server::{Http, Request, Response, Service};

struct Responder;

impl Service for Responder {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;

    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn call(&self, mut req: Self::Request) -> Self::Future {
        let digest = req
            .headers_mut()
            .remove::<DigestHeader>()
            .ok_or(hyper::Error::Header);

        let fut = req
            .body()
            .concat2()
            .join(digest)
            .and_then(|(body, digest)| {
                if digest.0.verify(&body).is_ok() {
                    println!("Verified!");
                    Ok(Response::new().with_body(body))
                } else {
                    println!("Bad Request!");
                    Err(hyper::Error::Header)
                }
            });

        Box::new(fut)
    }
}

Handling requests with Rocket

use digest_headers::use_rocket::DigestHeader;
use rocket::data::{self, FromData};

struct DigestVerifiedBody<T>(pub T);

impl FromData for DigestVerifiedBody<Vec<u8>> {
    type Error = ();

    fn from_data(req: &Request, data: Data) -> data::Outcome<Self, Self::Error> {
        let digest = match req.guard::<DigestHeader>() {
            Outcome::Success(dh) => dh.0,
            Outcome::Failure((status, _)) => return Outcome::Failure((status, ())),
            Outcome::Forward(_) => return Outcome::Forward(data),
        };

        let mut body = Vec::new();

        // This is a really obvious Denial-of-service attack.
        // Please see the rocket example for a better way to do this.
        // https://github.com/asonix/digest-headers/blob/master/examples/rocket.rs
        if let Err(_) = data.open().read_to_end(&mut body) {
            return Outcome::Failure((Status::InternalServerError, ()));
        }

        if digest.verify(&body).is_err() {
            return Outcome::Failure((Status::BadRequest, ()));
        }

        Outcome::Success(DigestVerifiedBody(body))
    }
}

#[post("/", data = "<data>")]
fn index(data: DigestVerifiedBody<Vec<u8>>) -> String {
    if let Ok(data) = std::str::from_utf8(&data.0) {
        println!("Received {}", data);
        format!("Verified!: {}", data)
    } else {
        format!("Failed to verify data")
    }
}

What this library supports

  • Creation of Digest Header strings
  • Verification of Digest Header strings
  • Adding Digest Headers to Hyper Requests (with the use_hyper feature).
  • Digest and Content Length Header request guards for Rocket (with the use_rocket feature).

Examples

  • Hyper Client example, very short and sweet
  • Rocket Server Example. This one is more in-depth. It implements rocket::request::FromRequest for two custom structs for the Digest and ContentLength headers, and implements FromData for a simple wrapper around a Vec<u8>. See the example for the full implementation.

Notes

  • The Rocket and Hyper servers run on the same port, so you can't run them simultaneously
  • The Hyper Client example is configured to send POST requests to the Rocket and Hyper Server examples.

Contributing

Please be aware that all code contributed to this project will be licensed under the GPL version 3.

License

Digest Headers is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Digest Headers is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. This file is part of Digest Headers

You should have received a copy of the GNU General Public License along with Digest Headers If not, see http://www.gnu.org/licenses/.