예제 #1
0
파일: Static.py 프로젝트: lhotakj/Mamlambo
    def __init__(self, config, request, response):
        response.complete = False

        # check first static stuff
        for extension_static in config.extensions_static:
            extension = list(extension_static)[0].lower()
            values = dict(extension_static).get(extension)
            if request.path_info.lower().endswith(extension):
                # static extension registered, now check the file system
                # remove first character as it's always / so join would not work
                expected_file_path = os.path.join(
                    config.document_root, request.path_info.lstrip('/'))
                try:
                    with open(expected_file_path, "rb") as static_file_reader:
                        static_file_content = static_file_reader.read()
                        response.code = 200
                        response.content_bytes = static_file_content
                        response.mime = values["mime"]
                        response.add_header_from_config(values["headers"])
                        response.end()
                        return
                except Exception as e:
                    response_exception = MamlamboException.render(
                        404,
                        error="Page not found",
                        description="The URL cannot be found.",
                        details="Static file can't be read "
                        "`{expected_file_path}`. ".format(
                            expected_file_path=expected_file_path) + str(e))

                    response.code = response_exception.code
                    response.content_bytes = response_exception.content_bytes
                    response.mime = response_exception.mime
                    response.end()
                    return

        # check and check for dynamic stuff
        for extension_dynamic in config.extensions_dynamic:
            extension = list(extension_dynamic)[0].lower()
            print("extension_dy:" + extension)
            values = dict(extension_dynamic).get(extension)
            if request.path_info.lower().endswith(extension):
                # ok known
                return

        # something got wrong so return an error!
        response_exception = MamlamboException.render(
            404,
            error="Page not found",
            description="The URL is not recognized.",
            details="The extension is not registered in the server. Please "
            "check `extensions` section in your configuration.")
        response.code = response_exception.code
        response.content_bytes = response_exception.content_bytes
        response.mime = response_exception.mime
        response.end()
        return
예제 #2
0
파일: Default.py 프로젝트: lhotakj/Mamlambo
    def __init__(self, config, request, response):

        if request.path_info.endswith("/"):
            map_path = os.path.join(config.document_root,
                                    request.path_info.lstrip('/'))
            if self.check_path(map_path, config, request):
                return
            else:
                response_exception = MamlamboException.render(
                    404,
                    error="Page not found",
                    description="Do default document.",
                    details="The folder `{path_info}` doesn't contain "
                    "a default document, check `default_document` "
                    "section in your configuration.".format(
                        path_info=map_path))
                response.code = response_exception.code
                response.content_bytes = response_exception.content_bytes
                response.mime = response_exception.mime
                response.end()
                return

        else:
            if config.trailing_slash_redirect:
                # try trailing slash
                path_info_with_slash = request.path_info + "/"
                map_path = os.path.join(config.document_root,
                                        path_info_with_slash.lstrip('/'))
                if os.path.exists(map_path) and os.path.isdir(map_path):
                    if self.check_path(map_path, config, request):
                        response.content_str = ""
                        new_url = path_info_with_slash if not request.query_string else \
                            path_info_with_slash + "?" + request.query_string
                        print("redir to: " + new_url)
                        response.add_header("Location", new_url)
                        response.code = 301
                        response.end()
                        return
                    else:
                        response_exception = MamlamboException.render(
                            404,
                            error="Page not found",
                            description="Do default document.",
                            details="The folder `{path_info}` doesn't contain "
                            "a default document, check `default_document` "
                            "section in your configuration.".format(
                                path_info=map_path))
                        response.code = response_exception.code
                        response.content_bytes = response_exception.content_bytes
                        response.mime = response_exception.mime
                        response.end()
                        return
예제 #3
0
 def read_file(self):
     try:
         with open(self.__page_filename) as f:
             self.__page_raw = f.read().strip()
             return True
     except Exception as ex:
         response_exception = MamlamboException.render(
             500,
             error="Page processing error",
             description="File {file_name} cannot be loaded".format(
                 file_name=self.__page_filename))
         self.__page_result = response_exception.content_bytes.decode(
             'UTF-8')
         self.__page_code = response_exception.status
         self.__page_mime = response_exception.mime
         return False
예제 #4
0
 def load_code(self):
     filename = self.__page_code  # solve paths
     r = ""
     try:
         with open(filename) as f:
             r = f.read()
     except Exception as ex:
         response_exception = MamlamboException.render(
             500,
             error="Page processing error",
             description="Code behind File `{file_name}` cannot be loaded".
             format(file_name=self.__page_code))
         self.__page_result = response_exception.content_bytes.decode(
             'UTF-8')
         self.__page_code = response_exception.status
         self.__page_mime = response_exception.mime
         return None
     return r
예제 #5
0
    def process_directive_attributes(self, attributes):
        code = ""
        file_name_folder = os.path.dirname(
            os.path.abspath(self.__page_filename))
        self.__directive_attributes = self.parse_attributes(attributes)
        for atr, val in self.__directive_attributes.items():
            if atr == "code":
                self.__page_code = val
                self.__page_code = os.path.join(file_name_folder, val)
                self.verbose("SOURCE=" + self.__page_code)
                if self.__page_code:
                    self.__page_code_source = self.load_code()
                    if not isinstance(self.__page_code_source, str):
                        return False
                    self.verbose("SOURCE_CODE=" + str(self.__page_code_source))
            elif atr == "mime":
                self.__page_mime = val
            elif atr == "masterpage":
                # absolute like -- /var/www/html/folder/x
                self.__page_master = os.path.normpath(
                    os.path.join(file_name_folder, val))
                # make dynamic -- /folder/x - hack!
                self.__page_master = self.__page_master.replace(
                    Configuration().map_path("/"), "")
            else:

                response_exception = MamlamboException.render(
                    500,
                    error="Page processing error",
                    description="Unknown attribute `{atr}`!".format(atr=atr))
                self.__page_result = response_exception.content_bytes.decode(
                    'UTF-8')
                self.__page_code = response_exception.status
                self.__page_mime = response_exception.mime
                return False
        return True
예제 #6
0
파일: Router.py 프로젝트: lhotakj/Mamlambo
    def __init__(self, env, path_to_configuration=None):

        response = Response()  # instantiate empty singleton
        response.complete = False
        # Singleton.Singleton.reset(response)

        # read the yaml configuration and fill request singleton
        config = Configuration()  # instantiate empty singleton, persistent

        internal_cache = False
        if internal_cache:
            cache = Cache()

        # load only first time
        if not config.loaded:
            exception_response = config.parse_config(env, path_to_configuration)
            if isinstance(exception_response, Response):
                self.__content = [exception_response.content_bytes]
                self.__headers = exception_response.headers_render
                self.__status = exception_response.status
                return

        request = Request.Request()
        exception_response = config.parse_request(env, request)
        if isinstance(exception_response, Response):
            self.__content = [exception_response.content_bytes]
            self.__headers = exception_response.headers_render
            self.__status = exception_response.status
            return

        if internal_cache:
            cached_object = cache.get(request.uri)
            if cached_object:
                (cached_content, cached_headers, cached_status) = cached_object
                self.__content = cached_content
                self.__headers = cached_headers
                self.__status = cached_status
                return

        # process request ---------------------------------------------------------------------------------------
        # 1) check redirections
        Routes(config.redirections, request, response, Mode.redirection)
        if response.complete:
            self.__content = [b'']
            self.__headers = response.headers_render
            self.__status = response.status
            if internal_cache:
                cache.set(url=request.uri, content=[response.content_bytes], headers=response.headers,
                          status=response.status)
            return

        # 2) check routes
        Routes(config.routes, request, response, Mode.route)

        # 3) check default document
        Default.Default(config, request, response)
        if response.complete:
            self.__content = [response.content_bytes]
            self.__headers = response.headers_render
            self.__status = response.status
            if internal_cache:
                cache.set(url=request.uri, content=[response.content_bytes], headers=response.headers,
                          status=response.status)
            return

        # 4) check static content
        Static.Static(config, request, response)
        if response.complete:
            self.__content = [response.content_bytes]
            self.__headers = response.headers_render
            self.__status = response.status
            if internal_cache:
                cache.set(url=request.uri, content=[response.content_bytes], headers=response.headers,
                          status=response.status)
            return

        # print('--after-statisc --')
        # print("response.content=" + str(response.content_bytes))
        # print("response.complete=" + str(response.complete))
        # print("response.status=" + str(response.status))

        Dynamic.RendererMain(request, response)
        if response.complete:
            self.__content = [response.content_bytes]
            self.__headers = response.headers_render
            self.__status = response.status
            return
        else:
            response = MamlamboException.render(
                http_code=404,
                error="Page not found",
                details="The requested resource is not available. Please try to navigate back to the homepage")
            self.__content = [response.content_bytes]
            self.__headers = response.headers_render
            self.__status = response.status

        return
