Skip to content

Commit 7b71f9c

Browse files
committed
Fixes #372
1 parent 0fd2785 commit 7b71f9c

File tree

3 files changed

+53
-31
lines changed

3 files changed

+53
-31
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Fix issue [#367](https://github.com/intersystems/language-server/issues/367): Support `objectscript.multilineMethodArgs` being set per workspace folder
66
- Fix issue [#370](https://github.com/intersystems/language-server/issues/370): Infinite recursion when a variable is set to the result of one of its instance methods
77
- Fix issue [#371](https://github.com/intersystems/language-server/issues/371): Don't report problems for code enclosed in `#if 0` blocks
8+
- Fix issue [#372](https://github.com/intersystems/language-server/issues/372): Log out of web sessions when VS Code exits
89
- Parser changes:
910
- DP-438845, DP-440271: Support new keywords for deferred filing of indices and computed fields
1011

client/src/extension.ts

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
TransportKind
2121
} from 'vscode-languageclient/node';
2222

23-
import { gt, lte } from "semver";
23+
import { gt, lte, lt } from "semver";
2424
import * as serverManager from "@intersystems-community/intersystems-servermanager";
2525

2626
import { ObjectScriptEvaluatableExpressionProvider } from './evaluatableExpressionProvider';
@@ -40,8 +40,29 @@ export let client: LanguageClient;
4040
/**
4141
* Cache for cookies from REST requests to InterSystems servers.
4242
*/
43-
export let cookiesCache: Cache;
43+
let cookiesCache: Cache;
4444

45+
export async function updateCookies(newCookies: string[], server: ServerSpec): Promise<string[]> {
46+
const key = `${server.username}@${server.host}:${server.port}${server.pathPrefix}`;
47+
const cookies = cookiesCache.get(key, []);
48+
newCookies.forEach((cookie) => {
49+
const [cookieName] = cookie.split("=");
50+
const index = cookies.findIndex((el) => el.startsWith(cookieName));
51+
if (index >= 0) {
52+
cookies[index] = cookie;
53+
} else {
54+
cookies.push(cookie);
55+
}
56+
});
57+
await cookiesCache.put(key, cookies);
58+
return cookies;
59+
}
60+
61+
export function getCookies(server: ServerSpec): string[] {
62+
return cookiesCache.get(`${server.username}@${server.host}:${server.port}${server.pathPrefix}`, []);
63+
}
64+
65+
let objectScriptApi;
4566
let serverManagerApi: serverManager.ServerManagerAPI;
4667

4768
type MakeRESTRequestParams = {
@@ -57,7 +78,7 @@ type MakeRESTRequestParams = {
5778
export async function activate(context: ExtensionContext) {
5879
// Get the main extension exported API
5980
const objectScriptExt = extensions.getExtension("intersystems-community.vscode-objectscript");
60-
const objectScriptApi = objectScriptExt.isActive ? objectScriptExt.exports : await objectScriptExt.activate();
81+
objectScriptApi = objectScriptExt.isActive ? objectScriptExt.exports : await objectScriptExt.activate();
6182

6283
cookiesCache = new Cache(context, "cookies");
6384
// The server is implemented in node
@@ -346,9 +367,28 @@ export async function activate(context: ExtensionContext) {
346367
}
347368
}
348369

349-
export function deactivate(): Thenable<void> | undefined {
350-
if (!client) {
351-
return undefined;
370+
export async function deactivate(): Promise<void> {
371+
// Stop the server and log out of all CSP sessions
372+
const loggedOut: Set<string> = new Set();
373+
const promises: Promise<any>[] = client ? [client.stop()] : [];
374+
for (const f of workspace.workspaceFolders ?? []) {
375+
const serverSpec: ServerSpec = objectScriptApi.serverForUri(f.uri);
376+
if (!serverSpec?.active) continue;
377+
const sessionCookie = getCookies(serverSpec).find((c) => c.startsWith("CSPSESSIONID-"));
378+
if (!sessionCookie || loggedOut.has(sessionCookie)) continue;
379+
loggedOut.add(sessionCookie);
380+
promises.push(
381+
makeRESTRequest(
382+
"HEAD",
383+
0,
384+
undefined,
385+
serverSpec,
386+
undefined,
387+
undefined,
388+
// Prefer IRISLogout for servers that support it
389+
lt(serverSpec.serverVersion, "2018.2.0") ? { CacheLogout: "end" } : { IRISLogout: "end" }
390+
)
391+
);
352392
}
353-
return client.stop();
393+
await Promise.allSettled(promises);
354394
}

client/src/makeRESTRequest.ts

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { workspace } from 'vscode';
33
import axios, { AxiosResponse } from 'axios';
44
import * as https from 'https';
55

6-
import { client, cookiesCache } from './extension';
6+
import { client, getCookies, updateCookies } from './extension';
77

88
export type ServerSpec = {
99
scheme: string,
@@ -15,29 +15,10 @@ export type ServerSpec = {
1515
username: string,
1616
serverName: string,
1717
password: string,
18+
serverVersion: string,
1819
active: boolean
1920
};
2021

21-
async function updateCookies(newCookies: string[], server: ServerSpec): Promise<string[]> {
22-
const key = `${server.username}@${server.host}:${server.port}${server.pathPrefix}`;
23-
const cookies = cookiesCache.get(key, []);
24-
newCookies.forEach((cookie) => {
25-
const [cookieName] = cookie.split("=");
26-
const index = cookies.findIndex((el) => el.startsWith(cookieName));
27-
if (index >= 0) {
28-
cookies[index] = cookie;
29-
} else {
30-
cookies.push(cookie);
31-
}
32-
});
33-
await cookiesCache.put(key, cookies);
34-
return cookies;
35-
}
36-
37-
function getCookies(server: ServerSpec): string[] {
38-
return cookiesCache.get(`${server.username}@${server.host}:${server.port}${server.pathPrefix}`, []);
39-
}
40-
4122
/**
4223
* Send a REST request to an InterSystems server.
4324
*
@@ -49,7 +30,7 @@ function getCookies(server: ServerSpec): string[] {
4930
* @param checksum Optional checksum. Only passed for SASchema requests.
5031
* @param params Optional URL parameters. Only passed for GET /doc/ requests.
5132
*/
52-
export async function makeRESTRequest(method: "GET"|"POST", api: number, path: string, server: ServerSpec, data?: any, checksum?: string, params?: any): Promise<AxiosResponse<any> | undefined> {
33+
export async function makeRESTRequest(method: "GET"|"POST"|"HEAD", api: number, path: string, server: ServerSpec, data?: any, checksum?: string, params?: any): Promise<AxiosResponse<any> | undefined> {
5334
if (server.host === "") {
5435
// No server connection is configured
5536
client.warn("Cannot make required REST request because no server connection is configured.");
@@ -75,7 +56,7 @@ export async function makeRESTRequest(method: "GET"|"POST", api: number, path: s
7556
}
7657

7758
// Build the URL
78-
let url = encodeURI(`${server.scheme}://${server.host}:${server.port}${server.pathPrefix}/api/atelier/v${server.apiVersion}/${server.namespace}${path}`);
59+
let url = encodeURI(`${server.scheme}://${server.host}:${server.port}${server.pathPrefix}/api/atelier/${api ? `v${server.apiVersion}/${server.namespace}${path}` : "" }`);
7960

8061
// Create the HTTPS agent
8162
const httpsAgent = new https.Agent({ rejectUnauthorized: workspace.getConfiguration("http").get("proxyStrictSSL") });
@@ -234,7 +215,7 @@ export async function makeRESTRequest(method: "GET"|"POST", api: number, path: s
234215
}
235216
}
236217
);
237-
if (respdata.status === 401) {
218+
if (respdata.status === 401 && api) { // api is only 0 when calling HEAD / to log out of the session
238219
// Either we had no cookies or they expired, so resend the request with basic auth
239220

240221
respdata = await axios.request(

0 commit comments

Comments
 (0)