Repository: seanmonstar/warp (language: rust)

Issue:
Add function to obtain the close frame information from ws::Message
**Is your feature request related to a problem? Please describe.**
There is no way to obtain the close code or close reason from `ws::Message`. I learnt from this [discussion on discord](https://discord.com/channels/500028886025895936/671042482770935808/796029022281924650) that `Message::into_bytes` returns the close reason but this behavior isn't clear from documentation. Making matters worse, `Message::as_bytes` doesn't have the same behavior, instead [it returns an empty slice](https://github.com/seanmonstar/warp/blob/42fd14fdab8145d27ae770fe4b5c843a99bc2a44/src/filters/ws.rs#L342) when `Message` is of `Close` type.

**Describe the solution you'd like**
A function to obtain the close frame information like: 
```rust
/// (u16, &str) = (close_code, close_reason)
fn close_frame(&self) -> (u16, &str)
```

It would also be nice to have `as_bytes` and `into_bytes` to behave the same way.

**Describe alternatives you've considered**
None available

**Additional context**
N/A



Discussion / hints:

Fix patch:
diff --git a/src/filters/ws.rs b/src/filters/ws.rs
index bbd1836d2..8475523af 100644
--- a/src/filters/ws.rs
+++ b/src/filters/ws.rs
@@ -324,6 +324,15 @@ impl Message {
         self.inner.is_pong()
     }
 
+    /// Try to get the close frame (close code and reason)
+    pub fn close_frame(&self) -> Option<(u16, &str)> {
+        if let protocol::Message::Close(Some(ref close_frame)) = self.inner {
+            Some((close_frame.code.into(), close_frame.reason.as_ref()))
+        } else {
+            None
+        }
+    }
+
     /// Try to get a reference to the string text, if this is a Text message.
     pub fn to_str(&self) -> Result<&str, ()> {
         match self.inner {


Test patch:
diff --git a/tests/ws.rs b/tests/ws.rs
index ad7913318..5ff23e482 100644
--- a/tests/ws.rs
+++ b/tests/ws.rs
@@ -81,6 +81,21 @@ async fn binary() {
     assert_eq!(msg.as_bytes(), &b"bonk"[..]);
 }
 
+#[tokio::test]
+async fn close_frame() {
+    let _ = pretty_env_logger::try_init();
+
+    let route = warp::ws().map(|ws: warp::ws::Ws| {
+        ws.on_upgrade(|mut websocket| async move {
+            let msg = websocket.next().await.expect("item").expect("ok");
+            let _ = msg.close_frame().expect("close frame");
+        })
+    });
+
+    let client = warp::test::ws().handshake(route).await.expect("handshake");
+    drop(client);
+}
+
 #[tokio::test]
 async fn send_ping() {
     let _ = pretty_env_logger::try_init();