Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion crates/trusted-server-core/src/cookies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@ pub fn expire_ec_cookie(settings: &Settings, response: &mut fastly::Response) {

#[cfg(test)]
mod tests {
use fastly::http::HeaderValue;

use crate::error::TrustedServerError;
use crate::test_support::tests::create_test_settings;

use super::*;
Expand Down Expand Up @@ -338,7 +341,7 @@ mod tests {
}

#[test]
fn test_handle_request_cookies_invalid_cookie_header() {
fn test_handle_request_cookies_malformed_cookie_string() {
let req = Request::get("http://example.com").with_header(header::COOKIE, "invalid");
let jar = handle_request_cookies(&req)
.expect("should parse cookies")
Expand All @@ -347,6 +350,26 @@ mod tests {
assert!(jar.iter().count() == 0);
}

#[test]
fn test_handle_request_cookies_invalid_utf8_cookie_header() {
let invalid_cookie_value = HeaderValue::from_bytes(b"ts-ec=valid-prefix\xF0\x90\x80")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick\xF0\x90\x80 is a truncated 4-byte UTF-8 sequence: \xF0 introduces a 4-byte code point but only two continuation bytes follow, so to_str() rejects it. A one-line comment above the literal would save future readers a trip to the Unicode tables.

// Truncated 4-byte UTF-8 sequence: `\xF0` starts a 4-byte code point but
// only two continuation bytes follow, so `to_str()` rejects it.
let invalid_cookie_value = HeaderValue::from_bytes(b"ts-ec=valid-prefix\xF0\x90\x80")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick — The ts-ec=valid-prefix portion adds no coverage. HeaderValue::to_str() validates the entire byte slice; there is no partial parsing to test. A bare b"\xF0\x90\x80" would exercise the same code path more clearly. Harmless either way.

.expect("should build header value");
let req =
Request::get("http://example.com").with_header(header::COOKIE, invalid_cookie_value);

let err =
handle_request_cookies(&req).expect_err("should reject invalid UTF-8 cookie header");

assert!(
matches!(
err.current_context(),
TrustedServerError::InvalidHeaderValue { message }
if message.contains("invalid UTF-8")
),
"should return invalid header value error for non-UTF-8 cookie header"
);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 wrench — Brittle assertion: the if message.contains("invalid UTF-8") guard locks this test to the literal string set in cookies.rs:108 ("Cookie header contains invalid UTF-8"). A reasonable rewording of that message (e.g. "Cookie header is not valid UTF-8") would silently break this test even though behavior is unchanged. Production code branches on the variant, not the message — the variant check alone is sufficient.

Fix:

assert!(
    matches!(
        err.current_context(),
        TrustedServerError::InvalidHeaderValue { .. }
    ),
    "should return InvalidHeaderValue for non-UTF-8 cookie header"
);

}

#[test]
fn test_set_ec_cookie() {
let settings = create_test_settings();
Expand Down
14 changes: 0 additions & 14 deletions crates/trusted-server-core/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,6 @@ mod tests {
assert_eq!(callback.url, "https://example.com/track/impression");
}

#[test]
fn test_callback_type_field_rename() {
// Test that "type" is correctly renamed to callback_type
let json_str = r#"{
"type": "click",
"url": "https://example.com/track/click"
}"#;

let callback: Callback =
serde_json::from_str(json_str).expect("should deserialize callback from str");
assert_eq!(callback.callback_type, "click");
assert_eq!(callback.url, "https://example.com/track/click");
}

#[test]
fn test_ad_response_full_deserialization() {
let json_data = json!({
Expand Down
Loading