예제 #7
0
    def __init__(self,
                 request,
                 file_name,
                 is_fragment=False,
                 is_nested_call=0,
                 default_response=None):
        self.__request = request
        if default_response:
            self.__page_mime = default_response.mime
            self.__page_headers = default_response.headers
        else:
            self.__page_mime = "text/html"
        self.__http_code = 200
        self.__page_filename = file_name
        self.__is_nested_call = is_nested_call
        self.verbose("RendererDynamic.init('" + str(file_name) +
                     "',is_nested_call=" + str(is_nested_call) + ")")
        if not self.read_file():
            return

        # detect <@page ... > ------------------------------------------------------------------------------------------
        regex_page = r"^(\s+|)*<%(\s+|)*[pP][aA][gG][eE](.*|\n)%>"
        self.verbose("RendererDynamic.after")
        self.verbose("ANALYSIS: self.__page_raw: --")
        self.verbose(self.__page_raw)
        self.verbose("-----------------------------")
        matches = re.findall(regex_page,
                             self.__page_raw,
                             flags=re.IGNORECASE | re.MULTILINE)
        self.verbose("RendererDynamic.matches pages = " + str(matches))
        self.verbose("RendererDynamic.matches len(matches) = " +
                     str(len(matches)))

        len_matches = len(matches)

        # more than one <%page %>
        if len_matches > 1:
            # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!|||||!!
            # ! experimental error handling !!!!!!!!!!
            # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!|||||!!
            # apply to addl
            response_exception = MamlamboException.render(
                500,
                error="Page directive error",
                description="Multiple %page directives")
            self.__page_result = response_exception.content_bytes.decode(
                'UTF-8')
            self.__page_code = response_exception.status
            self.__page_mime = response_exception.mime
            return

        # no <%page %> so expects '<?python: ?>' or shebang '#!/...'
        elif len_matches == 0:
            try:
                self.__page_raw = self.__page_raw.strip("\n").strip("").strip(
                    "\n")
                first_line = str(self.__page_raw.partition('\n')[0]).lower()
                if first_line[:8] == "<?python" or first_line[:3] == "#!/":
                    if self.__page_raw.endswith("?>"):
                        self.__page_raw = self.__page_raw[:-2]
                    lines = self.__page_raw.splitlines()
                    lines[0] = ""
                    self.__page_raw = "\n".join(lines)
                    self.verbose("ONLY CODE:\n---------------" +
                                 self.__page_raw)

                    # execute_code
                    self.execute_code(self.__page_raw)
                    return
                else:  # not decorated so display as static
                    self.__page_result = self.__page_raw
                    self.__http_code = 200
            except Exception as ex:
                response_exception = MamlamboException.render(
                    500,
                    error="Page rendering error",
                    description="Error in rendering.",
                    stack_trace=str(ex).replace("\n", "<br />") + "<br>" +
                    traceback.format_exc().replace("\n", "<br>"))
                self.__page_result = response_exception.content_bytes.decode(
                    'UTF-8')
                self.__http_code = response_exception.code
                self.__page_mime = response_exception.mime
                return

            # return

        # one <%page %>
        elif len_matches == 1:
            attributes_string = " ".join(list(matches[0])).replace("\n",
                                                                   "").strip()
            if not self.process_directive_attributes(attributes_string):
                return
            self.verbose("PAGE ATTRIBUTES: " +
                         str(self.__directive_attributes))
            ok = self.process_directive_page(matches)
            self.verbose("OK in __init__ :" + str(ok))
            if not ok:
                return
            try:
                self.verbose("KAJIKI process:" + self.__page_raw)
                x = kajiki.xml_template.XMLTemplate(source=self.__page_raw,
                                                    is_fragment=is_fragment,
                                                    encoding=u'utf-8',
                                                    autoblocks=None,
                                                    cdata_scripts=False,
                                                    strip_text=True)
                self.__page_result = x().render()
                # dirty trick how to get the response using exec()
                hidden_response = re.findall(
                    r"__HIDDEN__RESPONSE__OUT__=b'.*'", self.__page_raw)
                #if hidden_response:
                #    hidden_response_value = hidden_response[0]
                #    # I have the result, just need to evaluate the HIDDEN variable
                #    self.execute_code(hidden_response_value, set_output=False)

            except Exception as ex:
                response_exception = MamlamboException.render(
                    500,
                    error="Page rendering error",
                    description="An error occurred in rendering.",
                    stack_trace=str(ex)
                    # str(ex).replace("\n", "<br />") + "<br>" +
                    #   traceback.format_exc().replace("\n", "<br>")
                )
                self.__page_result = response_exception.content_bytes.decode(
                    'UTF-8')
                self.__http_code = response_exception.code
                self.__page_mime = response_exception.mime
                return
            return

        # detect <@master ... > ----------------------------------------------------------------------------------------
        regex_master = r"^(\s+|)*<%(\s+|)*[mM][aA][sS][tT][eE][rR](.*|\n)%>"
        matches = re.findall(regex_master,
                             self.__page_raw,
                             flags=re.IGNORECASE | re.MULTILINE)
        self.verbose("RendererDynamic.matches master = " + str(matches))
        if len(matches) > 1:
            self.__page_result = MamlamboException.render(
                500,
                error="Page directive error",
                description="Multiple %master directives")
            return
        elif len(matches) == 1:
            attributes_string = " ".join(list(matches[0])).replace("\n",
                                                                   "").strip()
            if not self.process_directive_attributes(attributes_string):
                return

            if self.__is_nested_call == 0:
                response_exception = MamlamboException.render(
                    500,
                    error="Invalid call",
                    description="Master page cannot be called")
                self.__page_result = response_exception.content_bytes.decode(
                    'UTF-8')
                self.__http_code = response_exception.code
                self.__page_mime = response_exception.mime
                return

            self.verbose("MASTER ATTRIBUTES: " +
                         str(self.__directive_attributes))
            ok = self.process_directive_master(matches)
            if not ok:
                return
