From 6feea82d618499b42f480d7b68bf7398ab99016e Mon Sep 17 00:00:00 2001 From: Kai Jewson Date: Sun, 12 Dec 2021 16:03:20 +0000 Subject: [PATCH] Enforce stronger validation of SSE values (#599) * Enforce stronger validation of SSE values * Mention `sse::Event` strictness in changelog Co-authored-by: David Pedersen --- axum/CHANGELOG.md | 3 +++ axum/Cargo.toml | 1 + axum/src/response/sse.rs | 49 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/axum/CHANGELOG.md b/axum/CHANGELOG.md index a25e226c..f9d0db4c 100644 --- a/axum/CHANGELOG.md +++ b/axum/CHANGELOG.md @@ -7,8 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # Unreleased +- **fixed:** `sse::Event` is more strict about what field values it supports, disallowing any SSE + events that break the specification (such as field values containing carriage returns) ([#599]) - **added:** `axum::AddExtension::layer` ([#607]) +[#599]: https://github.com/tokio-rs/axum/pull/599 [#607]: https://github.com/tokio-rs/axum/pull/607 # 0.4.2 (06. December, 2021) diff --git a/axum/Cargo.toml b/axum/Cargo.toml index 51651b7c..5795104e 100644 --- a/axum/Cargo.toml +++ b/axum/Cargo.toml @@ -30,6 +30,7 @@ http-body = "0.4.4" mime = "0.3.16" hyper = { version = "0.14.14", features = ["server", "tcp", "stream"] } matchit = "0.4.4" +memchr = "2.4.1" percent-encoding = "2.1" pin-project-lite = "0.2.7" serde = "1.0" diff --git a/axum/src/response/sse.rs b/axum/src/response/sse.rs index 8a37d00b..b8dbe23b 100644 --- a/axum/src/response/sse.rs +++ b/axum/src/response/sse.rs @@ -188,11 +188,21 @@ impl Event { /// This corresponds to [`MessageEvent`'s data field]. /// /// [`MessageEvent`'s data field]: https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data + /// + /// # Panics + /// + /// Panics if `data` contains any carriage returns, as they cannot be transmitted over SSE. pub fn data(mut self, data: T) -> Event where T: Into, { - self.data = Some(DataType::Text(data.into())); + let data = data.into(); + assert_eq!( + memchr::memchr(b'\r', data.as_bytes()), + None, + "SSE data cannot contain carriage returns", + ); + self.data = Some(DataType::Text(data)); self } @@ -214,11 +224,22 @@ impl Event { /// Set the event's comment field (`:`). /// /// This field will be ignored by most SSE clients. + /// + /// # Panics + /// + /// Panics if `comment` contains any newlines or carriage returns, as they are not allowed in + /// comments. pub fn comment(mut self, comment: T) -> Event where T: Into, { - self.comment = Some(comment.into()); + let comment = comment.into(); + assert_eq!( + memchr::memchr2(b'\r', b'\n', comment.as_bytes()), + None, + "SSE comment cannot contain newlines or carriage returns" + ); + self.comment = Some(comment); self } @@ -231,11 +252,21 @@ impl Event { /// /// [`EventSource`]: https://developer.mozilla.org/en-US/docs/Web/API/EventSource /// [`message` event]: https://developer.mozilla.org/en-US/docs/Web/API/EventSource/message_event + /// + /// # Panics + /// + /// Panics if `event` contains any newlines or carriage returns. pub fn event(mut self, event: T) -> Event where T: Into, { - self.event = Some(event.into()); + let event = event.into(); + assert_eq!( + memchr::memchr2(b'\r', b'\n', event.as_bytes()), + None, + "SSE event name cannot contain newlines or carriage returns" + ); + self.event = Some(event); self } @@ -256,11 +287,21 @@ impl Event { /// string. /// /// [`MessageEvent`'s `lastEventId` field]: https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/lastEventId + /// + /// # Panics + /// + /// Panics if `id` contains any newlines, carriage returns or null characters. pub fn id(mut self, id: T) -> Event where T: Into, { - self.id = Some(id.into()); + let id = id.into(); + assert_eq!( + memchr::memchr3(b'\r', b'\n', b'\0', id.as_bytes()), + None, + "Event ID cannot contain newlines, carriage returns or null characters", + ); + self.id = Some(id); self } }