Skip to content

Commit

Permalink
fix(lsp): normalize "deno:" urls statelessly (denoland#20867)
Browse files Browse the repository at this point in the history
  • Loading branch information
nayeemrmn committed Oct 10, 2023
1 parent 7b80b27 commit 2215a3e
Showing 1 changed file with 72 additions and 28 deletions.
100 changes: 72 additions & 28 deletions cli/lsp/urls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ pub static INVALID_SPECIFIER: Lazy<ModuleSpecifier> =
/// the component percent encoding set.
///
/// See: <https://url.spec.whatwg.org/#component-percent-encode-set>
///
// TODO(@kitsonk) - refactor when #9934 is landed.
const COMPONENT: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS
.add(b' ')
.add(b'"')
Expand All @@ -47,6 +45,7 @@ const COMPONENT: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS
.add(b'^')
.add(b'|')
.add(b'$')
.add(b'%')
.add(b'&')
.add(b'+')
.add(b',');
Expand All @@ -60,6 +59,43 @@ fn hash_data_specifier(specifier: &ModuleSpecifier) -> String {
crate::util::checksum::gen(&[file_name_str.as_bytes()])
}

fn to_deno_url(specifier: &Url) -> String {
let mut string = String::with_capacity(specifier.as_str().len() + 6);
string.push_str("deno:/");
string.push_str(specifier.scheme());
for p in specifier[Position::BeforeHost..].split('/') {
string.push('/');
string.push_str(
&percent_encoding::utf8_percent_encode(p, COMPONENT).to_string(),
);
}
string
}

fn from_deno_url(url: &Url) -> Option<Url> {
if url.scheme() != "deno" {
return None;
}
let mut segments = url.path_segments()?;
let mut string = String::with_capacity(url.as_str().len());
string.push_str(segments.next()?);
string.push_str(":https://");
string.push_str(
&percent_encoding::percent_decode(segments.next()?.as_bytes())
.decode_utf8()
.ok()?,
);
for segment in segments {
string.push('/');
string.push_str(
&percent_encoding::percent_decode(segment.as_bytes())
.decode_utf8()
.ok()?,
);
}
Url::parse(&string).ok()
}

/// This exists to make it a little bit harder to accidentally use a `Url`
/// in the wrong place where a client url should be used.
#[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
Expand Down Expand Up @@ -171,16 +207,7 @@ impl LspUrlMap {
extension
)
} else {
let mut str = String::with_capacity(specifier.as_str().len() + 6);
str.push_str("deno:/");
str.push_str(specifier.scheme());
for p in specifier[Position::BeforeHost..].split('/') {
str.push('/');
str.push_str(
&percent_encoding::utf8_percent_encode(p, COMPONENT).to_string(),
);
}
str
to_deno_url(specifier)
};
let url = LspClientUrl(Url::parse(&specifier_str)?);
inner.put(specifier.clone(), url.clone());
Expand Down Expand Up @@ -210,23 +237,22 @@ impl LspUrlMap {
}
let mut inner = self.inner.lock();
if let Some(specifier) = inner.get_specifier(url).cloned() {
specifier
} else {
let specifier = if url.scheme() == "file" {
if let Ok(path) = url.to_file_path() {
match kind {
LspUrlKind::Folder => Url::from_directory_path(path).unwrap(),
LspUrlKind::File => Url::from_file_path(path).unwrap(),
}
} else {
url.clone()
}
} else {
url.clone()
};
inner.put(specifier.clone(), LspClientUrl(url.clone()));
specifier
return specifier;
}
let mut specifier = None;
if url.scheme() == "file" {
if let Ok(path) = url.to_file_path() {
specifier = Some(match kind {
LspUrlKind::Folder => Url::from_directory_path(path).unwrap(),
LspUrlKind::File => Url::from_file_path(path).unwrap(),
});
}
} else if let Some(s) = from_deno_url(url) {
specifier = Some(s);
}
let specifier = specifier.unwrap_or_else(|| url.clone());
inner.put(specifier.clone(), LspClientUrl(url.clone()));
specifier
}
}

Expand Down Expand Up @@ -261,6 +287,24 @@ mod tests {
assert_eq!(actual_specifier, fixture);
}

#[test]
fn test_lsp_url_reverse() {
let map = LspUrlMap::default();
let fixture =
resolve_url("deno:/https/deno.land/x/pkg%401.0.0/mod.ts").unwrap();
let actual_specifier = map.normalize_url(&fixture, LspUrlKind::File);
let expected_specifier =
Url::parse("https://deno.land/x/[email protected]/mod.ts").unwrap();
assert_eq!(&actual_specifier, &expected_specifier);

let actual_url = map
.normalize_specifier(&actual_specifier)
.unwrap()
.as_url()
.clone();
assert_eq!(actual_url, fixture);
}

#[test]
fn test_lsp_url_map_complex_encoding() {
// Test fix for #9741 - not properly encoding certain URLs
Expand Down

0 comments on commit 2215a3e

Please sign in to comment.