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}