Пример #1
0
 def load_config(self):
     config_kwargs = {
         name: getattr(local_config, name)
         for name in dir(local_config) if not name.startswith("_")
     }
     self.server_config = ServerConfig(debug=self.debug, **config_kwargs)
     self.logger.info(self.server_config.sanitized_dict())
    def __init__(self, server_config, charset='utf-8', debug_mode=False):
        """Inicialização de servidor externo, recebe uma instancia de ServerConfig"""

        # TODO: docstring
        if isinstance(server_config, ServerSignature):
            server_config = ServerConfig(server_config, charset, debug_mode)

        self.server_config = server_config
Пример #3
0
 def __init__(self, config_name="config.json"):
     self.__config = ServerConfig(config_name)
     logging.basicConfig(filename=self.__config.log_file,
                         level=logging.DEBUG,
                         format='%(asctime)s %(message)s')
     self.thread_pool = ThreadPool()
     cache_dir = Path.cwd() / self.__config.cache_dir
     self.cache = CacheStorage(cache_dir)
     self.request_handler = RequestHandler(self.cache)
Пример #4
0
    def test_load_balanced(self):
        # =-=-=-=-=-=-=-
        # read server_config.json and .odbc.ini
        cfg = ServerConfig()

        if cfg.get('catalog_database_type') == "postgres":
            # =-=-=-=-=-=-=-
            # seed load table with fake values - rescA should win
            secs = int(time.time())
            cfg.exec_sql_cmd(
                "insert into r_server_load_digest values ('rescA', 50, %s)" %
                secs)
            cfg.exec_sql_cmd(
                "insert into r_server_load_digest values ('rescB', 75, %s)" %
                secs)
            cfg.exec_sql_cmd(
                "insert into r_server_load_digest values ('rescC', 95, %s)" %
                secs)

            # =-=-=-=-=-=-=-
            # build a logical path for putting a file
            test_file = self.admin.session_collection + "/test_file.txt"

            # =-=-=-=-=-=-=-
            # put a test_file.txt - should be on rescA given load table values
            self.admin.assert_icommand(
                "iput -f ./test_load_balanced_suite.py " + test_file)
            self.admin.assert_icommand("ils -L " + test_file,
                                       'STDOUT_SINGLELINE', "rescA")
            self.admin.assert_icommand("irm -f " + test_file)

            # =-=-=-=-=-=-=-
            # drop rescC to a load of 15 - this should now win
            cfg.exec_sql_cmd(
                "update r_server_load_digest set load_factor=15 where resc_name='rescC'"
            )

            # =-=-=-=-=-=-=-
            # put a test_file.txt - should be on rescC given load table values
            self.admin.assert_icommand(
                "iput -f ./test_load_balanced_suite.py " + test_file)
            self.admin.assert_icommand("ils -L " + test_file,
                                       'STDOUT_SINGLELINE', "rescC")
            self.admin.assert_icommand("irm -f " + test_file)

            # =-=-=-=-=-=-=-
            # clean up our alterations to the load table
            cfg.exec_sql_cmd(
                "delete from r_server_load_digest where resc_name='rescA'")
            cfg.exec_sql_cmd(
                "delete from r_server_load_digest where resc_name='rescB'")
            cfg.exec_sql_cmd(
                "delete from r_server_load_digest where resc_name='rescC'")
        else:
            print 'skipping test_load_balanced due to unsupported database for this test.'
Пример #5
0
class Response:
    __config = ServerConfig()
    __error_page = ErrorPage()

    def __init__(self, code, def_headers=None):
        """
        HTTP response data class
        :type def_headers: dict
        :type code: int
        """
        if def_headers is None:
            def_headers = self.__config.default_headers.copy()
        self.code = code
        if self.__is_error(code):
            self.body = self.__error_page.get_page_content(code)
        else:
            self.body = ""
        self.headers = def_headers
        if len(self.body) != 0:
            body_len = len(bytes(self.body, "utf-8"))
            self.headers["Content-Length"] = body_len

    def add_header(self, name, value):
        """Adds a header for response
        :type value: str
        :type name: str
        """
        self.headers[name] = value

    def get_headers_string(self):
        """Return headers as a string"""
        response = ""
        for row in self.headers:
            response += f"{row}: {self.headers[row]}\r\n"
        return response

    def get_bytes(self):
        """Returns response as byte array"""
        return bytearray(
            f"HTTP/1.1 {self.code}\r\n"
            f"{self.get_headers_string()}\r\n"
            f"{self.body}", "utf-8")

    @staticmethod
    def __is_error(code):
        return int(code / 100) == 4 or int(code / 100) == 5
