Skip to content

Commit 13229cf

Browse files
committed
Merge pull request #6597 from elastic/jasper/backport/6581-4.5.0-issues/6127
[backport] PR #6581 to 4.5.0
2 parents 18adac4 + e84f1b6 commit 13229cf

File tree

3 files changed

+211
-37
lines changed

3 files changed

+211
-37
lines changed

src/server/http/__tests__/index.js

Lines changed: 69 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,88 @@
11
import expect from 'expect.js';
2-
import requirefrom from 'requirefrom';
32

4-
const requireFromTest = requirefrom('test');
5-
const kbnTestServer = requireFromTest('utils/kbn_server');
3+
import * as kbnTestServer from '../../../../test/utils/kbn_server';
4+
import fromRoot from '../../../utils/fromRoot';
5+
6+
describe('routes', function () {
7+
this.slow(10000);
8+
this.timeout(60000);
69

7-
describe('cookie validation', function () {
810
let kbnServer;
911
beforeEach(function () {
10-
kbnServer = kbnTestServer.createServer();
12+
kbnServer = kbnTestServer.createServer({
13+
plugins: {
14+
scanDirs: [
15+
fromRoot('src/plugins')
16+
]
17+
}
18+
});
1119
return kbnServer.ready();
1220
});
1321
afterEach(function () {
1422
return kbnServer.close();
1523
});
1624

17-
it('allows non-strict cookies', function (done) {
18-
const options = {
19-
method: 'GET',
20-
url: '/',
21-
headers: {
22-
cookie: 'test:80=value;test_80=value'
23-
}
24-
};
25-
kbnTestServer.makeRequest(kbnServer, options, (res) => {
26-
expect(res.payload).not.to.contain('Invalid cookie header');
27-
done();
25+
describe('cookie validation', function () {
26+
it('allows non-strict cookies', function (done) {
27+
const options = {
28+
method: 'GET',
29+
url: '/',
30+
headers: {
31+
cookie: 'test:80=value;test_80=value'
32+
}
33+
};
34+
kbnTestServer.makeRequest(kbnServer, options, (res) => {
35+
expect(res.payload).not.to.contain('Invalid cookie header');
36+
done();
37+
});
38+
});
39+
40+
it('returns an error if the cookie can\'t be parsed', function (done) {
41+
const options = {
42+
method: 'GET',
43+
url: '/',
44+
headers: {
45+
cookie: 'a'
46+
}
47+
};
48+
kbnTestServer.makeRequest(kbnServer, options, (res) => {
49+
expect(res.payload).to.contain('Invalid cookie header');
50+
done();
51+
});
2852
});
2953
});
3054

31-
it('returns an error if the cookie can\'t be parsed', function (done) {
32-
const options = {
33-
method: 'GET',
34-
url: '/',
35-
headers: {
36-
cookie: 'a'
55+
describe('url shortener', () => {
56+
const shortenOptions = {
57+
method: 'POST',
58+
url: '/shorten',
59+
payload: {
60+
url: '/app/kibana#/visualize/create'
3761
}
3862
};
39-
kbnTestServer.makeRequest(kbnServer, options, (res) => {
40-
expect(res.payload).to.contain('Invalid cookie header');
41-
done();
63+
64+
it('generates shortened urls', (done) => {
65+
kbnTestServer.makeRequest(kbnServer, shortenOptions, (res) => {
66+
expect(typeof res.payload).to.be('string');
67+
expect(res.payload.length > 0).to.be(true);
68+
done();
69+
});
70+
});
71+
72+
it('redirects shortened urls', (done) => {
73+
kbnTestServer.makeRequest(kbnServer, shortenOptions, (res) => {
74+
const gotoOptions = {
75+
method: 'GET',
76+
url: '/goto/' + res.payload
77+
};
78+
kbnTestServer.makeRequest(kbnServer, gotoOptions, (res) => {
79+
expect(res.statusCode).to.be(302);
80+
expect(res.headers.location).to.be(shortenOptions.payload.url);
81+
done();
82+
});
83+
});
4284
});
85+
4386
});
87+
4488
});
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import _ from 'lodash';
2+
import sinon from 'sinon';
3+
import expect from 'expect.js';
4+
import ngMock from 'ngMock';
5+
import chrome from 'ui/chrome';
6+
import LibUrlShortenerProvider from 'ui/share/lib/url_shortener';
7+
8+
describe('Url shortener', () => {
9+
let $rootScope;
10+
let $location;
11+
let $http;
12+
let urlShortener;
13+
let $httpBackend;
14+
const shareId = 'id123';
15+
16+
beforeEach(ngMock.module('kibana'));
17+
beforeEach(ngMock.inject(function (_$rootScope_, _$location_, _$httpBackend_, Private) {
18+
$location = _$location_;
19+
$rootScope = _$rootScope_;
20+
$httpBackend = _$httpBackend_;
21+
urlShortener = Private(LibUrlShortenerProvider);
22+
}));
23+
24+
describe('Shorten without base path', () => {
25+
it('should shorten urls with a port', function (done) {
26+
$httpBackend.when('POST', '/shorten').respond(function (type, route, data) {
27+
expect(JSON.parse(data).url).to.be('/app/kibana#123');
28+
return [200, shareId];
29+
});
30+
urlShortener.shortenUrl('http://localhost:5601/app/kibana#123').then(function (url) {
31+
expect(url).to.be(`http://localhost:5601/goto/${shareId}`);
32+
done();
33+
});
34+
$httpBackend.flush();
35+
});
36+
37+
it('should shorten urls without a port', function (done) {
38+
$httpBackend.when('POST', '/shorten').respond(function (type, route, data) {
39+
expect(JSON.parse(data).url).to.be('/app/kibana#123');
40+
return [200, shareId];
41+
});
42+
urlShortener.shortenUrl('http://localhost/app/kibana#123').then(function (url) {
43+
expect(url).to.be(`http://localhost/goto/${shareId}`);
44+
done();
45+
});
46+
$httpBackend.flush();
47+
});
48+
});
49+
50+
describe('Shorten with base path', () => {
51+
const basePath = '/foo';
52+
53+
let getBasePath;
54+
beforeEach(ngMock.inject((Private) => {
55+
getBasePath = sinon.stub(chrome, 'getBasePath', () => basePath);
56+
urlShortener = Private(LibUrlShortenerProvider);
57+
}));
58+
59+
it('should shorten urls with a port', (done) => {
60+
$httpBackend.when('POST', `${basePath}/shorten`).respond((type, route, data) => {
61+
expect(JSON.parse(data).url).to.be('/app/kibana#123');
62+
return [200, shareId];
63+
});
64+
urlShortener.shortenUrl(`http://localhost:5601${basePath}/app/kibana#123`).then((url) => {
65+
expect(url).to.be(`http://localhost:5601${basePath}/goto/${shareId}`);
66+
done();
67+
});
68+
$httpBackend.flush();
69+
});
70+
71+
it('should shorten urls without a port', (done) => {
72+
$httpBackend.when('POST', `${basePath}/shorten`).respond((type, route, data) => {
73+
expect(JSON.parse(data).url).to.be('/app/kibana#123');
74+
return [200, shareId];
75+
});
76+
urlShortener.shortenUrl(`http://localhost${basePath}/app/kibana#123`).then((url) => {
77+
expect(url).to.be(`http://localhost${basePath}/goto/${shareId}`);
78+
done();
79+
});
80+
$httpBackend.flush();
81+
});
82+
83+
it('should shorten urls with a query string', (done) => {
84+
$httpBackend.when('POST', `${basePath}/shorten`).respond((type, route, data) => {
85+
expect(JSON.parse(data).url).to.be('/app/kibana?foo#123');
86+
return [200, shareId];
87+
});
88+
urlShortener.shortenUrl(`http://localhost${basePath}/app/kibana?foo#123`).then((url) => {
89+
expect(url).to.be(`http://localhost${basePath}/goto/${shareId}`);
90+
done();
91+
});
92+
$httpBackend.flush();
93+
});
94+
95+
it('should shorten urls without a hash', (done) => {
96+
$httpBackend.when('POST', `${basePath}/shorten`).respond((type, route, data) => {
97+
expect(JSON.parse(data).url).to.be('/app/kibana');
98+
return [200, shareId];
99+
});
100+
urlShortener.shortenUrl(`http://localhost${basePath}/app/kibana`).then((url) => {
101+
expect(url).to.be(`http://localhost${basePath}/goto/${shareId}`);
102+
done();
103+
});
104+
$httpBackend.flush();
105+
});
106+
107+
it('should shorten urls with a query string in the hash', (done) => {
108+
const relativeUrl = "/app/kibana#/discover?_g=(refreshInterval:(display:Off,pause:!f,value:0),time:(from:now-15m,mode:quick,to:now))&_a=(columns:!(_source),index:%27logstash-*%27,interval:auto,query:(query_string:(analyze_wildcard:!t,query:%27*%27)),sort:!(%27@timestamp%27,desc))"; //eslint-disable-line max-len, quotes
109+
$httpBackend.when('POST', `${basePath}/shorten`).respond((type, route, data) => {
110+
expect(JSON.parse(data).url).to.be(relativeUrl);
111+
return [200, shareId];
112+
});
113+
urlShortener.shortenUrl(`http://localhost${basePath}${relativeUrl}`).then((url) => {
114+
expect(url).to.be(`http://localhost${basePath}/goto/${shareId}`);
115+
done();
116+
});
117+
$httpBackend.flush();
118+
});
119+
120+
afterEach(() => {
121+
getBasePath.restore();
122+
});
123+
});
124+
});

src/ui/public/share/lib/url_shortener.js

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
import chrome from 'ui/chrome';
2+
import url from 'url';
23

34
export default function createUrlShortener(Notifier, $http, $location) {
45
const notify = new Notifier({
56
location: 'Url Shortener'
67
});
7-
const basePath = chrome.getBasePath();
8-
const baseUrl = `${$location.protocol()}://${$location.host()}:${$location.port()}${basePath}`;
98

10-
async function shortenUrl(url) {
11-
const relativeUrl = url.replace(baseUrl, '');
12-
const formData = { url: relativeUrl };
9+
function shortenUrl(absoluteUrl) {
10+
const basePath = chrome.getBasePath();
11+
12+
const parsedUrl = url.parse(absoluteUrl);
13+
const path = parsedUrl.path.replace(basePath, '');
14+
const hash = parsedUrl.hash ? parsedUrl.hash : '';
15+
const relativeUrl = path + hash;
1316

14-
try {
15-
const result = await $http.post(`${basePath}/shorten`, formData);
17+
const formData = { url: relativeUrl };
1618

17-
return `${baseUrl}/goto/${result.data}`;
18-
} catch (err) {
19-
notify.error(err);
20-
throw err;
21-
}
19+
return $http.post(`${basePath}/shorten`, formData).then((result) => {
20+
return url.format({
21+
protocol: parsedUrl.protocol,
22+
host: parsedUrl.host,
23+
pathname: `${basePath}/goto/${result.data}`
24+
});
25+
}).catch((response) => {
26+
notify.error(response);
27+
});
2228
}
2329

2430
return {

0 commit comments

Comments
 (0)