flowchart LR
R["client request URI"] --> N{"scheme is<br>readonly-remote?<br>authority is workspace?"}
N -->|no| E["RemotePathError"]
N -->|yes| S{"root-relative path<br>is safe?"}
S -->|no| E
S -->|yes| OK["ParsedRemotePath<br>→ host read"]///|
fn resolved(raw : String) -> String raise {
match @server.resolve_remote_document_uri(@base_common.Uri::parse(raw)) {
ParsedRemotePath(path) => "ok:" + path.to_string()
RemotePathError(error) => "rejected:" + error.code.to_string()
}
}
///|
test "only in-namespace, non-traversing paths resolve" {
debug_inspect(
[
"readonly-remote://workspace/src/main.mbt", "readonly-remote://workspace/../outside.mbt",
"readonly-remote://other/src/main.mbt", "file:///src/main.mbt",
].map(resolved),
content=(
#|[
#| "ok:src/main.mbt",
#| "rejected:InvalidUri",
#| "rejected:InvalidUri",
#| "rejected:InvalidUri",
#|]
),
)
}///|
test "constructing a remote URI agrees with resolving one" {
debug_inspect(
["src/main.mbt", "../escape.mbt", "/absolute.mbt"].map(path => {
@server.remote_document_uri(path).map(uri => uri.to_string())
}),
content=(
#|[Some("readonly-remote://workspace/src/main.mbt"), None, None]
),
)
}pub(open) trait ServerHost {
async fn read_directory(Self, String, String) -> ServerHostResolveResult
async fn read_text_file(Self, String, SourcePath) -> ServerHostReadResult
fn watch_text_file(Self, String, SourcePath, async (FileChangeType) -> Unit, (async () -> Unit) -> Unit) -> ServerWatch
}pub(all) enum RemoteDirectoryResult {
ParsedRemoteDirectory(String, String)
RemoteDirectoryError(ProtocolError)
} derive(Debug)pub(all) enum RemotePathResult {
ParsedRemotePath(SourcePath)
RemotePathError(ProtocolError)
} derive(Debug)type RemoteServerasync fn RemoteServer::definition(self : RemoteServer, request : DocumentPositionRequest) -> ServerPacketasync fn RemoteServer::document_symbols(self : RemoteServer, request : DocumentRevisionRequest) -> ServerPacketasync fn RemoteServer::handle_client_packet(self : RemoteServer, packet : ClientPacket, emit : async (ServerPacket) -> Unit, spawn_watch : (async () -> Unit) -> Unit) -> Array[ServerPacket]async fn RemoteServer::hover(self : RemoteServer, request : DocumentPositionRequest) -> ServerPacketasync fn RemoteServer::open_document(self : RemoteServer, request : DocumentRequest) -> ServerPacketasync fn RemoteServer::references(self : RemoteServer, request : DocumentPositionRequest) -> ServerPacketasync fn RemoteServer::resolve_directory(self : RemoteServer, request : DocumentRequest) -> ServerPacketfn RemoteServer::set_document_sync_listener(self : RemoteServer, listener : (DocumentSnapshot) -> Unit?) -> Unitasync fn RemoteServer::watch_document(self : RemoteServer, request : DocumentRequest, emit : async (ServerPacket) -> Unit, spawn_watch : (async () -> Unit) -> Unit) -> ServerPacketfn RemoteServer::with_language_providers(workspace_root : String, host : &ServerHost, hover_provider : &HoverProvider, definition_provider : &DefinitionProvider, references_provider : &ReferencesProvider, document_symbol_provider : &DocumentSymbolProvider) -> RemoteServerpub(all) enum ServerHostReadResult {
ServerHostReadOk(DocumentContent)
ServerHostReadError(FileSystemProviderErrorCode, String)
} derive(Debug)pub(all) enum ServerHostResolveResult {
ServerHostResolveOk(Array[WorkspaceStat])
ServerHostResolveError(FileSystemProviderErrorCode, String)
} derive(Debug)type ServerWatch