(* * <COPYRIGHT> * Copyright 2002 Joachim Schrod Network and Publication Consultance GmbH, Gerd Stolpmann * * <GPL> * This file is part of WDialog. * * WDialog is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * WDialog is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with WDialog; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * </> *) (* $Id: wd_dialog.mli,v 3.7 2004-12-12 17:57:32 stolpmann Exp $ * ---------------------------------------------------------------------- * *) (** This module defines the base class [dialog] from which all dialog * classes should inherit *) open Wd_types open Wd_template val dump_interactors : Format.formatter -> interactors -> unit (** Prints a readable description of the contents of the [interactors] * argument to the passed [formatter]. This function is a valid printer * for the toplevel and the debugger. *) (** The class [dialog] is the implementation of {!Wd_types.dialog_type} that * should be used as base definition for all dialog objects. This class * defines all methods but [handle] and [prepare_page] - these must be * defined in the subclasses provided by the application programmer. * Furthermore, there are some extensions to {!Wd_types.dialog_type} * realized as private methods to simplify access to templates. * These additional methods begin with [t_], but are otherwise named * like the corresponding function in the module {!Wd_template}. * * The class takes three anonymous parameters: * * - The universe for which the dialog is defined * - The name of the dialog in the UI definition * - The environment of the current CGI activation *) class virtual dialog : universe_type -> (* name: *) string -> environment -> object inherit Wd_types.dialog_type (** This class implements [dialog_type] *) (** The following private methods are shortcuts for the {!Wd_template} * module. *) method private t_get : string -> template (** Returns the template *) method private t_apply : template -> (string * tree) list -> tree (** Applies the template, and passes the parameters to it *) method private t_apply_byname : string -> (string * tree) list -> tree (** Applies the named template, and passes the parameters to it *) method private t_apply_lazily : string -> (string * tree) list -> tree (** Constructs the expression that applies the names template on * demand. *) method private t_concat : tree -> tree list -> tree (** Concatenates the [tree list], and put the separator [tree] between * the parts *) method private t_empty : tree (** The empty XML tree *) method private t_text : string -> tree (** The XML tree containing this text *) method private t_html : string -> tree (** The XML tree containing this HTML material *) method private t_to_string : tree -> string (** Evaluates the XML tree in the current environment, and returns * the corresponding output string (HTML code) *) method private put_tree : string -> Wd_template.tree -> unit (** Sets the [string] variable to the string representation * of the [tree] *) end (** {b Construction} * [new dialog universe name env]: Makes a new dialog called [name] which * is bound to the [universe] * * Normally, the class [dialog] is not used directly. It is intended * to inherit from [dialog], and to define the two methods [prepare_page] * and [handle]; these are virtual in the base class: * * {[class my_dialog universe name env = * object (self) * inherit dialog universe name env * method prepare_page = ... * method handle = ... * end]} * * After defining such a class, you can create a new [my_dialog] by * [new my_dialog universe "my_dialog" env]. * However, it is not recommended to do it this way. The module {!Wd_universe} * includes a registry of constructors, and every dialog should put * its constructor into it: * * [universe # register "my_dialog" (new my_dialog)] * * For example, you can place this statement where you call * {!Wd_run_cgi.run}: * * {[let universe = new Wd_universe.universe in * universe # register ...; * Wd_run_cgi.run ... ~universe]} * * After the dialog has been registered, you can create new instances * of the dialog by calling [universe#create]: * * [let dlg = universe # create env "my_dialog"] *) class instant_session_manager : unit -> Wd_types.session_manager_type (** The "instant" session manager serializes the state of the dialog, * and includes it literally into the HTML form. The serialized string is included * in the generated HTML forms, and passed by CGI parameter from one activation * to the next activation. The advantages are that you need not to set up any * database to store the sessions, and that the session state is included * in the history of the browser. The disadvantages are increased network * traffic, and missing protection of the session data (the end user can * decode the session state), i.e. the class is insecure, and should only * be used in trusted environments. *) exception Invalid_session_checksum (** Raised when the session checksum as stored in the database is not the * same that is transmitted by the browser. This normally means that a * historic page was submitted ("Back" button). *) exception Session_not_found (** Raises when the current session was not found in the database. *) class database_session_manager : ?private_key : string -> ?enable_checksum : bool -> allocate:(unit -> int) -> insert:(int -> string -> unit) -> update:(int -> string -> string -> string -> unit) -> lookup:(int -> string -> (string * string)) -> unit -> Wd_types.session_manager_type (** The database session manager allows it to store the contents of * sessions in databases. The database table should consist of rows * with at least the four columns * * - [id]: The row identifier chosen by the database system. This is * an integer * - [skey]: The secure key consists of 32 hex digits, and is another * identifier for the row that is chosen by WDialog * - [value]: The value is a large BASE64-encoded string. The length * depends on the session size * - [checksum]: A checksum of [value], again 32 hex digits * * Note that sessions stored in databases behave differently with * respect to the history function of the browser. It is not possible * to "go back", or to select historic pages otherwise, and submit * them again. This will be detected by the [database_session_manager], * and the exception [Invalid_session_checksum] will be raised. There * is currently no way to turn this check off, nor to make the * check more fine-grained. (Maybe an implementation with multiple * versions of the same session is the way to go, I don't know yet.) * * The [database_session_manager] does never delete sessions. It is * recommended to remove unused sessions after a timeout period. * * For a transaction-based DBMS, it is sufficient if the [update] * function commits the current transaction. * * @param allocate The function [allocate] must allocate a new [id] * and return it. * * @param insert The function [insert] must insert a new row, containing only * the [id] and the passed [skey]; the other two fields can be * empty (empty string, or "null"). * * @param update The function [update] takes the [id], the [skey], the [value], and * the [checksum] as arguments, and must update the row identified * by [id] and [skey]. It is up to the implementation whether the * [id] or the [skey] is the preferred lookup key; however it MUST * be checked whether the found row has the demanded [skey] for * security reasons; if this is not the case, the exception * [Session_not_found] must be raised. This exception must be * raised, too, if the row cannot be found at all. (If there are * several matching rows, this is an implementation error!) * * @param lookup The function [lookup] gets the [id] and the [skey] as arguments, * and must return the corresponding [value] and [checksum] as * pair. Again, the exception [Session_not_found] must be raised * if the row cannot be found, or the [skey] is wrong. * * @param private_key The optional argument [private_key] can be used to inject randomness * into the algorithm that computes the secure key. This makes the * secure key unpredictable for the user, so nobody can "hijack" a * session by guessing the secure key. * * @param enable_checksum If true (the default), the checksum of the * web request is compared with the database checksum. This ensures that * only responses of the latest dialog state can be processed. By * setting this parameter to [false], the checksum is ignored, and the * user can also submit historical web forms. In general, this is a bad * idea, and you will run into trouble, unless your application is can * cope with that. * *) (* ====================================================================== * History: * * $Log: wd_dialog.mli,v $ * Revision 3.7 2004-12-12 17:57:32 stolpmann * Added <q:wd-link> and <q:wd-xlink> to generate links for * applications that cannot use Javascript. Limited functionality, however. * See stdlib.xml for details. * * Revision 3.6 2003/03/21 20:57:54 stolpmann * ocamldoc problems * * Revision 3.5 2003/03/21 14:23:44 stolpmann * ocamldoc updated * * Revision 3.4 2003/03/09 17:08:29 stolpmann * New class database_session_manager * * Revision 3.3 2002/02/16 17:29:45 stolpmann * mostly ocamldoc. * * Revision 3.2 2002/02/14 16:15:21 stolpmann * Added copyright notice. * * Revision 3.1 2002/02/12 20:29:22 stolpmann * Initial release at sourceforge. * * Revision 1.10 2002/02/05 18:44:16 gerd * New: class instant_session_manager * * Revision 1.9 2002/01/14 15:03:24 gerd * Major change: Typing has been completely revised, and almost * every tiny thing has now a new type. Also renamed a lot. * * Revision 1.8 2000/12/21 15:00:37 gerd * Server popups: The generated "open" function has now a second * parameter which is passed back to the application. The Popup_request * event gets this parameter. The parameter can be used freely by the * application. * * Revision 1.7 2000/12/04 18:27:50 gerd * Added several type and exception definitions that were * previously only accessible in Uiobject_pre. * * Revision 1.6 2000/12/04 12:00:07 gerd * Moved dump_interactors from uiobject_pre to this module. * * Revision 1.5 2000/11/30 18:41:11 gerd * New interface is_server_popup_request. * exn_default_context has been removed. * * Revision 1.4 2000/05/15 11:46:33 gerd * Necessary changes for uidebugger. * * Revision 1.3 2000/05/08 15:31:26 gerd * New methods: exn_object_declaration and exn_default_context. * * Revision 1.2 2000/04/17 10:10:52 gerd * New Cgi module. * File upload strongly improved. * * Revision 1.1 2000/04/13 17:42:58 gerd * Initial revision. * * *)