urllib 3.19.3 → 3.21.0

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.
@@ -0,0 +1,34 @@
1
+ import type { RawResponseWithMeta, SocketInfo } from './Response.js';
2
+ import type { IncomingHttpHeaders } from './IncomingHttpHeaders.js';
3
+
4
+ // need to support ES2021
5
+ interface ErrorOptions {
6
+ cause?: Error;
7
+ }
8
+
9
+ export class HttpClientRequestError extends Error {
10
+ status?: number;
11
+ headers?: IncomingHttpHeaders;
12
+ socket?: SocketInfo;
13
+ res?: RawResponseWithMeta;
14
+ }
15
+
16
+ export class HttpClientRequestTimeoutError extends HttpClientRequestError {
17
+ constructor(timeout: number, options: ErrorOptions) {
18
+ const message = `Request timeout for ${timeout} ms`;
19
+ super(message, options);
20
+ this.name = this.constructor.name;
21
+ Error.captureStackTrace(this, this.constructor);
22
+ }
23
+ }
24
+
25
+ export class HttpClientConnectTimeoutError extends HttpClientRequestError {
26
+ code: string;
27
+
28
+ constructor(message: string, code: string, options: ErrorOptions) {
29
+ super(message, options);
30
+ this.name = this.constructor.name;
31
+ this.code = code;
32
+ Error.captureStackTrace(this, this.constructor);
33
+ }
34
+ }
package/src/Response.ts CHANGED
@@ -13,7 +13,12 @@ export type SocketInfo = {
13
13
  handledRequests: number;
14
14
  handledResponses: number;
15
15
  connectedTime?: Date;
16
+ connectErrorTime?: Date;
16
17
  lastRequestEndTime?: Date;
18
+ attemptedRemoteAddresses?: string[];
19
+ connectProtocol?: string;
20
+ connectHost?: string;
21
+ connectPort?: string;
17
22
  };
18
23
 
