mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
The fetch() API won't send cookies or other type of credentials unless you set the credentials init option. Some datasources like Prometheus and Elasticsearch have `withCredentials` option in Browser access mode, but this option is not currently getting passed in the fetch() API. Fixes #23338.
117 lines
3.2 KiB
TypeScript
117 lines
3.2 KiB
TypeScript
import { BackendSrvRequest } from '@grafana/runtime';
|
|
import omitBy from 'lodash/omitBy';
|
|
|
|
export const parseInitFromOptions = (options: BackendSrvRequest): RequestInit => {
|
|
const method = options.method;
|
|
const headers = parseHeaders(options);
|
|
const isAppJson = isContentTypeApplicationJson(headers);
|
|
const body = parseBody(options, isAppJson);
|
|
|
|
if (options?.withCredentials) {
|
|
return {
|
|
method,
|
|
headers,
|
|
body,
|
|
credentials: 'include',
|
|
};
|
|
}
|
|
|
|
return {
|
|
method,
|
|
headers,
|
|
body,
|
|
};
|
|
};
|
|
|
|
interface HeaderParser {
|
|
canParse: (options: BackendSrvRequest) => boolean;
|
|
parse: (headers: Headers) => Headers;
|
|
}
|
|
|
|
const defaultHeaderParser: HeaderParser = {
|
|
canParse: () => true,
|
|
parse: headers => {
|
|
const accept = headers.get('accept');
|
|
if (accept) {
|
|
return headers;
|
|
}
|
|
|
|
headers.set('accept', 'application/json, text/plain, */*');
|
|
return headers;
|
|
},
|
|
};
|
|
|
|
const parseHeaderByMethodFactory = (methodPredicate: string): HeaderParser => ({
|
|
canParse: options => {
|
|
const method = options?.method ? options?.method.toLowerCase() : '';
|
|
return method === methodPredicate;
|
|
},
|
|
parse: headers => {
|
|
const contentType = headers.get('content-type');
|
|
if (contentType) {
|
|
return headers;
|
|
}
|
|
|
|
headers.set('content-type', 'application/json');
|
|
return headers;
|
|
},
|
|
});
|
|
|
|
const postHeaderParser: HeaderParser = parseHeaderByMethodFactory('post');
|
|
const putHeaderParser: HeaderParser = parseHeaderByMethodFactory('put');
|
|
|
|
const headerParsers = [postHeaderParser, putHeaderParser, defaultHeaderParser];
|
|
|
|
export const parseHeaders = (options: BackendSrvRequest) => {
|
|
const headers = options?.headers ? new Headers(options.headers) : new Headers();
|
|
const parsers = headerParsers.filter(parser => parser.canParse(options));
|
|
const combinedHeaders = parsers.reduce((prev, parser) => {
|
|
return parser.parse(prev);
|
|
}, headers);
|
|
|
|
return combinedHeaders;
|
|
};
|
|
|
|
export const isContentTypeApplicationJson = (headers: Headers) => {
|
|
if (!headers) {
|
|
return false;
|
|
}
|
|
|
|
const contentType = headers.get('content-type');
|
|
if (contentType && contentType.toLowerCase() === 'application/json') {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
export const parseBody = (options: BackendSrvRequest, isAppJson: boolean) => {
|
|
if (!options) {
|
|
return options;
|
|
}
|
|
|
|
if (!options.data || typeof options.data === 'string') {
|
|
return options.data;
|
|
}
|
|
|
|
return isAppJson ? JSON.stringify(options.data) : new URLSearchParams(options.data);
|
|
};
|
|
|
|
export function serializeParams(data: Record<string, any>): string {
|
|
return Object.keys(data)
|
|
.map(key => {
|
|
const value = data[key];
|
|
if (Array.isArray(value)) {
|
|
return value.map(arrayValue => `${encodeURIComponent(key)}=${encodeURIComponent(arrayValue)}`).join('&');
|
|
}
|
|
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
|
})
|
|
.join('&');
|
|
}
|
|
|
|
export const parseUrlFromOptions = (options: BackendSrvRequest): string => {
|
|
const cleanParams = omitBy(options.params, v => v === undefined || (v && v.length === 0));
|
|
const serializedParams = serializeParams(cleanParams);
|
|
return options.params && serializedParams.length ? `${options.url}?${serializedParams}` : options.url;
|
|
};
|