-
Notifications
You must be signed in to change notification settings - Fork 898
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
Add support for non-binary WebMKS websocket #17200
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉 👍 🍻
lib/websocket_proxy.rb
Outdated
# able to use it :) We workaround this by only forcing the 'uint8utf8' protocol which actually works. | ||
force_uint8 = console.protocol.to_s.end_with?('uint8utf8') | ||
protocols = force_uint8 ? ['uint8utf8'] : ['binary'] | ||
@driver = WebSocket::Driver.rack(self, :protocols => protocols) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see no point of having the condition, is it OK for the client to always send both protocols?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it's a bit complicated. JavaScript SDK (webmks/wmks.min.js
) is eager to grab binary
protocol if offered, even if it doesn't know how to handle it. It took me days to figure, but binary
protocol is simply not working with vCloud, for some reason. It seems to be working with vCenter (InfraManager), but not with vCloud.
That being said, it would be better to patch the JavaScript SDK to use text socket even if binary is offered, but:
a) only minified version of the SDK is available, so the patching is not trivial
b) InfraManager uses the same SDK and actually uses binary sockets, so we're in danger to spoil it there
I don't like it either, but wasn't able to connect otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW: isn't it actually dangerous to list multiple protocols here, since it's just proxy socket?
USER ---> proxy socket ---> MIQ ---> actual socket ---> PROVIDER
If PROVIDER
(actual socket) would only support uint8utf8
protocol, but MIQ (proxy socket) would advertise [binary, uint8utf8]
, then binary wouldn't work anyway I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, then just let's increase the readability:
protocol = console.protocol.to_s.end_with?('uint8utf8') ? 'uint8utf8' : 'binary'
@driver = WebSocket::Driver.rack(self, :protocols => [protocol])
lib/websocket_proxy.rb
Outdated
@@ -51,7 +63,7 @@ def transmit(sockets, is_ws) | |||
@driver.parse(data) | |||
else | |||
@right.fetch(64.kilobytes) do |data| | |||
@driver.binary(data) | |||
@driver.frame(data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please explain this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@driver.binary(data)
forcibly threats data obtained as :binary
(source code) while
@driver.frame(data)
lets underlying library, websocket-driver, probe the type (see this line). In the first case our uint8utf8
data gets spoiled because it's intepreted incorrectly - should be interpreted as :text
but is forcibly interpreted as :binary
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -0,0 +1,31 @@ | |||
class WebsocketWebmksUint8utf8 < WebsocketSSLSocket |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't be better to inherit from the WebsocketWebmks
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would BUT then we can't invoke WebsocketSSLSocket
's constructor to setup SSL stuff for us. On the other hand, we must not invoke WebsocketWebmks
's constructor because it'll start the wrong driver for us, so...
Can you feel the pain? 😄
In other words:
WebsocketWebmksUint8utf8 <--- WebsocketWebmks <--- WebsocketSSLSocket
|------------- super.super ------------------^
From what I know, Ruby does not support invoking super.super
methods, therefore we need to do the ugly copy-pasting here... But maybe I missed something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super (pun intended), keep it like this...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @skateman for a fast reply, you ask very good questions. Please see my answers, looking forward to discuss further. Also, I do know we need unit tests for all this, will try to come up with something.
lib/websocket_proxy.rb
Outdated
# able to use it :) We workaround this by only forcing the 'uint8utf8' protocol which actually works. | ||
force_uint8 = console.protocol.to_s.end_with?('uint8utf8') | ||
protocols = force_uint8 ? ['uint8utf8'] : ['binary'] | ||
@driver = WebSocket::Driver.rack(self, :protocols => protocols) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it's a bit complicated. JavaScript SDK (webmks/wmks.min.js
) is eager to grab binary
protocol if offered, even if it doesn't know how to handle it. It took me days to figure, but binary
protocol is simply not working with vCloud, for some reason. It seems to be working with vCenter (InfraManager), but not with vCloud.
That being said, it would be better to patch the JavaScript SDK to use text socket even if binary is offered, but:
a) only minified version of the SDK is available, so the patching is not trivial
b) InfraManager uses the same SDK and actually uses binary sockets, so we're in danger to spoil it there
I don't like it either, but wasn't able to connect otherwise.
lib/websocket_proxy.rb
Outdated
# able to use it :) We workaround this by only forcing the 'uint8utf8' protocol which actually works. | ||
force_uint8 = console.protocol.to_s.end_with?('uint8utf8') | ||
protocols = force_uint8 ? ['uint8utf8'] : ['binary'] | ||
@driver = WebSocket::Driver.rack(self, :protocols => protocols) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW: isn't it actually dangerous to list multiple protocols here, since it's just proxy socket?
USER ---> proxy socket ---> MIQ ---> actual socket ---> PROVIDER
If PROVIDER
(actual socket) would only support uint8utf8
protocol, but MIQ (proxy socket) would advertise [binary, uint8utf8]
, then binary wouldn't work anyway I think.
lib/websocket_proxy.rb
Outdated
@@ -51,7 +63,7 @@ def transmit(sockets, is_ws) | |||
@driver.parse(data) | |||
else | |||
@right.fetch(64.kilobytes) do |data| | |||
@driver.binary(data) | |||
@driver.frame(data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@driver.binary(data)
forcibly threats data obtained as :binary
(source code) while
@driver.frame(data)
lets underlying library, websocket-driver, probe the type (see this line). In the first case our uint8utf8
data gets spoiled because it's intepreted incorrectly - should be interpreted as :text
but is forcibly interpreted as :binary
.
@@ -0,0 +1,31 @@ | |||
class WebsocketWebmksUint8utf8 < WebsocketSSLSocket |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would BUT then we can't invoke WebsocketSSLSocket
's constructor to setup SSL stuff for us. On the other hand, we must not invoke WebsocketWebmks
's constructor because it'll start the wrong driver for us, so...
Can you feel the pain? 😄
In other words:
WebsocketWebmksUint8utf8 <--- WebsocketWebmks <--- WebsocketSSLSocket
|------------- super.super ------------------^
From what I know, Ruby does not support invoking super.super
methods, therefore we need to do the ugly copy-pasting here... But maybe I missed something?
f44b84b
to
05d8575
Compare
@skateman This one is now green. Please let me know if you'd like to have any additional rspec tests. |
spec/lib/websocket_proxy_spec.rb
Outdated
it_behaves_like('picking protocol', 'spice', WebsocketSocket, ['binary'], true) | ||
it_behaves_like('picking protocol', 'webmks', WebsocketWebmks, ['binary'], true) | ||
it_behaves_like('picking protocol', 'webmks-uint8utf8', WebsocketWebmksUint8utf8, ['uint8utf8'], false) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather prefer include_examples
over it_behaves_like
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also having a hash as arguments can be much more descriptive here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Done.
6833c86
to
8bec11d
Compare
8bec11d
to
f0dd280
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This breaks the VNC console support, I'm suspecting the frame
call on the websocket driver.
Until now, 'binary' protocol for websockets was assumed. But VMware vCloud console access only works via legacy 'uint8utf8' protocol. To make it even more interesting, vCloud's JavaScript SDK actually thinks it supports 'binary', but in fact it doesn't. Well 'binary' protocol works when connecting to vCenter (i.e. `Vmware::InfraManager`), but not for vCloud (`Vmware::CloudManager`). With this commit we implement websocket proxy client for 'uint8utf8' protocol and remove 'binary' from list of offered protocols when 'uint8utf8' is used to make sure JavaScript SDK doesn't overestimate itself (and then fail). Signed-off-by: Miha Pleško <miha.plesko@xlab.si>
061037d
to
374b873
Compare
@skateman I've quickly refactored the code so that we use custom Haven't bothered with unit tests yet, just wanted to ask your opinion. Also, I'd kinly ask you to test against vCenter. Looking forward to be hearing your opinion. PS: Naturally, it would be even better to also refactor the existing |
6d22c44
to
89b9aa3
Compare
@skateman I'm sorry to push you, but is there any chance we try to converge with this PR today? We're catching CFME 4.6.2 code freeze and time is not our friend... So I've just pushed a much nicer implementation of WebsocketProxy than before - I'm quite confident that we're not breaking any exisiting functionality for that reason. TBH I like this solution much more than what we had here before, but am looking forward to be hearing your opinion. In unit tests I've fallen back to |
@miha-plesko I just tested your solution from yesterday and it worked, why did you change it? Introducing a new proxy class is IMO not a good idea. |
89b9aa3
to
061037d
Compare
Checked commit miha-plesko@061037d with ruby 2.3.3, rubocop 0.52.1, haml-lint 0.20.0, and yamllint 1.10.0 lib/websocket_proxy.rb
|
Sorry @skateman, I've pushed back the same code as yesterday. If it works then we're good to go 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add support for non-binary WebMKS websocket (cherry picked from commit 85754f5) https://bugzilla.redhat.com/show_bug.cgi?id=1563364
Gaprindashvili backport details:
|
Until now, 'binary' protocol for websockets was assumed. But VMware vCloud console access only works via legacy 'uint8utf8' protocol. To make it even more interesting, vCloud's JavaScript SDK actually thinks it supports 'binary', but in fact it doesn't. Well 'binary' protocol works when connecting to vCenter (i.e.
Vmware::InfraManager
), but not for vCloud Director (Vmware::CloudManager
).With this commit we extend original (binary) websocket proxy to implement our own uint8utf8 socket proxying.
BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1560517
@miq-bot add_label enhancement,gaprindashvili/yes
@miq-bot assign @skateman
Followup PRs:
ManageIQ/manageiq-ui-classic#3679
ManageIQ/manageiq-providers-vmware#218
/cc @bmclaughlin @gberginc