Repository: seanmonstar/reqwest (language: rust)

Issue:
Acess body/header content from RequestBuilder
I'm trying to implement a trait for the RequestBuilder that automatically signs the Request with the required information to allow access to Amazon AWS services (see [here](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)):

```
pub trait AwsSignAndSend {
    fn aws_sign_and_send(self,id: &str,key: &str,region: &str,srvcs: &str) -> Result<reqwest::Response,reqwest::Error>;
}
```

so in the code instead of `send()` I could just do 

```
client.post(url).json(&data).aws_sign_and_send("aws_id","aws_key","region","service")
```

however to do the signing I need (1) access to the body contents (if any) and the headers that have been added so far.  From what I can gather it is currently not possible to access the contents of the body after they have been passed to the RequestBuilder. Is this correct? I'm trying to do something along the lines of this snippet:

```
    fn aws_sign_and_send(self,id: &str,key: &str,region: &str,srvcs: &str) -> Result<reqwest::Response,reqwest::Error> {
        let request = self.build()?;
        // (1) if there is a body hash it and add the header
        if let Some(content) = request.body() {
            self.header("X-Amz-Content-Sha256",content_hash(content));
        }
        self.send()
    }
```

which would modify the actual request with the necessary headers and metadata such that the AWS server accepts it.

Is there any way around this restriction to make this work?









Discussion / hints:
Are you looking for something like this?
```rust
fn aws_sign_and_send(self,id: &str,key: &str,region: &str,srvcs: &str) -> Result<reqwest::Response, reqwest::Error> {
        let mut request = self.build()?;
        // (1) if there is a body hash it and add the header
        if let Some(content) = request.body() {
            let mut headers = request.headers_mut();
            headers.insert("X-Amz-Content-Sha256",content_hash(content));
        }
        // sending request;
        let client = Client::new();
        Client::execute(request)
    }
```
Yes, but I thought you can't retrieve the content using `request.body()`. The method exists but it returns a Body object which you can't use to retrieve the content? Maybe I'm wrong?
You could try this
```rust
body.clone().into::<Vec<u8>>();
```
even if it does work, there should be at least the following method
```rust
fn as_bytes(&self) -> impl Future<Output = &Bytes>;
```

Fix patch:
diff --git a/src/async_impl/body.rs b/src/async_impl/body.rs
index dbe280906..3f26723ee 100644
--- a/src/async_impl/body.rs
+++ b/src/async_impl/body.rs
@@ -35,6 +35,16 @@ struct WrapStream<S>(S);
 struct WrapHyper(hyper::Body);
 
 impl Body {
+    /// Returns a reference to the internal data of the `Body`.
+    ///
+    /// `None` is returned, if the underlying data is a stream.
+    pub fn as_bytes(&self) -> Option<&[u8]> {
+        match &self.inner {
+            Inner::Reusable(bytes) => Some(bytes.as_ref()),
+            Inner::Streaming { .. } => None,
+        }
+    }
+
     /// Wrap a futures `Stream` in a box inside `Body`.
     ///
     /// # Example
@@ -339,3 +349,15 @@ impl HttpBody for WrapHyper {
         HttpBody::size_hint(&self.0)
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::Body;
+
+    #[test]
+    fn test_as_bytes() {
+        let test_data = b"Test body";
+        let body = Body::from(&test_data[..]);
+        assert_eq!(body.as_bytes(), Some(&test_data[..]));
+    }
+}


Test patch: