Skip to main content

opys_dev/
url.rs

1//! URL escaping for build-time resolvers.
2//!
3//! `percent-encoding` does the work — it is already in the tree under `ureq`,
4//! which does not re-export it. It began in `opys-java` and moved here when a
5//! second resolver needed it: a GitLab project path travels as one segment,
6//! `group%2Fname`.
7
8use percent_encoding::{percent_decode_str, utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};
9
10/// `encodeURIComponent`'s unreserved set: `A-Za-z0-9-_.!~*'()`.
11const URI_COMPONENT: &AsciiSet = &NON_ALPHANUMERIC
12    .remove(b'-')
13    .remove(b'_')
14    .remove(b'.')
15    .remove(b'!')
16    .remove(b'~')
17    .remove(b'*')
18    .remove(b'\'')
19    .remove(b'(')
20    .remove(b')');
21
22/// Escape one path segment or query value, `encodeURIComponent`-style. Needed
23/// wherever a caller's string reaches a URL: a Temurin release name like
24/// `jdk-21.0.13+11` has to travel as `%2B`, or Adoptium reads it as a space
25/// and the lookup misses.
26pub fn encode_uri_component(s: &str) -> String {
27    utf8_percent_encode(s, URI_COMPONENT).to_string()
28}
29
30/// Undo [`encode_uri_component`] on one path segment. A segment that does not
31/// decode to UTF-8 is returned as it was written — it is somebody's file name,
32/// and being wrong about its spelling is worse than leaving it escaped.
33pub fn decode_uri_component(s: &str) -> String {
34    percent_decode_str(s)
35        .decode_utf8()
36        .map(|decoded| decoded.into_owned())
37        .unwrap_or_else(|_| s.to_owned())
38}