mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-02 12:54:32 +00:00
* fix(web-shell): preserve session URL context * fix(web-shell): keep daemon token out of the session URL (#7926) Restore the daemon token stripping that was dropped alongside the base-path fix: removeDaemonTokenFromUrl() on startup and the ?token= delete in replaceStandaloneSessionUrl. The ?token= query path is still supported for backward compatibility, so without stripping it leaks into the address bar, history, access logs, and Referer headers. Also extract the session pathname building into buildSessionPathname() with unit tests covering root/sub-path deployments, the no-session case, trailing slashes, and id encoding. * fix(web-shell): anchor session URL parser to agree with writer (#7926) Extract parseSessionId() next to buildSessionPathname() and anchor it to the last /session/<id> segment so the parser agrees with the greedy writer. Previously a base path ending in a session segment produced /app/session/session/<id>, which the first-match parser read back as the literal id "session". Add round-trip and trailing-slash coverage. * test(web-shell): cover parseSessionId malformed-encoding catch branch (#7926) * fix(web-shell): preserve base path in split-view URL (#7926) --------- Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
98 lines
3.1 KiB
TypeScript
98 lines
3.1 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2026 Qwen Team
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
import { buildSessionPathname, parseSessionId } from './sessionPath';
|
|
|
|
describe('buildSessionPathname', () => {
|
|
it('replaces an existing session segment at the root', () => {
|
|
expect(buildSessionPathname('/session/old', 'new')).toBe('/session/new');
|
|
});
|
|
|
|
it('preserves a sub-path deployment base', () => {
|
|
expect(buildSessionPathname('/app/session/old', 'new')).toBe(
|
|
'/app/session/new',
|
|
);
|
|
});
|
|
|
|
it('appends a session under a base path with no existing session', () => {
|
|
expect(buildSessionPathname('/app', 'new')).toBe('/app/session/new');
|
|
});
|
|
|
|
it('appends a session at the root when there is no existing session', () => {
|
|
expect(buildSessionPathname('/', 'new')).toBe('/session/new');
|
|
});
|
|
|
|
it('strips a trailing slash from the base path', () => {
|
|
expect(buildSessionPathname('/app/', 'new')).toBe('/app/session/new');
|
|
});
|
|
|
|
it('strips a trailing slash after an existing session id', () => {
|
|
expect(buildSessionPathname('/session/old/', 'new')).toBe('/session/new');
|
|
expect(buildSessionPathname('/app/session/old/', 'new')).toBe(
|
|
'/app/session/new',
|
|
);
|
|
});
|
|
|
|
it('encodes the session id', () => {
|
|
expect(buildSessionPathname('/', 'a b/c')).toBe('/session/a%20b%2Fc');
|
|
});
|
|
|
|
it('returns the base path when no session is given', () => {
|
|
expect(buildSessionPathname('/app/session/old', undefined)).toBe('/app');
|
|
});
|
|
|
|
it('returns "/" when no session is given at the root', () => {
|
|
expect(buildSessionPathname('/', undefined)).toBe('/');
|
|
expect(buildSessionPathname('/session/old', undefined)).toBe('/');
|
|
});
|
|
});
|
|
|
|
describe('parseSessionId', () => {
|
|
it('reads the session id at the root', () => {
|
|
expect(parseSessionId('/session/abc')).toBe('abc');
|
|
});
|
|
|
|
it('reads the last session segment under a base path', () => {
|
|
expect(parseSessionId('/app/session/abc')).toBe('abc');
|
|
});
|
|
|
|
it('ignores a trailing slash', () => {
|
|
expect(parseSessionId('/session/abc/')).toBe('abc');
|
|
});
|
|
|
|
it('decodes the session id', () => {
|
|
expect(parseSessionId('/session/a%20b%2Fc')).toBe('a b/c');
|
|
});
|
|
|
|
it('returns undefined for malformed percent-encoding', () => {
|
|
expect(parseSessionId('/session/%E0%A4%A')).toBeUndefined();
|
|
});
|
|
|
|
it('returns undefined when there is no session segment', () => {
|
|
expect(parseSessionId('/')).toBeUndefined();
|
|
expect(parseSessionId('/app')).toBeUndefined();
|
|
});
|
|
|
|
it('returns undefined for an empty session id', () => {
|
|
expect(parseSessionId('/app/session/')).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('build/parse round-trip', () => {
|
|
it('reads back the written session id', () => {
|
|
for (const base of ['/', '/app', '/app/', '/app/session/old']) {
|
|
expect(parseSessionId(buildSessionPathname(base, 'real-id'))).toBe(
|
|
'real-id',
|
|
);
|
|
}
|
|
});
|
|
|
|
it('reads back the written id when the base path ends in a session segment', () => {
|
|
const pathname = buildSessionPathname('/app/session/', 'real-id');
|
|
expect(parseSessionId(pathname)).toBe('real-id');
|
|
});
|
|
});
|