Commit c79db67d authored by Illya Klymov's avatar Illya Klymov

Merge branch '329895-quick-length-fix' into 'master'

Pipeline Graph: Fix query length bug

See merge request gitlab-org/gitlab!65564
parents fadb3319 d88abce5
......@@ -2,12 +2,13 @@ import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloClient } from 'apollo-client';
import { ApolloLink } from 'apollo-link';
import { BatchHttpLink } from 'apollo-link-batch-http';
import { createHttpLink } from 'apollo-link-http';
import { HttpLink } from 'apollo-link-http';
import { createUploadLink } from 'apollo-upload-client';
import ActionCableLink from '~/actioncable_link';
import { apolloCaptchaLink } from '~/captcha/apollo_captcha_link';
import { StartupJSLink } from '~/lib/utils/apollo_startup_js_link';
import csrf from '~/lib/utils/csrf';
import { objectToQuery, queryToObject } from '~/lib/utils/url_utility';
import PerformanceBarService from '~/performance_bar/services/performance_bar_service';
export const fetchPolicies = {
......@@ -18,6 +19,31 @@ export const fetchPolicies = {
CACHE_ONLY: 'cache-only',
};
export const stripWhitespaceFromQuery = (url, path) => {
/* eslint-disable-next-line no-unused-vars */
const [_, params] = url.split(path);
if (!params) {
return url;
}
const decoded = decodeURIComponent(params);
const paramsObj = queryToObject(decoded);
if (!paramsObj.query) {
return url;
}
const stripped = paramsObj.query
.split(/\s+|\n/)
.join(' ')
.trim();
paramsObj.query = stripped;
const reassembled = objectToQuery(paramsObj);
return `${path}?${reassembled}`;
};
export default (resolvers = {}, config = {}) => {
const {
assumeImmutableResults,
......@@ -58,10 +84,31 @@ export default (resolvers = {}, config = {}) => {
});
});
/*
This custom fetcher intervention is to deal with an issue where we are using GET to access
eTag polling, but Apollo Client adds excessive whitespace, which causes the
request to fail on certain self-hosted stacks. When we can move
to subscriptions entirely or can land an upstream PR, this can be removed.
Related links
Bug report: https://gitlab.com/gitlab-org/gitlab/-/issues/329895
Moving to subscriptions: https://gitlab.com/gitlab-org/gitlab/-/issues/332485
Apollo Client issue: https://github.com/apollographql/apollo-feature-requests/issues/182
*/
const fetchIntervention = (url, options) => {
return fetch(stripWhitespaceFromQuery(url, path), options);
};
const requestLink = ApolloLink.split(
() => useGet,
new HttpLink({ ...httpOptions, fetch: fetchIntervention }),
new BatchHttpLink(httpOptions),
);
const uploadsLink = ApolloLink.split(
(operation) => operation.getContext().hasUpload || operation.getContext().isSingleRequest,
createUploadLink(httpOptions),
useGet ? createHttpLink(httpOptions) : new BatchHttpLink(httpOptions),
);
const performanceBarLink = new ApolloLink((operation, forward) => {
......@@ -99,6 +146,7 @@ export default (resolvers = {}, config = {}) => {
new StartupJSLink(),
apolloCaptchaLink,
uploadsLink,
requestLink,
]),
);
......
import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
import { stripWhitespaceFromQuery } from '~/lib/graphql';
import { queryToObject } from '~/lib/utils/url_utility';
describe('stripWhitespaceFromQuery', () => {
const operationName = 'getPipelineDetails';
const variables = `{
projectPath: 'root/abcd-dag',
iid: '44'
}`;
const testQuery = getPipelineDetails.loc.source.body;
const defaultPath = '/api/graphql';
const encodedVariables = encodeURIComponent(variables);
it('shortens the query argument by replacing multiple spaces and newlines with a single space', () => {
const testString = `${defaultPath}?query=${encodeURIComponent(testQuery)}`;
expect(testString.length > stripWhitespaceFromQuery(testString, defaultPath).length).toBe(true);
});
it('does not contract a single space', () => {
const simpleSingleString = `${defaultPath}?query=${encodeURIComponent('fragment Nonsense')}`;
expect(stripWhitespaceFromQuery(simpleSingleString, defaultPath)).toEqual(simpleSingleString);
});
it('works with a non-default path', () => {
const newPath = 'another/graphql/path';
const newPathSingleString = `${newPath}?query=${encodeURIComponent('fragment Nonsense')}`;
expect(stripWhitespaceFromQuery(newPathSingleString, newPath)).toEqual(newPathSingleString);
});
it('does not alter other arguments', () => {
const bareParams = `?query=${encodeURIComponent(
testQuery,
)}&operationName=${operationName}&variables=${encodedVariables}`;
const testLongString = `${defaultPath}${bareParams}`;
const processed = stripWhitespaceFromQuery(testLongString, defaultPath);
const decoded = decodeURIComponent(processed);
const params = queryToObject(decoded);
expect(params.operationName).toBe(operationName);
expect(params.variables).toBe(variables);
});
it('works when there are no query params', () => {
expect(stripWhitespaceFromQuery(defaultPath, defaultPath)).toEqual(defaultPath);
});
it('works when the params do not include a query', () => {
const paramsWithoutQuery = `${defaultPath}&variables=${encodedVariables}`;
expect(stripWhitespaceFromQuery(paramsWithoutQuery, defaultPath)).toEqual(paramsWithoutQuery);
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment