From 4a412bb432a9dd05629bec3daa8fe7c86573ea63 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Oct 2022 12:39:11 +0200 Subject: [PATCH] Fix for potential race condition in packages search (#13153) * search on input allowing to wait for copy/paste etc * invoke resourcePromise() with correct parameters * return the xhrStatus allowing the caller to check if the request was aborted * fix: send in canceler.promise to allow the timeout to work * catch any errors and ignore aborts if they happen * move the logic to handle cancellations outside Angulars $scope.$apply * remove file accidentally committed --- .../ourpackagerrepository.resource.js | 8 ++-- .../services/umbrequesthelper.service.js | 3 +- .../views/packages/views/repo.controller.js | 38 +++++++++++++------ .../src/views/packages/views/repo.html | 2 +- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/ourpackagerrepository.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/ourpackagerrepository.resource.js index be13e6d0ec..430f05c2c4 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/ourpackagerrepository.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/ourpackagerrepository.resource.js @@ -57,7 +57,7 @@ function ourPackageRepositoryResource($q, $http, umbDataFormatter, umbRequestHel if (canceler) { httpConfig["timeout"] = canceler; } - + if (category === undefined) { category = ""; } @@ -69,8 +69,10 @@ function ourPackageRepositoryResource($q, $http, umbDataFormatter, umbRequestHel var order = !orderBy ? "&order=Default" : ("&order=" + orderBy); return umbRequestHelper.resourcePromise( - $http.get(baseurl + "?pageIndex=" + pageIndex + "&pageSize=" + pageSize + "&category=" + category + "&query=" + query + order + "&version=" + Umbraco.Sys.ServerVariables.application.version), - httpConfig, + $http.get( + baseurl + "?pageIndex=" + pageIndex + "&pageSize=" + pageSize + "&category=" + category + "&query=" + query + order + "&version=" + Umbraco.Sys.ServerVariables.application.version, + httpConfig + ), 'Failed to query packages'); } diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js index 2b5447cdf6..b419600653 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js @@ -197,7 +197,8 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe return $q.reject({ errorMsg: result.errorMsg, data: result.data, - status: result.status + status: result.status, + xhrStatus: response.xhrStatus }); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js index 8360663be6..b690efacdf 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function PackagesRepoController($scope, $timeout, ourPackageRepositoryResource, $q, localizationService) { + function PackagesRepoController($scope, $timeout, ourPackageRepositoryResource, $q, localizationService, notificationsService) { var vm = this; @@ -197,18 +197,14 @@ var searchDebounced = _.debounce(function (e) { + //a canceler exists, so perform the cancelation operation and reset + if (canceler) { + canceler.resolve(); + } - $scope.$apply(function () { - - //a canceler exists, so perform the cancelation operation and reset - if (canceler) { - canceler.resolve(); - canceler = $q.defer(); - } - else { - canceler = $q.defer(); - } + canceler = $q.defer(); + $scope.$apply(function () { currSort = vm.searchQuery ? "Default" : "Latest"; ourPackageRepositoryResource.search(vm.pagination.pageNumber - 1, @@ -216,7 +212,7 @@ currSort, "", vm.searchQuery, - canceler) + canceler.promise) .then(function (pack) { vm.packages = pack.packages; vm.pagination.totalPages = Math.ceil(pack.total / vm.pagination.pageSize); @@ -224,6 +220,24 @@ vm.loading = false; //set back to null so it can be re-created canceler = null; + }) + .catch(function (err) { + canceler = null; + + if (err) { + // If an abort happened, ignore it since it happened because of a new search + if (err.xhrStatus === 'abort') { + return; + } + + // Otherwise, show the error + if (err.errorMsg) { + notificationsService.error(err.errorMsg); + return; + } + } + + console.error(err); }); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html index f7e976de1e..1c3e3ec5d8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html @@ -17,7 +17,7 @@ localize="placeholder" placeholder="@packager_packageSearch" ng-model="vm.searchQuery" - ng-change="vm.search()" + ng-on-input="vm.search()" no-dirty-check />