Пример #6
0
    def _msg_recv(self, bts_msg, orig_tup):
        """Método interno para recebimento de mensagem, enviado como callback
        para a thread separada.  Recebe o byte string da mensagem e a tupla IP
        porta de quem a mensagem foi recebida.  Retornar valores valorados como
        falso implica em para a thread de recebimento de mensagens. Trata mensagens:
            - get_server_list
            - hello
            - halt
            - confirm_token (se estiver aguardado a confirmação)
            - server_list (se estiver aguardado a lista)
            - token (se o valor não foi processado em nenhuma opção anterior e
              a evaluação da mensagem é um token, o token é processado.)"""

        str_msg = self.server_config.decode(bts_msg)

        sig = ServerSignature(*orig_tup, True)
        conf = ServerConfig(sig)

        if str_msg == 'get_server_list':
            return self._recv_server_list_request(conf)
    
        if str_msg == 'hello':
            return self._recv_hello(conf)

        if str_msg == 'halt':
            return False

        if str_msg == 'confirm_token':
            if self.expecting == 'confirm_token':
                return self._recv_confirm_token()

        if self.expecting == 'serverList':
            try:
                result = self._recv_server_list(str_msg)
                self.expecting = False
                return result
            except:
                pass

        try:
            token = eval(str_msg)
            if isinstance(token, Token):
                return self._recv_token(conf, token)
        except:
            return True
Пример #7
0
def update_database_to_latest_version():
    # get config
    cfg = ServerConfig()
    # get current version
    current_schema_version = get_current_schema_version(cfg)
    # get target version
    target_schema_version = get_target_schema_version()
    # check if any work to be done
    if current_schema_version > target_schema_version:
        print_error('Catalog Schema Version is from the future (current=%d > target=%d).' % (
            current_schema_version, target_schema_version))
        return
    if current_schema_version == target_schema_version:
        print('Catalog Schema Version is already up to date (version=%d).' %
              target_schema_version)
        return
    # read possible update sql files
    foundfiles = get_update_files(current_schema_version, cfg.get('catalog_database_type'))
    print_debug('files: %s' % foundfiles)
    updatefiles = {}
    for f in foundfiles:
        version = int(f.split('/')[-1].split('.')[0])
        updatefiles[version] = f
    print_debug('updatefiles: %s' % updatefiles)
    # check all necessary update files exist
    for version in range(current_schema_version + 1, target_schema_version + 1):
        print_debug('checking... %d' % version)
        if version not in updatefiles.keys():
            print_error('ERROR: SQL Update File Not Found for Schema Version %d' % version)
            return
    # run each update sql file
    for version in range(current_schema_version + 1, target_schema_version + 1):
        print('Updating to Catalog Schema... %d' % version)
        print_debug('running: %s' % updatefiles[version])
        result = cfg.exec_sql_file(updatefiles[version])
        if result[2].decode('utf-8') != '':
            print_error('ERROR: SQL did not complete...')
            print_error(result[2])
            return
        print_debug('sql result...')
        print_debug(result)
        # update schema_version in database
        update_schema_version(cfg, version)
    # done
    print('Done.')
Пример #8
0
class ThreadPool:
    __config = ServerConfig()

    def __init__(self):
        """
        Inits a pool of worker threads which serves the clients requests
        """
        self.tasks = Queue(self.__config.threads_count)
        self.workers = []
        for i in range(self.__config.threads_count):
            self.workers.append(Worker(self.tasks, f"worker {i} "))

    def add_task(self, func, *args, **kwargs):
        """Add a task to the queue"""
        self.tasks.put((func, args, kwargs))

    def terminate_all_workers(self):
        """Terminate all workers"""
        for pill in [None for i in range(len(self.workers))]:
            self.tasks.put(pill)
