diff --git a/mogan/console/__init__.py b/mogan/console/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mogan/console/shellinabox.py b/mogan/console/shellinabox.py new file mode 100644 index 00000000..00f1dd14 --- /dev/null +++ b/mogan/console/shellinabox.py @@ -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()