Add shellinabox console handler
Change-Id: I11d3fecc9c767c95c1c1035806c28769ad7a895b Partially-Implements: bp console-support
This commit is contained in:
parent
ddf694a7c8
commit
7e27639fdb
0
mogan/console/__init__.py
Normal file
0
mogan/console/__init__.py
Normal file
146
mogan/console/shellinabox.py
Normal file
146
mogan/console/shellinabox.py
Normal file
@ -0,0 +1,146 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import select
|
||||
import socket
|
||||
|
||||
import BaseHTTPServer
|
||||
from oslo_context import context
|
||||
import six
|
||||
import SocketServer
|
||||
import urlparse
|
||||
|
||||
from mogan.common import exception
|
||||
from mogan.consoleauth import rpcapi as consoleauth_rpcapi
|
||||
|
||||
|
||||
class ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
rbufsize = 0
|
||||
|
||||
def setup(self):
|
||||
self.connection = self.request
|
||||
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
|
||||
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
|
||||
|
||||
def _connect_to(self, connect_info, soc):
|
||||
host_port = connect_info['host'], connect_info['port']
|
||||
try:
|
||||
soc.connect(host_port)
|
||||
except socket.error as e:
|
||||
self.send_error(404, six.text_type(e))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def _check_valid(self):
|
||||
query = urlparse.urlparse(self.path).query
|
||||
token = urlparse.parse_qs(query).get("token", [""]).pop()
|
||||
referer = self.headers.get('Referer', None)
|
||||
if not token:
|
||||
token = referer.split('?token=')[1]
|
||||
|
||||
ctxt = context.get_admin_context()
|
||||
rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
|
||||
connect_info = rpcapi.check_token(ctxt, token=token)
|
||||
|
||||
if not connect_info:
|
||||
self.send_error(404, 'The token is invalid or has expired')
|
||||
self.connection.close()
|
||||
raise exception.InvalidToken(token=token)
|
||||
|
||||
return connect_info
|
||||
|
||||
def do_CONNECT(self):
|
||||
connect_info = self._check_valid()
|
||||
|
||||
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
if self._connect_to(connect_info, soc):
|
||||
self.log_request(200)
|
||||
self.wfile.write(
|
||||
self.protocol_version +
|
||||
" 200 Connection Established\r\nConnection: close\r\n\r\n")
|
||||
self.wfile.write("\r\n")
|
||||
self._read_write(soc, 300)
|
||||
finally:
|
||||
soc.close()
|
||||
self.connection.close()
|
||||
|
||||
def do_GET(self):
|
||||
connect_info = self._check_valid()
|
||||
|
||||
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
if self._connect_to(connect_info, soc):
|
||||
self.log_request()
|
||||
soc.send("%s %s %s\r\n" % (
|
||||
self.command,
|
||||
urlparse.urlunparse(('', '', self.path, '', '', '')),
|
||||
self.request_version))
|
||||
self.headers['Connection'] = 'close'
|
||||
for key_val in self.headers.items():
|
||||
soc.send("%s: %s\r\n" % key_val)
|
||||
soc.send("\r\n")
|
||||
if self.command != 'GET':
|
||||
length = int(self.headers['content-length'])
|
||||
content = self.rfile.read(length)
|
||||
soc.send("%s\r\n" % content)
|
||||
soc.send("\r\n")
|
||||
self._read_write(soc)
|
||||
finally:
|
||||
soc.close()
|
||||
self.connection.close()
|
||||
|
||||
def _read_write(self, soc, max_idling=20):
|
||||
iw = [self.connection, soc]
|
||||
ow = []
|
||||
count = 0
|
||||
while 1:
|
||||
count += 1
|
||||
(ins, _, exs) = select.select(iw, ow, iw, 3)
|
||||
if exs:
|
||||
break
|
||||
if ins:
|
||||
for i in ins:
|
||||
if i is soc:
|
||||
out = self.connection
|
||||
else:
|
||||
out = soc
|
||||
data = i.recv(8192)
|
||||
if data:
|
||||
out.send(data)
|
||||
count = 0
|
||||
if count == max_idling:
|
||||
break
|
||||
|
||||
def do_OPTIONS(self):
|
||||
try:
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
do_HEAD = do_GET
|
||||
do_POST = do_GET
|
||||
do_PUT = do_GET
|
||||
do_DELETE = do_GET
|
||||
|
||||
|
||||
class ThreadingHTTPServer(SocketServer.ThreadingMixIn,
|
||||
BaseHTTPServer.HTTPServer):
|
||||
def __init__(self, server_address, RequestHandlerClass, logger=None):
|
||||
BaseHTTPServer.HTTPServer.__init__(self, server_address,
|
||||
RequestHandlerClass)
|
||||
|
||||
def service_start(self):
|
||||
self.serve_forever()
|
Loading…
Reference in New Issue
Block a user