Пример #9
0
class FileCache:
    __config = ServerConfig()

    def __init__(self):
        self.__cache_max_size = self.__config.file_cache_size
        self.__cache_errors = self.__config.file_cache_errors
        self.__read_file_desc = self.__prepare_read_file_desc()

    def get_fd(self, path):
        """
        Get descriptor of specified file
        :param path: path to file
        :return: None or file descriptor
        """
        if self.__cache_errors:
            return self.__read_file_desc(path)
        else:
            try:
                return self.__read_file_desc(path)
            except IOError:
                return None

    def __prepare_read_file_desc(self):
        """
        Wraps a descriptor read function with an LRU cache
        :return: read descriptor func decorated with LRU cache
        """
        @lru_cache(maxsize=self.__cache_max_size)
        def result(filename):
            if self.__cache_errors:
                descriptor = None
                try:
                    descriptor = os.open(filename, os.O_RDONLY)
                except IOError:
                    pass
            else:
                descriptor = os.open(filename, os.O_RDONLY)
            return descriptor

        return result
Пример #10
0
    def __init__(self, signature, start_server=None, timeout_limit = 2, debug_mode = False):
        """Inicialização do servidor, necessita o recebimento da assinatura do
        servidor (instancia de ServerSignature).  Opcionalmente também pode ser
        receber uma instancia de external server para se conectar a rede da
        qual ele faz parte.  Não sendo informado um servidor, será inicializado
        uma nova rede.  Outro parâmetro opcinal é o timeout_limit, default 2,
        que é a quantidade em segundos que o servidor deve esperar uma
        requisição antes de considerar que o servidor para quem foi enviada não
        está no ar."""

        self.server_config = ServerConfig(signature, debug_mode = debug_mode)
        self.timeout_limit = timeout_limit
        self._server_list = set()

        thr = self.server_config.server_thread(self._msg_recv)
        thr.start()
        self.server_thread = thr

        self.token_thread_list = []
        
        self.expecting = False
        if start_server:
            self.expecting = 'serverList'
            start_server.get_server_list(self.signature)
Пример #11
0
def main(argv):
    config_logging()

    # We don't want to be too aggressive with concurrency.
    test_cpu_count = int(multiprocessing.cpu_count() / 4)

    # The build bots tend to be overloaded, so we want to restrict
    # cpu usage to prevent strange timeout issues we have seen in the past.
    # We can increment this once we are building on our own controlled macs
    if platform.system() == 'Darwin':
        test_cpu_count = 2

    parser = argparse.ArgumentParser(
        description="Configures the android emulator cmake project so it can be build"
    )
    parser.add_argument(
        "--out_dir", type=str, required=True, help="The ouput directory")
    parser.add_argument(
        "--dist_dir", type=str, required=True, help="The destination directory")
    parser.add_argument(
        "--build-id",
        type=str,
        default=[],
        required=True,
        dest="build_id",
        help="The emulator build number")
    parser.add_argument(
        "--test_jobs",
        type=int,
        default=test_cpu_count,
        dest="test_jobs",
        help="Specifies  the number of tests to run simultaneously")
    parser.add_argument(
        "--target",
        type=str,
        default=platform.system(),
        help="The build target, defaults to current os")
    parser.add_argument(
        "--qtwebengine",
        action='store_true',
        help="Build emulator with QtWebEngine libraries")
    parser.add_argument(
        "--gfxstream",
        action='store_true',
        help="Build gfxstream libraries")
    parser.add_argument(
        "--crosvm",
        action='store_true',
        help="Build crosvm")

    args = parser.parse_args()
    version = "{0[0]}.{0[1]}.{0[2]}".format(sys.version_info)
    logging.info("Building with %s on %s - %s, Python: %s",
                 PYTHON_EXE,
                 platform.system(),
                 platform.uname(),
                 version)

    target = platform.system().lower()
    if args.target:
        target = args.target.lower()

    if not os.path.isabs(args.out_dir):
        args.out_dir = os.path.join(AOSP_ROOT, args.out_dir)

    # Make sure we have all the build dependencies
    install_deps()

    # This how we are going to launch the python build script
    launcher = [PYTHON_EXE,
                os.path.join(AOSP_ROOT, "external", "qemu", "android", "build", "python",
                             "cmake.py")
                ]

    gfxstream_arg = "--gfxstream"
    crosvm_arg = "--crosvm"

    # Standard arguments for both debug & production.
    if args.qtwebengine:
        qtwebengine_arg = "--qtwebengine"
    else:
        qtwebengine_arg = "--noqtwebengine"
    cmd = [
        qtwebengine_arg, "--noshowprefixforinfo", "--out", args.out_dir,
        "--sdk_build_number", args.build_id, "--target", target, "--dist",
        args.dist_dir, "--test_jobs", str(args.test_jobs)
    ]
    prod = ["--crash", "prod"]
    debug = ["--config", "debug"]

    if args.gfxstream:
        cmd.append(gfxstream_arg)
    if args.crosvm:
        cmd.append(crosvm_arg)

    # Kick of builds for 2 targets. (debug/release)
    with ServerConfig(is_presubmit(args.build_id)) as cfg:
        run(launcher + cmd + prod, cfg.get_env(), 'rel')
        if not args.gfxstream and not args.crosvm:
            run(launcher + cmd + debug, cfg.get_env(), 'dbg')

    logging.info("Build completed!")
