Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Commit 9e063ef

Browse files
author
kaliubuntu0206
authored
Fixed broken fetch for Node.js > 18.x and fixed double callback (#6381)
* web3-providers-http: Fixed broken fetch for Node.js > 18.x and fixed double callback * web3-providers-http: Append globalThis.fetch for tests * web3-providers-http: Bump deps version
1 parent 3e685bf commit 9e063ef

File tree

6 files changed

+41
-18
lines changed

6 files changed

+41
-18
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,3 +693,7 @@ Released with 1.0.0-beta.37 code base.
693693

694694

695695
## [Unreleased]
696+
697+
### Fixed
698+
699+
- Fixed broken fetch for Node.js > 18.x and fixed double callback (#6381)

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
"chai": "^4.2.0",
113113
"chai-as-promised": "^7.1.1",
114114
"core-js": "^3.6.5",
115+
"cross-fetch": "^4.0.0",
115116
"crypto-browserify": "^3.12.0",
116117
"crypto-js": "^3.3.0",
117118
"decache": "^4.6.0",

packages/web3-providers-http/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
"types": "types/index.d.ts",
1515
"main": "lib/index.js",
1616
"dependencies": {
17-
"abortcontroller-polyfill": "^1.7.3",
18-
"cross-fetch": "^3.1.4",
17+
"abortcontroller-polyfill": "^1.7.5",
18+
"cross-fetch": "^4.0.0",
1919
"es6-promise": "^4.2.8",
2020
"web3-core-helpers": "1.10.1"
2121
},

packages/web3-providers-http/src/index.js

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@
2424
*/
2525

2626
var errors = require('web3-core-helpers').errors;
27+
var fetch = require('cross-fetch');
2728
var http = require('http');
2829
var https = require('https');
2930

3031
// Apply missing polyfill for IE
31-
require('cross-fetch/polyfill');
3232
require('es6-promise').polyfill();
3333

3434
// import abortController if abortController is not included in node
3535
if(typeof global !== "undefined" && !global.AbortController){
36-
require('abortcontroller-polyfill/dist/polyfill-patch-fetch')
36+
require('abortcontroller-polyfill/dist/polyfill-patch-fetch');
3737
}
3838

3939
/**
@@ -46,6 +46,7 @@ var HttpProvider = function HttpProvider(host, options) {
4646
this.timeout = options.timeout || 0;
4747
this.headers = options.headers;
4848
this.agent = options.agent;
49+
this.forceGlobalFetch = options.forceGlobalFetch || false;
4950
this.connected = false;
5051

5152
// keepAlive is true unless explicitly set to false
@@ -74,6 +75,7 @@ HttpProvider.prototype.send = function (payload, callback) {
7475
};
7576
var headers = {};
7677
var controller;
78+
var fetchFunc = this.forceGlobalFetch ? globalThis.fetch : fetch;
7779

7880
if (typeof AbortController !== 'undefined') {
7981
controller = new AbortController();
@@ -138,11 +140,25 @@ HttpProvider.prototype.send = function (payload, callback) {
138140
}
139141

140142
// Response is a stream data so should be awaited for json response
141-
response.json().then(function (data) {
142-
callback(null, data);
143-
}).catch(function (error) {
144-
callback(errors.InvalidResponse(response));
145-
});
143+
response
144+
.json()
145+
.then(
146+
function (data) {
147+
callback(null, data);
148+
},
149+
function () {
150+
response
151+
.text()
152+
.then(
153+
function (text) {
154+
callback(errors.InvalidResponse(text));
155+
},
156+
function () {
157+
callback(errors.InvalidResponse(""));
158+
}
159+
);
160+
}
161+
);
146162
};
147163

148164
var failed = function (error) {
@@ -152,14 +168,14 @@ HttpProvider.prototype.send = function (payload, callback) {
152168

153169
if (error.name === 'AbortError') {
154170
callback(errors.ConnectionTimeout(this.timeout));
171+
return;
155172
}
156173

157174
callback(errors.InvalidConnection(this.host, error));
158-
}
175+
};
159176

160-
fetch(this.host, options)
161-
.then(success.bind(this))
162-
.catch(failed.bind(this));
177+
fetchFunc(this.host, options)
178+
.then(success.bind(this), failed.bind(this));
163179
};
164180

165181
HttpProvider.prototype.disconnect = function () {

packages/web3-providers-http/types/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export class HttpProvider extends HttpProviderBase {
4949
timeout: number;
5050
headers?: HttpHeader[];
5151
agent?: HttpProviderAgent;
52+
forceGlobalFetch?: boolean;
5253
connected: boolean;
5354

5455
constructor(host?: string, options?: HttpProviderOptions);

test/httpprovider.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ var http = require('http');
77
var https = require('https');
88
var Web3 = require('../packages/web3');
99
var HttpProvider = require('../packages/web3-providers-http');
10+
// Mock test with globalThis.fetch func
1011
var fetchMock = require('fetch-mock');
12+
require('cross-fetch/polyfill');
1113

1214
function isObject(object) {
1315
return object != null && typeof object === 'object';
@@ -72,15 +74,14 @@ describe('web3-providers-http', function () {
7274
describe('send', function () {
7375
it('should fail with invalid remote node connection', async function () {
7476

75-
var provider = new HttpProvider('http://localhost:8545');
77+
var provider = new HttpProvider('http://localhost:8545', { forceGlobalFetch: true });
7678
var web3 = new Web3(provider);
7779

7880
await expect(web3.eth.getChainId()).to.be.rejectedWith(Error, "CONNECTION ERROR: Couldn't connect to node http://localhost:8545.");
79-
8081
});
8182

8283
it('should fail for non-json format response', async function () {
83-
var provider = new HttpProvider('/fetchMock');
84+
var provider = new HttpProvider('/fetchMock', { forceGlobalFetch: true });
8485
var web3 = new Web3(provider);
8586

8687
fetchMock.mock('/fetchMock', 'Testing non-json format response');
@@ -90,7 +91,7 @@ describe('web3-providers-http', function () {
9091
});
9192

9293
it('should timeout by delayed response', async function () {
93-
var provider = new HttpProvider('/fetchMock', { timeout: 500 });
94+
var provider = new HttpProvider('/fetchMock', { forceGlobalFetch: true, timeout: 500 });
9495
var web3 = new Web3(provider);
9596

9697
fetchMock.mock('/fetchMock', 'Testing non-json format response', { delay: 1000 });
@@ -100,7 +101,7 @@ describe('web3-providers-http', function () {
100101
});
101102

102103
it('should send basic async request', async function () {
103-
var provider = new HttpProvider('/fetchMock');
104+
var provider = new HttpProvider('/fetchMock', { forceGlobalFetch: true });
104105

105106
var reqObject = {
106107
'jsonrpc': '2.0',

0 commit comments

Comments
 (0)