1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-07-30 04:23:07 +03:00

Fix: handle baseUrl with trailing slash in fetch.getUrl (#3455)

* tests

* tidy trailing slash in fetch.getUrl before forming url

* make sonar happy about Polynomial regular expression used on uncontrolled data
This commit is contained in:
Kerry
2023-06-09 09:36:34 +12:00
committed by GitHub
parent a03e3dd501
commit ef1f5bf232
2 changed files with 61 additions and 2 deletions

View File

@ -18,6 +18,7 @@ import { FetchHttpApi } from "../../../src/http-api/fetch";
import { TypedEventEmitter } from "../../../src/models/typed-event-emitter"; import { TypedEventEmitter } from "../../../src/models/typed-event-emitter";
import { ClientPrefix, HttpApiEvent, HttpApiEventHandlerMap, IdentityPrefix, IHttpOpts, Method } from "../../../src"; import { ClientPrefix, HttpApiEvent, HttpApiEventHandlerMap, IdentityPrefix, IHttpOpts, Method } from "../../../src";
import { emitPromise } from "../../test-utils/test-utils"; import { emitPromise } from "../../test-utils/test-utils";
import { QueryDict } from "../../../src/utils";
describe("FetchHttpApi", () => { describe("FetchHttpApi", () => {
const baseUrl = "http://baseUrl"; const baseUrl = "http://baseUrl";
@ -235,4 +236,58 @@ describe("FetchHttpApi", () => {
expect(fetchFn.mock.calls[0][1].headers.Authorization).toBeUndefined(); expect(fetchFn.mock.calls[0][1].headers.Authorization).toBeUndefined();
}); });
}); });
describe("getUrl()", () => {
const localBaseUrl = "http://baseurl";
const baseUrlWithTrailingSlash = "http://baseurl/";
const makeApi = (thisBaseUrl = baseUrl): FetchHttpApi<any> => {
const fetchFn = jest.fn();
const emitter = new TypedEventEmitter<HttpApiEvent, HttpApiEventHandlerMap>();
return new FetchHttpApi(emitter, { baseUrl: thisBaseUrl, prefix, fetchFn });
};
type TestParams = {
path: string;
queryParams?: QueryDict;
prefix?: string;
baseUrl?: string;
};
type TestCase = [TestParams, string];
const queryParams: QueryDict = {
test1: 99,
test2: ["a", "b"],
};
const testPrefix = "/just/testing";
const testUrl = "http://justtesting.com";
const testUrlWithTrailingSlash = "http://justtesting.com/";
const testCases: TestCase[] = [
[{ path: "/terms" }, `${localBaseUrl}${prefix}/terms`],
[{ path: "/terms", queryParams }, `${localBaseUrl}${prefix}/terms?test1=99&test2=a&test2=b`],
[{ path: "/terms", prefix: testPrefix }, `${localBaseUrl}${testPrefix}/terms`],
[{ path: "/terms", baseUrl: testUrl }, `${testUrl}${prefix}/terms`],
[{ path: "/terms", baseUrl: testUrlWithTrailingSlash }, `${testUrl}${prefix}/terms`],
[
{ path: "/terms", queryParams, prefix: testPrefix, baseUrl: testUrl },
`${testUrl}${testPrefix}/terms?test1=99&test2=a&test2=b`,
],
];
const runTests = (fetchBaseUrl: string) => {
it.each<TestCase>(testCases)(
"creates url with params %s",
({ path, queryParams, prefix, baseUrl }, result) => {
const api = makeApi(fetchBaseUrl);
expect(api.getUrl(path, queryParams, prefix, baseUrl)).toEqual(new URL(result));
},
);
};
describe("when fetch.opts.baseUrl does not have a trailing slash", () => {
runTests(localBaseUrl);
});
describe("when fetch.opts.baseUrl does have a trailing slash", () => {
runTests(baseUrlWithTrailingSlash);
});
});
}); });

View File

@ -298,11 +298,15 @@ export class FetchHttpApi<O extends IHttpOpts> {
* @param path - The HTTP path <b>after</b> the supplied prefix e.g. "/createRoom". * @param path - The HTTP path <b>after</b> the supplied prefix e.g. "/createRoom".
* @param queryParams - A dict of query params (these will NOT be urlencoded). * @param queryParams - A dict of query params (these will NOT be urlencoded).
* @param prefix - The full prefix to use e.g. "/_matrix/client/v2_alpha", defaulting to this.opts.prefix. * @param prefix - The full prefix to use e.g. "/_matrix/client/v2_alpha", defaulting to this.opts.prefix.
* @param baseUrl - The baseUrl to use e.g. "https://matrix.org/", defaulting to this.opts.baseUrl. * @param baseUrl - The baseUrl to use e.g. "https://matrix.org", defaulting to this.opts.baseUrl.
* @returns URL * @returns URL
*/ */
public getUrl(path: string, queryParams?: QueryDict, prefix?: string, baseUrl?: string): URL { public getUrl(path: string, queryParams?: QueryDict, prefix?: string, baseUrl?: string): URL {
const url = new URL((baseUrl ?? this.opts.baseUrl) + (prefix ?? this.opts.prefix) + path); const baseUrlWithFallback = baseUrl ?? this.opts.baseUrl;
const baseUrlWithoutTrailingSlash = baseUrlWithFallback.endsWith("/")
? baseUrlWithFallback.slice(0, -1)
: baseUrlWithFallback;
const url = new URL(baseUrlWithoutTrailingSlash + (prefix ?? this.opts.prefix) + path);
if (queryParams) { if (queryParams) {
encodeParams(queryParams, url.searchParams); encodeParams(queryParams, url.searchParams);
} }