Пример #12
0
    system_use_windows = 1

# flask init 配置web文件目录
app = Flask(__name__,
            static_folder="../web/static",
            template_folder='../web/templates')
# app.config['SECRET_KEY'] = 'secret!'
app.config['SECRET_KEY'] = os.urandom(
    24)  # 设置为24位的字符,每次运行服务器都是不同的,所以服务器启动一次上次的session就清除。
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)  # 设置session的保存时间。
app.config['ssl_context'] = 'adhoc'
socketio = SocketIO(app)
M_WEBSOCKET_RESPONSE = 'response'

# config information
server_config = ServerConfig()

# database
mysql_server_ip = server_config.get_mysql_server_ip()
mysql_server_port = server_config.get_mysql_server_port()
mysql_server_account = server_config.get_mysql_server_account()
mysql_server_passwd = server_config.get_mysql_server_passwd()
mysql_server_db = server_config.get_mysql_server_db()

sql_util = sqlHelper(mysql_server_ip, mysql_server_port, mysql_server_account,
                     mysql_server_passwd, mysql_server_db)
sql_util.connect_mysql()

# k8s helper
k8s_config_file = server_config.get_k8s_config_file()
k8sHelper = K8sHelper(k8s_config_file)
Пример #13
0
class ProxyPasser:
    __config = ServerConfig()
    __req_parser = RequestParser()
    __res_parser = ResponseParser()

    def __init__(self, client_socket):
        self.__client = client_socket
        self.__target = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def run(self):
        """
        Init connection client <> target
        :return:
        """
        logging.info(f"Client <> Target opened")

        raw_req = self.__client.recv(8192)
        if raw_req is None:
            logging.info(f"Client terminated (RECV)")
            self.__client.close()
            return
        _, req = self.__req_parser.parse(raw_req)
        host, port = self.__req_parser.get_destination(req)

        full_body = None
        content_len = req.headers.get('Content-Length')
        if content_len:
            full_body = self._read_http_message_content_length(self.__client, req.body, int(content_len))

        transfer_enc = req.headers.get('Transfer-Encoding')
        if transfer_enc == 'chunked':
            full_body = self._read_http_message_chunked_encoding(self.__client, req.body)

        if req.method not in ['POST','PUT', 'PATCH']:
            raw_req = req.headers_raw
        else:
            if not full_body:
                self.__client.close()
                return
            raw_req = req.headers_raw + full_body

        target_host_socket = self.__target
        target_host_socket.connect((host, port))
        target_host_socket.sendall(raw_req)

        raw_rsp = target_host_socket.recv(8192)
        if raw_rsp is None:
            logging.info(f"Server terminated (RECV)")
            self.__close_conn(target_host_socket)
            return
        orig_headers, mod_headers, body = self.__res_parser.parse(raw_rsp)

        full_body = None
        content_len = orig_headers.get('Content-Length')
        if content_len:
            full_body = self._read_http_message_content_length(target_host_socket, body, int(content_len))

        transfer_enc = orig_headers.get('Transfer-Encoding')
        if transfer_enc == 'chunked':
            full_body = self._read_http_message_chunked_encoding(target_host_socket, body)
        # if not full_body:
        #     return
        final_response = mod_headers + full_body
        self.__client.sendall(final_response)
        self.__close_conn(target_host_socket)


    def _read_http_message_content_length(self, client, body_bytes, total_len):
        """Reads request data from socket. If request method or protocol
        are not supported, rejects it"""
        result = body_bytes
        curr_len = len(body_bytes)
        while curr_len < total_len:
            chunk = client.recv(8192)
            if not chunk:
                break
            result += chunk
            curr_len += len(chunk)
        return result

    def _read_http_message_chunked_encoding(self, client, body_bytes):
        """Reads request data from socket. If request method or protocol
                are not supported, rejects it"""
        result = bytearray()
        avail_read = 0
        while True:
            if len(body_bytes) < 2:
                chunk = client.recv(8192)
                if not chunk:
                    break
                body_bytes += chunk

            if avail_read > 0:
                fragment = body_bytes[:avail_read]
                result += fragment
                body_bytes = body_bytes[avail_read:]
                avail_read -= len(fragment)
                if avail_read < 0:
                    avail_read = 0
            else:
                body_decoded = body_bytes.decode('utf-8', errors='ignore').splitlines()
                chunk_line = body_decoded[0]
                if chunk_line == '':
                    chunk_line = body_decoded[1]
                length = int(chunk_line.strip().split(';')[0], 16)
                chunk_line_len = len(chunk_line)
                if length == 0:
                    return result + body_bytes
                result += body_bytes[:length+chunk_line_len]
                avail_read = length + chunk_line_len - len(body_bytes[chunk_line_len:length+chunk_line_len])
                body_bytes = body_bytes[length+chunk_line_len:]
        return result

    def __close_conn(self, target_host_socket):
        """
        Close target and client connections
        :param target_host_socket:
        :return:
        """
        self.__client.close()
        target_host_socket.close()
        logging.info("Client <> Target closed")
