summaryrefslogtreecommitdiff
path: root/frontend-old/node_modules/@grpc/grpc-js/src/resolver-dns.ts
diff options
context:
space:
mode:
Diffstat (limited to 'frontend-old/node_modules/@grpc/grpc-js/src/resolver-dns.ts')
-rw-r--r--frontend-old/node_modules/@grpc/grpc-js/src/resolver-dns.ts412
1 files changed, 0 insertions, 412 deletions
diff --git a/frontend-old/node_modules/@grpc/grpc-js/src/resolver-dns.ts b/frontend-old/node_modules/@grpc/grpc-js/src/resolver-dns.ts
deleted file mode 100644
index 31e0d0b..0000000
--- a/frontend-old/node_modules/@grpc/grpc-js/src/resolver-dns.ts
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Copyright 2019 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import {
- Resolver,
- ResolverListener,
- registerResolver,
- registerDefaultScheme,
-} from './resolver';
-import * as dns from 'dns';
-import * as util from 'util';
-import { extractAndSelectServiceConfig, ServiceConfig } from './service-config';
-import { Status } from './constants';
-import { StatusObject } from './call-interface';
-import { Metadata } from './metadata';
-import * as logging from './logging';
-import { LogVerbosity } from './constants';
-import { SubchannelAddress, TcpSubchannelAddress } from './subchannel-address';
-import { GrpcUri, uriToString, splitHostPort } from './uri-parser';
-import { isIPv6, isIPv4 } from 'net';
-import { ChannelOptions } from './channel-options';
-import { BackoffOptions, BackoffTimeout } from './backoff-timeout';
-
-const TRACER_NAME = 'dns_resolver';
-
-function trace(text: string): void {
- logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text);
-}
-
-/**
- * The default TCP port to connect to if not explicitly specified in the target.
- */
-export const DEFAULT_PORT = 443;
-
-const DEFAULT_MIN_TIME_BETWEEN_RESOLUTIONS_MS = 30_000;
-
-const resolveTxtPromise = util.promisify(dns.resolveTxt);
-const dnsLookupPromise = util.promisify(dns.lookup);
-
-/**
- * Merge any number of arrays into a single alternating array
- * @param arrays
- */
-function mergeArrays<T>(...arrays: T[][]): T[] {
- const result: T[] = [];
- for (
- let i = 0;
- i <
- Math.max.apply(
- null,
- arrays.map(array => array.length)
- );
- i++
- ) {
- for (const array of arrays) {
- if (i < array.length) {
- result.push(array[i]);
- }
- }
- }
- return result;
-}
-
-/**
- * Resolver implementation that handles DNS names and IP addresses.
- */
-class DnsResolver implements Resolver {
- private readonly ipResult: SubchannelAddress[] | null;
- private readonly dnsHostname: string | null;
- private readonly port: number | null;
- /**
- * Minimum time between resolutions, measured as the time between starting
- * successive resolution requests. Only applies to successful resolutions.
- * Failures are handled by the backoff timer.
- */
- private readonly minTimeBetweenResolutionsMs: number;
- private pendingLookupPromise: Promise<dns.LookupAddress[]> | null = null;
- private pendingTxtPromise: Promise<string[][]> | null = null;
- private latestLookupResult: TcpSubchannelAddress[] | null = null;
- private latestServiceConfig: ServiceConfig | null = null;
- private latestServiceConfigError: StatusObject | null = null;
- private percentage: number;
- private defaultResolutionError: StatusObject;
- private backoff: BackoffTimeout;
- private continueResolving = false;
- private nextResolutionTimer: NodeJS.Timeout;
- private isNextResolutionTimerRunning = false;
- private isServiceConfigEnabled = true;
- private returnedIpResult = false;
- constructor(
- private target: GrpcUri,
- private listener: ResolverListener,
- channelOptions: ChannelOptions
- ) {
- trace('Resolver constructed for target ' + uriToString(target));
- const hostPort = splitHostPort(target.path);
- if (hostPort === null) {
- this.ipResult = null;
- this.dnsHostname = null;
- this.port = null;
- } else {
- if (isIPv4(hostPort.host) || isIPv6(hostPort.host)) {
- this.ipResult = [
- {
- host: hostPort.host,
- port: hostPort.port ?? DEFAULT_PORT,
- },
- ];
- this.dnsHostname = null;
- this.port = null;
- } else {
- this.ipResult = null;
- this.dnsHostname = hostPort.host;
- this.port = hostPort.port ?? DEFAULT_PORT;
- }
- }
- this.percentage = Math.random() * 100;
-
- if (channelOptions['grpc.service_config_disable_resolution'] === 1) {
- this.isServiceConfigEnabled = false;
- }
-
- this.defaultResolutionError = {
- code: Status.UNAVAILABLE,
- details: `Name resolution failed for target ${uriToString(this.target)}`,
- metadata: new Metadata(),
- };
-
- const backoffOptions: BackoffOptions = {
- initialDelay: channelOptions['grpc.initial_reconnect_backoff_ms'],
- maxDelay: channelOptions['grpc.max_reconnect_backoff_ms'],
- };
-
- this.backoff = new BackoffTimeout(() => {
- if (this.continueResolving) {
- this.startResolutionWithBackoff();
- }
- }, backoffOptions);
- this.backoff.unref();
-
- this.minTimeBetweenResolutionsMs =
- channelOptions['grpc.dns_min_time_between_resolutions_ms'] ??
- DEFAULT_MIN_TIME_BETWEEN_RESOLUTIONS_MS;
- this.nextResolutionTimer = setTimeout(() => {}, 0);
- clearTimeout(this.nextResolutionTimer);
- }
-
- /**
- * If the target is an IP address, just provide that address as a result.
- * Otherwise, initiate A, AAAA, and TXT lookups
- */
- private startResolution() {
- if (this.ipResult !== null) {
- if (!this.returnedIpResult) {
- trace('Returning IP address for target ' + uriToString(this.target));
- setImmediate(() => {
- this.listener.onSuccessfulResolution(
- this.ipResult!,
- null,
- null,
- null,
- {}
- );
- });
- this.returnedIpResult = true;
- }
- this.backoff.stop();
- this.backoff.reset();
- this.stopNextResolutionTimer();
- return;
- }
- if (this.dnsHostname === null) {
- trace('Failed to parse DNS address ' + uriToString(this.target));
- setImmediate(() => {
- this.listener.onError({
- code: Status.UNAVAILABLE,
- details: `Failed to parse DNS address ${uriToString(this.target)}`,
- metadata: new Metadata(),
- });
- });
- this.stopNextResolutionTimer();
- } else {
- if (this.pendingLookupPromise !== null) {
- return;
- }
- trace('Looking up DNS hostname ' + this.dnsHostname);
- /* We clear out latestLookupResult here to ensure that it contains the
- * latest result since the last time we started resolving. That way, the
- * TXT resolution handler can use it, but only if it finishes second. We
- * don't clear out any previous service config results because it's
- * better to use a service config that's slightly out of date than to
- * revert to an effectively blank one. */
- this.latestLookupResult = null;
- const hostname: string = this.dnsHostname;
- /* We lookup both address families here and then split them up later
- * because when looking up a single family, dns.lookup outputs an error
- * if the name exists but there are no records for that family, and that
- * error is indistinguishable from other kinds of errors */
- this.pendingLookupPromise = dnsLookupPromise(hostname, { all: true });
- this.pendingLookupPromise.then(
- addressList => {
- if (this.pendingLookupPromise === null) {
- return;
- }
- this.pendingLookupPromise = null;
- this.backoff.reset();
- this.backoff.stop();
- const ip4Addresses: dns.LookupAddress[] = addressList.filter(
- addr => addr.family === 4
- );
- const ip6Addresses: dns.LookupAddress[] = addressList.filter(
- addr => addr.family === 6
- );
- this.latestLookupResult = mergeArrays(ip6Addresses, ip4Addresses).map(
- addr => ({ host: addr.address, port: +this.port! })
- );
- const allAddressesString: string =
- '[' +
- this.latestLookupResult
- .map(addr => addr.host + ':' + addr.port)
- .join(',') +
- ']';
- trace(
- 'Resolved addresses for target ' +
- uriToString(this.target) +
- ': ' +
- allAddressesString
- );
- if (this.latestLookupResult.length === 0) {
- this.listener.onError(this.defaultResolutionError);
- return;
- }
- /* If the TXT lookup has not yet finished, both of the last two
- * arguments will be null, which is the equivalent of getting an
- * empty TXT response. When the TXT lookup does finish, its handler
- * can update the service config by using the same address list */
- this.listener.onSuccessfulResolution(
- this.latestLookupResult,
- this.latestServiceConfig,
- this.latestServiceConfigError,
- null,
- {}
- );
- },
- err => {
- if (this.pendingLookupPromise === null) {
- return;
- }
- trace(
- 'Resolution error for target ' +
- uriToString(this.target) +
- ': ' +
- (err as Error).message
- );
- this.pendingLookupPromise = null;
- this.stopNextResolutionTimer();
- this.listener.onError(this.defaultResolutionError);
- }
- );
- /* If there already is a still-pending TXT resolution, we can just use
- * that result when it comes in */
- if (this.isServiceConfigEnabled && this.pendingTxtPromise === null) {
- /* We handle the TXT query promise differently than the others because
- * the name resolution attempt as a whole is a success even if the TXT
- * lookup fails */
- this.pendingTxtPromise = resolveTxtPromise(hostname);
- this.pendingTxtPromise.then(
- txtRecord => {
- if (this.pendingTxtPromise === null) {
- return;
- }
- this.pendingTxtPromise = null;
- try {
- this.latestServiceConfig = extractAndSelectServiceConfig(
- txtRecord,
- this.percentage
- );
- } catch (err) {
- this.latestServiceConfigError = {
- code: Status.UNAVAILABLE,
- details: `Parsing service config failed with error ${
- (err as Error).message
- }`,
- metadata: new Metadata(),
- };
- }
- if (this.latestLookupResult !== null) {
- /* We rely here on the assumption that calling this function with
- * identical parameters will be essentialy idempotent, and calling
- * it with the same address list and a different service config
- * should result in a fast and seamless switchover. */
- this.listener.onSuccessfulResolution(
- this.latestLookupResult,
- this.latestServiceConfig,
- this.latestServiceConfigError,
- null,
- {}
- );
- }
- },
- err => {
- /* If TXT lookup fails we should do nothing, which means that we
- * continue to use the result of the most recent successful lookup,
- * or the default null config object if there has never been a
- * successful lookup. We do not set the latestServiceConfigError
- * here because that is specifically used for response validation
- * errors. We still need to handle this error so that it does not
- * bubble up as an unhandled promise rejection. */
- }
- );
- }
- }
- }
-
- private startNextResolutionTimer() {
- clearTimeout(this.nextResolutionTimer);
- this.nextResolutionTimer = setTimeout(() => {
- this.stopNextResolutionTimer();
- if (this.continueResolving) {
- this.startResolutionWithBackoff();
- }
- }, this.minTimeBetweenResolutionsMs).unref?.();
- this.isNextResolutionTimerRunning = true;
- }
-
- private stopNextResolutionTimer() {
- clearTimeout(this.nextResolutionTimer);
- this.isNextResolutionTimerRunning = false;
- }
-
- private startResolutionWithBackoff() {
- if (this.pendingLookupPromise === null) {
- this.continueResolving = false;
- this.backoff.runOnce();
- this.startNextResolutionTimer();
- this.startResolution();
- }
- }
-
- updateResolution() {
- /* If there is a pending lookup, just let it finish. Otherwise, if the
- * nextResolutionTimer or backoff timer is running, set the
- * continueResolving flag to resolve when whichever of those timers
- * fires. Otherwise, start resolving immediately. */
- if (this.pendingLookupPromise === null) {
- if (this.isNextResolutionTimerRunning || this.backoff.isRunning()) {
- if (this.isNextResolutionTimerRunning) {
- trace('resolution update delayed by "min time between resolutions" rate limit');
- } else {
- trace('resolution update delayed by backoff timer until ' + this.backoff.getEndTime().toISOString());
- }
- this.continueResolving = true;
- } else {
- this.startResolutionWithBackoff();
- }
- }
- }
-
- /**
- * Reset the resolver to the same state it had when it was created. In-flight
- * DNS requests cannot be cancelled, but they are discarded and their results
- * will be ignored.
- */
- destroy() {
- this.continueResolving = false;
- this.backoff.reset();
- this.backoff.stop();
- this.stopNextResolutionTimer();
- this.pendingLookupPromise = null;
- this.pendingTxtPromise = null;
- this.latestLookupResult = null;
- this.latestServiceConfig = null;
- this.latestServiceConfigError = null;
- this.returnedIpResult = false;
- }
-
- /**
- * Get the default authority for the given target. For IP targets, that is
- * the IP address. For DNS targets, it is the hostname.
- * @param target
- */
- static getDefaultAuthority(target: GrpcUri): string {
- return target.path;
- }
-}
-
-/**
- * Set up the DNS resolver class by registering it as the handler for the
- * "dns:" prefix and as the default resolver.
- */
-export function setup(): void {
- registerResolver('dns', DnsResolver);
- registerDefaultScheme('dns');
-}
-
-export interface DnsUrl {
- host: string;
- port?: string;
-}