mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
add DCS interface, payload limits for DCS/OSC
This commit is contained in:
+15
-7
@@ -22,6 +22,7 @@ import { IAttributeData, IDisposable } from 'common/Types';
|
||||
import { ICoreService, IBufferService, IOptionsService, ILogService, IDirtyRowService } from 'common/services/Services';
|
||||
import { ISelectionService } from 'browser/services/Services';
|
||||
import { OscHandlerFactory } from 'common/parser/OscParser';
|
||||
import { DcsHandlerFactory } from 'common/parser/DcsParser';
|
||||
|
||||
/**
|
||||
* Map collect to glevel. Used in `selectCharset`.
|
||||
@@ -485,13 +486,6 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
this._dirtyRowService.markDirty(buffer.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward addEscHandler from parser.
|
||||
*/
|
||||
public addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable {
|
||||
return this._parser.addEscHandler(collectAndFlag, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward addCsiHandler from parser.
|
||||
*/
|
||||
@@ -499,6 +493,20 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
return this._parser.addCsiHandler(flag, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward addDcsHandler from parser.
|
||||
*/
|
||||
public addDcsHandler(collectAndFlag: string, callback: (param: IParams, data: string) => boolean): IDisposable {
|
||||
return this._parser.addDcsHandler(collectAndFlag, new DcsHandlerFactory(callback));
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward addEscHandler from parser.
|
||||
*/
|
||||
public addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable {
|
||||
return this._parser.addEscHandler(collectAndFlag, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward addOscHandler from parser.
|
||||
*/
|
||||
|
||||
@@ -1397,6 +1397,11 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp
|
||||
return this._inputHandler.addEscHandler(collectAndFlag, handler);
|
||||
}
|
||||
|
||||
/** Add handler for DCS escape sequence. See xterm.d.ts for details. */
|
||||
public addDcsHandler(collectAndFlag: string, callback: (param: IParams, data: string) => boolean): IDisposable {
|
||||
return this._inputHandler.addDcsHandler(collectAndFlag, callback);
|
||||
}
|
||||
|
||||
/** Add handler for CSI escape sequence. See xterm.d.ts for details. */
|
||||
public addCsiHandler(flag: string, callback: (params: IParams, collect: string) => boolean): IDisposable {
|
||||
return this._inputHandler.addCsiHandler(flag, callback);
|
||||
|
||||
@@ -77,6 +77,9 @@ export class MockTerminal implements ITerminal {
|
||||
addCsiHandler(flag: string, callback: (params: IParams, collect: string) => boolean): IDisposable {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
addDcsHandler(collectAndFlag: string, callback: (param: IParams, data: string) => boolean): IDisposable {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -201,6 +201,7 @@ export interface IPublicTerminal extends IDisposable {
|
||||
open(parent: HTMLElement): void;
|
||||
attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void;
|
||||
addCsiHandler(flag: string, callback: (params: IParams, collect: string) => boolean): IDisposable;
|
||||
addDcsHandler(collectAndFlag: string, callback: (param: IParams, data: string) => boolean): IDisposable;
|
||||
addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable;
|
||||
addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable;
|
||||
registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): number;
|
||||
|
||||
@@ -138,7 +138,7 @@ describe('DcsParser', () => {
|
||||
});
|
||||
describe('DcsHandlerFactory', () => {
|
||||
it('should be called once on end(true)', () => {
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params, data])));
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -148,7 +148,7 @@ describe('DcsParser', () => {
|
||||
assert.deepEqual(reports, [[[1, 2, 3], 'Here comes the mouse!']]);
|
||||
});
|
||||
it('should not be called on end(false)', () => {
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params, data])));
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -158,8 +158,8 @@ describe('DcsParser', () => {
|
||||
assert.deepEqual(reports, []);
|
||||
});
|
||||
it('should be disposable', () => {
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push(['one', params, data])));
|
||||
const dispo = parser.addDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push(['two', params, data])));
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push(['one', params.toArray(), data])));
|
||||
const dispo = parser.addDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push(['two', params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { IDisposable } from 'common/Types';
|
||||
import { IDcsHandler, IParams, ParamsArray, IHandlerCollection, IDcsParser, DcsFallbackHandler } from 'common/parser/Types';
|
||||
import { utf32ToString } from 'common/input/TextDecoder';
|
||||
import { Params } from './Params';
|
||||
|
||||
|
||||
export class DcsParser implements IDcsParser {
|
||||
@@ -98,24 +99,47 @@ export class DcsParser implements IDcsParser {
|
||||
}
|
||||
}
|
||||
|
||||
// limit allowed payload for DcsHandlerFactory
|
||||
const PAYLOAD_LIMIT = 50000000;
|
||||
|
||||
/**
|
||||
* Convenient class to create a DCS handler from a single callback function.
|
||||
* Note: The payload is currently limited to 50 MB (hardcoded).
|
||||
*/
|
||||
export class DcsHandlerFactory implements IDcsHandler {
|
||||
private _data = '';
|
||||
private _params: IParams | undefined;
|
||||
constructor(private _handler: (params: ParamsArray, data: string) => any) {}
|
||||
private _hitLimit: boolean = false;
|
||||
|
||||
constructor(private _handler: (params: IParams, data: string) => any) {}
|
||||
|
||||
public hook(collect: string, params: IParams, flag: number): void {
|
||||
this._params = params.clone();
|
||||
this._data = '';
|
||||
this._hitLimit = false;
|
||||
}
|
||||
|
||||
public put(data: Uint32Array, start: number, end: number): void {
|
||||
if (this._hitLimit) {
|
||||
return;
|
||||
}
|
||||
this._data += utf32ToString(data, start, end);
|
||||
if (this._data.length > PAYLOAD_LIMIT) {
|
||||
this._data = '';
|
||||
this._hitLimit = true;
|
||||
}
|
||||
}
|
||||
|
||||
public unhook(success: boolean): any {
|
||||
let ret;
|
||||
if (success) {
|
||||
ret = this._handler(this._params ? this._params.toArray() : [], this._data);
|
||||
if (this._hitLimit) {
|
||||
ret = false;
|
||||
} else if (success) {
|
||||
ret = this._handler(this._params ? this._params : new Params(), this._data);
|
||||
}
|
||||
this._params = undefined;
|
||||
this._data = '';
|
||||
this._hitLimit = false;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,25 +163,44 @@ export class OscParser extends Disposable {
|
||||
}
|
||||
|
||||
|
||||
// limit allowed payload for OscHandlerFactory
|
||||
const PAYLOAD_LIMIT = 50000000;
|
||||
|
||||
/**
|
||||
* Convenient class to allow attaching string based handler functions
|
||||
* as OSC handlers.
|
||||
*/
|
||||
export class OscHandlerFactory implements IOscHandler {
|
||||
private _data = '';
|
||||
private _hitLimit: boolean = false;
|
||||
|
||||
constructor(private _handler: (data: string) => any) {}
|
||||
|
||||
public start(): void {
|
||||
this._data = '';
|
||||
this._hitLimit = false;
|
||||
}
|
||||
|
||||
public put(data: Uint32Array, start: number, end: number): void {
|
||||
if (this._hitLimit) {
|
||||
return;
|
||||
}
|
||||
this._data += utf32ToString(data, start, end);
|
||||
if (this._data.length > PAYLOAD_LIMIT) {
|
||||
this._data = '';
|
||||
this._hitLimit = true;
|
||||
}
|
||||
}
|
||||
|
||||
public end(success: boolean): any {
|
||||
let ret;
|
||||
if (success) {
|
||||
if (this._hitLimit) {
|
||||
ret = false;
|
||||
} else if (success) {
|
||||
ret = this._handler(this._data);
|
||||
}
|
||||
this._data = '';
|
||||
this._hitLimit = false;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,9 @@ export class Terminal implements ITerminalApi {
|
||||
public addCsiHandler(flag: string, callback: (params: (number | number[])[], collect: string) => boolean): IDisposable {
|
||||
return this._core.addCsiHandler(flag, (params: IParams, collect: string) => callback(params.toArray(), collect));
|
||||
}
|
||||
public addDcsHandler(collectAndFlag: string, callback: (param: (number | number[])[], data: string) => boolean): IDisposable {
|
||||
return this._core.addDcsHandler(collectAndFlag, (params: IParams, data: string) => callback(params.toArray(), data));
|
||||
}
|
||||
public addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable {
|
||||
return this._core.addEscHandler(collectAndFlag, handler);
|
||||
}
|
||||
|
||||
Vendored
+27
-4
@@ -515,10 +515,28 @@ declare module 'xterm' {
|
||||
*/
|
||||
addCsiHandler(flag: string, callback: (params: (number | number[])[], collect: string) => boolean): IDisposable;
|
||||
|
||||
/**
|
||||
* Adds a handler for DCS escape sequences.
|
||||
* @param collect Should be a string, which specifies the collect and the
|
||||
* final character (e.g "$q" for DECRQSS) of the DCS sequence.
|
||||
* @param callback The function to handle the escape sequence. Note that the
|
||||
* function will only be called once if the sequence finished sucessfully.
|
||||
* There is currently no way to intercept smaller data chunks, those will be stored up
|
||||
* until the sequence is finished. Since DCS sequences are not limited by the amount
|
||||
* of data this might impose a problem for big payloads. Currently xterm.js limits
|
||||
* DCS payload to 50 MB which should give enough room for most use cases.
|
||||
* The function gets numerical parameter and the data as arguments.
|
||||
* Return true if the sequence was handled; false if
|
||||
* we should try a previous handler (set by addDcsHandler or setDcsHandler).
|
||||
* The most recently-added handler is tried first.
|
||||
* @return An IDisposable you can call to remove this handler.
|
||||
*/
|
||||
addDcsHandler(collect: string, callback: (param: (number | number[])[], data: string) => boolean): IDisposable;
|
||||
|
||||
/**
|
||||
* Adds a handler for ESC escape sequences.
|
||||
* @param flag The flag should be a string, which specifies the
|
||||
* collect and the final character (e.g "%G" for default charset selection)
|
||||
* @param collect Should be a string, which specifies the collect and the
|
||||
* final character (e.g "%G" for default charset selection)
|
||||
* of the ESC sequence.
|
||||
* @param callback The function to handle the escape sequence.
|
||||
* Return true if the sequence was handled; false if
|
||||
@@ -531,8 +549,13 @@ declare module 'xterm' {
|
||||
/**
|
||||
* Adds a handler for OSC escape sequences.
|
||||
* @param ident The number (first parameter) of the sequence.
|
||||
* @param callback The function to handle the escape sequence. The callback
|
||||
* is called with OSC data string. Return true if the sequence was handled;
|
||||
* @param callback The function to handle the escape sequence. Note that the
|
||||
* function will only be called once if the sequence finished sucessfully.
|
||||
* There is currently no way to intercept smaller data chunks, those will be stored up
|
||||
* until the sequence is finished. Since OSC sequences are not limited by the amount
|
||||
* of data this might impose a problem for big payloads. Currently xterm.js limits
|
||||
* OSC payload to 50 MB which should give enough room for most use cases.
|
||||
* The callback is called with OSC data string. Return true if the sequence was handled;
|
||||
* false if we should try a previous handler (set by addOscHandler or
|
||||
* setOscHandler). The most recently-added handler is tried first.
|
||||
* @return An IDisposable you can call to remove this handler.
|
||||
|
||||
Reference in New Issue
Block a user