Пример #14
0
 def __init__(self, cache_storage: CacheStorage):
     self.__config = ServerConfig()
     self.__cache = cache_storage
Пример #15
0
class ProxyPasser:
    __config = ServerConfig()

    def __init__(self, client_socket, target_socket=None):
        self.__client = client_socket
        if target_socket is not None:
            self.__target = target_socket
        else:
            self.__target = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.__target_host = self.__config.proxy_pass_host
        self.__target_port = self.__config.proxy_pass_port

    def run(self):
        """
        Init connection client <> target
        :return:
        """
        logging.info(f"Client <> Target opened")
        self.__client.setblocking(False)
        target_host_socket = self.__target
        target_host_socket.connect((self.__target_host, self.__target_port))
        target_host_socket.setblocking(False)

        client_data = bytearray()
        target_data = bytearray()
        while True:
            inputs = [self.__client, target_host_socket]
            outputs = []

            if len(client_data) > 0:
                outputs.append(self.__client)

            if len(target_data) > 0:
                outputs.append(target_host_socket)

            try:
                in_rdy, out_rdy, _ = select(inputs, outputs, [], 1.0)
            except Exception as e:
                logging.error(e)
                logging.error(traceback.format_exc())
                break

            data = bytearray()
            for connection in in_rdy:
                try:
                    data = connection.recv(4096)
                except Exception as e:
                    logging.error(e)

                if data is not None:
                    if len(data) > 0:
                        if connection == self.__client:
                            target_data += data
                        else:
                            client_data += data
                    else:
                        self.__close_conn(target_host_socket)
                        return

            for connection in out_rdy:
                if connection == self.__client and len(client_data) > 0:
                    bytes_written = self.__client.send(client_data)
                    if bytes_written > 0:
                        client_data = client_data[bytes_written:]
                elif connection == target_host_socket and len(target_data) > 0:
                    bytes_written = target_host_socket.send(target_data)
                    if bytes_written > 0:
                        target_data = target_data[bytes_written:]

    def __close_conn(self, target_host_socket):
        """
        Close target and client connections
        :param target_host_socket:
        :return:
        """
        self.__client.close()
        target_host_socket.close()
        logging.info("Client <> Target closed")
