From a2967565deb39f8633da1fb4d653c909f505b409 Mon Sep 17 00:00:00 2001 From: Benjamin Schweizer Date: Mon, 30 Jul 2018 17:19:41 +0200 Subject: [PATCH 1/6] added urlescape formatting option --- docs/sources/reference/templating.md | 1 + public/app/features/templating/specs/template_srv.jest.ts | 5 +++++ public/app/features/templating/template_srv.ts | 7 +++++++ 3 files changed, 13 insertions(+) diff --git a/docs/sources/reference/templating.md b/docs/sources/reference/templating.md index ce1a1299d26..d59117fefea 100644 --- a/docs/sources/reference/templating.md +++ b/docs/sources/reference/templating.md @@ -52,6 +52,7 @@ Filter Option | Example | Raw | Interpolated | Description `csv`| ${servers:csv} | `'test1', 'test2'` | `test1,test2` | Formats multi-value variable as a comma-separated string `distributed`| ${servers:distributed} | `'test1', 'test2'` | `test1,servers=test2` | Formats multi-value variable in custom format for OpenTSDB. `lucene`| ${servers:lucene} | `'test', 'test2'` | `("test" OR "test2")` | Formats multi-value variable as a lucene expression. +`urlescape` | ${servers:urlescape} | `'foo()bar baz', 'test2'` | `{foo%28%29bar%20baz%2Ctest2}` | Formats multi-value variable into a glob, url escaped Test the formatting options on the [Grafana Play site](http://play.grafana.org/d/cJtIfcWiz/template-variable-formatting-options?orgId=1). diff --git a/public/app/features/templating/specs/template_srv.jest.ts b/public/app/features/templating/specs/template_srv.jest.ts index 86b6aa7ec99..040597888b6 100644 --- a/public/app/features/templating/specs/template_srv.jest.ts +++ b/public/app/features/templating/specs/template_srv.jest.ts @@ -275,6 +275,11 @@ describe('templateSrv', function() { expect(result).toBe('test,test2'); }); + it('multi value and urlescape format should render url-escaped string', function() { + var result = _templateSrv.formatValue(['foo()bar baz', 'test2'], 'urlescape'); + expect(result).toBe('foo%28%29bar%20baz%2Ctest2'); + }); + it('slash should be properly escaped in regex format', function() { var result = _templateSrv.formatValue('Gi3/14', 'regex'); expect(result).toBe('Gi3\\/14'); diff --git a/public/app/features/templating/template_srv.ts b/public/app/features/templating/template_srv.ts index fc79d12ff9e..7ce539b6506 100644 --- a/public/app/features/templating/template_srv.ts +++ b/public/app/features/templating/template_srv.ts @@ -124,6 +124,13 @@ export class TemplateSrv { } return value; } + case 'urlescape': { + // like glob, but url escaped + if (_.isArray(value)) { + return escape('{' + value.join(',') + '}'); + } + return escape(value); + } default: { if (_.isArray(value)) { return '{' + value.join(',') + '}'; From 7da9c33ae4dae4232d242e8ab6710be720bdfd35 Mon Sep 17 00:00:00 2001 From: Benjamin Schweizer Date: Mon, 30 Jul 2018 17:28:50 +0200 Subject: [PATCH 2/6] fixed test result --- public/app/features/templating/specs/template_srv.jest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/templating/specs/template_srv.jest.ts b/public/app/features/templating/specs/template_srv.jest.ts index 040597888b6..85a159fc098 100644 --- a/public/app/features/templating/specs/template_srv.jest.ts +++ b/public/app/features/templating/specs/template_srv.jest.ts @@ -277,7 +277,7 @@ describe('templateSrv', function() { it('multi value and urlescape format should render url-escaped string', function() { var result = _templateSrv.formatValue(['foo()bar baz', 'test2'], 'urlescape'); - expect(result).toBe('foo%28%29bar%20baz%2Ctest2'); + expect(result).toBe('%7Bfoo%28%29bar%20baz%2Ctest2%7D'); }); it('slash should be properly escaped in regex format', function() { From 9220f83b3dcd4376d1ec8a5ab5bdf0a0e031a65f Mon Sep 17 00:00:00 2001 From: Benjamin Schweizer Date: Mon, 6 Aug 2018 21:54:12 +0200 Subject: [PATCH 3/6] replaced escape() call, renamed formatter to be more expressive --- docs/sources/reference/templating.md | 2 +- .../features/templating/specs/template_srv.jest.ts | 6 +++--- public/app/features/templating/template_srv.ts | 13 ++++++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/sources/reference/templating.md b/docs/sources/reference/templating.md index d59117fefea..1482eb34350 100644 --- a/docs/sources/reference/templating.md +++ b/docs/sources/reference/templating.md @@ -52,7 +52,7 @@ Filter Option | Example | Raw | Interpolated | Description `csv`| ${servers:csv} | `'test1', 'test2'` | `test1,test2` | Formats multi-value variable as a comma-separated string `distributed`| ${servers:distributed} | `'test1', 'test2'` | `test1,servers=test2` | Formats multi-value variable in custom format for OpenTSDB. `lucene`| ${servers:lucene} | `'test', 'test2'` | `("test" OR "test2")` | Formats multi-value variable as a lucene expression. -`urlescape` | ${servers:urlescape} | `'foo()bar baz', 'test2'` | `{foo%28%29bar%20baz%2Ctest2}` | Formats multi-value variable into a glob, url escaped +`percentencode` | ${servers:percentencode} | `'foo()bar BAZ', 'test2'` | `{foo%28%29bar%20BAZ%2Ctest2}` | Formats multi-value variable into a glob, percent-escaped Test the formatting options on the [Grafana Play site](http://play.grafana.org/d/cJtIfcWiz/template-variable-formatting-options?orgId=1). diff --git a/public/app/features/templating/specs/template_srv.jest.ts b/public/app/features/templating/specs/template_srv.jest.ts index 85a159fc098..b4501e81f59 100644 --- a/public/app/features/templating/specs/template_srv.jest.ts +++ b/public/app/features/templating/specs/template_srv.jest.ts @@ -275,9 +275,9 @@ describe('templateSrv', function() { expect(result).toBe('test,test2'); }); - it('multi value and urlescape format should render url-escaped string', function() { - var result = _templateSrv.formatValue(['foo()bar baz', 'test2'], 'urlescape'); - expect(result).toBe('%7Bfoo%28%29bar%20baz%2Ctest2%7D'); + it('multi value and percentencode format should render percent-encoded string', function() { + var result = _templateSrv.formatValue(['foo()bar BAZ', 'test2'], 'percentencode'); + expect(result).toBe('%7Bfoo%28%29bar%20BAZ%2Ctest2%7D'); }); it('slash should be properly escaped in regex format', function() { diff --git a/public/app/features/templating/template_srv.ts b/public/app/features/templating/template_srv.ts index 7ce539b6506..3d462f1bcde 100644 --- a/public/app/features/templating/template_srv.ts +++ b/public/app/features/templating/template_srv.ts @@ -83,6 +83,13 @@ export class TemplateSrv { return '(' + quotedValues.join(' OR ') + ')'; } + // like encodeURIComponent() but for all characters except alpha-numerics + encodeURIQueryValue(str) { + return str.replace(/[^a-z0-9]/gi, function(c) { + return '%' + c.charCodeAt(0).toString(16); + }); + } + formatValue(value, format, variable) { // for some scopedVars there is no variable variable = variable || {}; @@ -124,12 +131,12 @@ export class TemplateSrv { } return value; } - case 'urlescape': { + case 'percentencode': { // like glob, but url escaped if (_.isArray(value)) { - return escape('{' + value.join(',') + '}'); + return this.encodeURIQueryValue('{' + value.join(',') + '}'); } - return escape(value); + return this.encodeURIQueryValue(value); } default: { if (_.isArray(value)) { From a653b277f312766ebfe0bb00ea0f6268139591d1 Mon Sep 17 00:00:00 2001 From: Benjamin Schweizer Date: Mon, 6 Aug 2018 22:04:33 +0200 Subject: [PATCH 4/6] switched to lowercase --- public/app/features/templating/specs/template_srv.jest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/templating/specs/template_srv.jest.ts b/public/app/features/templating/specs/template_srv.jest.ts index b4501e81f59..3d8b3af1ddd 100644 --- a/public/app/features/templating/specs/template_srv.jest.ts +++ b/public/app/features/templating/specs/template_srv.jest.ts @@ -277,7 +277,7 @@ describe('templateSrv', function() { it('multi value and percentencode format should render percent-encoded string', function() { var result = _templateSrv.formatValue(['foo()bar BAZ', 'test2'], 'percentencode'); - expect(result).toBe('%7Bfoo%28%29bar%20BAZ%2Ctest2%7D'); + expect(result).toBe('%7bfoo%28%29bar%20BAZ%2ctest2%7d'); }); it('slash should be properly escaped in regex format', function() { From f4b29b5782bea2efe8d428f9cc164678306cd7dd Mon Sep 17 00:00:00 2001 From: Benjamin Schweizer Date: Mon, 3 Sep 2018 16:08:52 +0200 Subject: [PATCH 5/6] fixed testcase --- public/app/features/templating/specs/template_srv.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/templating/specs/template_srv.test.ts b/public/app/features/templating/specs/template_srv.test.ts index 06c7ac552c9..3e5ddf8bf54 100644 --- a/public/app/features/templating/specs/template_srv.test.ts +++ b/public/app/features/templating/specs/template_srv.test.ts @@ -276,7 +276,7 @@ describe('templateSrv', function() { }); it('multi value and percentencode format should render percent-encoded string', function() { - var result = _templateSrv.formatValue(['foo()bar BAZ', 'test2'], 'percentencode'); + const result = _templateSrv.formatValue(['foo()bar BAZ', 'test2'], 'percentencode'); expect(result).toBe('%7bfoo%28%29bar%20BAZ%2ctest2%7d'); }); From bde4b76c167c0b45e1f77b75a8270afce0da5a6a Mon Sep 17 00:00:00 2001 From: Benjamin Schweizer Date: Tue, 22 Jan 2019 15:09:58 +0100 Subject: [PATCH 6/6] based on encodeURIComponent() using strict RFC 3986 sub-delims --- docs/sources/reference/templating.md | 2 +- .../features/templating/specs/template_srv.test.ts | 2 +- public/app/features/templating/template_srv.ts | 14 ++++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/sources/reference/templating.md b/docs/sources/reference/templating.md index 900288d15a7..3ef32b1b10f 100644 --- a/docs/sources/reference/templating.md +++ b/docs/sources/reference/templating.md @@ -52,7 +52,7 @@ Filter Option | Example | Raw | Interpolated | Description `csv`| ${servers:csv} | `'test1', 'test2'` | `test1,test2` | Formats multi-value variable as a comma-separated string `distributed`| ${servers:distributed} | `'test1', 'test2'` | `test1,servers=test2` | Formats multi-value variable in custom format for OpenTSDB. `lucene`| ${servers:lucene} | `'test', 'test2'` | `("test" OR "test2")` | Formats multi-value variable as a lucene expression. -`percentencode` | ${servers:percentencode} | `'foo()bar BAZ', 'test2'` | `{foo%28%29bar%20BAZ%2Ctest2}` | Formats multi-value variable into a glob, percent-escaped +`percentencode` | ${servers:percentencode} | `'foo()bar BAZ', 'test2'` | `{foo%28%29bar%20BAZ%2Ctest2}` | Formats multi-value variable into a glob, percent-encoded. Test the formatting options on the [Grafana Play site](http://play.grafana.org/d/cJtIfcWiz/template-variable-formatting-options?orgId=1). diff --git a/public/app/features/templating/specs/template_srv.test.ts b/public/app/features/templating/specs/template_srv.test.ts index 8d6bf5ed668..4288b5f3928 100644 --- a/public/app/features/templating/specs/template_srv.test.ts +++ b/public/app/features/templating/specs/template_srv.test.ts @@ -277,7 +277,7 @@ describe('templateSrv', () => { it('multi value and percentencode format should render percent-encoded string', () => { const result = _templateSrv.formatValue(['foo()bar BAZ', 'test2'], 'percentencode'); - expect(result).toBe('%7bfoo%28%29bar%20BAZ%2ctest2%7d'); + expect(result).toBe('%7Bfoo%28%29bar%20BAZ%2Ctest2%7D'); }); it('slash should be properly escaped in regex format', () => { diff --git a/public/app/features/templating/template_srv.ts b/public/app/features/templating/template_srv.ts index a969b058d7e..07656924c9c 100644 --- a/public/app/features/templating/template_srv.ts +++ b/public/app/features/templating/template_srv.ts @@ -77,10 +77,12 @@ export class TemplateSrv { return '(' + quotedValues.join(' OR ') + ')'; } - // like encodeURIComponent() but for all characters except alpha-numerics - encodeURIQueryValue(str) { - return str.replace(/[^a-z0-9]/gi, function(c) { - return '%' + c.charCodeAt(0).toString(16); + // encode string according to RFC 3986; in contrast to encodeURIComponent() + // also the sub-delims "!", "'", "(", ")" and "*" are encoded; + // unicode handling uses UTF-8 as in ECMA-262. + encodeURIComponentStrict(str) { + return encodeURIComponent(str).replace(/[!'()*]/g, (c) => { + return '%' + c.charCodeAt(0).toString(16).toUpperCase(); }); } @@ -128,9 +130,9 @@ export class TemplateSrv { case 'percentencode': { // like glob, but url escaped if (_.isArray(value)) { - return this.encodeURIQueryValue('{' + value.join(',') + '}'); + return this.encodeURIComponentStrict('{' + value.join(',') + '}'); } - return this.encodeURIQueryValue(value); + return this.encodeURIComponentStrict(value); } default: { if (_.isArray(value)) {