| 123456789101112131415161718192021222324252627282930313233343536 |
- //! Fuzz `redirect_uri` matching (`protocol::redirect_repo`, RFC 3986 §6.2.1
- //! plus the RFC 8252 §7.3 loopback exception).
- //!
- //! Both the requested URI (first input line) and the registered catalog set
- //! (following lines, capped) are hostile input: the matcher must never panic,
- //! never fall back to prefix/wildcard comparison, and only report `Exact`
- //! for a character-for-character member of the registered set.
- #![no_main]
- use d_oauth::protocol::redirect_repo::{RedirectDecision, match_redirect_uri};
- use libfuzzer_sys::fuzz_target;
- /// Maximum registered URIs taken from one input; matching is linear, so the
- /// cap keeps a single execution bounded.
- const MAX_REGISTERED: usize = 8;
- fuzz_target!(|data: &[u8]| {
- let Ok(text) = core::str::from_utf8(data) else {
- return;
- };
- let mut lines = text.split('\n');
- let Some(requested) = lines.next() else {
- return;
- };
- let registered: Vec<&str> = lines.take(MAX_REGISTERED).collect();
- let decision = match_redirect_uri(®istered, requested);
- // An empty catalog can never match.
- if registered.is_empty() {
- debug_assert_eq!(decision, RedirectDecision::Reject);
- }
- // `Exact` fires only for a character-for-character registered member.
- if decision == RedirectDecision::Exact {
- debug_assert!(registered.contains(&requested));
- }
- });
|