Пример #16
0
class ErrorPage:
    __errors = [{
        "code":
        400,
        "short_desc":
        "Bad Request",
        "long_desc":
        "Syntax of the request not understood by the server."
    }, {
        "code": 401,
        "short_desc": "Not Authorized",
        "long_desc": "Request requires user authentication"
    }, {
        "code": 402,
        "short_desc": "Payment Required",
        "long_desc": "Reserved for future use."
    }, {
        "code": 403,
        "short_desc": "Forbidden",
        "long_desc": "Server refuses to fulfill the request."
    }, {
        "code":
        404,
        "short_desc":
        "Not Found",
        "long_desc":
        "Document or file requested by the client was not"
        "found."
    }, {
        "code":
        405,
        "short_desc":
        "Method Not Allowed",
        "long_desc":
        "Method specified in the Request-Line was not allowed"
        "for the specified resource."
    }, {
        "code":
        406,
        "short_desc":
        "Not Acceptable",
        "long_desc":
        "Resource requested generates response entities that"
        "has content characteristics not specified in"
        "he accept headers."
    }, {
        "code":
        407,
        "short_desc":
        "Proxy Authentication Required",
        "long_desc":
        "Request requires the authentication with the proxy."
    }, {
        "code":
        408,
        "short_desc":
        "Request Timeout",
        "long_desc":
        "Client fails to send a request in the time allowed"
        "by the server."
    }, {
        "code":
        409,
        "short_desc":
        "Conflict",
        "long_desc":
        "Request was unsuccessful due to a conflict in the"
        "state of the resource."
    }, {
        "code":
        410,
        "short_desc":
        "Gone",
        "long_desc":
        "Resource requested is no longer available with no"
        "forwarding address"
    }, {
        "code":
        411,
        "short_desc":
        "Length Required",
        "long_desc":
        "Server doesn’t accept the request without a valid"
        "Content-Length header field."
    }, {
        "code":
        412,
        "short_desc":
        "Precondition Failed",
        "long_desc":
        "Precondition specified in the Request-Header field"
        "returns false."
    }, {
        "code":
        413,
        "short_desc":
        "Request Entity Too Large",
        "long_desc":
        "Request unsuccessful as the request entity is larger"
        "than that allowed by the server"
    }, {
        "code":
        414,
        "short_desc":
        "Request URL Too Long",
        "long_desc":
        "Request unsuccessful as the URL specified is longer"
        "than the one, the server is willing to process."
    }, {
        "code":
        415,
        "short_desc":
        "Unsupported Media Type",
        "long_desc":
        "Request unsuccessful as the entity of the request is"
        "in a format not supported by the requested resource"
    }, {
        "code":
        416,
        "short_desc":
        "Requested Range Not Satisfiable",
        "long_desc":
        "Request included a Range request-header field"
        "without any range-specifier value"
    }, {
        "code":
        417,
        "short_desc":
        "Expectation Failed",
        "long_desc":
        "Expectation given in the Expect request-header"
        "was not fulfilled by the server."
    }, {
        "code":
        422,
        "short_desc":
        "Unprocessable Entity",
        "long_desc":
        "Request well-formed but unable to process because"
        "of semantic errors"
    }, {
        "code": 423,
        "short_desc": "Locked",
        "long_desc": "Resource accessed was locked"
    }, {
        "code":
        424,
        "short_desc":
        "Failed Dependency",
        "long_desc":
        "Request failed because of the failure of a"
        "previous request"
    }, {
        "code": 426,
        "short_desc": "Upgrade Required",
        "long_desc": "Client should switch to Transport Layer Security"
    }, {
        "code":
        500,
        "short_desc":
        "Internal Server Error",
        "long_desc":
        "Request unsuccessful because of an unexpected"
        "condition encountered by the server."
    }, {
        "code":
        501,
        "short_desc":
        "Not Implemented",
        "long_desc":
        "Request unsuccessful as the server could not "
        "support the functionality needed to fulfill"
        " the request."
    }, {
        "code":
        502,
        "short_desc":
        "Bad Gateway",
        "long_desc":
        "Server received an invalid response from the"
        "upstream server while trying to fulfill the request."
    }, {
        "code":
        503,
        "short_desc":
        "Service Unavailable",
        "long_desc":
        "Request unsuccessful to the server being down"
        "or overloaded."
    }, {
        "code":
        504,
        "short_desc":
        "Gateway Timeout",
        "long_desc":
        "Upstream server failed to send a request in the"
        "time allowed by the server."
    }, {
        "code":
        505,
        "short_desc":
        "HTTP Version Not Supported",
        "long_desc":
        "Server does not support the HTTP version specified"
        "in the request."
    }]
    __instance = None
    __config = ServerConfig()

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, 'instance'):
            cls.__instance = super(ErrorPage, cls).__new__(cls)
        return cls.__instance

    def __init__(self):
        page_loc = Path.cwd() / self.__config.error_page_loc
        if page_loc.is_file():
            with open(page_loc, 'rb') as output:
                self.error_page = output.read().decode("utf-8")
        else:
            logging.error("Error page was not found. Using default.")
            self.error_page = "{{CODE}} {{SHORT_DESC}} {{LONG_DESC}}"

    @lru_cache()
    def get_page_content(self, code):
        """
        Get error page content as string
        :param code: error code
        :return:
        """
        error = next((e for e in self.__errors if e.get("code") == code), None)
        result = self.error_page.replace("{{CODE}}", str(code))
        result = result.replace("{{SHORT_DESC}}", error.get("short_desc"))
        return result.replace("{{LONG_DESC}}", error.get("long_desc"))
