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
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
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
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
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
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
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
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
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