19
24
  /**
@@ -35,9 +35,25 @@ function formatSocket(socket: Socket) {
35
35
  localPort: socket[symbols.kSocketLocalPort],
36
36
  remoteAddress: socket.remoteAddress,
37
37
  remotePort: socket.remotePort,
38
+ attemptedAddresses: socket.autoSelectFamilyAttemptedAddresses,
39
+ connecting: socket.connecting,
38
40
  };
39
41
  }
40
42
 
43
+ // make sure error contains socket info
44
+ const kDestroy = Symbol('kDestroy');
45
+ Socket.prototype[kDestroy] = Socket.prototype.destroy;
46
+ Socket.prototype.destroy = function(err?: any) {
47
+ if (err) {
48
+ Object.defineProperty(err, symbols.kErrorSocket, {
49
+ // don't show on console log
50
+ enumerable: false,
51
+ value: this,
52
+ });
53
+ }
54
+ return this[kDestroy](err);
55
+ };
56
+
41
57
  export function initDiagnosticsChannel() {
42
58
  // makre sure init global DiagnosticsChannel once
43
59
  if (initedDiagnosticsChannel) return;
@@ -67,10 +83,37 @@ export function initDiagnosticsChannel() {
67
83
  });
68
84
 
69
85
  // diagnosticsChannel.channel('undici:client:beforeConnect')
70
- // diagnosticsChannel.channel('undici:client:connectError')
86
+
87
+ subscribe('undici:client:connectError', (message, name) => {
88
+ const { error, connectParams } = message as DiagnosticsChannel.ClientConnectErrorMessage & { error: any };
89
+ let { socket } = message as DiagnosticsChannel.ClientConnectErrorMessage;
90
+ if (!socket && error[symbols.kErrorSocket]) {
91
+ socket = error[symbols.kErrorSocket];
92
+ }
93
+ if (socket) {
94
+ socket[symbols.kSocketId] = globalId('UndiciSocket');
95
+ socket[symbols.kSocketConnectErrorTime] = new Date();
96
+ socket[symbols.kHandledRequests] = 0;
97
+ socket[symbols.kHandledResponses] = 0;
98
+ // copy local address to symbol, avoid them be reset after request error throw
99
+ if (socket.localAddress) {
100
+ socket[symbols.kSocketLocalAddress] = socket.localAddress;
101
+ socket[symbols.kSocketLocalPort] = socket.localPort;
102
+ }
103
+ socket[symbols.kSocketConnectProtocol] = connectParams.protocol;
104
+ socket[symbols.kSocketConnectHost] = connectParams.host;
105
+ socket[symbols.kSocketConnectPort] = connectParams.port;
106
+ debug('[%s] Socket#%d connectError, connectParams: %o, error: %s, (sock: %o)',
107
+ name, socket[symbols.kSocketId], connectParams, (error as Error).message, formatSocket(socket));
108
+ } else {
109
+ debug('[%s] connectError, connectParams: %o, error: %o',
110
+ name, connectParams, error);
111
+ }
112
+ });
113
+
71
114
  // This message is published after a connection is established.
72
115
  subscribe('undici:client:connected', (message, name) => {
73
- const { socket } = message as DiagnosticsChannel.ClientConnectedMessage;
116
+ const { socket, connectParams } = message as DiagnosticsChannel.ClientConnectedMessage;
74
117
  socket[symbols.kSocketId] = globalId('UndiciSocket');
75
118
  socket[symbols.kSocketStartTime] = performance.now();
76
119
  socket[symbols.kSocketConnectedTime] = new Date();
@@ -79,6 +122,9 @@ export function initDiagnosticsChannel() {
79
122
  // copy local address to symbol, avoid them be reset after request error throw
80
123
  socket[symbols.kSocketLocalAddress] = socket.localAddress;
81
124
  socket[symbols.kSocketLocalPort] = socket.localPort;
125
+ socket[symbols.kSocketConnectProtocol] = connectParams.protocol;
126
+ socket[symbols.kSocketConnectHost] = connectParams.host;
127
+ socket[symbols.kSocketConnectPort] = connectParams.port;
82
128
  debug('[%s] Socket#%d connected (sock: %o)', name, socket[symbols.kSocketId], formatSocket(socket));
83
129
  });
84
130
 
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ import { RequestOptions, RequestURL } from './Request.js';
4
4
 
5
5
  let httpclient: HttpClient;
6
6
  const domainSocketHttpclients = new LRU(50);
7
+
7
8
  export async function request<T = any>(url: RequestURL, options?: RequestOptions) {
8
9
  if (options?.socketPath) {
9
10
  let domainSocketHttpclient = domainSocketHttpclients.get<HttpClient>(options.socketPath);
@@ -22,7 +23,7 @@ export async function request<T = any>(url: RequestURL, options?: RequestOptions
22
23
  return await httpclient.request<T>(url, options);
23
24
  }
24
25
 
25
- // export curl method is keep compatible with urlib.curl()
26
+ // export curl method is keep compatible with urllib.curl()
26
27
  // ```ts
27
28
  // import * as urllib from 'urllib';
28
29
  // urllib.curl(url);
@@ -52,7 +53,7 @@ export {
52
53
  export {
53
54
  IncomingHttpHeaders,
54
55
  } from './IncomingHttpHeaders.js';
55
-
56
+ export * from './HttpClientError.js';
56
57
 
57
58
  export default {
58
59
  request,
package/src/symbols.ts CHANGED
@@ -2,9 +2,13 @@ export default {
2
2
  kSocketId: Symbol('socket id'),
3
3
  kSocketStartTime: Symbol('socket start time'),
4
4
  kSocketConnectedTime: Symbol('socket connected time'),
5
+ kSocketConnectErrorTime: Symbol('socket connectError time'),
5
6
  kSocketRequestEndTime: Symbol('socket request end time'),
6
7
  kSocketLocalAddress: Symbol('socket local address'),
7
8
  kSocketLocalPort: Symbol('socket local port'),
9
+ kSocketConnectHost: Symbol('socket connect params: host'),
10
+ kSocketConnectPort: Symbol('socket connect params: port'),
11
+ kSocketConnectProtocol: Symbol('socket connect params: protocol'),
8
12
  kHandledRequests: Symbol('handled requests per socket'),
9
13
  kHandledResponses: Symbol('handled responses per socket'),
10
14
  kRequestSocket: Symbol('request on the socket'),
@@ -13,4 +17,5 @@ export default {
13
17
  kEnableRequestTiming: Symbol('enable request timing or not'),
14
18
  kRequestTiming: Symbol('request timing'),
15
19
  kRequestOriginalOpaque: Symbol('request original opaque'),
20
+ kErrorSocket: Symbol('socket of error'),
16
21
  };