diff --git a/src/index.ts b/src/index.ts index c1818d7..88064f8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -100,6 +100,19 @@ async function fetchResults( state.currentQuery = query const url = new URL(src, window.location.href) + if (url.origin !== window.location.origin) { + // Cancel and invalidate any pending request so it can't render stale results. + if (state.controller) { + state.controller.abort() + state.controller = null + remoteInput.removeAttribute('loading') + remoteInput.dispatchEvent(new CustomEvent('loadend')) + } + remoteInput.dispatchEvent( + new CustomEvent('remote-input-error', { bubbles: true }) + ) + return + } const params = new URLSearchParams(url.search) params.append(remoteInput.getAttribute('param') || 'q', query) url.search = params.toString() @@ -111,21 +124,29 @@ async function fetchResults( remoteInput.setAttribute('loading', '') } - state.controller = makeAbortController() + const controller = makeAbortController() + state.controller = controller let response let html = '' try { response = await fetchWithNetworkEvents(remoteInput, url.toString(), { - signal: state.controller.signal, + signal: controller.signal, credentials: 'same-origin', + mode: 'same-origin', headers: { accept: 'text/fragment+html' } }) html = await response.text() + // A newer request (or a rejected src) superseded this one. + if (state.controller !== controller) return remoteInput.removeAttribute('loading') state.controller = null } catch (error) { - if (error instanceof Error && error.name !== 'AbortError') { + if ( + error instanceof Error && + error.name !== 'AbortError' && + state.controller === controller + ) { remoteInput.removeAttribute('loading') state.controller = null } diff --git a/test/karma.config.js b/test/karma.config.js index 48b6e2f..b1d7605 100644 --- a/test/karma.config.js +++ b/test/karma.config.js @@ -4,6 +4,18 @@ function reply(request, response, next) { response.writeHead(500) response.ok = false response.end('Server error') + } else if (request.url.startsWith('/redirect')) { + const host = request.headers.host || '' + const other = host.startsWith('localhost') ? '127.0.0.1' : 'localhost' + response.writeHead(302, { + location: `http://${other}:${host.split(':')[1]}/results` + }) + response.end() + } else if (request.url.startsWith('/slow')) { + setTimeout(() => { + response.writeHead(200) + response.end('