Skip to content
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

Implement WebSocket API #2088

Merged
merged 11 commits into from Jan 16, 2018
Merged

Implement WebSocket API #2088

merged 11 commits into from Jan 16, 2018

Conversation

TimothyGu
Copy link
Member

Depends on web-platform-tests/wpt#8746 to be merged and rolled before this could be applied.

Fixes #1195. Closes #2075.

Travis CI will fail due to the tests not being current.

Secure-Close-1005-verify-code.htm: [fail, See https://github.com/websockets/ws/issues/1257]
closing-handshake/003.html*: [fail, See https://github.com/websockets/ws/issues/1257]
interfaces/WebSocket/close/close-basic.html*: [fail, Mutates globals]
interfaces/WebSocket/close/close-connecting.html*: [fail, Potentially buggy test as Chrome fails it too]
Copy link
Member Author

Choose a reason for hiding this comment

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

Firefox doesn’t fail it locally, however (even though wpt.fyi says otherwise). Fixing it seems to require digging through ws module's guts, which I didn't do.

Copy link

@lpinca lpinca Dec 27, 2017

Choose a reason for hiding this comment

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

This assertion fails in ws if close() is called when connecting as the 'close' event is emitted on the same tick.

This patch should fix the issue:

diff --git a/lib/websocket.js b/lib/websocket.js
index e0ed7c5..0730510 100644
--- a/lib/websocket.js
+++ b/lib/websocket.js
@@ -152,8 +152,6 @@ class WebSocket extends EventEmitter {
       this._closeMessage = reason;
       this._closeCode = code;
 
-      if (this._finalized) return;
-
       if (code === 1005) this.close();
       else this.close(code, reason);
     };
@@ -213,15 +211,14 @@ class WebSocket extends EventEmitter {
    * @private
    */
   emitClose () {
-    this.readyState = WebSocket.CLOSED;
-
-    this.emit('close', this._closeCode, this._closeMessage);
-
     if (this._extensions[PerMessageDeflate.extensionName]) {
       this._extensions[PerMessageDeflate.extensionName].cleanup();
     }
 
-    this.removeAllListeners();
+    process.nextTick(() => {
+      this.readyState = WebSocket.CLOSED;
+      this.emit('close', this._closeCode, this._closeMessage);
+    });
   }
 
   /**
@@ -282,7 +279,9 @@ class WebSocket extends EventEmitter {
     }
 
     if (this.readyState === WebSocket.CLOSING) {
-      if (this._closeFrameSent && this._closeFrameReceived) this._socket.end();
+      if (this._closeFrameSent && this._closeFrameReceived && !this._finalized) {
+        this._socket.end();
+      }
       return;
     }

Let me know if you need it or open a PR :)

Copy link
Member Author

Choose a reason for hiding this comment

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

The patch does not fix the issue, unfortunately :( Seems like the actual error thrown is

Error: Parse Error
    at Socket.socketOnData (_http_client.js:439:20)
    at Socket.emit (events.js:159:13)
    at addChunk (_stream_readable.js:265:12)
    at readableAddChunk (_stream_readable.js:252:11)
    at Socket.Readable.push (_stream_readable.js:209:10)
    at TCP.onread (net.js:608:20)

I assume we can't do much about this.

Copy link

Choose a reason for hiding this comment

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

Hmm this is weird.


DIR: websockets

Create-Secure-extensions-empty.htm: [fail, Buggy test as the test does not take into account the mandatory permessage-deflate extension]
Copy link
Member Author

Choose a reason for hiding this comment

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

All browsers fail this test, with Chrome and Firefox failing the same way we do: https://wpt.fyi/websockets/Create-Secure-extensions-empty.htm


Create-Secure-extensions-empty.htm: [fail, Buggy test as the test does not take into account the mandatory permessage-deflate extension]
Secure-Close-1005-verify-code.htm: [fail, See https://github.com/websockets/ws/issues/1257]
closing-handshake/003.html*: [fail, See https://github.com/websockets/ws/issues/1257]
Copy link
Member Author

Choose a reason for hiding this comment

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

These two have a chance of being fixed upstream soon. See linked ticket.

Create-Secure-extensions-empty.htm: [fail, Buggy test as the test does not take into account the mandatory permessage-deflate extension]
Secure-Close-1005-verify-code.htm: [fail, See https://github.com/websockets/ws/issues/1257]
closing-handshake/003.html*: [fail, See https://github.com/websockets/ws/issues/1257]
interfaces/WebSocket/close/close-basic.html*: [fail, Mutates globals]
Copy link
Member Author

Choose a reason for hiding this comment

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

This test passes because we implement things correctly, but because the wrappers are shared across JSDOM windows it will affect the next test, thus causing failures. (This one was a pain to debug as one can imagine.)

Copy link
Member

@Zirro Zirro Dec 28, 2017

Choose a reason for hiding this comment

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

I know at least one more test which behaves this way, though it's among the CSSOM tests and not included here yet. Annoying to debug, indeed.

Since we eventually want to run most failing tests to make sure that they're still failing, we ought to add a new failure reason ([mutates-globals] or something more general?) for these tests to make sure they won't ever run and affect others later. That doesn't need to be done in this pull request though.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agreed on all counts.

We also need a new failure reason for flaky tests. I experienced one of them while auditing which tests we could enable after the WPT roll.

@domenic
Copy link
Member

domenic commented Dec 24, 2017

From what I can tell this also helps with #1629 / #1559, right? (Maybe #1911?) If so a test would be helpful.

@domenic
Copy link
Member

domenic commented Dec 24, 2017

Also it'd be good to add a WPT for the first commit.

@TimothyGu
Copy link
Member Author

TimothyGu commented Dec 26, 2017

Comments addressed. WPT rolled. #1559 fixed. Travis is green.

This PR is ready for review :)

@rgbkrk
Copy link

rgbkrk commented Dec 26, 2017

This is so great to see, thank you @TimothyGu. Wish I could be of help in review, I'll just watch and learn from this one.

resolve();
this._onConnectionClosed(...args);
});
this._ws.on("headers", headers => {
Copy link

Choose a reason for hiding this comment

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

This will be renamed to 'upgrade' in version 4. Listeners will receive the http.IncomingMessage instance.

Copy link
Member

@Zirro Zirro left a comment

Choose a reason for hiding this comment

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

Great work, I can only offer nitpicks.

While not directly related to your code, I notice that the WPT Python server becomes rather noisy during the WebSocket tests. I wonder if we can do something about that without silencing potentially useful information.

Regardless, LGTM :-)

// Event's constructor assumes all options correspond to IDL attributes with the same names, and sets them on `this`.
// That is not the case for these modifier boolean options, but since the options are set on `this` anyway we'll
// access them that way. The spec doesn't say much about the case where keyArg is not one of the valid ones
// (https://www.w3.org/TR/uievents-key/#keys-modifier), but at least Chrome returns false for invalid modifiers. Since
Copy link
Member

@Zirro Zirro Dec 28, 2017

Choose a reason for hiding this comment

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

I think we always try to reference the latest available version of a spec even if that means a draft, so this should probably be https://w3c.github.io/uievents-key/#keys-modifier instead.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yup, my bad.

Copy link
Member

Choose a reason for hiding this comment

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

Bump, in case this was missed.

Create-Secure-extensions-empty.htm: [fail, Buggy test as the test does not take into account the mandatory permessage-deflate extension]
Secure-Close-1005-verify-code.htm: [fail, See https://github.com/websockets/ws/issues/1257]
closing-handshake/003.html*: [fail, See https://github.com/websockets/ws/issues/1257]
interfaces/WebSocket/close/close-basic.html*: [fail, Mutates globals]
Copy link
Member

@Zirro Zirro Dec 28, 2017

Choose a reason for hiding this comment

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

I know at least one more test which behaves this way, though it's among the CSSOM tests and not included here yet. Annoying to debug, indeed.

Since we eventually want to run most failing tests to make sure that they're still failing, we ought to add a new failure reason ([mutates-globals] or something more general?) for these tests to make sure they won't ever run and affect others later. That doesn't need to be done in this pull request though.

@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html dir="rtl">
Copy link
Member

@Zirro Zirro Dec 28, 2017

Choose a reason for hiding this comment

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

Is the "rtl"-direction relevant here, or merely the result of copy-paste?

Copy link
Member Author

Choose a reason for hiding this comment

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

It was a copypasta issue 😕 thanks for spotting!

@TimothyGu
Copy link
Member Author

TimothyGu commented Dec 29, 2017

Hey @Zirro, thanks for the review. I’ll fix the issues as soon as I fully wake up.

@lpinca thanks for giving us the heads-up. how soon do you anticipate ws v4.x to be released? If it’s going to be soon I might just put this PR on hold until it is.

I’ll test out the patch you have for the closing-when-connecting issue. Done; it does not fix the issue. Not much we can do unfortunately.

Another issue we are seeing is around bufferedAmount – basically as it is currently implemented it does something else completely than intended (websockets/ws#492). For now we have a working workaround in jsdom but I’ll take a look at fixing it in ws as well.

@TimothyGu
Copy link
Member Author

@lpinca Something else that could be help greatly is if you could release some RC versions of ws so we could test against it right now, and not have to wait until the formal release. I guess that also helps flesh out the bugs that may have creeped in the major release of ws :)

@lpinca
Copy link

lpinca commented Dec 29, 2017

I'm only waiting for someone to take a look at websockets/ws@4e8bd12 to see if error messages/types are good enough. They have been criticized a lot in the past.

Changes are breaking but trivial so it doesn't have much sense to go through a beta/RC phase.

@TimothyGu
Copy link
Member Author

Permanently upgraded to ws@4. Only 5 failing tests left, none of which we can do much about.


// undefined check included so that we can omit the property in internal usage.
if (eventInitDict.view !== null && eventInitDict.view !== undefined) {
if (eventInitDict && eventInitDict.view !== null && eventInitDict.view !== undefined) {
Copy link
Member

Choose a reason for hiding this comment

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

When could eventInitDict be falsy? I would have though the Web IDL layer would have guaranteed it to be an object by now.

Copy link
Member Author

Choose a reason for hiding this comment

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

When we get lazy and call it like SomeEvent.createImpl(['name'])

blob/Blob-constructor.html: [fail, "- Blob is not a function
- a date is not instanceof Date
- a regexp is not instanceof Regexp
- strange v8 behaviour when error triggered in overridden array length
- HTMLSelectElement does not have indexed properties
- MessageChannel not implemented
- element attributes does not have indexed properties"]
file/File-constructor-endings.html: [needs-await]
file/File-constructor.html: [fail, WPT bug with fix available at https://github.com/w3c/web-platform-tests/pull/8802]
Copy link
Member

Choose a reason for hiding this comment

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

Merged the PR if you want to roll again

sequence<Touch> changedTouches = [];
};

[Constructor(DOMString type, optional TouchEventInit eventInitDict),
Copy link
Member

Choose a reason for hiding this comment

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

Please note in the commit message that this also adds the TouchEvent constructor

Copy link
Member

Choose a reason for hiding this comment

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

Well, I guess it won't work anyway, since we don't implement Touch instances or TouchList.

The `key in wrapper` check is fragile as it is susceptible to changes in
the wrapper's prototype object.
@TimothyGu
Copy link
Member Author

This should be ready to merge.

@domenic domenic merged commit 144b39b into jsdom:master Jan 16, 2018
@TimothyGu TimothyGu deleted the websocket branch January 16, 2018 06:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants