/* * Created by PyramIDE. * User: フランスのトトロ aka (David RENÉ) * Date: 07/10/2019 * Time: 10:49 * © David RENÉ */ website with: - controllers - web session in controller - plugin - web page renderer read system/logger.anubis read tools/printable_tree.anubis transmit xlib/web/cookies.anubis transmit xlib/web/web_session.anubis transmit types/controllers_web_site.anubis read plugin/plugin.anubis read making_a_web_site.anubis read xlib/web/plugin/plugin.anubis read config/logger_config.anubis type Previous_Session: not_found, // cannot retrieve the previous state out_of_date(WEB_Session p_session), // the previous state is out of date still_valid(WEB_Session p_session). // the previous state is still valid define Previous_Session retrieve_session ( HTTP_Info http_info, String session_directory, String website_name ) = if find_cookie("session_"+website_name, server_get_cookies(http_headers(http_info))) is { failure then not_found success(cookie) then //println("find_cookie(\"state_"+website_name+"\" success"); with session_name = value(cookie), with file_path = session_directory+"/"+session_name, //unserialize the stored session and his timeout value //println("retrieve session ["+session_name+"]"); if (RetrieveResult((Int, WEB_Session_No_Var)))retrieve(file_path) is ok(d) then ( //println("retrieve session OK ["+session_name+"]"); since d is (time_stamp, s_no_var), with s = to_WEB_Session(s_no_var), if time_stamp < now then ( forget(remove(file_path)); out_of_date(s) ) else still_valid(s) // state has been successfully retrieved ) else not_found } . define (List(String) file_names) -> One make_delete_out_of_date_sessions_function ( String state_directory, (LogLevel, String) -> One logger ) = (List(String) file_names) |-df-> if file_names is { [ ] then unique, [h . t] then if h = "." | h = ".." then df(t) else with file_path = state_directory+"/"+h, if (RetrieveResult((Int, WEB_Session_No_Var)))retrieve(file_path) is ok(d) then ( if d is (time_stamp, data) then if time_stamp < now then //println("session "+h+" out date will be deleted timestamp ["+time_stamp+"] now ["+now+"]"); (forget(remove(file_path)); df(t)) else //println("Session "+h+" still valid ["+time_stamp+"] now ["+now+"]"); df(t) ) else logger(logError, "Can't retreive session "+h+", hence will be deleted"); (forget(remove(file_path)); df(t)) }. define WEB_Session -> String // the function constructed returns the name of the state make_save_session_function ( Int timeout, String state_directory, (LogLevel, String) -> One logger ) = (WEB_Session s_var) |-> //Set the new timeout with time_stamp = now+timeout, s = to_WEB_Session_No_Var(s_var), to_be_saved = (time_stamp,s), //generate new session name //session_name = to_ascii(sha1(s)), session_name = s_var.session_id, //println("make_save_state_function " + state_directory+"/s"+state_name); if save(to_be_saved,state_directory+"/"+session_name) is ok then //logger(logInfo, "----- session ["+session_name+"] saved"+dump_WEB_Session_Fields(*s_var.fields)); session_name else logger(logError, ("Cannot create session file in '"+state_directory+"'.\n")); "" . public type WEB_Page_Renderer: web_page_renderer( String app, //application String name, //renderer name (WEB_Session _session, List(WEB_Plugin), HTML_Partial_Content _content) -> HTTP_Answer page_layout //call back for rendering page ) . define HTTP_Answer error_page ( HTTP_Status http_status, String message, WEB_Session _session, ) = html_page ( http_status, // status [], // list of 'META' tags (empty for this site) body // body of page ( // list of body options [ background_color(rgb(255,200,200)) ], // content of page sequence([ pre("Anubis Web Server - eXtended Lib v1.19.0.0 - Anubis language v1.19"), pre("Error "+to_String(http_status)), pre("Internal message :"+message), br, in_form(html_Id(""),text_area(wan(""), init(dump(_session)), 120, 60)) ]) ) ) . public define WEB_Controller_Result ajax ( HTTP_Answer http_answer )= ajax(failure, http_answer) . public define WEB_Controller_Result ajax ( WEB_Session session, //modified session HTTP_Answer http_answer )= ajax(success(session), http_answer) . public define WEB_Controller_Result ajax ( HTML_Partial_Content content )= ajax(failure, content, ""). public define WEB_Controller_Result ajax ( HTML_Partial_Content content, String additional_script )= ajax(failure, content, additional_script). public define WEB_Controller_Result ajax ( WEB_Session session, //modified session HTML_Partial_Content content )= ajax(success(session), content, ""). public define WEB_Controller_Result ajax ( WEB_Session session, //modified session HTML_Partial_Content content, String additional_script )= ajax(success(session), content, additional_script). public define WEB_Controller_Result ajax ( Printable_tree content )= ajax(failure, content, ""). public define WEB_Controller_Result ajax ( Printable_tree content, String additional_script )= ajax(failure, content, additional_script). public define WEB_Controller_Result ajax ( WEB_Session session, //modified session Printable_tree content )= ajax(success(session), content, ""). public define WEB_Controller_Result ajax ( WEB_Session session, //modified session Printable_tree content, String additional_script )= ajax(success(session), content, additional_script). public define WEB_Controller_Result renderer_content( HTML_Partial_Content content, )= renderer_content(failure, content) . public define WEB_Controller_Result renderer_content( WEB_Session session, //modified session if success else failure HTML_Partial_Content content, )= renderer_content(success(session), content) . public define WEB_Controller_Result partial_content ( HTML_Partial_Content content, )= http_answer(html_page( "", // title of web site [], // list of 'META' tags (empty for this site) body // body of page ( // list of body options [], // content of page partial(content) )) ) . define WEB_Page_Renderer default_page_renderer = web_page_renderer("AWS", "AWS_DEFAULT_PAGE", ( WEB_Session _session, List(WEB_Plugin) _plugins, HTML_Partial_Content _content ) |-> with _title = get_page_title(_session), html_page ( http_ok, [ title(_title), ]// title of web site , body // body of page ( [], //body options empty (HTML_Off_Form)partial(_content) ) ) ) . define WEB_Controller_Result apply_action ( WEB_Session _session, String requested_action_name, List(WEB_Action) actions_list ) = //println("apply_action "); if actions_list is { [] then http_answer(error_page(http_not_found, "["+requested_action_name+"] Action not found in all controllers", _session)), [h . t] then if h.name = no_action then http_answer( _session, html_content(http_no_content, empty)) else with action_name = if h.name is { no_action then "", controller_action(_, name) then name, action_name(name) then name, url(url) then url, }, if requested_action_name = action_name then with step = get_Int(_session.fields, "AWS_SESSION_STEP", 0) + 1, replace_Int(_session.fields, "AWS_SESSION_STEP", step); if h.allowed_proto is { //Action only in HTTP http then if _session.web_request.is_https then http_answer(error_page(http_forbidden, "Only HTTP authorized", _session)) else //ask to the server the authorization to execute that action if h.allow(_session) then h.do_it(_session) else http_answer(error_page(http_unauthorized, "you are not authorized for this action", _session)) //Action only in HTTPS https then if _session.web_request.is_https then //ask to the server the authorization to execute that action if h.allow(_session) then h.do_it(_session) else http_answer(error_page(http_unauthorized, "you are not authorized for this action", _session)) else http_answer(error_page(http_forbidden, "Only HTTPS authorized", _session)) //Action in both HTTP / HTTPS http_https then //ask to the server the authorization to execute that action if h.allow(_session) then //println("do_it "+action_name); h.do_it(_session) else http_answer(error_page(http_unauthorized, "you are not authorized for this action", _session)) } else apply_action(_session, requested_action_name, t) } . define Maybe(WEB_Controller) get_controller ( String controller_name, List(WEB_Controller) controllers, (LogLevel, String) -> One logger //logger )= if controllers is { [] then logger(logWarning, "Can't find controller ["+controller_name+"]"); failure, [h . t] then if h.name = controller_name then //println("Controller ["+controller_name+"] found"); success(h) else get_controller(controller_name, t, logger) } . define WEB_Page_Renderer get_page_renderer ( String renderer_name, List(WEB_Page_Renderer) renderers, (LogLevel, String) -> One logger //logger )= if renderers is { [] then logger(logWarning, "Can't find page_renderer ["+renderer_name+"], use the default"); default_page_renderer, [h . t] then if h.name = renderer_name then //println("renderer_name ["+renderer_name+"] found"); h else //println("renderer_name "+renderer_name+" not matching"); get_page_renderer(renderer_name, t, logger) } . define WEB_Page_Renderer get_page_renderer ( WEB_Session _session, WEB_Page_Renderer _current_page_renderer, List(WEB_Page_Renderer) renderers, (LogLevel, String) -> One logger //logger )= //get the renderer page name to use from the session "AWS_PAGE_RENDERER" if get_mb_String(_session.fields, "AWS_CURRENT_PAGE_RENDERER") is { failure then logger(logWarning, "No renderer defined, use the default"); default_page_renderer, success(renderer_name) then //check if the renderer_page already in cache if renderer_name = _current_page_renderer.name then _current_page_renderer else //if not in cache, use the selector function get_page_renderer(renderer_name, renderers, logger) } . public define JsonValue to_html_ajax_content(Printable_tree content_HTML, String additional_script). public define JsonValue to_html_ajax_content(HTML_Partial_Content content_HTML, CommonInfo cinfo, String additional_script). define String get_controller_from_web_arg ( List(Web_arg) lwa, String default )= if get_String(lwa, "aws_c") is { failure then if get_String(lwa, "aws_controller") is { failure then default, success(controller) then controller} success(controller) then controller } . define (Maybe(WEB_Session), HTTP_Answer) apply_controller_action ( WEB_Controller controller, List(WEB_Plugin) plugins, List(WEB_Controller) controllers, WEB_Page_Renderer _current_page_renderer, List(WEB_Page_Renderer) page_renderers, CommonInfo cinfo, WEB_Session _session, Maybe(String) _mb_action_name, (HTTP_Info, Var(List(Web_arg)), Bool is_https) -> WEB_Session initial_session, (LogLevel, String) -> One logger //logger )= //get the action name with mb_action_name = if _mb_action_name is { failure then if get_String(*_session.web_request.lwa, "aws_a") is { failure then get_String(*_session.web_request.lwa, "aws_action"), success(_an) then success(_an) } success(_an) then success(_an) }, if mb_action_name is { failure then //(failure, error_page(http_not_found, "Action name failure", _session)), with new_session = initial_session(_session.web_request.http_info, _session.web_request.lwa, _session.web_request.is_https), if get_controller(get_controller_from_web_arg(*new_session.web_request.lwa, "root"), controllers, logger) is { failure then (failure, error_page(http_not_found, "Initial Session Controller not found", new_session)), success(new_controller) then apply_controller_action(new_controller, plugins, controllers, _current_page_renderer, page_renderers, cinfo, new_session, failure, initial_session, logger), }, success(action_name) then //logger(logInfo, "ACTION_NAME ["+action_name+"] from IP "+get_String(_session.fields, "IP", "")); if apply_action(_session, action_name, *controller.controller_actions) is { http_answer(session, answer) then since session is web_session(id, lang, entries, current, previous, _), with new_web_session = web_session(id, lang, entries, current, previous, current), // println("***** http_answer(session, answer) record new draw point to *****"); // println("web arguments:"+ // dump_web_arg_values(*current.lwa)); // println("************************************"); (success(new_web_session), answer), http_answer(answer) then since _session is web_session(id, lang, entries, current, previous, _), with new_web_session = web_session(id, lang, entries, current, previous, current), // println("***** http_answer(answer) record new draw point to *****"); // println("web arguments:"+ // dump_web_arg_values(*current.lwa)); // println("************************************"); (success(new_web_session), answer), redirect(new_session) then if get_controller(get_controller_from_web_arg(*new_session.web_request.lwa, "root"), controllers, logger) is { failure then (failure, error_page(http_not_found, "Redirect Controller not found", new_session)), success(new_controller) then apply_controller_action(new_controller, plugins, controllers, _current_page_renderer, page_renderers, cinfo, new_session, failure, initial_session, logger), }, redirect(new_session, r_controller_name, r_action_name) then if get_controller(r_controller_name, controllers, logger) is { failure then (failure, error_page(http_not_found, "Redirect Controller "+r_controller_name+" not found", new_session)), success(new_controller) then apply_controller_action(new_controller, plugins, controllers, _current_page_renderer, page_renderers, cinfo, new_session, success(r_action_name), initial_session, logger), }, redirect_to_previous then if get_controller(get_controller_from_web_arg(*_session.previous_web_request.lwa, "root"), controllers, logger) is { failure then (failure, error_page(http_not_found, "Redirect to previous Controller not found", _session)), success(new_controller) then since _session is web_session(id, lang, entries, _, previous, draw), apply_controller_action(new_controller, plugins, controllers, _current_page_renderer, page_renderers, cinfo, web_session(id, lang, entries, previous, previous, draw), failure, initial_session, logger), }, redirect_to_previous(entries) then if get_controller(get_controller_from_web_arg(*_session.previous_web_request.lwa, "root"), controllers, logger) is { failure then (failure, error_page(http_not_found, "Redirect to previous Controller not found", _session)), success(new_controller) then since _session is web_session(id, lang, _, _, previous, draw), apply_controller_action(new_controller, plugins, controllers, _current_page_renderer, page_renderers, cinfo, web_session(id, lang, entries, previous, previous, draw), failure, initial_session, logger), }, //ajax(answer) then (failure, answer), //ajax with modified session that must be saved ajax(session, answer) then (session, answer), //ajax(content, additional_script) then (failure, json(http_ok, to_html_ajax_content(content, cinfo, additional_script))), ajax(session, content, additional_script) then (session, json(http_ok, to_html_ajax_content(content, cinfo, additional_script))), //ajax(content, additional_script) then (failure, json(http_ok, to_html_ajax_content(content, additional_script))), ajax(session, content, additional_script) then (session, json(http_ok, to_html_ajax_content(content, additional_script))), send_file(file_path, c_disposition) then (failure, send_file(file_path, c_disposition)), renderer_content(session, content) then with the_session = if session is {failure then _session, success(__session) then __session}, since the_session is web_session(id, lang, entries, current, previous, _), with new_web_session = web_session(id, lang, entries, current, previous, current), // println("***** renderer_content(session, content) record new draw point to *****"); // println(dump(new_web_session)); // println("web arguments:"+ // dump_web_arg_values(*current.lwa)); // println("************************************"); with page_renderer = get_page_renderer(new_web_session, _current_page_renderer, page_renderers, logger), (success(new_web_session), page_renderer.page_layout(new_web_session, plugins, content)) } } . public define Web_Site make_web_site_controller_description ( String website_name, // site_UID List(String) common_names, // for example: ["www.our-business.com"] String site_directory, String state_directory, One -> One init, (HTTP_Info, Var(List(Web_arg)), Bool is_https) -> WEB_Session initial_session, (WEB_Session, HTTP_Info, Var(List(Web_arg)), Bool is_https) -> WEB_Session expired_session, Var(List(WEB_Controller)) web_controllers, Var(List(WEB_Page_Renderer)) web_page_renderers, Var(List(WEB_Plugin)) web_plugins, Maybe(WEB_Session) -> List(HTTP_header) additional_headers, List(HTTP_header) constant_additional_headers, Int timeout, Redirections redirections, String charset, List(String) journal_extensions, List(String) journal_headers, (LogLevel, String) -> One logger, //logger String secret, List(MIME) known_mime_types, (String action_name, List(Web_arg) args) -> One before_send_file )= //call the initialization function init(unique); // // make required directories (if needed) // with //web_sites_directory = (String) make_directory(my_anubis_directory+"/web_sites"), base_directory = (String) make_directory(site_directory), // state_directory = make_directory(site_directory+"/states"), forget((String)make_directory(site_directory+"/public")); // // construct tool functions // TODO 'make_separate_web_args_function' must retrieve state_cookies before parsing web_args if using_state_cookies is true with save_session = make_save_session_function(timeout, state_directory, logger), with current_page_renderer = var((WEB_Page_Renderer)default_page_renderer), // with left_menu_list = get_left_menu_from_plugins(*web_plugins), // retrieve_session = make_retrieve_session_function(state_directory, website_name), //separate_web_args = make_separate_web_args_function(state_directory, retrieve_state), //apply_action = make_apply_action_function(actions), // // construct the site handler // site_handler = (Word32 http_port, Word32 https_port) |-> ((String host_name, HTTP_Info http_info, List(Web_arg) _lwa, Bool is_https) |-> //(Printable_tree) logger(logTrace,"host_name "+host_name); logger(logTrace, dump_http_info(http_info)); logger(logTrace, dump_web_arg_values(_lwa)); with cinfo = info(host_name, http_port, https_port, site_directory, secret), //retrieve the previous session and determine the new one with current_session = if retrieve_session(http_info, state_directory, website_name) is { not_found then logger(logInfo, "previous state not found"); initial_session(http_info, var(_lwa), is_https), out_of_date(previous_session) then logger(logInfo, "previous out_of_date"); //expired_session(previous_session, http_info, var(_lwa), is_https), since previous_session is web_session(id, lang, entries, previous, _, draw), replace_String(entries, "IP", http_header_value(http_info.http_headers, "x-forwarded-for", ip_addr_to_string(http_info.ip_address))); web_session(id, lang, entries, web_request(http_info, var(_lwa), is_https), previous, draw) still_valid(previous_session) then since previous_session is web_session(id, lang, entries, previous, _, draw), replace_String(entries, "IP", http_header_value(http_info.http_headers, "x-forwarded-for", ip_addr_to_string(http_info.ip_address))); web_session(id, lang, entries, web_request(http_info, var(_lwa), is_https), previous, draw) }, //apply the action according to current session //since apply_controller_action(get_controller(get_String(lwa, "aws_controller", "root"), *web_controllers), *web_controllers, current_session) since if get_controller(get_controller_from_web_arg(*current_session.web_request.lwa, "root"), *web_controllers, logger) is { failure then (failure, error_page(http_not_found, "Controller not found", current_session)), success(new_controller) then apply_controller_action(new_controller, *web_plugins, *web_controllers, *current_page_renderer, *web_page_renderers, cinfo, current_session, failure, initial_session, logger), } is (mb_new_session, http_answer), //save the session if need and construct the according cookie with cookie_headers = if mb_new_session is { failure then [], success(new_session) then with session_name = save_session(new_session), make_session_cookie_headers(website_name, session_name) }, //formatting and send http answer because this is the last function format(cinfo, //state_name, additional_headers(mb_new_session) + cookie_headers, http_answer, is_https, charset) ), // // make the delete_out_of_date function // delete_out_of_date = make_delete_out_of_date_sessions_function(site_directory+"/states", logger), // // construct the web site description // web_site((Word32 http_port, Word32 https_port) |-> web_site_description(common_names, site_directory, redirections, charset, journal_extensions, journal_headers, logger, secret, known_mime_types, site_handler(http_port,https_port), constant_additional_headers, (HTTP_Info http_info, List(Web_arg) lwa) |-> unique // if separate_web_args(lwa, http_info ) is // swa(mb_previous_state,mb_action_name,operands) then // if mb_action_name is // { // failure then unique // success(an) then before_send_file(an,operands) // } //using_state_cookies ), delete_out_of_date). define (WEB_Session)-> WEB_Controller_Result web_controller_error ( String name )= ( WEB_Session session ) |-> http_answer(session, web_controller_error_page(name)). public define WEB_Controller web_controller ( String name, //controller name Var(List(WEB_Action)) controller_actions //list of all actions of that controller //(WEB_Session)-> WEB_Controller_Result error //Error renderer )= web_controller(name, controller_actions, web_controller_error(name)) .