Fix the race condition with novnc

The first RFP negotiation message potentially arrived
earlier, in which case the message will be swallowed
by the recv() which receive response for the http
request. This commit is to ensure only the response
is removed from the socket buffer, so it won't impact
the following RFP negotiation.

Change-Id: I100e140acbc2d981f7b98e12b3e9ae02844f41fd
Closes-Bug: #1695844
This commit is contained in:
jianghua wang
2017-06-05 03:02:09 +01:00
committed by Jianghua Wang
parent 3d84232d7b
commit a7c054c551
2 changed files with 36 additions and 2 deletions

View File

@@ -147,12 +147,15 @@ class NovaProxyRequestHandlerBase(object):
if connect_info.get('internal_access_path'):
tsock.send("CONNECT %s HTTP/1.1\r\n\r\n" %
connect_info['internal_access_path'])
end_token = "\r\n\r\n"
while True:
data = tsock.recv(4096, socket.MSG_PEEK)
if data.find("\r\n\r\n") != -1:
token_loc = data.find(end_token)
if token_loc != -1:
if data.split("\r\n")[0].find("200") == -1:
raise exception.InvalidConnectionInfo()
tsock.recv(len(data))
# remove the response from recv buffer
tsock.recv(token_loc + len(end_token))
break
# Start proxying

View File

@@ -17,6 +17,8 @@
import mock
import socket
from nova.console import websocketproxy
from nova import exception
from nova import test
@@ -180,6 +182,35 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
self.wh.new_websocket_client)
check_token.assert_called_with(mock.ANY, token="123-456-789")
@mock.patch('nova.consoleauth.rpcapi.ConsoleAuthAPI.check_token')
def test_new_websocket_client_internal_access_path_rfb(self, check_token):
check_token.return_value = {
'host': 'node1',
'port': '10000',
'internal_access_path': 'vmid',
'console_type': 'novnc',
'access_url': 'https://example.net:6080'
}
tsock = mock.MagicMock()
HTTP_RESP = "HTTP/1.1 200 OK\r\n\r\n"
RFB_MSG = "RFB 003.003\n"
# RFB negotiation message may arrive earlier.
tsock.recv.side_effect = [HTTP_RESP + RFB_MSG,
HTTP_RESP]
self.wh.socket.return_value = tsock
self.wh.path = "http://127.0.0.1/?token=123-456-789"
self.wh.headers = self.fake_header
self.wh.new_websocket_client()
check_token.assert_called_with(mock.ANY, token="123-456-789")
self.wh.socket.assert_called_with('node1', 10000, connect=True)
tsock.recv.assert_has_calls([mock.call(4096, socket.MSG_PEEK),
mock.call(len(HTTP_RESP))])
self.wh.do_proxy.assert_called_with(tsock)
@mock.patch.object(websocketproxy, 'sys')
@mock.patch('nova.consoleauth.rpcapi.ConsoleAuthAPI.check_token')
def test_new_websocket_client_py273_good_scheme(