Repository: servo/servo
File: components/net/protocols/mod.rs (Rust)

Code before:
        context: &FetchContext,
    ) -> FutureResponse {
        let mut url = request.current_url();
        // Step 1. Assert: inputURL's scheme is normalizedScheme.
        assert!(url.scheme() == self.scheme);
        // Step 2. Set the username given inputURL and the empty string.
        //
        // Ignore errors if no username can be set, which depending on the
        // URL in the scheme handler might be bogus. For example, with a
        // `mailto:` handler, it doesn't have a base. See the
        // documentation at [`url::Url::set_username`]
        let _ = url.set_username("");

        // Step 3. Set the password given inputURL and the empty string.
        //
        // Ignore errors if no password can be set, which depending on the
        // URL in the scheme handler might be bogus. For example, with a
        // `mailto:` handler, it doesn't have a base. See the
        // documentation at [`url::Url::set_password`]
        let _ = url.set_password(None);

        // Step 4. Let inputURLString be the serialization of inputURL.
        // Step 5. Let encodedURL be the result of running UTF-8 percent-encode on inputURLString using the component percent-encode set.
        //
        // Url is already UTF-8, so encoding isn't required
        let encoded_url = &url.as_str()[(self.scheme.len() + 1)..];
        // Step 6. Let handlerURLString be normalizedURLString.
        // Step 7. Replace the first instance of "%s" in handlerURLString with encodedURL.
        let handler_url_string = self.url.replacen("%s", encoded_url, 1);
        // Step 8. Let resultURL be the result of parsing handlerURLString.
        let Ok(result_url) = ServoUrl::parse(&handler_url_string) else {
            return Box::pin(future::ready(Response::network_error(
                NetworkError::Internal("Failed to parse substituted protocol handler url".into()),
            )));
        };
        // Step 9. Navigate an appropriate navigable to resultURL.
        request.url_list.push(result_url);
        let request2 = request.clone();
        let context2 = context.clone();
        Box::pin(async move {
            let (sender, receiver) = tokio::sync::oneshot::channel();
            let mut collector = FetchResponseCollector {
                sender: Some(sender),
            };
            fetch(request2, &mut collector, &context2).await;
            receiver.await.unwrap_or_else(|_| {
                Response::network_error(NetworkError::Internal(
                    "Failed with internal fetch error".into(),
                ))
            })
        })

Review comment (suggestion):
```suggestion
        let encoded_url = &url[Position::AfterScheme..][1..];
```

Code after:
    ) -> FutureResponse {
        let mut url = request.current_url();
        // Step 1. Assert: inputURL's scheme is normalizedScheme.
        assert!(url.scheme() == self.scheme);
        // Step 2. Set the username given inputURL and the empty string.
        //
        // Ignore errors if no username can be set, which depending on the
        // URL in the scheme handler might be bogus. For example, with a
        // `mailto:` handler, it doesn't have a base. See the
        // documentation at [`url::Url::set_username`]
        let _ = url.set_username("");

        // Step 3. Set the password given inputURL and the empty string.
        //
        // Ignore errors if no password can be set, which depending on the
        // URL in the scheme handler might be bogus. For example, with a
        // `mailto:` handler, it doesn't have a base. See the
        // documentation at [`url::Url::set_password`]
        let _ = url.set_password(None);

        // Step 4. Let inputURLString be the serialization of inputURL.
        // Step 5. Let encodedURL be the result of running UTF-8 percent-encode on inputURLString using the component percent-encode set.
        //
        // Url is already UTF-8, so encoding isn't required
        let encoded_url = &url[Position::AfterScheme..][1..];
        // Step 6. Let handlerURLString be normalizedURLString.
        // Step 7. Replace the first instance of "%s" in handlerURLString with encodedURL.
        let handler_url_string = self.url.replacen("%s", encoded_url, 1);
        // Step 8. Let resultURL be the result of parsing handlerURLString.
        let Ok(result_url) = ServoUrl::parse(&handler_url_string) else {
            return Box::pin(future::ready(Response::network_error(
                NetworkError::Internal("Failed to parse substituted protocol handler url".into()),
            )));
        };
        // Ensure we did a proper substitution with a HTTP result
        assert!(matches!(result_url.scheme(), "http" | "https"));
        // Step 9. Navigate an appropriate navigable to resultURL.
        request.url_list.push(result_url);
        let request2 = request.clone();
        let context2 = context.clone();
        Box::pin(async move { fetch(request2, &mut DiscardFetch, &context2).await })
    }
}

/// Test if the URL is potentially trustworthy or the custom protocol is registered as secure
pub fn is_url_potentially_trustworthy(
    protocol_registry: &ProtocolRegistry,
    url: &ServoUrl,
) -> bool {
    url.is_potentially_trustworthy() || protocol_registry.is_secure(url.scheme())
}