예제 #8
0
    def process_directive_page(self, matches):
        self.__type = "page"
        self.__page_raw = re.sub(r"^(\s+|)*<%(\s+|)*[pP][aA][gG][eE](.*|\n)%>",
                                 "", self.__page_raw)
        self.verbose("process_directive_page: in " + self.__type)
        masterpage = None  # to hold source code

        if self.__page_master:
            self.verbose("►►►►► USES MASTER PAGE -")
            page_master_file_name = Configuration().map_path(
                path_info=self.__page_master)
            self.verbose("!RendererDynamic('" + page_master_file_name + "')")
            masterpage = Dynamic(self.__request,
                                 page_master_file_name,
                                 is_nested_call=1)
            self.verbose("!After RendererDynamic of master:" + str(masterpage))
            self.verbose('-- master info')
            self.verbose("master_placeholderse: " +
                         str(masterpage.master_placeholders))
            self.verbose("master_code:\n---\n" +
                         str(masterpage.__page_code_source) + "\n---")
            self.verbose('-- original page')
            self.parse_page_placholders()
            # self.verbose("page_placeholderse: " + str(self.page_placeholders))
            # print(self.__page_raw)
            # TODO:
            self.verbose(">>>>> page_placeholderse: " +
                         json.dumps(self.page_placeholders, indent=2))
            self.verbose(">>>>> master_placeholderse: " +
                         json.dumps(masterpage.master_placeholders, indent=2))

            # validate
            count_page_placeholders = len(self.page_placeholders)
            count_master_placeholders = len(masterpage.master_placeholders)
            if count_page_placeholders > count_master_placeholders:
                response_exception = MamlamboException.render(
                    500,
                    error="Page processing error",
                    description="Inconsistency between mastepage and page. "
                    "The master page contains {m} placeholders, but the page has "
                    "defined more placeholder ({p})".format(
                        m=str(count_master_placeholders),
                        p=str(count_page_placeholders)))
                self.__page_result = response_exception.content_bytes.decode(
                    'UTF-8')
                self.__page_code = response_exception.status
                self.__page_mime = response_exception.mime
                return False
            if count_page_placeholders < count_master_placeholders:
                response_exception = MamlamboException.render(
                    500,
                    error="Page processing error",
                    description="Inconsistency between mastepage and page. "
                    "The master page contains {m} placeholders, but the page has "
                    "defined less placeholder ({p})".format(
                        m=str(count_master_placeholders),
                        p=str(count_page_placeholders)))
                self.__page_result = response_exception.content_bytes.decode(
                    'UTF-8')
                self.__page_code = response_exception.status
                self.__page_mime = response_exception.mime
                return False

            new_page_raw = copy.copy(masterpage.__page_raw)
            # master page - attribute id validation
            for master_placeholder in masterpage.master_placeholders:
                if 'id' not in master_placeholder["attributes"]:
                    response_exception = MamlamboException.render(
                        500,
                        error="Page processing error",
                        description=
                        "Error in masterpage. Missing attribute 'id' in tag {tag}"
                        .format(tag=self.first_tag(master_placeholder["tag"])))
                    self.__page_result = response_exception.content_bytes.decode(
                        'UTF-8')
                    self.__page_code = response_exception.status
                    self.__page_mime = response_exception.mime

                    return False
                else:
                    master_id = master_placeholder["attributes"]["id"]
                    new_content = None
                    for page_placeholder in self.page_placeholders:
                        if 'id' not in page_placeholder["attributes"]:
                            response_exception = MamlamboException.render(
                                500,
                                error="Page processing error",
                                description=
                                "Error in page. Missing attribute 'id' in tag {tag}"
                                .format(tag=self.first_tag(
                                    page_placeholder["tag"])))
                            self.__page_result = response_exception.content_bytes.decode(
                                'UTF-8')
                            self.__page_code = response_exception.status
                            self.__page_mime = response_exception.mime
                            return False
                        else:
                            self.verbose("---")
                            self.verbose(page_placeholder['attributes']['id'])
                            if page_placeholder['attributes'][
                                    'id'] == master_id:
                                new_content = page_placeholder['content']
                                break
                    if not new_content:
                        response_exception = MamlamboException.render(
                            500,
                            error="Page processing error",
                            description=
                            "Error in page. Cannot find placeholder from master in page with id='{id}'"
                            .format(id=master_id))
                        self.__page_result = response_exception.content_bytes.decode(
                            'UTF-8')
                        self.__page_code = response_exception.status
                        self.__page_mime = response_exception.mime
                        return False

                    new_page_raw = new_page_raw.replace(
                        master_placeholder["tag"], new_content)

            self.__page_raw = new_page_raw

        # if page_code include the code.py
        regex_doctype = r"<[^\!].*[\^>]*>"  # tags not starting with <! like DOCTYPE
        matches = re.finditer(regex_doctype, self.__page_raw, re.MULTILINE)
        found = False
        for matches_count, match in enumerate(matches, start=0):
            found = True
            # if page has source code, inject it after <!DOCTYPE>

            if masterpage and masterpage.page_code_source:
                include_master_page_source_code = masterpage.page_code_source
            else:
                include_master_page_source_code = ""

            # TODO: REFACTOR
            request = self.__request
            self.verbose("METHOD=" + self.__request.method)
            self.__page_code_source = self.inject_code_for_execute(
                self.__page_code_source, kajiki_patch=False)

            print('~~~~~~~~')
            print('self.__page_code_source:\n' + str(self.__page_code_source))
            print('~~~~~~~~')

            if self.__page_code_source:
                self.__page_raw = self.insert_str(
                    self.__page_raw,
                    "\n<?python\n" + include_master_page_source_code + "\n" +
                    self.__page_code_source + "\n?>", match.end())
            break

        # if markup does not include code behind
        if not found:
            try:
                # no source
                if self.__page_code_source:
                    # execute_code
                    self.execute_code(self.__page_code_source,
                                      kajiki_patch=True)
                else:
                    self.__page_result = ""
            except Exception as ex:
                response_exception = MamlamboException.render(
                    500,
                    error="Page processing error",
                    description="Error executing code.",
                    details=str(ex) + "<br>" + traceback.format_exc())
                self.__page_result = response_exception.content_bytes.decode(
                    'UTF-8')
                self.__page_code = response_exception.status
                self.__page_mime = response_exception.mime
                return None
            finally:
                return False
        return True