Пример #17
0
class RequestHandler:
    __mime: MimeTypes = MimeTypes()
    __work_dir: Path = Path.cwd()
    __buff_size: int = 4096
    __config: ServerConfig = ServerConfig()
    __file_cache: FileCache = FileCache()
    __error_page: ErrorPage = ErrorPage()

    def handle_get(self, request):
        """GET request handler. Returns file to client
        :type request: Request
        """
        logging.info(f'Processing GET request {request.path}')
        path_to_file = self.__get_abs_path(request.path)
        file_descriptor = self.__file_cache.get_fd(path_to_file)
        if file_descriptor and path_to_file.is_file():
            response = Response(code=200)
            response.add_header("Content-Length",
                                str(path.getsize(path_to_file)))
            file_type, charset = self.__mime.guess_type(path_to_file.as_uri())
            response.add_header("Content-Type", file_type)
            return self.__send_file_response(
                response=response, file_descriptor=file_descriptor), response
        else:
            bad_req_response = Response(code=404)
            return self.__send_general_response(
                bad_req_response), bad_req_response

    @staticmethod
    def __send_file_response(response,
                             file_descriptor,
                             buffer_size=__buff_size):
        """Return response func with file loaded from specified path
        :type buffer_size: int
        :type file_descriptor: int
        :type response: Response
        """
        def result(client):
            request_data = response.get_bytes()
            client.sendall(request_data)
            with open(file_descriptor, 'rb', closefd=False) as output:
                while True:
                    data = output.read(buffer_size)
                    if not data:
                        break
                    client.sendall(data)
                output.seek(0)

        return result

    @staticmethod
    def __send_general_response(response):
        """Return simple response func
        :type response: Response
        """
        def result(client):
            data = response.get_bytes()
            client.sendall(data)

        return result

    def __get_abs_path(self, req_path):
        """Helper to get absolute path to requested file
        :type req_path: str
        """
        path_components = req_path.split("/")
        result = self.__work_dir / self.__config.www_dir
        for part in path_components:
            result = result / part
        return result
Пример #18
0
 def __init__(self, config_name="config.json"):
     self.__config = ServerConfig(config_name)
     logging.basicConfig(filename=self.__config.log_file,
                         level=logging.DEBUG,
                         format='%(asctime)s %(message)s')
     self.thread_pool = ThreadPool()