diff --git a/package-lock.json b/package-lock.json index ffd5501c3..d4ea68d84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9918,48 +9918,6 @@ "node-aead-crypto": "^2.0.0" } }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/node-gyp-build": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", @@ -15600,7 +15558,7 @@ "client-oauth2": "^4.2.5", "eventsource": "^2.0.2", "find-my-way": "^8.2.2", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "query-string": "^7.1.1", "rxjs": "5.5.11", "slugify": "^1.4.5" @@ -15641,6 +15599,44 @@ "@sinonjs/commons": "^3.0.1" } }, + "packages/binding-http/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "packages/binding-http/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "packages/binding-http/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "packages/binding-http/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "packages/binding-mbus": { "name": "@node-wot/binding-mbus", "version": "0.9.1", diff --git a/packages/binding-http/package.json b/packages/binding-http/package.json index 303f66ef9..83458ecab 100644 --- a/packages/binding-http/package.json +++ b/packages/binding-http/package.json @@ -39,7 +39,7 @@ "client-oauth2": "^4.2.5", "eventsource": "^2.0.2", "find-my-way": "^8.2.2", - "node-fetch": "^2.6.7", + "node-fetch": "^2.7.0", "query-string": "^7.1.1", "rxjs": "5.5.11", "slugify": "^1.4.5" diff --git a/packages/binding-http/src/http-client-browser.ts b/packages/binding-http/src/http-client-browser.ts index 24e24a8ad..575ddd4ff 100644 --- a/packages/binding-http/src/http-client-browser.ts +++ b/packages/binding-http/src/http-client-browser.ts @@ -13,7 +13,7 @@ * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 ********************************************************************************/ import { ProtocolHelpers } from "@node-wot/core"; -import { RequestInit, Request } from "node-fetch"; +import fetch, { RequestInit, Request } from "node-fetch"; import { Readable } from "stream"; import { HttpForm, HTTPMethodName } from "./http"; import HttpClient from "./http-client-impl"; @@ -24,10 +24,15 @@ export default class BrowserHttpClient extends HttpClient { defaultMethod: HTTPMethodName, additionalOptions?: RequestInit ): Promise { + // See https://github.com/eclipse-thingweb/node-wot/issues/790 if (additionalOptions?.body instanceof Readable) { const buffer = await ProtocolHelpers.readStreamFully(additionalOptions.body); additionalOptions.body = buffer; } return super.generateFetchRequest(form, defaultMethod, additionalOptions); } + + protected async _fetch(request: Request) { + return fetch(request); + } } diff --git a/packages/binding-http/src/http-client-impl.ts b/packages/binding-http/src/http-client-impl.ts index e6e7abbad..30c1e1b02 100644 --- a/packages/binding-http/src/http-client-impl.ts +++ b/packages/binding-http/src/http-client-impl.ts @@ -126,7 +126,7 @@ export default class HttpClient implements ProtocolClient { const request = await this.generateFetchRequest(form, "GET", { headers }); debug(`HttpClient (readResource) sending ${request.method} to ${request.url}`); - const result = await this.fetch(request); + const result = await this.doFetch(request); this.checkFetchResponse(result); @@ -150,7 +150,7 @@ export default class HttpClient implements ProtocolClient { request.url }` ); - const result = await this.fetch(request); + const result = await this.doFetch(request); debug(`HttpClient received ${result.status} from ${result.url}`); @@ -213,7 +213,7 @@ export default class HttpClient implements ProtocolClient { } to ${request.url}` ); - const result = await this.fetch(request); + const result = await this.doFetch(request); debug(`HttpClient received ${result.status} from ${request.url}`); debug(`HttpClient received Content-Type: ${result.headers.get("content-type")}`); @@ -245,7 +245,7 @@ export default class HttpClient implements ProtocolClient { Accept: "application/td+json", }; const request = await this.generateFetchRequest({ href: uri }, "GET", headers); - const response = await this.fetch(request); + const response = await this.doFetch(request); const body = ProtocolHelpers.toNodeStream(response.body as Readable); return new Content(response.headers.get("content-type") ?? "application/td+json", body); } @@ -410,12 +410,29 @@ export default class HttpClient implements ProtocolClient { return request; } - private async fetch(request: Request, content?: Content) { - const result = await fetch(request, { body: content?.body }); + /** + * Performs the fetch operation for the given request. + * + * This method is intended to be overridden in browser implementations due to differences + * in how the fetch operation handles streams in the request body. + * + * @param request - The HTTP request to be sent. + * @returns A promise that resolves to the HTTP response. + */ + protected _fetch(request: Request): Promise { + // TODO: need investigation. Even if the request has already a body + // if we don't pass it again to the fetch as request init the stream is + // not correctly consumed + // see https://github.com/eclipse-thingweb/node-wot/issues/1366. + return fetch(request, { body: request.body }); + } + + private async doFetch(request: Request) { + const result = await this._fetch(request); if (HttpClient.isOAuthTokenExpired(result, this.credential)) { this.credential = await (this.credential as OAuthCredential).refreshToken(); - return await fetch(await this.credential.sign(request)); + return await this._fetch(await this.credential.sign(request)); } return result; diff --git a/packages/binding-http/src/subscription-protocols.ts b/packages/binding-http/src/subscription-protocols.ts index bce8b4f12..32269c9c5 100644 --- a/packages/binding-http/src/subscription-protocols.ts +++ b/packages/binding-http/src/subscription-protocols.ts @@ -50,7 +50,7 @@ export class LongPollingSubscription implements InternalSubscription { timeout: 1000, signal: this.abortController.signal as AbortSignal, }); - const result = await this.client["fetch"](headRequest); + const result = await this.client["doFetch"](headRequest); if (result.ok) resolve(); } @@ -61,7 +61,7 @@ export class LongPollingSubscription implements InternalSubscription { }); debug(`HttpClient (subscribeResource) sending ${request.method} to ${request.url}`); - const result = await this.client["fetch"](request); + const result = await this.client["doFetch"](request); this.client["checkFetchResponse"](result);