예제 #9
0
    def __init__(self,
                 request,
                 file_name,
                 is_fragment=False,
                 is_nested_call=0):
        self.__request = request
        self.__page_mime = "text/html"
        self.__http_code = 200
        self.__page_filename = file_name
        self.__is_nested_call = is_nested_call
        self.verbose("RendererDynamic.init('" + str(file_name) +
                     "',is_nested_call=" + str(is_nested_call) + ")")
        self.read_file()

        # detect <@page ... > ------------------------------------------------------------------------------------------
        regex_page = r"^(\s+|)*<%(\s+|)*[pP][aA][gG][eE](.*|\n)%>"
        self.verbose("RendererDynamic.after")
        self.verbose("ANALYSIS: --")
        self.verbose(self.__page_raw)
        self.verbose("ANALYSIS: --")
        matches = re.findall(regex_page,
                             self.__page_raw,
                             flags=re.IGNORECASE | re.MULTILINE)
        self.verbose("RendererDynamic.matches pages = " + str(matches))
        if len(matches) > 1:
            # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!|||||!!
            # ! experimental error handling !!!!!!!!!!
            # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!|||||!!
            # apply to addl
            response_exception = MamlamboException.render(
                500,
                error="Page directive error",
                description="Multiple %page directives")
            self.__page_result = response_exception.content_bytes.decode(
                'UTF-8')
            self.__page_code = response_exception.status
            self.__page_mime = response_exception.mime
            return
        elif len(matches) == 1:
            attributes_string = " ".join(list(matches[0])).replace("\n",
                                                                   "").strip()
            if not self.process_directive_attributes(attributes_string):
                return
            self.verbose("PAGE ATTRIBUTES: " +
                         str(self.__directive_attributes))
            ok = self.process_directive_page(matches)
            self.verbose("OK in __init__ :" + str(ok))
            if not ok:
                return
            try:
                x = kajiki.xml_template.XMLTemplate(source=self.__page_raw,
                                                    is_fragment=is_fragment,
                                                    encoding=u'utf-8',
                                                    autoblocks=None,
                                                    cdata_scripts=True,
                                                    strip_text=True)
                self.__page_result = x().render()
            except Exception as ex:
                response_exception = MamlamboException.render(
                    500,
                    error="Page rendering error",
                    description="Error in rendering",
                    stack_trace=str(ex).replace("\n", "<br />") + "<br>" +
                    traceback.format_exc().replace("\n", "<br>"))
                self.__page_result = response_exception.content_bytes.decode(
                    'UTF-8')
                self.__http_code = response_exception.code
                self.__page_mime = response_exception.mime
                return
            return

        # detect <@master ... > ----------------------------------------------------------------------------------------
        regex_master = r"^(\s+|)*<%(\s+|)*[mM][aA][sS][tT][eE][rR](.*|\n)%>"
        matches = re.findall(regex_master,
                             self.__page_raw,
                             flags=re.IGNORECASE | re.MULTILINE)
        self.verbose("RendererDynamic.matches master = " + str(matches))
        if len(matches) > 1:
            self.__page_result = MamlamboException.render(
                500,
                error="Page directive error",
                description="Multiple %master directives")
            return
        elif len(matches) == 1:
            attributes_string = " ".join(list(matches[0])).replace("\n",
                                                                   "").strip()
            if not self.process_directive_attributes(attributes_string):
                return

            if self.__is_nested_call == 0:
                response_exception = MamlamboException.render(
                    500,
                    error="Invalid call",
                    description="Master page cannot be called")
                self.__page_result = response_exception.content_bytes.decode(
                    'UTF-8')
                self.__http_code = response_exception.code
                self.__page_mime = response_exception.mime
                return

            self.verbose("MASTER ATTRIBUTES: " +
                         str(self.__directive_attributes))
            ok = self.process_directive_master(matches)
            if not ok:
                return