From cdb7b3e274e00f794560951377dff32edf60105f Mon Sep 17 00:00:00 2001 From: Erwan Guyader Date: Thu, 21 Apr 2022 18:58:50 +0200 Subject: [PATCH] core: Handle `net::*` errors as Fetch errors When making some network requests, we can encounter network errors that are not of the `FetchError` type but are `net` system errors (with error codes starting with `net::`). For example, when switching from one network to another during a file download from the Cozy, the downloading stream will throw an error with the `net::ERR_NETWORKD_CHANGED` code. We want to handle these errors as `FetchError` errors and can do do so by simply looking for the `net::` string in the error message. --- core/remote/errors.js | 10 +++++++++- core/sync/errors.js | 6 +++--- test/unit/remote/errors.js | 18 ++++++++++++++++++ test/unit/sync/errors.js | 19 +++++++++++++++++++ 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 test/unit/remote/errors.js create mode 100644 test/unit/sync/errors.js diff --git a/core/remote/errors.js b/core/remote/errors.js index b7bf9c6e4..53c33c12f 100644 --- a/core/remote/errors.js +++ b/core/remote/errors.js @@ -188,7 +188,7 @@ const wrapError = ( err /*: FetchError | Error */, doc /*: ?SavedMetadata */ ) /*: RemoteError */ => { - if (err.name === 'FetchError') { + if (isNetworkError(err)) { // $FlowFixMe FetchErrors missing status will fallback to the default case const { status } = err @@ -379,6 +379,13 @@ function detail(err /*: FetchError */) /*: ?string */ { return detail } +function isNetworkError(err /*: Error */) { + return ( + err.name === 'FetchError' || + (typeof err.message === 'string' && err.message.includes('net::')) + ) +} + module.exports = { CozyDocumentMissingError, DirectoryNotFound, @@ -405,5 +412,6 @@ module.exports = { UNKNOWN_REMOTE_ERROR_CODE, UNREACHABLE_COZY_CODE, USER_ACTION_REQUIRED_CODE, + isNetworkError, wrapError } diff --git a/core/sync/errors.js b/core/sync/errors.js index 4723fd41c..f4e9dbbf2 100644 --- a/core/sync/errors.js +++ b/core/sync/errors.js @@ -295,10 +295,10 @@ const wrapError = ( return new SyncError({ sideName, err, code: INCOMPATIBLE_DOC_CODE, doc }) } else if (err instanceof remoteErrors.ExcludedDirError) { return new SyncError({ sideName, err, code: EXCLUDED_DIR_CODE, doc }) - } else if (sideName === 'remote' || err.name === 'FetchError') { + } else if (remoteErrors.isNetworkError(err)) { // FetchErrors can be raised from the LocalWriter when failing to download a - // file for example. In this case the sideName will be "local" but the error - // name will still be "FetchError". + // file for example. In this case the error name won't be "FetchError" but + // its message will still contain `net::`. // If err is a RemoteError, its code will be reused. return new SyncError({ sideName, diff --git a/test/unit/remote/errors.js b/test/unit/remote/errors.js new file mode 100644 index 000000000..119de81f5 --- /dev/null +++ b/test/unit/remote/errors.js @@ -0,0 +1,18 @@ +/* eslint-env mocha */ +/* @flow */ + +const should = require('should') + +const remoteErrors = require('../../../core/remote/errors') + +describe('Remote.wrapError', () => { + it('returns an UnreachableCozy error for net::ERR_NETWORKD_CHANGED errors', () => { + const netErr = new Error( + 'Failed request, reason: net::ERR_NETWORKD_CHANGED' + ) + should(remoteErrors.wrapError(netErr)).have.property( + 'code', + remoteErrors.UNREACHABLE_COZY_CODE + ) + }) +}) diff --git a/test/unit/sync/errors.js b/test/unit/sync/errors.js new file mode 100644 index 000000000..25048a462 --- /dev/null +++ b/test/unit/sync/errors.js @@ -0,0 +1,19 @@ +/* eslint-env mocha */ +/* @flow */ + +const should = require('should') + +const remoteErrors = require('../../../core/remote/errors') +const syncErrors = require('../../../core/sync/errors') + +describe('Sync.wrapError', () => { + it('returns an UnreachableCozy error for net::ERR_NETWORKD_CHANGED errors', () => { + const netErr = new Error( + 'Failed request, reason: net::ERR_NETWORKD_CHANGED' + ) + should(syncErrors.wrapError(netErr, 'local')).have.property( + 'code', + remoteErrors.UNREACHABLE_COZY_CODE + ) + }) +})