Skip to content

Protect against ReferenceError when creating SharedWorker #20575

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

zeripath
Copy link
Contributor

Some browsers do not have EventSource within the SharedWorker context even though
it is available in the normal context. This leads to a global error percolating
up to the main page.

Here we simply wrap the new Source in a try/catch and catch the error falling back
to a poller if so.

Fix #20572

Signed-off-by: Andrew Thornton [email protected]

Some browsers do not have EventSource within the SharedWorker context even though
it is available in the normal context. This leads to a global error percolating
up to the main page.

Here we simply wrap the new Source in a try/catch and catch the error falling back
to a poller if so.

Fix go-gitea#20572

Signed-off-by: Andrew Thornton <[email protected]>
Comment on lines +53 to +62
const pollerFn = (timeout, lastCount) => {
if (timeout <= 0) {
return;
}
setTimeout(() => {
const _promise = updateNotificationCountWithCallback(pollerFn, timeout, lastCount);
}, timeout);
};

pollerFn(notificationSettings.MinTimeout, notificationCount.text());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const pollerFn = (timeout, lastCount) => {
if (timeout <= 0) {
return;
}
setTimeout(() => {
const _promise = updateNotificationCountWithCallback(pollerFn, timeout, lastCount);
}, timeout);
};
pollerFn(notificationSettings.MinTimeout, notificationCount.text());
const timeout = notificationSettings.MinTimeout;
const lastCount = notificationCount.text();
if (timeout <= 0) {
return;
}
setTimeout(() => {
const _promise = updateNotificationCountWithCallback(pollerFn, timeout, lastCount);
}, timeout);
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've got rid of the definition of the pollerfn in this suggestion and then you use it later.

What's the point of this change? Why are you redefining as a constant?

It's deliberately structured the way it's structured.

worker.addEventListener('error', (event) => {
console.error(event);
worker.addEventListener('error', (error) => {
if (error.message && error.message === 'ReferenceError: EventSource is not defined') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm absolutely not a fan of comparing against error messages, and even less of doing some strange behavior in that case.
At least add a comment, if comparing against a specific error is impossible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, it's not necessary to use the error message if the error can be detected by a stable method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the specific error? Where is the specific error defined in the specs?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -70,6 +87,10 @@ export function initNotificationCount() {
if (event.data.type === 'notification-count') {
const _promise = receiveUpdateCount(event.data);
} else if (event.data.type === 'error') {
if (event.data.message === 'unable to create Source: ReferenceError: EventSource is not defined') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

worker.port.addEventListener('error', (e) => {
console.error(e);
worker.port.addEventListener('error', (error) => {
if (error.message && error.message === 'unable to create Source: ReferenceError: EventSource is not defined') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

Comment on lines +30 to +39
const fn = (timeout) => {
if (timeout <= 0) {
return;
}
setTimeout(() => {
const _promise = updateStopwatchWithCallback(fn, timeout);
}, timeout);
};

fn(notificationSettings.MinTimeout);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const fn = (timeout) => {
if (timeout <= 0) {
return;
}
setTimeout(() => {
const _promise = updateStopwatchWithCallback(fn, timeout);
}, timeout);
};
fn(notificationSettings.MinTimeout);
const timeout = notificationSettings.MinTimeout;
if (timeout <= 0) {
return;
}
setTimeout(() => {
const _promise = updateStopwatchWithCallback(fn, timeout);
}, timeout);
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No this suggestion is wrong. You have dropped the definition of the fn that is being called.

worker.addEventListener('error', (event) => {
console.error(event);
worker.addEventListener('error', (error) => {
if (error.message && error.message === 'ReferenceError: EventSource is not defined') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

@@ -47,6 +70,10 @@ export function initStopwatch() {
if (event.data.type === 'stopwatches') {
updateStopwatchData(JSON.parse(event.data.data));
} else if (event.data.type === 'error') {
if (event.data.message === 'unable to create Source: ReferenceError: EventSource is not defined') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

worker.port.addEventListener('error', (e) => {
console.error(e);
worker.port.addEventListener('error', (error) => {
if (error.message && error.message === 'ReferenceError: EventSource is not defined') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Jul 31, 2022
@wxiaoguang
Copy link
Contributor

wxiaoguang commented Aug 1, 2022

IMO the root problem here is that the SharedWorker doesn't have EventSource support.

Since the EventSource is only used by Source class, which is created by self.addEventListener('connect',

So, maybe there could be a one-line fix for it (then no need to poll in real-time since the browser is non-standard? and the real-time polling never worked before for such non-standard browsers?).

self.addEventListener('connect', (e) => {
  // return early if there is no EventSource in SharedWorker
  if (!self.EventSource) return;
  ...
}

Or:

  port.addEventListener('message', (event) => {
    ...
    ...
    if (!self.EventSource) {
      // Tell the caller to use poller clearly, but it's still more complex than before
      // I still prefer the one-line fix above, because the real-time polling never worked before 😆 
      port.postMessage({type: 'use-poller'});
    } else {
       source = new Source(url);
       ...
    }
  }

@zeripath
Copy link
Contributor Author

zeripath commented Aug 1, 2022

@wxiaoguang I think you have misunderstood what the purpose of the pollerfn is.

Here the error is such that the source will not work so the pollerfn is called to replace update notifications instead. There is no polling to check if the source is working.

@wxiaoguang
Copy link
Contributor

wxiaoguang commented Aug 1, 2022

I understand it correctly. So the second suggestion is to make a port.postMessage({type: 'use-poller'}); call to tell the caller to use the poller fn (instead of the confusing error message)

@zeripath
Copy link
Contributor Author

zeripath commented Aug 1, 2022

(!self.EventSource) won't work.

You need to be in the shared worker context to check if the eventsource is available.

@wxiaoguang
Copy link
Contributor

It will work, it's already in the context.

The context self is SharedWorkerGlobalScope class.

I have tested

@zeripath
Copy link
Contributor Author

zeripath commented Aug 1, 2022

Fine do it then.

@zeripath zeripath closed this Aug 1, 2022
@wxiaoguang
Copy link
Contributor

I thought that's your honor to do so ........

@zeripath zeripath deleted the fix-20572-protect-against-error-sharedworker branch August 5, 2022 02:12
@zeripath zeripath removed type/bug lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. backport/v1.17 labels Aug 21, 2022
@lunny lunny removed this from the 1.18.0 milestone Dec 20, 2022
@go-gitea go-gitea locked and limited conversation to collaborators May 3, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ReferenceError: EventSource is not defined in Pale Moon
5 participants