socket-function 1.2.17 → 1.2.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -1008,6 +1008,9 @@ declare module "socket-function/src/https" {
1008
1008
  [key: string]: string | undefined;
1009
1009
  };
1010
1010
  cancel?: Promise<void>;
1011
+ outHeaders?: {
1012
+ [key: string]: string | undefined;
1013
+ };
1011
1014
  }): Promise<Buffer>;
1012
1015
 
1013
1016
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socket-function",
3
- "version": "1.2.17",
3
+ "version": "1.2.19",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
package/src/https.d.ts CHANGED
@@ -5,4 +5,7 @@ export declare function httpsRequest(url: string, payload?: Buffer | Buffer[], m
5
5
  [key: string]: string | undefined;
6
6
  };
7
7
  cancel?: Promise<void>;
8
+ outHeaders?: {
9
+ [key: string]: string | undefined;
10
+ };
8
11
  }): Promise<Buffer>;
package/src/https.ts CHANGED
@@ -47,6 +47,8 @@ export function httpsRequest(
47
47
  config?: {
48
48
  headers?: { [key: string]: string | undefined },
49
49
  cancel?: Promise<void>;
50
+ // Populated with the response headers once they arrive, so the caller can read them.
51
+ outHeaders?: { [key: string]: string | undefined };
50
52
  }
51
53
  ): Promise<Buffer> {
52
54
  if (isNode()) {
@@ -96,6 +98,12 @@ export function httpsRequest(
96
98
  autoSelectFamily: true,
97
99
  } as https.RequestOptions,
98
100
  async httpResponse => {
101
+ if (config?.outHeaders) {
102
+ for (let [key, value] of Object.entries(httpResponse.headers)) {
103
+ config.outHeaders[key] = Array.isArray(value) ? value.join(", ") : value;
104
+ }
105
+ }
106
+
99
107
  let data: Buffer[] = [];
100
108
  httpResponse.on("data", chunk => {
101
109
  data.push(chunk);
@@ -158,6 +166,13 @@ export function httpsRequest(
158
166
  }
159
167
  return new Promise((resolve, reject) => {
160
168
  request.onload = () => {
169
+ if (config?.outHeaders) {
170
+ for (let line of request.getAllResponseHeaders().trim().split(/[\r\n]+/)) {
171
+ let index = line.indexOf(":");
172
+ if (index < 0) continue;
173
+ config.outHeaders[line.slice(0, index).trim().toLowerCase()] = line.slice(index + 1).trim();
174
+ }
175
+ }
161
176
  if (!request.status.toString().startsWith("2")) {
162
177
  try {
163
178
  // It should be an error.stack. But if it isn't... just throw the status text...
package/src/networking.ts CHANGED
@@ -1,13 +1,15 @@
1
1
  import net from "net";
2
2
  import { lazy } from "./caching";
3
3
  import { httpsRequest } from "./https";
4
+ import { dnsCacheLookup } from "./dnsCache";
4
5
  import { measureWrap } from "./profiling/measure";
5
6
 
6
7
  export const testTCPIsListening = measureWrap(async function testTCPIsListening(host: string, port: number): Promise<boolean> {
7
8
  // We need to establish a TCP connection, then close it? Yeah... so it is
8
9
  // not even a SocketFunction call, because it can't be, because that woule be TLS,
9
10
  // which we can't do with an ip!
10
- let socket = net.connect({ host, port });
11
+ // Resolve through our DNS cache rather than getaddrinfo, to avoid glibc's sticky failure cache.
12
+ let socket = net.connect({ host, port, lookup: dnsCacheLookup });
11
13
  return new Promise((resolve) => {
12
14
  socket.on("connect", () => {
13
15
  socket.end();
package/src/upreal.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as fs from "fs";
2
2
  import * as path from "path";
3
- import * as https from "https";
4
3
  import { spawn } from "child_process";
4
+ import { httpsRequest } from "./https";
5
5
 
6
6
  // Dependency sections in package.json that upreal is willing to update, in the order we search them.
7
7
  const DEP_SECTIONS = [
@@ -86,18 +86,9 @@ async function getLatestVersion(packageName: string): Promise<string> {
86
86
  : encodeURIComponent(packageName);
87
87
  let url = `https://registry.npmjs.org/${encodedName}/latest`;
88
88
 
89
- let body = await new Promise<string>((resolve, reject) => {
90
- https.get(url, res => {
91
- if (res.statusCode !== 200) {
92
- res.resume();
93
- reject(new Error(`Registry returned ${res.statusCode} for ${url}`));
94
- return;
95
- }
96
- let chunks: Buffer[] = [];
97
- res.on("data", chunk => chunks.push(chunk));
98
- res.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
99
- }).on("error", reject);
100
- });
89
+ // Via httpsRequest so registry lookups go through the DNS cache (and its re-resolve/retry), rather
90
+ // than getaddrinfo, which caches certain failures forever.
91
+ let body = (await httpsRequest(url)).toString("utf8");
101
92
 
102
93
  let parsed = JSON.parse(body) as { version?: string };
103
94
  if (!parsed.version) {
@@ -3,6 +3,7 @@ import { isNode } from "./misc";
3
3
  import { SenderInterface } from "./CallFactory";
4
4
  import { getTrustedCertificates } from "./certStore";
5
5
  import { getNodeIdLocation } from "./nodeCache";
6
+ import { dnsCacheLookup } from "./dnsCache";
6
7
  import debugbreak from "debugbreak";
7
8
  import { SocketFunction } from "../SocketFunction";
8
9
  import type * as ws from "ws";
@@ -44,7 +45,13 @@ export function createWebsocketFactory(): WebsocketFactory {
44
45
  const ws = require("ws") as typeof import("ws");
45
46
  let webSocket = new ws.WebSocket(`wss://${address}:${port}`, proposedProtocols, {
46
47
  ca: getTrustedCertificates(),
47
- });
48
+ // Resolve through our DNS cache instead of getaddrinfo, to avoid glibc's sticky failure
49
+ // cache. ws forwards these to the underlying tls/https connect. We don't get httpsRequest's
50
+ // connection-level re-resolve+retry here, but the DNS-level retries, positive cache, and
51
+ // negative cache still apply, and CallFactory's reconnect picks up a re-resolved address.
52
+ lookup: dnsCacheLookup,
53
+ autoSelectFamily: true,
54
+ } as ws.ClientOptions);
48
55
 
49
56
  // NOTE: Little setup is done here, because Sometimes websockets are created here,
50
57
  // and sometimes via incoming connections, We should do most setup in